diff --git a/source/audio.cpp b/source/audio.cpp index 3d434cc..1ad94b5 100644 --- a/source/audio.cpp +++ b/source/audio.cpp @@ -29,65 +29,58 @@ #include "snes9x/spc7110.h" #include "snes9x/controls.h" +extern int ScreenshotRequested; extern int ConfigRequested; /*** Double buffered audio ***/ +#define SAMPLES_TO_PROCESS 1024 #define AUDIOBUFFER 2048 -static unsigned char soundbuffer[2][AUDIOBUFFER] __attribute__ ((__aligned__ (32))); -static int whichab = 0; /*** Audio buffer flip switch ***/ +#define BUFFERCOUNT 16 +static u8 soundbuffer[BUFFERCOUNT][AUDIOBUFFER] __attribute__ ((__aligned__ (32))); +static int playab = 0; +static int nextab = 0; +int available = 0; -#define AUDIOSTACK 16384 -static lwpq_t audioqueue; -static lwp_t athread; -static uint8 astack[AUDIOSTACK]; -static mutex_t audiomutex = LWP_MUTEX_NULL; +static inline void updateAvailable(int diff) { + available += diff; -/**************************************************************************** - * Audio Threading - ***************************************************************************/ -static void * -AudioThread (void *arg) -{ - LWP_InitQueue (&audioqueue); - - while (1) - { - if (ConfigRequested) - memset (soundbuffer[whichab], 0, AUDIOBUFFER); - else - { - LWP_MutexLock(audiomutex); - S9xMixSamples (soundbuffer[whichab], AUDIOBUFFER >> 1); - LWP_MutexUnlock(audiomutex); - } - DCFlushRange (soundbuffer[whichab], AUDIOBUFFER); - LWP_ThreadSleep (audioqueue); + if(available < 0) { + available = 0; } - - return NULL; -} - -/**************************************************************************** - * MixSamples - * This continually calls S9xMixSamples On each DMA Completion - ***************************************************************************/ -static void -GCMixSamples () -{ - if (!ConfigRequested) - { - whichab ^= 1; - AUDIO_InitDMA ((u32) soundbuffer[whichab], AUDIOBUFFER); - LWP_ThreadSignal (audioqueue); + else if(available > BUFFERCOUNT-1) { + available = BUFFERCOUNT-1; } } -static void FinalizeSamplesCallback (void *data) -{ - LWP_MutexLock(audiomutex); - UpdatePlaybackRateWithDynamicRate(); +static void DMACallback () { + if (!ScreenshotRequested && !ConfigRequested) { + AUDIO_InitDMA ((u32) soundbuffer[playab], AUDIOBUFFER); + updateAvailable(-1); + playab = (playab + 1) % BUFFERCOUNT; + } +} + +static void S9xAudioCallback (void *data) { + //S9xUpdateDynamicRate(); // TODO: what arguments should be passed here? S9xFinalizeSamples(); - LWP_MutexUnlock(audiomutex); + int availableSamples = S9xGetSampleCount(); + + if (ScreenshotRequested || ConfigRequested) { + AUDIO_StopDMA(); + } + else if(availableSamples >= SAMPLES_TO_PROCESS) { + nextab = (nextab + 1) % BUFFERCOUNT; + updateAvailable(1); + S9xMixSamples (soundbuffer[nextab], SAMPLES_TO_PROCESS); + DCFlushRange (soundbuffer[nextab], AUDIOBUFFER); + + if(playab == -1) { + if(available > 2) { + playab = 0; + AUDIO_StartDMA(); + } + } + } } /**************************************************************************** @@ -99,12 +92,10 @@ InitAudio () #ifdef NO_SOUND AUDIO_Init (NULL); AUDIO_SetDSPSampleRate(AI_SAMPLERATE_48KHZ); - AUDIO_RegisterDMACallback(GCMixSamples); + AUDIO_RegisterDMACallback(DMACallback); #else ASND_Init(); #endif - LWP_MutexInit(&audiomutex, false); - LWP_CreateThread (&athread, AudioThread, NULL, astack, AUDIOSTACK, 70); } /**************************************************************************** @@ -123,16 +114,9 @@ SwitchAudioMode(int mode) AUDIO_StopDMA(); AUDIO_RegisterDMACallback(NULL); DSP_Halt(); - AUDIO_RegisterDMACallback(GCMixSamples); + AUDIO_RegisterDMACallback(DMACallback); #endif - memset(soundbuffer[0],0,AUDIOBUFFER); - memset(soundbuffer[1],0,AUDIOBUFFER); - DCFlushRange(soundbuffer[0],AUDIOBUFFER); - DCFlushRange(soundbuffer[1],AUDIOBUFFER); - AUDIO_InitDMA((u32)soundbuffer[whichab],AUDIOBUFFER); - AUDIO_StartDMA(); - - S9xSetSamplesAvailableCallback(FinalizeSamplesCallback, NULL); + S9xSetSamplesAvailableCallback(S9xAudioCallback, NULL); } else // menu { @@ -166,5 +150,7 @@ void ShutdownAudio() void AudioStart () { - GCMixSamples (); + available = 0; + nextab = 0; + playab = -1; } diff --git a/source/preferences.cpp b/source/preferences.cpp index ba9b398..d80ac66 100644 --- a/source/preferences.cpp +++ b/source/preferences.cpp @@ -485,6 +485,7 @@ DefaultSettings () Settings.SoundPlaybackRate = 48000; Settings.SoundInputRate = 31950; Settings.DynamicRateControl = true; + Settings.DynamicRateLimit = 1; // Graphics Settings.Transparency = true; diff --git a/source/snes9x/apu/apu.cpp b/source/snes9x/apu/apu.cpp index 7235831..2317e66 100644 --- a/source/snes9x/apu/apu.cpp +++ b/source/snes9x/apu/apu.cpp @@ -387,27 +387,6 @@ int S9xGetSampleCount (void) return (spc::resampler->avail() >> (Settings.Stereo ? 0 : 1)); } -#ifdef GEKKO -static double new_dynamic_rate_multiplier = 1.0; - -void UpdatePlaybackRateWithDynamicRate() { - if(spc::dynamic_rate_multiplier != new_dynamic_rate_multiplier) { - spc::dynamic_rate_multiplier = new_dynamic_rate_multiplier; - UpdatePlaybackRate(); - } -} - -static inline void IncreaseDynamicRateMultiplier () -{ - new_dynamic_rate_multiplier = 1.01; -} - -static inline void ResetDynamicRateMultiplier () -{ - new_dynamic_rate_multiplier = 1.0; -} -#endif - void S9xFinalizeSamples (void) { bool drop_current_msu1_samples = TRUE; @@ -420,7 +399,6 @@ void S9xFinalizeSamples (void) { /* We weren't able to process the entire buffer. Potential overrun. */ spc::sound_in_sync = FALSE; - S9xClearSamples(); if (Settings.SoundSync && !Settings.TurboMode) return; @@ -452,13 +430,6 @@ void S9xFinalizeSamples (void) else spc::sound_in_sync = FALSE; - if(spc::sound_in_sync) { - ResetDynamicRateMultiplier (); - } - else { - IncreaseDynamicRateMultiplier (); - } - spc_core->set_output((SNES_SPC::sample_t *) spc::landing_buffer, spc::buffer_size >> 1); } @@ -494,6 +465,14 @@ void S9xSetSamplesAvailableCallback (apu_callback callback, void *data) spc::extra_data = data; } +void S9xUpdateDynamicRate (int avail, int buffer_size) +{ + spc::dynamic_rate_multiplier = 1.0 + (Settings.DynamicRateLimit * (buffer_size - 2 * avail)) / + (double)(1000 * buffer_size); + + UpdatePlaybackRate(); +} + void UpdatePlaybackRate (void) { if (Settings.SoundInputRate == 0) diff --git a/source/snes9x/apu/apu.h b/source/snes9x/apu/apu.h index 78557f8..6c02fab 100644 --- a/source/snes9x/apu/apu.h +++ b/source/snes9x/apu/apu.h @@ -211,10 +211,10 @@ void S9xSetSoundControl (uint8); void S9xSetSoundMute (bool8); void S9xLandSamples (void); void S9xFinalizeSamples (void); -void UpdatePlaybackRateWithDynamicRate(); void S9xClearSamples (void); bool8 S9xMixSamples (uint8 *, int); void S9xSetSamplesAvailableCallback (apu_callback, void *); +void S9xUpdateDynamicRate (int, int); extern SNES_SPC *spc_core; diff --git a/source/snes9x/snes9x.h b/source/snes9x/snes9x.h index dbf9e65..eab2420 100644 --- a/source/snes9x/snes9x.h +++ b/source/snes9x/snes9x.h @@ -388,6 +388,7 @@ struct SSettings bool8 ReverseStereo; bool8 Mute; bool8 DynamicRateControl; + int32 DynamicRateLimit; /* Multiplied by 1000 */ bool8 SupportHiRes; bool8 Transparency;