summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon/Src/Mixer.cpp
diff options
context:
space:
mode:
authorayuanx <ayuanx@gmail.com>2009-12-23 15:34:14 +0000
committerayuanx <ayuanx@gmail.com>2009-12-23 15:34:14 +0000
commit9eea60ca69afac82abb60fc1b1a0c6962f522ced (patch)
tree98d0e1d46c0d337c24218fb6e1b4e8048443c397 /Source/Core/AudioCommon/Src/Mixer.cpp
parent0d0a7c515fe60e4899f4669fb52a115cfd1f7431 (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.cpp214
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);
}