fIxing audio buffer

This commit is contained in:
Samuel Walker 2025-02-18 06:27:08 -07:00
parent ea91ebf5c3
commit 87cc770aa6
Signed by: piwalker
GPG Key ID: 616B1928705EA4C9
2 changed files with 140 additions and 59 deletions

View File

@ -120,12 +120,13 @@ typedef struct {
u8 sq1_sample_val; u8 sq1_sample_val;
u64 sq1_write_index; u64 sq1_write_index;
u64 sq1_read_index; u64 sq1_read_index;
u8 *sq1_audio_buffer; u32 buffer_cnt;
float *sq1_audio_buffer;
u8 sq2_sample_val; u8 sq2_sample_val;
u8 *sq2_audio_buffer; float *sq2_audio_buffer;
u8 *ch3_audio_buffer; float *ch3_audio_buffer;
u8 *ch4_audio_buffer; float *ch4_audio_buffer;
} audio_context; } audio_context;

View File

@ -6,13 +6,14 @@
#include <portaudio.h> #include <portaudio.h>
#include <pa_ringbuffer.h> #include <pa_ringbuffer.h>
#include <math.h> #include <math.h>
#include <string.h>
#define SAMPLE_RATE 44100.0 #define SAMPLE_RATE 44100.0
#define FRAMES_PER_BUFFER 64 #define FRAMES_PER_BUFFER 64
#define TIME_PER_SAMPLE 1.0f / (SAMPLE_RATE/1000.0f/1000.0f) #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 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 2157281.28 / SAMPLE_RATE
#define TIME_PER_WAVE_TICK 1.0f / (2097152.0f/1000.0f/1000.0f) #define TIME_PER_WAVE_TICK 1.0f / (2104718.0f/1000.0f/1000.0f)
#define LFSR_BASE_CLOCK 262144.0f #define LFSR_BASE_CLOCK 262144.0f
#define AUDIO_BUFFER_SIZE 102400 #define AUDIO_BUFFER_SIZE 102400
@ -95,12 +96,15 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
float *out = (float *)output_buffer; float *out = (float *)output_buffer;
for(int i = 0; i < framesPerBuffer; i++) { for(int i = 0; i < framesPerBuffer; i++) {
samples_occured = samples_occured + AUDIO_TICKS_PER_SAMPLE; samples_occured = samples_occured + AUDIO_TICKS_PER_SAMPLE;
ctx.sq1_read_index += (int)samples_occured; if(ctx.buffer_cnt < (u8)samples_occured) {
samples_occured -= (int)samples_occured; //samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt);
if(ctx.sq1_read_index > ctx.sq1_write_index) { //ctx.sq1_read_index = ctx.sq1_write_index-1;
ctx.sq1_read_index = ctx.sq1_write_index-1; printf("buffer underflow\n");
//printf("buffer underflow\n"); } else {
return paContinue; ctx.buffer_cnt -= (u8)samples_occured;
ctx.sq1_read_index += (u8)samples_occured;
ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
samples_occured -= (u8)samples_occured;
} }
if(ppu_get_context()->paused) { if(ppu_get_context()->paused) {
*out++ = 0; *out++ = 0;
@ -109,34 +113,6 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
} }
float left = 0; float left = 0;
float right = 0; float right = 0;
audio_time += TIME_PER_SAMPLE;
wave_time += TIME_PER_SAMPLE;
for(;audio_time >= TIME_PER_AUDIO_TICK;audio_time -= TIME_PER_AUDIO_TICK) {
//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;
//}
}
for(;wave_time >= TIME_PER_WAVE_TICK;wave_time -= TIME_PER_WAVE_TICK) {
//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;
// }
//}
}
float sq1_val = 0; float sq1_val = 0;
float sq2_val = 0; float sq2_val = 0;
float ch3_val = 0; float ch3_val = 0;
@ -146,7 +122,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
sq1_val = -1; sq1_val = -1;
if(ctx.sq1_enable) { if(ctx.sq1_enable) {
//sq1_val = ((float)ctx.sq1_volume/15.0f) * (((float)(square_sample[ctx.sq1_duty][ctx.sq1_sample]) - 7.5f)/7.5f); //sq1_val = ((float)ctx.sq1_volume/15.0f) * (((float)(square_sample[ctx.sq1_duty][ctx.sq1_sample]) - 7.5f)/7.5f);
sq1_val = ((float)ctx.sq1_volume/15.0f) * (((float)(ctx.sq1_audio_buffer[ctx.sq1_read_index % AUDIO_BUFFER_SIZE]) - 7.5f)/7.5f); sq1_val = ctx.sq1_audio_buffer[ctx.sq1_read_index];
if(ctx.ch1_left) { if(ctx.ch1_left) {
left += sq1_val; left += sq1_val;
}else { }else {
@ -166,7 +142,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
sq2_val = -1; sq2_val = -1;
if(ctx.sq2_enable) { if(ctx.sq2_enable) {
//sq2_val = ((float)ctx.sq2_volume/15.0f) * (((float)(square_sample[ctx.sq2_duty][ctx.sq2_sample]) - 7.5f)/7.5f); //sq2_val = ((float)ctx.sq2_volume/15.0f) * (((float)(square_sample[ctx.sq2_duty][ctx.sq2_sample]) - 7.5f)/7.5f);
sq2_val = ((float)ctx.sq2_volume/15.0f) * (((float)(ctx.sq2_audio_buffer[ctx.sq1_read_index % AUDIO_BUFFER_SIZE]) - 7.5f)/7.5f); sq2_val = ctx.sq2_audio_buffer[ctx.sq1_read_index];//((float)ctx.sq2_volume/15.0f) * (((float)(ctx.sq2_audio_buffer[ctx.sq1_read_index]) - 7.5f)/7.5f);
if(ctx.ch2_left) { if(ctx.ch2_left) {
left += sq2_val; left += sq2_val;
}else { }else {
@ -186,7 +162,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
ch3_val = -1; ch3_val = -1;
if(ctx.ch3_enable) { if(ctx.ch3_enable) {
//ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f); //ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f);
ch3_val = (((float)(ctx.ch3_audio_buffer[ctx.sq1_read_index % AUDIO_BUFFER_SIZE]) - 7.5f)/7.5f); ch3_val = ctx.ch3_audio_buffer[ctx.sq1_index];//(((float)(ctx.ch3_audio_buffer[ctx.sq1_read_index]) - 7.5f)/7.5f);
if(ctx.ch3_left) { if(ctx.ch3_left) {
left += ch3_val; left += ch3_val;
//printf("left: %d\n", ctx.ch3_volume); //printf("left: %d\n", ctx.ch3_volume);
@ -207,7 +183,7 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
ch4_val = -1; ch4_val = -1;
if(ctx.ch4_enable) { if(ctx.ch4_enable) {
//ch4_val = ((ctx.ch4_lfsr & 0b1) == 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f; //ch4_val = ((ctx.ch4_lfsr & 0b1) == 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f;
ch4_val = ((float)ctx.ch4_volume/15.0f) * (((float)(ctx.ch4_audio_buffer[ctx.sq1_read_index % AUDIO_BUFFER_SIZE]) - 7.5f)/7.5f); ch4_val = ctx.ch4_audio_buffer[ctx.sq1_read_index];//((float)ctx.ch4_volume/15.0f) * (((float)(ctx.ch4_audio_buffer[ctx.sq1_read_index]) - 7.5f)/7.5f);
if(ctx.ch4_left) { if(ctx.ch4_left) {
left += ch4_val; left += ch4_val;
//printf("left: %d\n", ctx.ch3_volume); //printf("left: %d\n", ctx.ch3_volume);
@ -233,6 +209,9 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
//left /= 4; //left /= 4;
//right /= 4; //right /= 4;
left = ctx.sq1_audio_buffer[ctx.sq1_read_index];
right = ctx.sq2_audio_buffer[ctx.sq1_read_index];
bool dacs = ctx.ch1_dac || ctx.ch2_dac || ctx.ch3_dac || ctx.ch4_dac; bool dacs = ctx.ch1_dac || ctx.ch2_dac || ctx.ch3_dac || ctx.ch4_dac;
float left_out = 0; float left_out = 0;
@ -306,10 +285,15 @@ void audio_init(){
PaStreamParameters output_parameters; PaStreamParameters output_parameters;
PaError err; PaError err;
ctx.sq1_audio_buffer = malloc(sizeof(u8) * AUDIO_BUFFER_SIZE); ctx.sq1_audio_buffer = malloc(sizeof(float) * AUDIO_BUFFER_SIZE);
ctx.sq2_audio_buffer = malloc(sizeof(u8) * AUDIO_BUFFER_SIZE); ctx.sq2_audio_buffer = malloc(sizeof(float) * AUDIO_BUFFER_SIZE);
ctx.ch3_audio_buffer = malloc(sizeof(u8) * AUDIO_BUFFER_SIZE); ctx.ch3_audio_buffer = malloc(sizeof(float) * AUDIO_BUFFER_SIZE);
ctx.ch4_audio_buffer = malloc(sizeof(u8) * AUDIO_BUFFER_SIZE); ctx.ch4_audio_buffer = malloc(sizeof(float) * AUDIO_BUFFER_SIZE);
memset(ctx.sq1_audio_buffer, 0, sizeof(float) * AUDIO_BUFFER_SIZE);
memset(ctx.sq2_audio_buffer, 0, sizeof(float) * AUDIO_BUFFER_SIZE);
memset(ctx.ch3_audio_buffer, 0, sizeof(float) * AUDIO_BUFFER_SIZE);
memset(ctx.ch4_audio_buffer, 0, sizeof(float) * AUDIO_BUFFER_SIZE);
ctx.audio_enabled = false; ctx.audio_enabled = false;
ctx.ch1_left = false; ctx.ch1_left = false;
@ -354,7 +338,9 @@ void audio_init(){
ctx.sq2_env_direction = false; ctx.sq2_env_direction = false;
ctx.sq2_env_pace = 0x0; ctx.sq2_env_pace = 0x0;
ctx.sq2_env_timer = 0x0; ctx.sq2_env_timer = 0x0;
ctx.sq1_write_index = 1; ctx.sq1_write_index = AUDIO_BUFFER_SIZE / 2;
ctx.sq1_read_index = 0;
ctx.buffer_cnt = AUDIO_BUFFER_SIZE / 2;
err = Pa_Initialize(); err = Pa_Initialize();
if (err != paNoError) goto error; if (err != paNoError) goto error;
@ -408,7 +394,7 @@ void audio_period_tick() {
u32 end = get_ticks(); u32 end = get_ticks();
samples_per_sec++; samples_per_sec++;
if (end - start >= 1000) { if (end - start >= 1000) {
printf("Samples Per Second: %d\n", samples_per_sec); printf("Samples In Buffer: %ld\n", ctx.buffer_cnt);
start = end; start = end;
samples_per_sec = 0; samples_per_sec = 0;
} }
@ -458,12 +444,106 @@ void audio_period_tick() {
ctx.ch4_lfsr &= ~bit_mask; ctx.ch4_lfsr &= ~bit_mask;
} }
} }
if(ctx.sq1_write_index < (ctx.sq1_read_index + AUDIO_BUFFER_SIZE)){
ctx.sq1_audio_buffer[(ctx.sq1_write_index)%AUDIO_BUFFER_SIZE] = square_sample[ctx.sq1_duty][ctx.sq1_sample]; float left = 0;
ctx.sq2_audio_buffer[(ctx.sq1_write_index)%AUDIO_BUFFER_SIZE] = square_sample[ctx.sq2_duty][ctx.sq2_sample]; float right = 0;
ctx.ch3_audio_buffer[(ctx.sq1_write_index)%AUDIO_BUFFER_SIZE] = ctx.ch3_last_sample >> shift; float sq1_val = 0;
ctx.ch4_audio_buffer[(ctx.sq1_write_index)%AUDIO_BUFFER_SIZE] = (ctx.ch4_lfsr & 0b1) ? 0xF : 0x0; float sq2_val = 0;
ctx.sq1_write_index++; float ch3_val = 0;
float ch4_val = 0;
if(ctx.audio_enabled){
if(ctx.ch1_dac){
sq1_val = -1;
if(ctx.sq1_enable) {
sq1_val = ((float)ctx.sq1_volume/15.0f) * (((float)(square_sample[ctx.sq1_duty][ctx.sq1_sample]) - 7.5f)/7.5f);
if(ctx.ch1_left) {
left += sq1_val;
}else {
left -= 1;
}
if(ctx.ch1_right) {
right += sq1_val;
}else {
right -= 1;
}
} else {
left -= 1;
right -= 1;
}
}
if(ctx.ch2_dac){
sq2_val = -1;
if(ctx.sq2_enable) {
sq2_val = ((float)ctx.sq2_volume/15.0f) * (((float)(square_sample[ctx.sq2_duty][ctx.sq2_sample]) - 7.5f)/7.5f);
if(ctx.ch2_left) {
left += sq2_val;
}else {
left -= 1;
}
if(ctx.ch2_right) {
right += sq2_val;
}else {
right -= 1;
}
} else {
left -= 1;
right -= 1;
}
}
if(ctx.ch3_dac){
ch3_val = -1;
if(ctx.ch3_enable) {
ch3_val = (((float)(ctx.ch3_last_sample >> shift) - 7.5f)/7.5f);
if(ctx.ch3_left) {
left += ch3_val;
//printf("left: %d\n", ctx.ch3_volume);
}else {
left -= 1;
}
if(ctx.ch3_right) {
right += ch3_val;
}else {
right -= 1;
}
} else {
left -= 1;
right -= 1;
}
}
if(ctx.ch4_dac){
ch4_val = -1;
if(ctx.ch4_enable) {
ch4_val = ((ctx.ch4_lfsr & 0b1) == 0b1) ? (((float)ctx.ch4_volume - 7.5f)/7.5f) : -1.0f;
if(ctx.ch4_left) {
left += ch4_val;
//printf("left: %d\n", ctx.ch3_volume);
}else {
left -= 1;
}
if(ctx.ch4_right) {
right += ch4_val;
} else {
right -= 1;
}
} else {
left -= 1;
right -= 1;
}
}
}
u8 left_vol = ctx.volume_left == 0 ? 1 : ctx.volume_left;
u8 right_vol = ctx.volume_right == 0 ? 1 : ctx.volume_right;
left *= (float)left_vol/7.0f;
right *= (float)right_vol/7.0f;
if(ctx.buffer_cnt < AUDIO_BUFFER_SIZE){
ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = left;
ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = right;
//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++;
} else { } else {
printf("buffer overflow\n"); printf("buffer overflow\n");
} }
@ -1017,7 +1097,7 @@ void audio_write(u16 address, u8 value){
ctx.ch4_len = ctx.ch4_initial_len; ctx.ch4_len = ctx.ch4_initial_len;
ctx.ch4_len_fz = false; ctx.ch4_len_fz = false;
//printf("ch4 len: %02X\n", ctx.ch4_len); //printf("ch4 len: %02X\n", ctx.ch4_len);
printf("Write Ch4 Len: %02X\n", value); //printf("Write Ch4 Len: %02X\n", value);
} }
if(address == 0xFF21) { if(address == 0xFF21) {
@ -1030,7 +1110,7 @@ void audio_write(u16 address, u8 value){
} else { } else {
ctx.ch4_dac = true; ctx.ch4_dac = true;
} }
printf("Write Ch4 env: %02X\n", value); //printf("Write Ch4 env: %02X\n", value);
} }
if(address == 0xFF22) { if(address == 0xFF22) {
@ -1041,7 +1121,7 @@ void audio_write(u16 address, u8 value){
float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (float)(1 << ctx.ch4_clock_shift)); float lfsr_rate = (LFSR_BASE_CLOCK) / (div * (float)(1 << ctx.ch4_clock_shift));
lfsr_clock_buffer = 1.0f / (lfsr_rate/1000.0f/1000.0f); lfsr_clock_buffer = 1.0f / (lfsr_rate/1000.0f/1000.0f);
//printf("Ch4 clock: Shift: %01X, Width: %d, Div: %f (%01X), Rate: %f, Clock %f\n", ctx.ch4_clock_shift, ctx.ch4_lfsr_width, div, ctx.ch4_clock_divider, lfsr_rate, lfsr_clock); //printf("Ch4 clock: Shift: %01X, Width: %d, Div: %f (%01X), Rate: %f, Clock %f\n", ctx.ch4_clock_shift, ctx.ch4_lfsr_width, div, ctx.ch4_clock_divider, lfsr_rate, lfsr_clock);
printf("Write Ch4 Clock: %02X\n", value); //printf("Write Ch4 Clock: %02X\n", value);
} }
if(address == 0xFF23) { if(address == 0xFF23) {
@ -1068,6 +1148,6 @@ void audio_write(u16 address, u8 value){
if(value & 0x80) { if(value & 0x80) {
enable_noise(); enable_noise();
} }
printf("Write Ch4 Trigger: %02X\n", value); //printf("Write Ch4 Trigger: %02X\n", value);
} }
} }