From a094e5123ba399b23047942671f075b17765d3d6 Mon Sep 17 00:00:00 2001 From: Samuel Walker Date: Tue, 18 Feb 2025 17:15:17 -0700 Subject: [PATCH] Fixed audio buffer popping --- include/audio.h | 1 + lib/audio.c | 183 ++++++++++++++++++++++++++++++------------------ lib/timer.c | 2 +- 3 files changed, 116 insertions(+), 70 deletions(-) diff --git a/include/audio.h b/include/audio.h index 001d83c..5f35b33 100644 --- a/include/audio.h +++ b/include/audio.h @@ -134,6 +134,7 @@ void audio_init(); void audio_tick(); void audio_period_tick(); void lfsr_tick(); +void audio_sample_tick(); u8 audio_read(u16 address); void audio_write(u16 address, u8 value); diff --git a/lib/audio.c b/lib/audio.c index f6e94eb..53b8cd0 100644 --- a/lib/audio.c +++ b/lib/audio.c @@ -12,10 +12,11 @@ #define FRAMES_PER_BUFFER 64 #define TIME_PER_SAMPLE 1.0f / (SAMPLE_RATE/1000.0f/1000.0f) #define TIME_PER_AUDIO_TICK 1.0f / (1048576.0f/1000.0f/1000.0f) -#define AUDIO_TICKS_PER_SAMPLE 2157281.28 / SAMPLE_RATE +#define AUDIO_TICKS_PER_SAMPLE 4194304.0 / SAMPLE_RATE +#define SAMPLES_PER_AUDIO_TICK SAMPLE_RATE / 4194304.0 #define TIME_PER_WAVE_TICK 1.0f / (2104718.0f/1000.0f/1000.0f) #define LFSR_BASE_CLOCK 262144.0f -#define AUDIO_BUFFER_SIZE (int)(SAMPLE_RATE / 10) +#define AUDIO_BUFFER_SIZE FRAMES_PER_BUFFER static audio_context ctx; @@ -103,14 +104,17 @@ static int audio_callback(const void* input_uffer, void *output_buffer, //} for(int i = 0; i < framesPerBuffer; i++) { //samples_occured = samples_occured + AUDIO_TICKS_PER_SAMPLE-1; - while(ctx.buffer_cnt == 0) { - delay(1); - } + //while(ctx.buffer_cnt == 0) { + // delay(1); + //} if(ctx.buffer_cnt == 0) { //samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt); //ctx.sq1_read_index = ctx.sq1_write_index-1; //printf("buffer underflow\n"); - return paContinue; + continue; + //ctx.buffer_cnt++; + //ctx.sq1_read_index--; + //ctx.sq1_read_index %= AUDIO_BUFFER_SIZE; } else { //ctx.buffer_cnt -= (u8)samples_occured; //ctx.sq1_read_index += (u8)samples_occured; @@ -218,9 +222,6 @@ static int audio_callback(const void* input_uffer, void *output_buffer, left *= (float)left_vol/7.0f; right *= (float)right_vol/7.0f; - //left /= 4; - //right /= 4; - left = ctx.sq1_audio_buffer[ctx.sq1_read_index]; right = ctx.sq2_audio_buffer[ctx.sq1_read_index]; ctx.sq1_read_index++; @@ -233,8 +234,8 @@ static int audio_callback(const void* input_uffer, void *output_buffer, if(dacs) { left_out = left - left_cap; right_out = right - right_cap; - left_cap = left - left_out * 0.996f; - right_cap = right - right_out * 0.996f; + left_cap = left - left_out * 0.999958f; + right_cap = right - right_out * 0.999958f; } @@ -333,9 +334,9 @@ void audio_init(){ ctx.sq2_env_direction = false; ctx.sq2_env_pace = 0x0; ctx.sq2_env_timer = 0x0; - ctx.sq1_write_index = 0; + ctx.sq1_write_index = AUDIO_BUFFER_SIZE - 1; ctx.sq1_read_index = 0; - ctx.buffer_cnt = 0; + ctx.buffer_cnt = AUDIO_BUFFER_SIZE - 1; err = Pa_Initialize(); if (err != paNoError) goto error; @@ -345,7 +346,7 @@ void audio_init(){ goto error; } output_parameters.channelCount = 2; - output_parameters.sampleFormat = paFloat32; + output_parameters.sampleFormat = paFloat32 | paNonInterleaved; output_parameters.suggestedLatency = Pa_GetDeviceInfo(output_parameters.device)->defaultLowOutputLatency; output_parameters.hostApiSpecificStreamInfo = NULL; printf("default sample rate: %lf\n", Pa_GetDeviceInfo(output_parameters.device)->defaultSampleRate); @@ -354,9 +355,9 @@ void audio_init(){ NULL, &output_parameters, SAMPLE_RATE, - paFramesPerBufferUnspecified, + FRAMES_PER_BUFFER, paNoFlag, - audio_callback, + NULL, &ctx); if(err != paNoError) goto error; err = Pa_StartStream(stream); @@ -399,51 +400,10 @@ void lfsr_tick() { } } +static double cycles_needed = 0; -void audio_period_tick() { - period_tick++; - u32 end = get_ticks(); - samples_per_sec++; - if (end - start >= 1000) { - printf("Samples In Buffer: %ld\n", ctx.buffer_cnt); - start = end; - samples_per_sec = 0; - } - if(period_tick % 2 == 0){ - ctx.sq1_period_timer++; - ctx.sq2_period_timer++; - - if(ctx.sq1_period_timer >= 0x800) { - ctx.sq1_period_timer = ctx.sq1_period_reset; - ctx.sq1_sample = (ctx.sq1_sample + 1) % 8; - } - - if(ctx.sq2_period_timer >= 0x800) { - ctx.sq2_period_timer = ctx.sq2_period_reset; - ctx.sq2_sample = (ctx.sq2_sample + 1) % 8; - } - } - u8 shift = 0; - if(ctx.ch3_volume == 0b10) { - shift = 1; - } - if(ctx.ch3_volume == 0b00) { - shift = 4; - } - if(ctx.ch3_volume == 0b11) { - shift = 2; - } - ctx.ch3_period_timer++; - if(ctx.ch3_period_timer >= 0x800) { - ctx.ch3_period_timer = ctx.ch3_period_reset; - ctx.ch3_sample = (ctx.ch3_sample + 1) % 32; - if((ctx.ch3_sample & 0b1) == 0b1) { - ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] & 0xF; - } else { - ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4; - } - } - +void audio_sample_tick() { + lfsr_tick(); float left = 0; float right = 0; float sq1_val = 0; @@ -490,6 +450,16 @@ void audio_period_tick() { } } if(ctx.ch3_dac){ + u8 shift = 0; + if(ctx.ch3_volume == 0b10) { + shift = 1; + } + if(ctx.ch3_volume == 0b00) { + shift = 4; + } + if(ctx.ch3_volume == 0b11) { + shift = 2; + } ch3_val = -1; if(ctx.ch3_enable) { ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f); @@ -557,25 +527,100 @@ void audio_period_tick() { ctx.ch4_index = 0; } } - smooth_left = smooth_left - (LPF_Beta * (smooth_left - left)); smooth_right = smooth_right - (LPF_Beta * (smooth_right - right)); - - if((period_tick % (int)(AUDIO_TICKS_PER_SAMPLE)) == 0){ + cycles_needed += SAMPLES_PER_AUDIO_TICK; + if(cycles_needed > 1){ //printf("tick\n"); - while(ctx.buffer_cnt == AUDIO_BUFFER_SIZE){ + //if(ctx.buffer_cnt == AUDIO_BUFFER_SIZE){ //ctx.buffer_cnt--; //ctx.sq1_read_index++; //ctx.sq1_read_index %= AUDIO_BUFFER_SIZE; - delay(10); + //delay(1); //printf("overflow\n"); + //return; + //} + cycles_needed -= 1; + + bool dacs = ctx.ch1_dac || ctx.ch2_dac || ctx.ch3_dac || ctx.ch4_dac; + float left_out = 0; + float right_out = 0; + if(dacs) { + left_out = smooth_left - left_cap; + right_out = smooth_right - right_cap; + left_cap = smooth_left - left_out * 0.996f; + right_cap = smooth_right - right_out * 0.996f; } - ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = smooth_left; - ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = smooth_right; + + + left_out /= 4; + right_out /= 4; + + if(left_out < -1.0f) { + left_out = -1; + } + if(left_out > 1.0f) { + left_out = 1; + } + if(right_out < -1.0f) { + right_out = -1; + } + if(right_out > 1.0f) { + right_out = 1; + } + + ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = left_out; + ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = right_out; //ctx.ch3_audio_buffer[(ctx.sq1_write_index)] = (((float)(ctx.ch3_last_sample >> shift)-7.5f)/7.5f); //ctx.ch4_audio_buffer[(ctx.sq1_write_index)] = (ctx.ch4_lfsr & 0b1) ? (float)(ctx.ch4_volume-7.5f)/7.5f : -1.0f; - ctx.sq1_write_index = (ctx.sq1_write_index + 1) % AUDIO_BUFFER_SIZE; - ctx.buffer_cnt++; + ctx.sq1_write_index = (ctx.sq1_write_index + 1); + //ctx.buffer_cnt++; + if(ctx.sq1_write_index == FRAMES_PER_BUFFER) { + ctx.sq1_write_index = 0; + float *data[2]; + data[0] = ctx.sq1_audio_buffer; + data[1] = ctx.sq2_audio_buffer; + int err = Pa_WriteStream(stream, data, FRAMES_PER_BUFFER); + if(err != paNoError) { + fprintf(stderr, "portaudio stream error\n\tError Number: %d\n\tError Message: %s\n", err, Pa_GetErrorText(err)); + } + } + } +} + +bool skipped = false; +void audio_period_tick() { + period_tick++; + u32 end = get_ticks(); + samples_per_sec++; + if (end - start >= 1000) { + printf("Samples In Buffer: %ld\n", ctx.buffer_cnt); + start = end; + samples_per_sec = 0; + } + if(period_tick % 2 == 0){ + ctx.sq1_period_timer++; + ctx.sq2_period_timer++; + + if(ctx.sq1_period_timer >= 0x800) { + ctx.sq1_period_timer = ctx.sq1_period_reset; + ctx.sq1_sample = (ctx.sq1_sample + 1) % 8; + } + + if(ctx.sq2_period_timer >= 0x800) { + ctx.sq2_period_timer = ctx.sq2_period_reset; + ctx.sq2_sample = (ctx.sq2_sample + 1) % 8; + } + } + ctx.ch3_period_timer++; + if(ctx.ch3_period_timer >= 0x800) { + ctx.ch3_period_timer = ctx.ch3_period_reset; + ctx.ch3_sample = (ctx.ch3_sample + 1) % 32; + if((ctx.ch3_sample & 0b1) == 0b1) { + ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] & 0xF; + } else { + ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4; + } } } diff --git a/lib/timer.c b/lib/timer.c index 46a5139..59edfbd 100644 --- a/lib/timer.c +++ b/lib/timer.c @@ -39,7 +39,7 @@ void timer_tick() { } } - lfsr_tick(); + audio_sample_tick(); if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){ audio_tick();