From 2f1c528a6c37558760b28638d271f5ff9ba45e4f Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 6 Sep 2011 20:18:34 +0300 Subject: [PATCH] tweak sound buffering and timing to better match pandora's refresh. this also changes how direct sound channels are started and sample step precision is increased to hopefully fix gbc + direct channel desync that has been reported on the forums. --- common.h | 7 +++++++ main.h | 9 ++++---- sound.c | 64 +++++++++++++++++++++++--------------------------------- sound.h | 23 ++++++++++---------- 4 files changed, 48 insertions(+), 55 deletions(-) diff --git a/common.h b/common.h index 7eea8b6..da22d2e 100644 --- a/common.h +++ b/common.h @@ -180,6 +180,7 @@ typedef u32 fixed16_16; +typedef u32 fixed8_24; #define float_to_fp16_16(value) \ (fixed16_16)((value) * 65536.0) \ @@ -196,6 +197,12 @@ typedef u32 fixed16_16; #define fp16_16_fractional_part(value) \ ((value) & 0xFFFF) \ +#define float_to_fp8_24(value) \ + (fixed8_24)((value) * 16777216.0) \ + +#define fp8_24_fractional_part(value) \ + ((value) & 0xFFFFFF) \ + #define fixed_div(numerator, denominator, bits) \ (((numerator * (1 << bits)) + (denominator / 2)) / denominator) \ diff --git a/main.h b/main.h index 6cd471e..671974c 100644 --- a/main.h +++ b/main.h @@ -48,7 +48,7 @@ typedef struct u32 reload; u32 prescale; u32 stop_cpu_ticks; - fixed16_16 frequency_step; + fixed8_24 frequency_step; timer_ds_channel_type direct_sound_channels; timer_irq_type irq; timer_status_type status; @@ -132,8 +132,7 @@ static u32 prescale_table[] = { 0, 6, 8, 10 }; if(timer[timer_number].direct_sound_channels & (0x01 << channel)) \ { \ direct_sound_channel[channel].buffer_index = \ - (direct_sound_channel[channel].buffer_index + buffer_adjust) % \ - BUFFER_SIZE; \ + (gbc_sound_buffer_index + buffer_adjust) % BUFFER_SIZE; \ } \ #define trigger_timer(timer_number) \ @@ -164,8 +163,8 @@ static u32 prescale_table[] = { 0, 6, 8, 10 }; if(timer_number < 2) \ { \ u32 buffer_adjust = \ - (u32)(((float)(cpu_ticks - timer[timer_number].stop_cpu_ticks) * \ - sound_frequency) / 16777216.0) * 2; \ + (u32)(((float)(cpu_ticks - gbc_sound_last_cpu_ticks) * \ + sound_frequency) / GBC_BASE_RATE) * 2; \ \ sound_update_frequency_step(timer_number); \ adjust_sound_buffer(timer_number, 0); \ diff --git a/sound.c b/sound.c index 9810407..9b21e6c 100644 --- a/sound.c +++ b/sound.c @@ -84,31 +84,31 @@ void sound_timer_queue32(u32 channel, u32 value) #define render_sample_left() \ sound_buffer[buffer_index] += current_sample + \ - fp16_16_to_u32((next_sample - current_sample) * fifo_fractional) \ + fp16_16_to_u32((next_sample - current_sample) * (fifo_fractional >> 8)) \ #define render_sample_right() \ sound_buffer[buffer_index + 1] += current_sample + \ - fp16_16_to_u32((next_sample - current_sample) * fifo_fractional) \ + fp16_16_to_u32((next_sample - current_sample) * (fifo_fractional >> 8)) \ #define render_sample_both() \ dest_sample = current_sample + \ - fp16_16_to_u32((next_sample - current_sample) * fifo_fractional); \ + fp16_16_to_u32((next_sample - current_sample) * (fifo_fractional >> 8)); \ sound_buffer[buffer_index] += dest_sample; \ sound_buffer[buffer_index + 1] += dest_sample \ #define render_samples(type) \ - while(fifo_fractional <= 0xFFFF) \ + while(fifo_fractional <= 0xFFFFFF) \ { \ render_sample_##type(); \ fifo_fractional += frequency_step; \ buffer_index = (buffer_index + 2) % BUFFER_SIZE; \ } \ -void sound_timer(fixed16_16 frequency_step, u32 channel) +void sound_timer(fixed8_24 frequency_step, u32 channel) { direct_sound_struct *ds = direct_sound_channel + channel; - fixed16_16 fifo_fractional = ds->fifo_fractional; + fixed8_24 fifo_fractional = ds->fifo_fractional; u32 buffer_index = ds->buffer_index; s16 current_sample, next_sample, dest_sample; @@ -149,7 +149,7 @@ void sound_timer(fixed16_16 frequency_step, u32 channel) } ds->buffer_index = buffer_index; - ds->fifo_fractional = fp16_16_fractional_part(fifo_fractional); + ds->fifo_fractional = fp8_24_fractional_part(fifo_fractional); if(((ds->fifo_top - ds->fifo_base) % 32) <= 16) { @@ -264,8 +264,8 @@ u32 gbc_sound_master_volume; if(rate > 2048) \ rate = 2048; \ \ - frequency_step = float_to_fp16_16(((131072.0 / (2048 - rate)) * 8.0) / \ - sound_frequency); \ + frequency_step = float_to_fp16_16(((131072.0f / (2048 - rate)) * 8.0f) \ + / sound_frequency); \ \ gs->frequency_step = frequency_step; \ gs->rate = rate; \ @@ -309,13 +309,6 @@ u32 gbc_sound_master_volume; #define update_tone_noenvelope() \ -#define gbc_sound_synchronize() \ - while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > \ - (audio_buffer_size * 2)) \ - { \ - SDL_CondWait(sound_cv, sound_mutex); \ - } \ - #define update_tone_counters(envelope_op, sweep_op) \ tick_counter += gbc_sound_tick_step; \ if(tick_counter > 0xFFFF) \ @@ -428,19 +421,10 @@ u32 gbc_sound_master_volume; wave_bank[i2 + 1] = ((current_sample & 0x0F) - 8); \ } \ -void synchronize_sound() -{ - SDL_LockMutex(sound_mutex); - - gbc_sound_synchronize(); - - SDL_UnlockMutex(sound_mutex); -} - void update_gbc_sound(u32 cpu_ticks) { - fixed16_16 buffer_ticks = float_to_fp16_16(((float)(cpu_ticks - - gbc_sound_last_cpu_ticks) * sound_frequency) / 16777216.0); + fixed16_16 buffer_ticks = float_to_fp16_16((float)(cpu_ticks - + gbc_sound_last_cpu_ticks) * sound_frequency / GBC_BASE_RATE); u32 i, i2; gbc_sound_struct *gs = gbc_sound_channel; fixed16_16 sample_index, frequency_step; @@ -466,8 +450,8 @@ void update_gbc_sound(u32 cpu_ticks) SDL_LockMutex(sound_mutex); if(synchronize_flag) { - if(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > - (audio_buffer_size * 3 / 2)) + if(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) >= + (audio_buffer_size * 2)) { while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) > (audio_buffer_size * 3 / 2)) @@ -705,10 +689,12 @@ void reset_sound() gbc_sound_struct *gs = gbc_sound_channel; u32 i; + SDL_LockMutex(sound_mutex); + sound_on = 0; sound_buffer_base = 0; sound_last_cpu_ticks = 0; - memset(sound_buffer, 0, audio_buffer_size); + memset(sound_buffer, 0, sizeof(sound_buffer)); for(i = 0; i < 2; i++, ds++) { @@ -736,6 +722,8 @@ void reset_sound() gs->sample_data = square_pattern_duty[2]; gs->active_flag = 0; } + + SDL_UnlockMutex(sound_mutex); } void sound_exit() @@ -772,14 +760,6 @@ void init_sound() NULL }; - gbc_sound_tick_step = - float_to_fp16_16(256.0 / sound_frequency); - - init_noise_table(noise_table15, 32767, 14); - init_noise_table(noise_table7, 127, 6); - - reset_sound(); - sound_mutex = SDL_CreateMutex(); sound_cv = SDL_CreateCond(); @@ -793,6 +773,14 @@ void init_sound() printf("audio: freq %d, size %d\n", sound_frequency, audio_buffer_size); #endif + gbc_sound_tick_step = + float_to_fp16_16(256.0f / sound_frequency); + + init_noise_table(noise_table15, 32767, 14); + init_noise_table(noise_table7, 127, 6); + + reset_sound(); + SDL_PauseAudio(0); } diff --git a/sound.h b/sound.h index d71c733..58d823b 100644 --- a/sound.h +++ b/sound.h @@ -22,17 +22,14 @@ #define BUFFER_SIZE 65536 -// A lot of sound cards on PC can't handle such small buffers but this -// seems to work well on PSP. - -#ifdef PSP_BUILD - -#define SOUND_BUFFER_SIZE 4096 +#define GBA_XTAL 16777216.0f +#define GBA_60HZ_RATE 16853760.0f /* 228*(272+960)*60 */ +#if !defined(PSP_BUILD) && !defined(WIZ_BUILD) + // run GBA at 60Hz (~0.5% faster) to better match host display + #define GBC_BASE_RATE GBA_60HZ_RATE #else - -#define SOUND_BUFFER_SIZE 16384 - + #define GBC_BASE_RATE GBA_XTAL #endif typedef enum @@ -54,7 +51,7 @@ typedef struct s8 fifo[32]; u32 fifo_base; u32 fifo_top; - fixed16_16 fifo_fractional; + fixed8_24 fifo_fractional; // The + 1 is to give some extra room for linear interpolation // when wrapping around. u32 buffer_index; @@ -109,6 +106,8 @@ extern s8 square_pattern_duty[4][8]; extern u32 gbc_sound_master_volume_left; extern u32 gbc_sound_master_volume_right; extern u32 gbc_sound_master_volume; +extern u32 gbc_sound_buffer_index; +extern u32 gbc_sound_last_cpu_ticks; extern u32 sound_frequency; extern u32 sound_on; @@ -122,7 +121,7 @@ extern SDL_mutex *sound_mutex; void sound_timer_queue8(u32 channel, u8 value); void sound_timer_queue16(u32 channel, u16 value); void sound_timer_queue32(u32 channel, u32 value); -void sound_timer(fixed16_16 frequency_step, u32 channel); +void sound_timer(fixed8_24 frequency_step, u32 channel); void sound_reset_fifo(u32 channel); void update_gbc_sound(u32 cpu_ticks); void init_sound(); @@ -320,7 +319,7 @@ static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 }; #define sound_update_frequency_step(timer_number) \ timer[timer_number].frequency_step = \ - float_to_fp16_16(16777216.0 / (timer_reload * sound_frequency)) \ + float_to_fp8_24(GBC_BASE_RATE / (timer_reload * sound_frequency)) \ #endif // IN_MEMORY_C -- 2.39.5