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.
This commit is contained in:
magumagu
2014-04-10 18:28:19 -07:00
parent d7736ac714
commit d43ecd0bd1
6 changed files with 146 additions and 249 deletions

View File

@ -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);
}