Merge pull request #259 from magumagu/dtk-rewrite

DTK rewrite
This commit is contained in:
Lioncash
2014-06-26 20:01:07 -04:00
7 changed files with 180 additions and 253 deletions

View File

@ -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

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
@ -45,7 +34,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples, bool consider_
u32 indexR = Common::AtomicLoad(m_indexR);
u32 indexW = Common::AtomicLoad(m_indexW);
float numLeft = ((indexW - indexR) & INDEX_MASK) / 2;
float numLeft = (float)(((indexW - indexR) & INDEX_MASK) / 2);
m_numLeftI = (numLeft + m_numLeftI*(CONTROL_AVG-1)) / CONTROL_AVG;
float offset = (m_numLeftI - LOW_WATERMARK) * CONTROL_FACTOR;
if (offset > MAX_FREQ_SHIFT) offset = MAX_FREQ_SHIFT;
@ -56,29 +45,36 @@ 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");
s32 lvolume = m_LVolume;
s32 rvolume = m_RVolume;
// TODO: consider a higher-quality resampling algorithm.
for (; currentSample < numSamples*2 && ((indexW-indexR) & INDEX_MASK) > 2; currentSample+=2) {
u32 indexR2 = indexR + 2; //next sample
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 = (sampleL * lvolume) >> 8;
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 = (sampleR * rvolume) >> 8;
sampleR += samples[currentSample];
MathUtil::Clamp(&sampleR, -32767, 32767);
samples[currentSample] = sampleR;
frac += ratio;
@ -87,36 +83,57 @@ 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)
s[0] = (s[0] * lvolume) >> 8;
s[1] = (s[1] * rvolume) >> 8;
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 +172,23 @@ 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);
}
void CMixer::SetStreamingVolume(unsigned int lvolume, unsigned int rvolume)
{
m_streaming_mixer.SetVolume(lvolume, rvolume);
}
void CMixer::MixerFifo::SetVolume(unsigned int lvolume, unsigned int rvolume)
{
m_LVolume = lvolume + (lvolume >> 7);
m_RVolume = rvolume + (rvolume >> 7);
}

View File

@ -15,29 +15,21 @@
#define LOW_WATERMARK 1280 // 40 ms
#define MAX_FREQ_SHIFT 200 // per 32000 Hz
#define CONTROL_FACTOR 0.2 // in freq_shift per fifo size offset
#define CONTROL_FACTOR 0.2f // in freq_shift per fifo size offset
#define CONTROL_AVG 32
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,9 @@ 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 SetStreamingVolume(unsigned int lvolume, unsigned int rvolume);
void SetThrottle(bool use) { m_throttle = use;}
@ -87,11 +81,36 @@ 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)
, m_LVolume(256)
, m_RVolume(256)
{
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);
void SetVolume(unsigned int lvolume, unsigned int rvolume);
private:
CMixer *m_mixer;
unsigned m_input_sample_rate;
short m_buffer[MAX_SAMPLES * 2];
volatile u32 m_indexW;
volatile u32 m_indexR;
// Volume ranges from 0-256
volatile s32 m_LVolume;
volatile s32 m_RVolume;
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 +118,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:
};