Mercurial > repos > blastem
comparison psg.c @ 964:e6dc30231b83
Fix PSG linear resampling and implement a low pass filter
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 20 Apr 2016 00:18:01 -0700 |
parents | bd549b25c362 |
children | 8d032a368dd5 |
comparison
equal
deleted
inserted
replaced
963:bd549b25c362 | 964:e6dc30231b83 |
---|---|
7 #include "render.h" | 7 #include "render.h" |
8 #include "blastem.h" | 8 #include "blastem.h" |
9 #include <string.h> | 9 #include <string.h> |
10 #include <stdlib.h> | 10 #include <stdlib.h> |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 #include <math.h> | |
13 #define LOWPASS_CUTOFF 3390 | |
12 | 14 |
13 void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame) | 15 void psg_init(psg_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t samples_frame) |
14 { | 16 { |
15 memset(context, 0, sizeof(*context)); | 17 memset(context, 0, sizeof(*context)); |
16 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); | 18 context->audio_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); |
17 context->back_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); | 19 context->back_buffer = malloc(sizeof(*context->audio_buffer) * samples_frame); |
18 context->clock_inc = clock_div; | 20 context->clock_inc = clock_div; |
19 context->sample_rate = sample_rate; | 21 context->sample_rate = sample_rate; |
20 context->samples_frame = samples_frame; | 22 context->samples_frame = samples_frame; |
23 double rc = (1.0 / (double)LOWPASS_CUTOFF) / (2.0 * M_PI); | |
24 double dt = 1.0 / ((double)master_clock / (double)clock_div); | |
25 double alpha = dt / (dt + rc); | |
26 context->lowpass_alpha = (int32_t)(((double)0x10000) * alpha); | |
21 psg_adjust_master_clock(context, master_clock); | 27 psg_adjust_master_clock(context, master_clock); |
22 for (int i = 0; i < 4; i++) { | 28 for (int i = 0; i < 4; i++) { |
23 context->volume[i] = 0xF; | 29 context->volume[i] = 0xF; |
24 } | 30 } |
25 } | 31 } |
125 } | 131 } |
126 } | 132 } |
127 if (context->noise_out) { | 133 if (context->noise_out) { |
128 context->accum += volume_table[context->volume[3]]; | 134 context->accum += volume_table[context->volume[3]]; |
129 } | 135 } |
130 context->sample_count++; | 136 int32_t tmp = context->accum * context->lowpass_alpha + context->last_sample * (0x10000 - context->lowpass_alpha); |
137 context->accum = tmp >> 16; | |
131 | 138 |
132 context->buffer_fraction += context->buffer_inc; | 139 context->buffer_fraction += context->buffer_inc; |
133 if (context->buffer_fraction >= BUFFER_INC_RES) { | 140 if (context->buffer_fraction >= BUFFER_INC_RES) { |
134 context->buffer_fraction -= BUFFER_INC_RES; | 141 context->buffer_fraction -= BUFFER_INC_RES; |
135 uint32_t tmp = context->last_sample * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc)); | 142 int32_t tmp = context->last_sample * ((context->buffer_fraction << 16) / context->buffer_inc); |
136 tmp += context->accum * ((context->buffer_fraction << 16) / context->buffer_inc); | 143 tmp += context->accum * (0x10000 - ((context->buffer_fraction << 16) / context->buffer_inc)); |
137 printf("Last: %d, Cur: %d, Fraction: %d, Inc: %d, Result: %d, Samples: %d, Float: %f, Fixed: %X\n", | |
138 context->last_sample, context->accum, (int)context->buffer_fraction, (int)context->buffer_inc, tmp >> 16, context->sample_count, (float)context->buffer_fraction/(float)context->buffer_inc, (int)((context->buffer_fraction << 16) / context->buffer_inc)); | |
139 | |
140 context->audio_buffer[context->buffer_pos++] = tmp >> 16; | 144 context->audio_buffer[context->buffer_pos++] = tmp >> 16; |
141 context->sample_count = 0; | 145 |
142 if (context->buffer_pos == context->samples_frame) { | 146 if (context->buffer_pos == context->samples_frame) { |
143 if (!headless) { | 147 if (!headless) { |
144 render_wait_psg(context); | 148 render_wait_psg(context); |
145 } | 149 } |
146 } | 150 } |