aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNebuleon Fumika2013-02-01 06:11:59 -0500
committerNebuleon Fumika2013-02-01 06:11:59 -0500
commit58948ffd1d05084f3d84bc12a2e75144741b292c (patch)
tree4416bdb33891695b2f42677bf9662f0bd8ddd736
parent58a3dc9b1762ef0b1b12090d1b707a7f7fc9d9f9 (diff)
downloadsnes9x2005-58948ffd1d05084f3d84bc12a2e75144741b292c.tar.gz
snes9x2005-58948ffd1d05084f3d84bc12a2e75144741b292c.tar.bz2
snes9x2005-58948ffd1d05084f3d84bc12a2e75144741b292c.zip
Make the audio timing more precise.
* Fake out the buffer timing by sending a buffer full of silence when returning from pause. Reduces crackling introduced by the next point. * Send buffers only once every 23.22 milliseconds, not up to four buffers at once (92.88 milliseconds) and randomly thereafter. Reduces note-length jumpiness. * Audio may have trouble catching up if external jitter reaches 11.61 milliseconds. That happens if Mode 7 images or filtered modes take a long time to render, or if chips take a long time to execute.
-rw-r--r--source/nds/entry.cpp216
1 files changed, 121 insertions, 95 deletions
diff --git a/source/nds/entry.cpp b/source/nds/entry.cpp
index 6fab5fc..c0c8efa 100644
--- a/source/nds/entry.cpp
+++ b/source/nds/entry.cpp
@@ -677,6 +677,7 @@ void S9xSyncSpeed ()
skip_rate = 0;
ds2_setCPUclocklevel(0);
if (syncdif > 0)
+ // TODO Turn this delay into a ProcessSound loop?
udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */);
set_cpu_clock(clock_speed_number);
S9xProcessSound (0);
@@ -709,6 +710,7 @@ void S9xSyncSpeed ()
if (syncdif > 0)
{
ds2_setCPUclocklevel(0);
+ // TODO Turn this delay into a ProcessSound loop?
udelay(syncdif * 128 / 3 /* times 42 + 2/3 microseconds */);
set_cpu_clock(clock_speed_number);
S9xProcessSound (0);
@@ -903,6 +905,9 @@ void S9xGenerateSound ()
}
}
+#define SOUND_EMISSION_INTERVAL ((unsigned int) ((((unsigned long long) DS2_BUFFER_SIZE * 1000000) / SND_SAMPLE_RATE) * 3 / 128))
+unsigned int LastSoundEmissionTime = 0;
+
void S9xProcessSound (unsigned int)
{
unsigned short *audiobuff;
@@ -910,143 +915,164 @@ void S9xProcessSound (unsigned int)
if (so.mute_sound || !game_enable_audio)
return;
- if(ds2_checkAudiobuff() > 4)
+ if(ds2_checkAudiobuff() > AUDIO_BUFFER_COUNT / 2)
+ {
+ LastSoundEmissionTime++;
return;
+ }
- /* Number of samples to generate now */
- int sample_count;
- sample_count = so.buffer_size;
-#ifndef FOREVER_16_BIT_SOUND
- if (so.sixteen_bit)
+ unsigned int Now = getSysTime();
+ if (Now - LastSoundEmissionTime >= SOUND_EMISSION_INTERVAL)
{
+ if (Now - LastSoundEmissionTime >= 11719 /* 500 milliseconds */)
+ {
+ LastSoundEmissionTime = Now;
+ // We were probably paused. Restart sending sound with an
+ // empty buffer.
+ do {
+ audiobuff = (unsigned short*)ds2_getAudiobuff();
+ } while (audiobuff == NULL); //There are audio queue in sending or wait to send
+
+ memset(audiobuff, 0, DS2_BUFFER_SIZE);
+
+ ds2_updateAudio();
+ // And then the real audio. (fall through)
+ }
+ else
+ {
+ LastSoundEmissionTime += SOUND_EMISSION_INTERVAL;
+ }
+ /* Number of samples to generate now */
+ int sample_count = so.buffer_size;
+#ifndef FOREVER_16_BIT_SOUND
+ if (so.sixteen_bit)
+ {
#endif
- /* to prevent running out of buffer space,
- * create less samples
- */
- sample_count >>= 1;
+ /* to prevent running out of buffer space,
+ * create less samples
+ */
+ sample_count >>= 1;
#ifndef FOREVER_16_BIT_SOUND
- }
+ }
#endif
- audiobuff = (unsigned short*)ds2_getAudiobuff();
- if(NULL == audiobuff) //There are audio queue in sending or wait to send
- {
- return;
- }
+ do {
+ audiobuff = (unsigned short*)ds2_getAudiobuff();
+ } while (audiobuff == NULL); //There are audio queue in sending or wait to send
- /* If we need more audio samples */
- if (so.samples_mixed_so_far < sample_count)
- {
- /* Where to put the samples to */
+ /* If we need more audio samples */
+ if (so.samples_mixed_so_far < sample_count)
+ {
+ /* Where to put the samples to */
#ifndef FOREVER_16_BIT_SOUND
- unsigned byte_offset = (so.play_position +
- (so.sixteen_bit ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far)) & SOUND_BUFFER_SIZE_MASK;
+ unsigned byte_offset = (so.play_position +
+ (so.sixteen_bit ? (so.samples_mixed_so_far << 1) : so.samples_mixed_so_far)) & SOUND_BUFFER_SIZE_MASK;
#else
- unsigned byte_offset = (so.play_position +
- (so.samples_mixed_so_far << 1)) & SOUND_BUFFER_SIZE_MASK;
+ unsigned byte_offset = (so.play_position +
+ (so.samples_mixed_so_far << 1)) & SOUND_BUFFER_SIZE_MASK;
#endif
- //printf ("%d:", sample_count - so.samples_mixed_so_far); fflush (stdout);
- if (Settings.SoundSync == 2)
- {
- /*memset (Buf + (byte_offset & SOUND_BUFFER_SIZE_MASK), 0,
- sample_count - so.samples_mixed_so_far);*/
- }
- else
- {
- /* Mix the missing samples */
+ if (Settings.SoundSync == 2)
+ {
+ /*memset (Buf + (byte_offset & SOUND_BUFFER_SIZE_MASK), 0,
+ sample_count - so.samples_mixed_so_far);*/
+ }
+ else
+ {
+ /* Mix the missing samples */
#ifndef FOREVER_16_BIT_SOUND
- int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) :
- so.samples_mixed_so_far;
+ int bytes_so_far = so.sixteen_bit ? (so.samples_mixed_so_far << 1) :
+ so.samples_mixed_so_far;
#else
- int bytes_so_far = so.samples_mixed_so_far << 1;
+ int bytes_so_far = so.samples_mixed_so_far << 1;
#endif
- uint32 samples_to_write = sample_count - so.samples_mixed_so_far;
- do
- {
- int bytes_this_run = samples_to_write;
+ uint32 samples_to_write = sample_count - so.samples_mixed_so_far;
+ do
+ {
+ int bytes_this_run = samples_to_write;
#ifndef FOREVER_16_BIT_SOUND
- if (so.sixteen_bit)
+ if (so.sixteen_bit)
#endif
- bytes_this_run <<= 1;
+ bytes_this_run <<= 1;
- if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE)
- {
- bytes_this_run = SOUND_BUFFER_SIZE - byte_offset;
- }
+ if (byte_offset + bytes_this_run > SOUND_BUFFER_SIZE)
+ {
+ bytes_this_run = SOUND_BUFFER_SIZE - byte_offset;
+ }
- if (bytes_so_far + bytes_this_run > so.buffer_size)
- {
- bytes_this_run = so.buffer_size - bytes_so_far;
- if (bytes_this_run == 0)
- break;
- }
+ if (bytes_so_far + bytes_this_run > so.buffer_size)
+ {
+ bytes_this_run = so.buffer_size - bytes_so_far;
+ if (bytes_this_run == 0)
+ break;
+ }
- int samples_this_run = bytes_this_run;
+ int samples_this_run = bytes_this_run;
#ifndef FOREVER_16_BIT_SOUND
- if (so.sixteen_bit)
+ if (so.sixteen_bit)
#endif
- samples_this_run >>= 1;
+ samples_this_run >>= 1;
- S9xMixSamples (Buf + byte_offset, samples_this_run);
- so.samples_mixed_so_far += samples_this_run;
- samples_to_write -= samples_this_run;
+ S9xMixSamples (Buf + byte_offset, samples_this_run);
+ so.samples_mixed_so_far += samples_this_run;
+ samples_to_write -= samples_this_run;
#ifndef FOREVER_16_BIT_SOUND
- bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) :
- samples_this_run;
+ bytes_so_far += so.sixteen_bit ? (samples_this_run << 1) :
+ samples_this_run;
#else
- bytes_so_far += samples_this_run << 1;
+ bytes_so_far += samples_this_run << 1;
#endif
- byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK;
- } while (samples_to_write > 0);
+ byte_offset = (byte_offset + bytes_this_run) & SOUND_BUFFER_SIZE_MASK;
+ } while (samples_to_write > 0);
+ }
}
- }
-// if (!so.mute_sound)
- {
- unsigned bytes_to_write = sample_count;
+ // if (!so.mute_sound)
+ {
+ unsigned bytes_to_write = sample_count;
#ifndef FOREVER_16_BIT_SOUND
- if(so.sixteen_bit)
+ if(so.sixteen_bit)
#endif
- bytes_to_write <<= 1;
+ bytes_to_write <<= 1;
- unsigned byte_offset = so.play_position;
- so.play_position = (so.play_position + bytes_to_write) & SOUND_BUFFER_SIZE_MASK; /* wrap to beginning */
+ unsigned byte_offset = so.play_position;
+ so.play_position = (so.play_position + bytes_to_write) & SOUND_BUFFER_SIZE_MASK; /* wrap to beginning */
- unsigned short *dst_pt = audiobuff;
- unsigned short *dst_pt1 = dst_pt + DS2_BUFFER_SIZE;
+ unsigned short *dst_pt = audiobuff;
+ unsigned short *dst_pt1 = dst_pt + DS2_BUFFER_SIZE;
- /* Feed the samples to the soundcard until nothing is left */
- for(;;)
- {
- int I = bytes_to_write;
- if (byte_offset + I > SOUND_BUFFER_SIZE)
+ /* Feed the samples to the soundcard until nothing is left */
+ for(;;)
{
- I = SOUND_BUFFER_SIZE - byte_offset;
- }
- if(I == 0) break;
+ int I = bytes_to_write;
+ if (byte_offset + I > SOUND_BUFFER_SIZE)
+ {
+ I = SOUND_BUFFER_SIZE - byte_offset;
+ }
+ if(I == 0) break;
-// memcpy(dst_pt, (char *) Buf + byte_offset, I);
-// dst_pt += I;
+ // memcpy(dst_pt, (char *) Buf + byte_offset, I);
+ // dst_pt += I;
- unsigned short *src_pt= (unsigned short*)(Buf + byte_offset);
- for(int m= 0; m < I/4; m++)
- {
- *dst_pt++= *src_pt++;//(*src_pt++) <<1;
- *dst_pt1++= *src_pt++;//(*src_pt++) <<1;
+ unsigned short *src_pt= (unsigned short*)(Buf + byte_offset);
+ for(int m= 0; m < I/4; m++)
+ {
+ *dst_pt++= *src_pt++;//(*src_pt++) <<1;
+ *dst_pt1++= *src_pt++;//(*src_pt++) <<1;
+ }
+
+ bytes_to_write -= I;
+ byte_offset = (byte_offset + I) & SOUND_BUFFER_SIZE_MASK; /* wrap */
}
- bytes_to_write -= I;
- byte_offset = (byte_offset + I) & SOUND_BUFFER_SIZE_MASK; /* wrap */
- }
+ ds2_updateAudio();
- ds2_updateAudio();
+ /* All data sent. */
+ }
- /* All data sent. */
+ so.samples_mixed_so_far -= sample_count;
}
-
- so.samples_mixed_so_far -= sample_count;
}
/*