fixed audio buffer.

This commit is contained in:
Samuel Walker 2025-02-18 11:14:53 -07:00
parent d3bc68924c
commit 2af25cc87c
3 changed files with 74 additions and 52 deletions

View File

@ -133,6 +133,7 @@ typedef struct {
void audio_init(); void audio_init();
void audio_tick(); void audio_tick();
void audio_period_tick(); void audio_period_tick();
void lfsr_tick();
u8 audio_read(u16 address); u8 audio_read(u16 address);
void audio_write(u16 address, u8 value); void audio_write(u16 address, u8 value);

View File

@ -15,7 +15,7 @@
#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 / (2104718.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 10240
static audio_context ctx; static audio_context ctx;
@ -25,7 +25,7 @@ audio_context *audio_get_context() {
static float audio_time = 0; static float audio_time = 0;
static float wave_time = 0; static float wave_time = 0;
static float lfsr_timer = 0; static u32 lfsr_timer = 0;
static float lfsr_clock = LFSR_BASE_CLOCK; static float lfsr_clock = LFSR_BASE_CLOCK;
static float lfsr_clock_buffer = LFSR_BASE_CLOCK; static float lfsr_clock_buffer = LFSR_BASE_CLOCK;
@ -94,17 +94,25 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
PaStreamCallbackFlags status_flags, PaStreamCallbackFlags status_flags,
void *userData ) { void *userData ) {
float *out = (float *)output_buffer; float *out = (float *)output_buffer;
//while(ctx.buffer_cnt < framesPerBuffer*AUDIO_TICKS_PER_SAMPLE) {
// delay(1);
//}
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-1;
if(ctx.buffer_cnt < (u8)samples_occured) { while(ctx.buffer_cnt == 0) {
//delay(1);
}
if(ctx.buffer_cnt == 0) {
//samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt); //samples_occured = samples_occured - ((int)samples_occured - ctx.buffer_cnt);
//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");
return paContinue;
} else { } else {
ctx.buffer_cnt -= (u8)samples_occured; //ctx.buffer_cnt -= (u8)samples_occured;
ctx.sq1_read_index += (u8)samples_occured; //ctx.sq1_read_index += (u8)samples_occured;
ctx.sq1_read_index %= AUDIO_BUFFER_SIZE; //ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
samples_occured -= (u8)samples_occured; //samples_occured -= (u8)samples_occured;
ctx.buffer_cnt--;
} }
if(ppu_get_context()->paused) { if(ppu_get_context()->paused) {
*out++ = 0; *out++ = 0;
@ -211,6 +219,8 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
left = ctx.sq1_audio_buffer[ctx.sq1_read_index]; left = ctx.sq1_audio_buffer[ctx.sq1_read_index];
right = ctx.sq2_audio_buffer[ctx.sq1_read_index]; right = ctx.sq2_audio_buffer[ctx.sq1_read_index];
ctx.sq1_read_index++;
ctx.sq1_read_index %= AUDIO_BUFFER_SIZE;
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;
@ -240,27 +250,8 @@ static int audio_callback(const void* input_uffer, void *output_buffer,
right_out = 1; right_out = 1;
} }
history_timer++; history_timer++;
if(history_timer >= history_interval){ if(history_timer >= 5){
history_timer = 0; history_timer = 0;
ctx.sq1_history[ctx.sq1_index++] = sq1_val;
if (ctx.sq1_index == 384) {
ctx.sq1_index = 0;
}
ctx.sq2_history[ctx.sq2_index++] = sq2_val;
if (ctx.sq2_index == 384) {
ctx.sq2_index = 0;
}
ctx.ch3_history[ctx.ch3_index++] = ch3_val;
if (ctx.ch3_index == 384) {
ctx.ch3_index = 0;
}
ctx.ch4_history[ctx.ch4_index++] = ch4_val;
if (ctx.ch4_index == 384) {
ctx.ch4_index = 0;
}
ctx.left_history[ctx.left_index++] = left_out; ctx.left_history[ctx.left_index++] = left_out;
if (ctx.left_index == 384) { if (ctx.left_index == 384) {
ctx.left_index = 0; ctx.left_index = 0;
@ -338,9 +329,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 = AUDIO_BUFFER_SIZE / 2; ctx.sq1_write_index = 0;
ctx.sq1_read_index = 0; ctx.sq1_read_index = 0;
ctx.buffer_cnt = AUDIO_BUFFER_SIZE / 2; ctx.buffer_cnt = 0;
err = Pa_Initialize(); err = Pa_Initialize();
if (err != paNoError) goto error; if (err != paNoError) goto error;
@ -388,6 +379,21 @@ static u32 start = 0;
static u32 period_tick; static u32 period_tick;
static u32 samples_per_sec = 0; static u32 samples_per_sec = 0;
void lfsr_tick() {
lfsr_timer--;
if(lfsr_timer == 0) {
lfsr_timer = (ctx.ch4_clock_divider > 0 ? (ctx.ch4_clock_divider << 4) : 8) << ctx.ch4_clock_shift;
unsigned bit_mask = ctx.ch4_lfsr_width ? 0x4040 : 0x4000;
bool new_bit = (ctx.ch4_lfsr ^ (ctx.ch4_lfsr >> 1) ^ 1) & 1;
ctx.ch4_lfsr >>= 1;
if(new_bit) {
ctx.ch4_lfsr |= bit_mask;
} else {
ctx.ch4_lfsr &= ~bit_mask;
}
}
}
void audio_period_tick() { void audio_period_tick() {
period_tick++; period_tick++;
@ -432,18 +438,6 @@ void audio_period_tick() {
ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4; ctx.ch3_last_sample = ctx.wave_ram[ctx.ch3_sample >> 1] >> 4;
} }
} }
lfsr_timer--;
if(lfsr_timer == 0) {
lfsr_timer = (ctx.ch4_clock_divider > 0 ? (ctx.ch4_clock_divider << 4) : 8) << ctx.ch4_clock_shift;
unsigned bit_mask = ctx.ch4_lfsr_width ? 0x4040 : 0x4000;
bool new_bit = (ctx.ch4_lfsr ^ (ctx.ch4_lfsr >> 1) ^ 1) & 1;
ctx.ch4_lfsr >>= 1;
if(new_bit) {
ctx.ch4_lfsr |= bit_mask;
} else {
ctx.ch4_lfsr &= ~bit_mask;
}
}
float left = 0; float left = 0;
float right = 0; float right = 0;
@ -537,15 +531,40 @@ void audio_period_tick() {
left *= (float)left_vol/7.0f; left *= (float)left_vol/7.0f;
right *= (float)right_vol/7.0f; right *= (float)right_vol/7.0f;
if(ctx.buffer_cnt < AUDIO_BUFFER_SIZE){ if(period_tick % 100 == 0){
ctx.sq1_history[ctx.sq1_index++] = sq1_val;
if (ctx.sq1_index == 384) {
ctx.sq1_index = 0;
}
ctx.sq2_history[ctx.sq2_index++] = sq2_val;
if (ctx.sq2_index == 384) {
ctx.sq2_index = 0;
}
ctx.ch3_history[ctx.ch3_index++] = ch3_val;
if (ctx.ch3_index == 384) {
ctx.ch3_index = 0;
}
ctx.ch4_history[ctx.ch4_index++] = ch4_val;
if (ctx.ch4_index == 384) {
ctx.ch4_index = 0;
}
}
if((period_tick % (int)(AUDIO_TICKS_PER_SAMPLE)) == 0){
//printf("tick\n");
while(ctx.buffer_cnt == AUDIO_BUFFER_SIZE){
//delay(1);
//printf("overflow\n");
}
ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = left; ctx.sq1_audio_buffer[(ctx.sq1_write_index)] = left;
ctx.sq2_audio_buffer[(ctx.sq1_write_index)] = right; 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.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.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.sq1_write_index = (ctx.sq1_write_index + 1) % AUDIO_BUFFER_SIZE;
ctx.buffer_cnt++; ctx.buffer_cnt++;
} else {
//printf("buffer overflow\n");
} }
} }
@ -692,9 +711,6 @@ void enable_wave() {
} }
void enable_noise() { void enable_noise() {
if(!ctx.ch4_dac){
return;
}
ctx.ch4_enable = true; ctx.ch4_enable = true;
ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8; ctx.ch4_env_timer = ctx.ch4_env_pace_buffer != 0 ? ctx.ch4_env_pace_buffer : 8;
ctx.ch4_env_direction = ctx.ch4_env_direction_buffer; ctx.ch4_env_direction = ctx.ch4_env_direction_buffer;
@ -702,7 +718,10 @@ void enable_noise() {
ctx.ch4_volume = ctx.ch4_initial_volume; ctx.ch4_volume = ctx.ch4_initial_volume;
ctx.ch4_lfsr = 0; ctx.ch4_lfsr = 0;
lfsr_clock = lfsr_clock_buffer; lfsr_clock = lfsr_clock_buffer;
lfsr_timer = (ctx.ch4_clock_divider > 0 ? (ctx.ch4_clock_divider << 8) : 8) << ctx.ch4_clock_shift; lfsr_timer = (ctx.ch4_clock_divider > 0 ? (ctx.ch4_clock_divider << 4) : 8) << ctx.ch4_clock_shift;
if(!ctx.ch4_dac){
ctx.ch4_enable = false;
}
} }
u8 audio_read(u16 address) { u8 audio_read(u16 address) {
@ -1117,9 +1136,9 @@ void audio_write(u16 address, u8 value){
ctx.ch4_clock_shift = (value >> 4) & 0xF; ctx.ch4_clock_shift = (value >> 4) & 0xF;
ctx.ch4_lfsr_width = (value & 0x08); ctx.ch4_lfsr_width = (value & 0x08);
ctx.ch4_clock_divider = value & 0b111; ctx.ch4_clock_divider = value & 0b111;
float div = (ctx.ch4_clock_divider == 0 ? 0.5f : (float)ctx.ch4_clock_divider); //float div = (ctx.ch4_clock_divider == 0 ? 0.5f : (float)ctx.ch4_clock_divider);
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);
} }

View File

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