diff options
| author | ayuanx <ayuanx@gmail.com> | 2009-12-23 15:34:14 +0000 |
|---|---|---|
| committer | ayuanx <ayuanx@gmail.com> | 2009-12-23 15:34:14 +0000 |
| commit | 9eea60ca69afac82abb60fc1b1a0c6962f522ced (patch) | |
| tree | 98d0e1d46c0d337c24218fb6e1b4e8048443c397 /Source/Core/AudioCommon/Src/Mixer.cpp | |
| parent | 0d0a7c515fe60e4899f4669fb52a115cfd1f7431 (diff) | |
Sound System Rework: Phase 2
. Performance boost
(Completely non-blocking between Sound thread and CPU thread, in the meantime keeping them thread safe)
. Both 32KHz & 48KHz sound can be handled properly now
(But up-sampling is still not implemented, and I don't think any game requires it.)
. Strategy adjustment
When your PC is *NOT* capable to run the game at 100%:
>> DSound Could yield more fluent sound than OpenAL sometimes, but you will lose the sync between video & audio (since audio is played before video to guarantee fluency)
>> OpenAL Ensures video & audio are always sync'ed, but sound could be intermittent(to let slow video catch up)
. Changed default frame limit to: Auto
(Somehow this can dramatically decrease the chance of wiimote desync in game NSMB)
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4724 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core/AudioCommon/Src/Mixer.cpp')
| -rw-r--r-- | Source/Core/AudioCommon/Src/Mixer.cpp | 214 |
1 files changed, 122 insertions, 92 deletions
diff --git a/Source/Core/AudioCommon/Src/Mixer.cpp b/Source/Core/AudioCommon/Src/Mixer.cpp index 63bc8c7088..00b3a2587b 100644 --- a/Source/Core/AudioCommon/Src/Mixer.cpp +++ b/Source/Core/AudioCommon/Src/Mixer.cpp @@ -16,112 +16,65 @@ // http://code.google.com/p/dolphin-emu/ -// This queue solution is temporary. I'll implement something more efficient later. -#include <queue> // System - -#include "Thread.h" // Common +#include "Atomic.h" #include "Mixer.h" -#include "FixedSizeQueue.h" #include "AudioCommon.h" -int CMixer::Mix(short *samples, int numSamples) +// Executed from sound stream thread +unsigned int CMixer::Mix(short* samples, unsigned int numSamples) { - if (! samples) { - Premix(NULL, 0); + if (!samples) return 0; - } - // silence - memset(samples, 0, numSamples * 2 * sizeof(short)); - if (g_dspInitialize.pEmulatorState) { + if (g_dspInitialize.pEmulatorState) + { if (*g_dspInitialize.pEmulatorState != 0) - return 0; - } - - // first get the DTK Music - if (m_EnableDTKMusic) { - g_dspInitialize.pGetAudioStreaming(samples, numSamples); + { + // Silence + memset(samples, 0, numSamples * 4); + return numSamples; + } } - Premix(samples, numSamples); - - int count = 0; + unsigned int numLeft = Common::AtomicLoad(m_numSamples); + numLeft = (numLeft > numSamples) ? numSamples : numLeft; - push_sync.Enter(); - while (m_queueSize > queue_minlength && count < numSamples * 2) + // Do re-sampling if needed + if (m_sampleRate == m_dspSampleRate) { - int x = samples[count]; - x += sample_queue.front(); - if (x > 32767) x = 32767; - if (x < -32767) x = -32767; - samples[count++] = x; - sample_queue.pop(); - x = samples[count]; - x += sample_queue.front(); - if (x > 32767) x = 32767; - if (x < -32767) x = -32767; - samples[count++] = x; - sample_queue.pop(); - m_queueSize-=2; + for (unsigned int i = 0; i < numLeft * 2; i++) + samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]); + m_indexR += numLeft * 2; } - push_sync.Leave(); + else if (m_sampleRate < m_dspSampleRate) // If down-sampling needed + { + _dbg_assert_msg_(DSPHLE, !(numSamples % 2), "Number of Samples: %i must be even!", numSamples); - return count; -} + short *pDest = samples; + int last_l, last_r, cur_l, cur_r; + for (unsigned int i = 0; i < numLeft * 3 / 2; i++) + { + cur_l = Common::swap16(m_buffer[(m_indexR + i * 2) & INDEX_MASK]); + cur_r = Common::swap16(m_buffer[(m_indexR + i * 2 + 1) & INDEX_MASK]); -void CMixer::PushSamples(short *samples, int num_stereo_samples, int core_sample_rate) -{ - push_sync.Enter(); - if (m_queueSize == 0) - { - m_queueSize = queue_minlength; - for (int i = 0; i < queue_minlength; i++) - sample_queue.push((s16)0); - } - push_sync.Leave(); - -#ifdef _WIN32 - if (GetAsyncKeyState(VK_TAB)) - return; -#endif + if (i % 3) + { + *pDest++ = (last_l + cur_r) / 2; + *pDest++ = (last_r + cur_r) / 2; + } - // Write Other Audio - if (!m_throttle) - return; - - // ----------------------------------------------------------------------- - // The auto throttle function. This loop will put a ceiling on the CPU MHz. - // ---------------------------- - /* This is only needed for non-AX sound, currently directly - streamed and DTK sound. For AX we call SoundStream::Update in - AXTask() for example. */ - while (m_queueSize > queue_maxlength / 2) - { - // Urgh. - if (g_dspInitialize.pEmulatorState) { - if (*g_dspInitialize.pEmulatorState != 0) - return; + last_l = cur_l; + last_r = cur_r; } - soundStream->Update(); - SLEEP(1); - } - // ----------------------------------------------------------------------- - push_sync.Enter(); - while (num_stereo_samples) - { - sample_queue.push(Common::swap16(*samples)); - samples++; - sample_queue.push(Common::swap16(*samples)); - samples++; - m_queueSize += 2; - num_stereo_samples--; + m_indexR += numLeft * 2 * 3 / 2; } - push_sync.Leave(); - return; - + else if (m_sampleRate > m_dspSampleRate) + { + // AyuanX: Up-sampling is not implemented yet + PanicAlert("Mixer: Up-sampling is not implemented yet!"); /* static int PV1l=0,PV2l=0,PV3l=0,PV4l=0; static int PV1r=0,PV2r=0,PV3r=0,PV4r=0; @@ -183,16 +136,93 @@ void CMixer::PushSamples(short *samples, int num_stereo_samples, int core_sample sample_queue.push(r); m_queueSize += 2; } - push_sync.Leave(); */ + } + // Padding + if (numSamples > numLeft) + memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4); + + // Add the HLE sound + if (m_sampleRate < m_dspSampleRate) + { + PanicAlert("Mixer: DSPHLE down-sampling is not implemented yet!\n" + "Usually no game should require this, please report!"); + } + else + { + Premix(samples, numSamples, m_sampleRate); + } + + // Add the DTK Music + if (m_EnableDTKMusic) + { + // Re-sampling is done inside + g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate); + } + + Common::AtomicAdd(m_numSamples, -(int)numLeft); + + return numSamples; +} + + +void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int sample_rate) +{ + // The auto throttle function. This loop will put a ceiling on the CPU MHz. + if (m_throttle) + { + // AyuanX: Remember to reserve "num_samples * 1.5" free sample space at least! + // Becuse we may do re-sampling later + while (Common::AtomicLoad(m_numSamples) >= MAX_SAMPLES - RESERVED_SAMPLES) + { + if (g_dspInitialize.pEmulatorState) + { + if (*g_dspInitialize.pEmulatorState != 0) + break; + } + soundStream->Update(); + SLEEP(1); + } + } + + // Check if we have enough free space + if (num_samples > MAX_SAMPLES - Common::AtomicLoad(m_numSamples)) + return; + + // AyuanX: Actual re-sampling work has been moved to sound thread + // to alleviates the workload on main thread + // and we simply store raw data here to make fast mem copy + int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (m_indexW & INDEX_MASK)) * sizeof(short); + if (over_bytes > 0) + { + memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes); + memcpy(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes); + } + else + { + memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4); + } + + m_indexW += num_samples * 2; + + if (m_sampleRate < m_dspSampleRate) + { + // This is kind of tricky :P + num_samples = num_samples * 2 / 3; + } + else if (m_sampleRate > m_dspSampleRate) + { + PanicAlert("Mixer: Up-sampling is not implemented yet!"); + } + + Common::AtomicAdd(m_numSamples, num_samples); + + return; } -int CMixer::GetNumSamples() +unsigned int CMixer::GetNumSamples() { - return m_queueSize / 2; - //int ret = (m_queueSize - queue_minlength) / 2; - //ret = (ret > 0) ? ret : 0; - //return ret; + return Common::AtomicLoad(m_numSamples); } |
