tweak sound buffering and timing to better match pandora's refresh.
authornotaz <notaz@pixelinis>
Tue, 6 Sep 2011 17:18:34 +0000 (20:18 +0300)
committernotaz <notaz@pixelinis>
Wed, 7 Sep 2011 21:48:33 +0000 (00:48 +0300)
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
main.h
sound.c
sound.h

index 7eea8b6..da22d2e 100644 (file)
--- a/common.h
+++ b/common.h
 
 
 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 (file)
--- 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 (file)
--- 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 (file)
--- a/sound.h
+++ b/sound.h
 
 #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