summaryrefslogtreecommitdiff
path: root/Source/Core/AudioCommon
diff options
context:
space:
mode:
authormagumagu <magumagu9@gmail.com>2014-04-10 18:28:19 -0700
committermagumagu <magumagu9@gmail.com>2014-06-14 15:55:20 -0700
commitd43ecd0bd1c3387a1d7ea968069b093e1ba81f2d (patch)
tree85001bd0a1b487ee88b15c5b9674e0c69d9d0dfb /Source/Core/AudioCommon
parentd7736ac7144ae5a16f2a60fd02523040ee8e0ea3 (diff)
Rewrite handling of DTK (streaming) audio.
The primary motivation here is to make sure we submit samples from the CPU thread. This makes sure the timing of related interrupts accurate, and generally keeps the different kinds of audio synchronized. This will also allow improvements to audio dumping functionality. The new code is also more concise because it gets rid of some duplicated audio mixing code.
Diffstat (limited to 'Source/Core/AudioCommon')
-rw-r--r--Source/Core/AudioCommon/AudioCommon.cpp5
-rw-r--r--Source/Core/AudioCommon/Mixer.cpp73
-rw-r--r--Source/Core/AudioCommon/Mixer.h59
3 files changed, 80 insertions, 57 deletions
diff --git a/Source/Core/AudioCommon/AudioCommon.cpp b/Source/Core/AudioCommon/AudioCommon.cpp
index c476fe6a5c..5cc57800b5 100644
--- a/Source/Core/AudioCommon/AudioCommon.cpp
+++ b/Source/Core/AudioCommon/AudioCommon.cpp
@@ -28,10 +28,7 @@ namespace AudioCommon
{
SoundStream *InitSoundStream(void *hWnd)
{
- unsigned int AISampleRate, DACSampleRate;
- AudioInterface::Callback_GetSampleRate(AISampleRate, DACSampleRate);
- delete soundStream;
- CMixer *mixer = new CMixer(AISampleRate, DACSampleRate, 48000);
+ CMixer *mixer = new CMixer(48000);
// TODO: possible memleak with mixer
diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp
index c1ff49dd03..3e75777f9a 100644
--- a/Source/Core/AudioCommon/Mixer.cpp
+++ b/Source/Core/AudioCommon/Mixer.cpp
@@ -6,6 +6,7 @@
#include "AudioCommon/Mixer.h"
#include "Common/Atomic.h"
#include "Common/CPUDetect.h"
+#include "Common/MathUtil.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/HW/AudioInterface.h"
@@ -19,20 +20,8 @@
#endif
// Executed from sound stream thread
-unsigned int CMixer::Mix(short* samples, unsigned int numSamples, bool consider_framelimit)
+unsigned int CMixer::MixerFifo::Mix(short* samples, unsigned int numSamples, bool consider_framelimit)
{
- if (!samples)
- return 0;
-
- std::lock_guard<std::mutex> lk(m_csMixing);
-
- if (PowerPC::GetState() != PowerPC::CPU_RUNNING)
- {
- // Silence
- memset(samples, 0, numSamples * 4);
- return numSamples;
- }
-
unsigned int currentSample = 0;
// Cache access in non-volatile variable
@@ -56,14 +45,14 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples, bool consider_
//remember fractional offset
u32 framelimit = SConfig::GetInstance().m_Framelimit;
- float aid_sample_rate = AudioInterface::GetAIDSampleRate() + offset;
+ float aid_sample_rate = m_input_sample_rate + offset;
if (consider_framelimit && framelimit > 2)
{
aid_sample_rate = aid_sample_rate * (framelimit - 1) * 5 / VideoInterface::TargetRefreshRate;
}
static u32 frac = 0;
- const u32 ratio = (u32)( 65536.0f * aid_sample_rate / (float)m_sampleRate );
+ const u32 ratio = (u32)( 65536.0f * aid_sample_rate / (float)m_mixer->m_sampleRate );
if (ratio > 0x10000)
ERROR_LOG(AUDIO, "ratio out of range");
@@ -74,11 +63,15 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples, bool consider_
s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); //current
s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); //next
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
+ sampleL += samples[currentSample + 1];
+ MathUtil::Clamp(&sampleL, -32767, 32767);
samples[currentSample+1] = sampleL;
s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); //current
s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); //next
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)frac) >> 16;
+ sampleR += samples[currentSample];
+ MathUtil::Clamp(&sampleR, -32767, 32767);
samples[currentSample] = sampleR;
frac += ratio;
@@ -87,36 +80,55 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples, bool consider_
}
// Padding
- unsigned short s[2];
+ short s[2];
s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]);
s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]);
for (; currentSample < numSamples*2; currentSample+=2)
{
- samples[currentSample] = s[0];
- samples[currentSample+1] = s[1];
+ int sampleR = s[0] + samples[currentSample];
+ MathUtil::Clamp(&sampleR, -32767, 32767);
+ samples[currentSample] = sampleR;
+ int sampleL = s[1] + samples[currentSample + 1];
+ MathUtil::Clamp(&sampleL, -32767, 32767);
+ samples[currentSample + 1] = sampleL;
}
// Flush cached variable
Common::AtomicStore(m_indexR, indexR);
- // Add the DTK Music
- // Re-sampling is done inside
- AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
- if (m_logAudio)
- g_wave_writer.AddStereoSamples(samples, numSamples);
-
return numSamples;
}
+unsigned int CMixer::Mix(short* samples, unsigned int num_samples, bool consider_framelimit)
+{
+ if (!samples)
+ return 0;
-void CMixer::PushSamples(const short *samples, unsigned int num_samples)
+ std::lock_guard<std::mutex> lk(m_csMixing);
+
+ memset(samples, 0, num_samples * 2 * sizeof(short));
+
+ if (PowerPC::GetState() != PowerPC::CPU_RUNNING)
+ {
+ // Silence
+ return num_samples;
+ }
+
+ m_dma_mixer.Mix(samples, num_samples, consider_framelimit);
+ m_streaming_mixer.Mix(samples, num_samples, consider_framelimit);
+ if (m_logAudio)
+ g_wave_writer.AddStereoSamples(samples, num_samples);
+ return num_samples;
+}
+
+void CMixer::MixerFifo::PushSamples(const short *samples, unsigned int num_samples)
{
// Cache access in non-volatile variable
// indexR isn't allowed to cache in the audio throttling loop as it
// needs to get updates to not deadlock.
u32 indexW = Common::AtomicLoad(m_indexW);
- if (m_throttle)
+ if (m_mixer->m_throttle)
{
// The auto throttle function. This loop will put a ceiling on the CPU MHz.
while (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= MAX_SAMPLES * 2)
@@ -155,3 +167,12 @@ void CMixer::PushSamples(const short *samples, unsigned int num_samples)
return;
}
+void CMixer::PushSamples(const short *samples, unsigned int num_samples)
+{
+ m_dma_mixer.PushSamples(samples, num_samples);
+}
+
+void CMixer::PushStreamingSamples(const short *samples, unsigned int num_samples)
+{
+ m_streaming_mixer.PushSamples(samples, num_samples);
+}
diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h
index f7fcdbf14b..b693c3bb3f 100644
--- a/Source/Core/AudioCommon/Mixer.h
+++ b/Source/Core/AudioCommon/Mixer.h
@@ -21,23 +21,15 @@
class CMixer {
public:
- CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000, unsigned int BackendSampleRate = 32000)
- : m_aiSampleRate(AISampleRate)
- , m_dacSampleRate(DACSampleRate)
- , m_bits(16)
- , m_channels(2)
+ CMixer(unsigned int BackendSampleRate)
+ : m_dma_mixer(this, 32000)
+ , m_streaming_mixer(this, 48000)
+ , m_sampleRate(BackendSampleRate)
, m_logAudio(0)
- , m_indexW(0)
- , m_indexR(0)
- , m_numLeftI(0.0f)
+ , m_throttle(false)
+ , m_speed(0)
{
- // AyuanX: The internal (Core & DSP) sample rate is fixed at 32KHz
- // So when AI/DAC sample rate differs than 32KHz, we have to do re-sampling
- m_sampleRate = BackendSampleRate;
-
- memset(m_buffer, 0, sizeof(m_buffer));
-
- INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized (AISampleRate:%i, DACSampleRate:%i)", AISampleRate, DACSampleRate);
+ INFO_LOG(AUDIO_INTERFACE, "Mixer is initialized");
}
virtual ~CMixer() {}
@@ -47,7 +39,8 @@ public:
// Called from main thread
virtual void PushSamples(const short* samples, unsigned int num_samples);
- unsigned int GetSampleRate() const {return m_sampleRate;}
+ virtual void PushStreamingSamples(const short* samples, unsigned int num_samples);
+ unsigned int GetSampleRate() const { return m_sampleRate; }
void SetThrottle(bool use) { m_throttle = use;}
@@ -87,11 +80,30 @@ public:
void UpdateSpeed(volatile float val) { m_speed = val; }
protected:
+ class MixerFifo {
+ public:
+ MixerFifo(CMixer *mixer, unsigned sample_rate)
+ : m_mixer(mixer)
+ , m_input_sample_rate(sample_rate)
+ , m_indexW(0)
+ , m_indexR(0)
+ , m_numLeftI(0.0f)
+ {
+ memset(m_buffer, 0, sizeof(m_buffer));
+ }
+ void PushSamples(const short* samples, unsigned int num_samples);
+ unsigned int Mix(short* samples, unsigned int numSamples, bool consider_framelimit = true);
+ private:
+ CMixer *m_mixer;
+ unsigned m_input_sample_rate;
+ short m_buffer[MAX_SAMPLES * 2];
+ volatile u32 m_indexW;
+ volatile u32 m_indexR;
+ float m_numLeftI;
+ };
+ MixerFifo m_dma_mixer;
+ MixerFifo m_streaming_mixer;
unsigned int m_sampleRate;
- unsigned int m_aiSampleRate;
- unsigned int m_dacSampleRate;
- int m_bits;
- int m_channels;
WaveFileWriter g_wave_writer;
@@ -99,14 +111,7 @@ protected:
bool m_throttle;
- short m_buffer[MAX_SAMPLES * 2];
- volatile u32 m_indexW;
- volatile u32 m_indexR;
-
std::mutex m_csMixing;
- float m_numLeftI;
volatile float m_speed; // Current rate of the emulation (1.0 = 100% speed)
-private:
-
};