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.
This commit is contained in:
parent
a231964c35
commit
2f1c528a6c
7
common.h
7
common.h
|
@ -180,6 +180,7 @@
|
||||||
|
|
||||||
|
|
||||||
typedef u32 fixed16_16;
|
typedef u32 fixed16_16;
|
||||||
|
typedef u32 fixed8_24;
|
||||||
|
|
||||||
#define float_to_fp16_16(value) \
|
#define float_to_fp16_16(value) \
|
||||||
(fixed16_16)((value) * 65536.0) \
|
(fixed16_16)((value) * 65536.0) \
|
||||||
|
@ -196,6 +197,12 @@ typedef u32 fixed16_16;
|
||||||
#define fp16_16_fractional_part(value) \
|
#define fp16_16_fractional_part(value) \
|
||||||
((value) & 0xFFFF) \
|
((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) \
|
#define fixed_div(numerator, denominator, bits) \
|
||||||
(((numerator * (1 << bits)) + (denominator / 2)) / denominator) \
|
(((numerator * (1 << bits)) + (denominator / 2)) / denominator) \
|
||||||
|
|
||||||
|
|
9
main.h
9
main.h
|
@ -48,7 +48,7 @@ typedef struct
|
||||||
u32 reload;
|
u32 reload;
|
||||||
u32 prescale;
|
u32 prescale;
|
||||||
u32 stop_cpu_ticks;
|
u32 stop_cpu_ticks;
|
||||||
fixed16_16 frequency_step;
|
fixed8_24 frequency_step;
|
||||||
timer_ds_channel_type direct_sound_channels;
|
timer_ds_channel_type direct_sound_channels;
|
||||||
timer_irq_type irq;
|
timer_irq_type irq;
|
||||||
timer_status_type status;
|
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)) \
|
if(timer[timer_number].direct_sound_channels & (0x01 << channel)) \
|
||||||
{ \
|
{ \
|
||||||
direct_sound_channel[channel].buffer_index = \
|
direct_sound_channel[channel].buffer_index = \
|
||||||
(direct_sound_channel[channel].buffer_index + buffer_adjust) % \
|
(gbc_sound_buffer_index + buffer_adjust) % BUFFER_SIZE; \
|
||||||
BUFFER_SIZE; \
|
|
||||||
} \
|
} \
|
||||||
|
|
||||||
#define trigger_timer(timer_number) \
|
#define trigger_timer(timer_number) \
|
||||||
|
@ -164,8 +163,8 @@ static u32 prescale_table[] = { 0, 6, 8, 10 };
|
||||||
if(timer_number < 2) \
|
if(timer_number < 2) \
|
||||||
{ \
|
{ \
|
||||||
u32 buffer_adjust = \
|
u32 buffer_adjust = \
|
||||||
(u32)(((float)(cpu_ticks - timer[timer_number].stop_cpu_ticks) * \
|
(u32)(((float)(cpu_ticks - gbc_sound_last_cpu_ticks) * \
|
||||||
sound_frequency) / 16777216.0) * 2; \
|
sound_frequency) / GBC_BASE_RATE) * 2; \
|
||||||
\
|
\
|
||||||
sound_update_frequency_step(timer_number); \
|
sound_update_frequency_step(timer_number); \
|
||||||
adjust_sound_buffer(timer_number, 0); \
|
adjust_sound_buffer(timer_number, 0); \
|
||||||
|
|
64
sound.c
64
sound.c
|
@ -84,31 +84,31 @@ void sound_timer_queue32(u32 channel, u32 value)
|
||||||
|
|
||||||
#define render_sample_left() \
|
#define render_sample_left() \
|
||||||
sound_buffer[buffer_index] += current_sample + \
|
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() \
|
#define render_sample_right() \
|
||||||
sound_buffer[buffer_index + 1] += current_sample + \
|
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() \
|
#define render_sample_both() \
|
||||||
dest_sample = current_sample + \
|
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] += dest_sample; \
|
||||||
sound_buffer[buffer_index + 1] += dest_sample \
|
sound_buffer[buffer_index + 1] += dest_sample \
|
||||||
|
|
||||||
#define render_samples(type) \
|
#define render_samples(type) \
|
||||||
while(fifo_fractional <= 0xFFFF) \
|
while(fifo_fractional <= 0xFFFFFF) \
|
||||||
{ \
|
{ \
|
||||||
render_sample_##type(); \
|
render_sample_##type(); \
|
||||||
fifo_fractional += frequency_step; \
|
fifo_fractional += frequency_step; \
|
||||||
buffer_index = (buffer_index + 2) % BUFFER_SIZE; \
|
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;
|
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;
|
u32 buffer_index = ds->buffer_index;
|
||||||
s16 current_sample, next_sample, dest_sample;
|
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->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)
|
if(((ds->fifo_top - ds->fifo_base) % 32) <= 16)
|
||||||
{
|
{
|
||||||
|
@ -264,8 +264,8 @@ u32 gbc_sound_master_volume;
|
||||||
if(rate > 2048) \
|
if(rate > 2048) \
|
||||||
rate = 2048; \
|
rate = 2048; \
|
||||||
\
|
\
|
||||||
frequency_step = float_to_fp16_16(((131072.0 / (2048 - rate)) * 8.0) / \
|
frequency_step = float_to_fp16_16(((131072.0f / (2048 - rate)) * 8.0f) \
|
||||||
sound_frequency); \
|
/ sound_frequency); \
|
||||||
\
|
\
|
||||||
gs->frequency_step = frequency_step; \
|
gs->frequency_step = frequency_step; \
|
||||||
gs->rate = rate; \
|
gs->rate = rate; \
|
||||||
|
@ -309,13 +309,6 @@ u32 gbc_sound_master_volume;
|
||||||
|
|
||||||
#define update_tone_noenvelope() \
|
#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) \
|
#define update_tone_counters(envelope_op, sweep_op) \
|
||||||
tick_counter += gbc_sound_tick_step; \
|
tick_counter += gbc_sound_tick_step; \
|
||||||
if(tick_counter > 0xFFFF) \
|
if(tick_counter > 0xFFFF) \
|
||||||
|
@ -428,19 +421,10 @@ u32 gbc_sound_master_volume;
|
||||||
wave_bank[i2 + 1] = ((current_sample & 0x0F) - 8); \
|
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)
|
void update_gbc_sound(u32 cpu_ticks)
|
||||||
{
|
{
|
||||||
fixed16_16 buffer_ticks = float_to_fp16_16(((float)(cpu_ticks -
|
fixed16_16 buffer_ticks = float_to_fp16_16((float)(cpu_ticks -
|
||||||
gbc_sound_last_cpu_ticks) * sound_frequency) / 16777216.0);
|
gbc_sound_last_cpu_ticks) * sound_frequency / GBC_BASE_RATE);
|
||||||
u32 i, i2;
|
u32 i, i2;
|
||||||
gbc_sound_struct *gs = gbc_sound_channel;
|
gbc_sound_struct *gs = gbc_sound_channel;
|
||||||
fixed16_16 sample_index, frequency_step;
|
fixed16_16 sample_index, frequency_step;
|
||||||
|
@ -466,8 +450,8 @@ void update_gbc_sound(u32 cpu_ticks)
|
||||||
SDL_LockMutex(sound_mutex);
|
SDL_LockMutex(sound_mutex);
|
||||||
if(synchronize_flag)
|
if(synchronize_flag)
|
||||||
{
|
{
|
||||||
if(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) >
|
if(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) >=
|
||||||
(audio_buffer_size * 3 / 2))
|
(audio_buffer_size * 2))
|
||||||
{
|
{
|
||||||
while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) >
|
while(((gbc_sound_buffer_index - sound_buffer_base) % BUFFER_SIZE) >
|
||||||
(audio_buffer_size * 3 / 2))
|
(audio_buffer_size * 3 / 2))
|
||||||
|
@ -705,10 +689,12 @@ void reset_sound()
|
||||||
gbc_sound_struct *gs = gbc_sound_channel;
|
gbc_sound_struct *gs = gbc_sound_channel;
|
||||||
u32 i;
|
u32 i;
|
||||||
|
|
||||||
|
SDL_LockMutex(sound_mutex);
|
||||||
|
|
||||||
sound_on = 0;
|
sound_on = 0;
|
||||||
sound_buffer_base = 0;
|
sound_buffer_base = 0;
|
||||||
sound_last_cpu_ticks = 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++)
|
for(i = 0; i < 2; i++, ds++)
|
||||||
{
|
{
|
||||||
|
@ -736,6 +722,8 @@ void reset_sound()
|
||||||
gs->sample_data = square_pattern_duty[2];
|
gs->sample_data = square_pattern_duty[2];
|
||||||
gs->active_flag = 0;
|
gs->active_flag = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_UnlockMutex(sound_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sound_exit()
|
void sound_exit()
|
||||||
|
@ -772,14 +760,6 @@ void init_sound()
|
||||||
NULL
|
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_mutex = SDL_CreateMutex();
|
||||||
sound_cv = SDL_CreateCond();
|
sound_cv = SDL_CreateCond();
|
||||||
|
|
||||||
|
@ -793,6 +773,14 @@ void init_sound()
|
||||||
printf("audio: freq %d, size %d\n", sound_frequency, audio_buffer_size);
|
printf("audio: freq %d, size %d\n", sound_frequency, audio_buffer_size);
|
||||||
#endif
|
#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);
|
SDL_PauseAudio(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
sound.h
23
sound.h
|
@ -22,17 +22,14 @@
|
||||||
|
|
||||||
#define BUFFER_SIZE 65536
|
#define BUFFER_SIZE 65536
|
||||||
|
|
||||||
// A lot of sound cards on PC can't handle such small buffers but this
|
#define GBA_XTAL 16777216.0f
|
||||||
// seems to work well on PSP.
|
#define GBA_60HZ_RATE 16853760.0f /* 228*(272+960)*60 */
|
||||||
|
|
||||||
#ifdef PSP_BUILD
|
|
||||||
|
|
||||||
#define SOUND_BUFFER_SIZE 4096
|
|
||||||
|
|
||||||
|
#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
|
#else
|
||||||
|
#define GBC_BASE_RATE GBA_XTAL
|
||||||
#define SOUND_BUFFER_SIZE 16384
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
@ -54,7 +51,7 @@ typedef struct
|
||||||
s8 fifo[32];
|
s8 fifo[32];
|
||||||
u32 fifo_base;
|
u32 fifo_base;
|
||||||
u32 fifo_top;
|
u32 fifo_top;
|
||||||
fixed16_16 fifo_fractional;
|
fixed8_24 fifo_fractional;
|
||||||
// The + 1 is to give some extra room for linear interpolation
|
// The + 1 is to give some extra room for linear interpolation
|
||||||
// when wrapping around.
|
// when wrapping around.
|
||||||
u32 buffer_index;
|
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_left;
|
||||||
extern u32 gbc_sound_master_volume_right;
|
extern u32 gbc_sound_master_volume_right;
|
||||||
extern u32 gbc_sound_master_volume;
|
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_frequency;
|
||||||
extern u32 sound_on;
|
extern u32 sound_on;
|
||||||
|
@ -122,7 +121,7 @@ extern SDL_mutex *sound_mutex;
|
||||||
void sound_timer_queue8(u32 channel, u8 value);
|
void sound_timer_queue8(u32 channel, u8 value);
|
||||||
void sound_timer_queue16(u32 channel, u16 value);
|
void sound_timer_queue16(u32 channel, u16 value);
|
||||||
void sound_timer_queue32(u32 channel, u32 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 sound_reset_fifo(u32 channel);
|
||||||
void update_gbc_sound(u32 cpu_ticks);
|
void update_gbc_sound(u32 cpu_ticks);
|
||||||
void init_sound();
|
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) \
|
#define sound_update_frequency_step(timer_number) \
|
||||||
timer[timer_number].frequency_step = \
|
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
|
#endif // IN_MEMORY_C
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue