Fixed audio buffer popping

This commit is contained in:
Samuel Walker 2025-02-18 17:15:17 -07:00
parent 8e5c3234ef
commit a094e5123b
3 changed files with 116 additions and 70 deletions

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -39,7 +39,7 @@ void timer_tick() {
}
}
lfsr_tick();
audio_sample_tick();
if((prev_div & (1 << 12)) && (!(ctx.div & (1 << 12)))){
audio_tick();