Skip to content

Commit a35caac

Browse files
committed
improve handling of freqencies above sample rate
1 parent df3865f commit a35caac

File tree

1 file changed

+64
-56
lines changed

1 file changed

+64
-56
lines changed

audio.c

Lines changed: 64 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static struct chan {
4949

5050
// square
5151
int duty;
52-
float fval;
52+
int duty_counter;
5353

5454
// noise
5555
uint16_t lfsr_reg;
@@ -58,7 +58,7 @@ static struct chan {
5858

5959
// wave
6060
int sample_cursor;
61-
float sample;
61+
uint8_t sample;
6262
} chans[4];
6363

6464
#define FREQ 44100.0f
@@ -69,7 +69,7 @@ static size_t nsamples;
6969
static float* samples;
7070

7171
static SDL_AudioDeviceID audio;
72-
static const float duty[] = { 0.125, 0.25, 0.5, 0.75 };
72+
static const int duty_lookup[] = { 1, 2, 4, 6 };
7373
static float logbase;
7474
static float vol_l, vol_r;
7575
static const char* notes[] = {
@@ -119,7 +119,6 @@ void update_env(struct chan* c){
119119
}
120120

121121
void update_len(struct chan* c){
122-
123122
if(c->len.enabled){
124123
c->len.counter += c->len.inc;
125124
if(c->len.counter > 1.0f){
@@ -129,16 +128,18 @@ void update_len(struct chan* c){
129128
}
130129
}
131130

132-
int update_freq(struct chan* c){
133-
c->freq_counter += c->freq_inc;
131+
bool update_freq(struct chan* c, float* pos){
132+
float inc = c->freq_inc - *pos;
133+
c->freq_counter += inc;
134134

135-
int result = 0;
136-
while(c->freq_counter > 1.0f){
137-
c->freq_counter -= 1.0f;
138-
result++;
135+
if(c->freq_counter > 1.0f){
136+
*pos = c->freq_inc - (c->freq_counter - 1.0f);
137+
c->freq_counter = 0.0f;
138+
return true;
139+
} else {
140+
*pos = c->freq_inc;
141+
return false;
139142
}
140-
141-
return result;
142143
}
143144

144145
void update_sweep(struct chan* c){
@@ -152,23 +153,21 @@ void update_sweep(struct chan* c){
152153
c->freq += inc;
153154
c->sweep.freq = c->freq;
154155

155-
set_note_freq(c, 4194304 / (float)((2048 - c->freq) << 5));
156+
set_note_freq(c, 4194304.0f / (float)((2048 - c->freq) << 5));
157+
c->freq_inc *= 8.0f;
156158
} else {
157159
c->enabled = 0;
158160
}
159161
c->sweep.counter -= 1.0f;
160162
}
161163
}
162164

163-
float lerp(float a, float b, float t){
164-
return a + (b - a) * t;
165-
}
166-
167165
void update_square(bool ch2){
168166
struct chan* c = chans + ch2;
169167
if(!c->powered) return;
170168

171169
set_note_freq(c, 4194304.0f / (float)((2048 - c->freq) << 5));
170+
c->freq_inc *= 8.0f;
172171

173172
for(int i = 0; i < nsamples; i+=2){
174173
update_len(c);
@@ -177,16 +176,21 @@ void update_square(bool ch2){
177176
update_env(c);
178177
if(!ch2) update_sweep(c);
179178

180-
float d;
181-
if(update_freq(c)){
182-
c->fval = (2*c->freq_counter - c->freq_inc) / c->freq_inc;
183-
} else if((d = c->freq_counter - duty[c->duty]) > 0.0f){
184-
c->fval = MAX(-1.0f, (c->freq_inc - 2*d) / c->freq_inc);
185-
} else {
186-
c->fval = 1.0f;
187-
}
179+
float pos = 0.0f;
180+
float prev_pos = 0.0f;
181+
float sample = 0.0f;
188182

189-
float sample = hipass(c, c->fval * (c->volume / 15.0f));
183+
while(update_freq(c, &pos)){
184+
c->duty_counter = (c->duty_counter + 1) & 7;
185+
sample += ((pos - prev_pos) / c->freq_inc) * (float)c->val;
186+
187+
if(!c->duty_counter || c->duty_counter == c->duty){
188+
c->val = ~(c->val-1);
189+
}
190+
prev_pos = pos;
191+
}
192+
sample += ((pos - prev_pos) / c->freq_inc) * (float)c->val;
193+
sample = hipass(c, sample * (c->volume / 15.0f));
190194

191195
if(!c->user_mute){
192196
samples[i+0] += sample * 0.25f * c->on_left * vol_l;
@@ -200,34 +204,41 @@ void update_wave(void){
200204
struct chan* c = chans + 2;
201205
if(!c->powered) return;
202206

203-
set_note_freq(c, 4194304 / (float)((2048 - c->freq) << 5));
204-
c->freq_inc *= 16.0f;
207+
float freq = 4194304.0f / (float)((2048 - c->freq) << 5);
208+
set_note_freq(c, freq);
209+
210+
if(freq >= 131079) c->enabled = false;
211+
else c->freq_inc *= 16.0f;
205212

206213
for(int i = 0; i < nsamples; i+=2){
207214
update_len(c);
208215

209216
if(c->enabled){
210-
float t = 1.0f;
217+
float pos = 0.0f;
218+
float prev_pos = 0.0f;
219+
float sample = 0.0f;
211220

212-
if(update_freq(c)){
221+
while(update_freq(c, &pos)){
213222
c->sample_cursor = c->val;
214223
c->val = (c->val + 1) & 31;
215-
t = c->freq_counter / c->freq_inc;
216-
}
217224

218-
uint8_t s = mem[0xFF30 + c->sample_cursor / 2];
219-
if(c->sample_cursor & 1){
220-
s &= 0xF;
221-
} else {
222-
s >>= 4;
225+
c->sample = mem[0xFF30 + c->sample_cursor / 2];
226+
if(c->sample_cursor & 1){
227+
c->sample &= 0xF;
228+
} else {
229+
c->sample >>= 4;
230+
}
231+
232+
c->sample = (c->volume) ? (c->sample >> (c->volume-1)) : 0;
233+
sample += ((pos - prev_pos) / c->freq_inc) * c->sample;
234+
prev_pos = pos;
223235
}
236+
sample += ((pos - prev_pos) / c->freq_inc) * c->sample;
224237

225238
if(c->volume > 0){
226-
s >>= (c->volume - 1);
227239
float diff = (float[]){ 7.5f, 3.75f, 1.5f }[c->volume - 1];
228-
c->sample = lerp(c->sample, (float)s, t);
240+
sample = hipass(c, (sample - diff) / 7.5f);
229241

230-
float sample = hipass(c, (c->sample - diff) / 7.5f);
231242
if(!c->user_mute){
232243
samples[i+0] += sample * 0.25f * c->on_left * vol_l;
233244
samples[i+1] += sample * 0.25f * c->on_right * vol_r;
@@ -250,24 +261,24 @@ void update_noise(void){
250261
if(c->enabled){
251262
update_env(c);
252263

253-
float sample = c->val;
254-
int count = update_freq(c);
255-
for(int j = 0; j < count; ++j){
264+
float pos = 0.0f;
265+
float prev_pos = 0.0f;
266+
float sample = 0.0f;
267+
268+
while(update_freq(c, &pos)){
256269
c->lfsr_reg = (c->lfsr_reg << 1) | (c->val == 1);
257270

258271
if(c->lfsr_wide){
259272
c->val = !(((c->lfsr_reg >> 14) & 1) ^ ((c->lfsr_reg >> 13) & 1)) ? 1 : -1;
260273
} else {
261274
c->val = !(((c->lfsr_reg >> 6 ) & 1) ^ ((c->lfsr_reg >> 5 ) & 1)) ? 1 : -1;
262275
}
263-
sample += c->val;
276+
sample += ((pos - prev_pos) / c->freq_inc) * c->val;
277+
prev_pos = pos;
264278
}
265-
266-
if(count){
267-
sample /= (float)count;
268-
}
269-
279+
sample += ((pos - prev_pos) / c->freq_inc) * c->val;
270280
sample = hipass(c, sample * (c->volume / 15.0f));
281+
271282
if(!c->user_mute){
272283
samples[i+0] += sample * 0.25f * c->on_left * vol_l;
273284
samples[i+1] += sample * 0.25f * c->on_right * vol_r;
@@ -330,6 +341,7 @@ void audio_reset(void){
330341
memset(chans, 0, sizeof(chans));
331342
memset(samples, 0, nsamples * sizeof(float));
332343
SDL_ClearQueuedAudio(audio);
344+
chans[0].val = chans[1].val = 1;
333345
}
334346

335347
void audio_init(void){
@@ -420,18 +432,14 @@ void chan_trigger(int i){
420432

421433
if(i == 2){ // wave
422434
len_max = 256;
435+
c->val = 0;
423436
} else if(i == 3){ // noise
424437
c->lfsr_reg = 0xFFFF;
438+
c->val = -1;
425439
}
426440

427441
c->len.inc = (256.0f / (float)(len_max - c->len.load)) / FREQ;
428442
c->len.counter = 0.0f;
429-
430-
if(i < 2){
431-
c->val = 1;
432-
} else {
433-
c->val = 0;
434-
}
435443
}
436444

437445
void audio_write(uint16_t addr, uint8_t val){
@@ -479,7 +487,7 @@ void audio_write(uint16_t addr, uint8_t val){
479487
case 0xFF16:
480488
case 0xFF20:
481489
chans[i].len.load = val & 0x3f;
482-
chans[i].duty = val >> 6;
490+
chans[i].duty = duty_lookup[val >> 6];
483491
break;
484492

485493
case 0xFF1B:

0 commit comments

Comments
 (0)