Sound System Rework: Phase 2 (cont'ed)

. Fixed super fast refresh rate issue

. Recovered <TAB> shortcut key for ThrottleSkipping

. Removed redundant "soundstream->Update()" in DSPLLE
  (Thanks to LordMark)


git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4728 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
ayuanx
2009-12-25 11:59:04 +00:00
parent eddafd450e
commit 06218e9ebb
20 changed files with 96 additions and 139 deletions

View File

@ -111,7 +111,7 @@ void DSound::SoundLoop()
int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
if (numBytesToRender >= 256)
{
if (numBytesToRender > sizeof(realtimeBuffer) * sizeof(short))
if (numBytesToRender > sizeof(realtimeBuffer))
PanicAlert("soundThread: too big render call");
m_mixer->Mix(realtimeBuffer, numBytesToRender / 4);
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);

View File

@ -17,7 +17,6 @@
#include "Atomic.h"
#include "Mixer.h"
#include "AudioCommon.h"
@ -41,37 +40,13 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
numLeft = (numLeft > numSamples) ? numSamples : numLeft;
// Do re-sampling if needed
if (m_sampleRate == m_dspSampleRate)
if (m_sampleRate == 32000)
{
for (unsigned int i = 0; i < numLeft * 2; i++)
samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]);
m_indexR += numLeft * 2;
}
else if (m_sampleRate < m_dspSampleRate) // If down-sampling needed
{
_dbg_assert_msg_(DSPHLE, !(numSamples % 2), "Number of Samples: %i must be even!", numSamples);
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]);
if (i % 3)
{
*pDest++ = (last_l + cur_r) / 2;
*pDest++ = (last_r + cur_r) / 2;
}
last_l = cur_l;
last_r = cur_r;
}
m_indexR += numLeft * 2 * 3 / 2;
}
else if (m_sampleRate > m_dspSampleRate)
else
{
// AyuanX: Up-sampling is not implemented yet
PanicAlert("Mixer: Up-sampling is not implemented yet!");
@ -143,16 +118,8 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
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 DSPHLE sound, re-sampling is done inside
Premix(samples, numSamples);
// Add the DTK Music
if (m_EnableDTKMusic)
@ -161,19 +128,17 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate);
}
Common::AtomicAdd(m_numSamples, -(int)numLeft);
Common::AtomicAdd(m_numSamples, -(s32)numLeft);
return numSamples;
}
void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int sample_rate)
void CMixer::PushSamples(short *samples, unsigned int num_samples)
{
// 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)
@ -181,8 +146,12 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
if (*g_dspInitialize.pEmulatorState != 0)
break;
}
soundStream->Update();
// Shortcut key for Throttle Skipping
#ifdef _WIN32
if (GetAsyncKeyState(VK_TAB)) break;;
#endif
SLEEP(1);
soundStream->Update();
}
}
@ -191,7 +160,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
return;
// AyuanX: Actual re-sampling work has been moved to sound thread
// to alleviates the workload on main thread
// to alleviate 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)
@ -206,12 +175,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
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)
if (m_sampleRate != 32000)
{
PanicAlert("Mixer: Up-sampling is not implemented yet!");
}

View File

@ -19,16 +19,16 @@
#define _MIXER_H_
// 16 bit Stereo
#define MAX_SAMPLES (1024 * 4)
#define MAX_SAMPLES (1024 * 8)
#define INDEX_MASK (MAX_SAMPLES * 2 - 1)
#define RESERVED_SAMPLES (MAX_SAMPLES / 8)
#define RESERVED_SAMPLES (256)
class CMixer {
public:
CMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000)
CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000)
: m_aiSampleRate(AISampleRate)
, m_dspSampleRate(DSPSampleRate)
, m_dacSampleRate(DACSampleRate)
, m_bits(16)
, m_channels(2)
, m_HLEready(false)
@ -36,19 +36,21 @@ public:
, m_indexW(0)
, m_indexR(0)
{
// AyuanX: When sample rate differs, we have to do re-sampling
// 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
// I perfer speed so let's do down-sampling instead of up-sampling
// If you like better sound than speed, feel free to implement the up-sampling code
m_sampleRate = (m_aiSampleRate < m_dspSampleRate) ? m_aiSampleRate : m_dspSampleRate;
m_sampleRate = 32000;
NOTICE_LOG(AUDIO_INTERFACE, "Mixer is initialized (AISampleRate:%i, DACSampleRate:%i)", AISampleRate, DACSampleRate);
}
// Called from audio threads
virtual unsigned int Mix(short* samples, unsigned int numSamples);
virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate) {}
virtual void Premix(short *samples, unsigned int numSamples) {}
unsigned int GetNumSamples();
// Called from main thread
virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate);
virtual void PushSamples(short* samples, unsigned int num_samples);
unsigned int GetSampleRate() {return m_sampleRate;}
void SetThrottle(bool use) { m_throttle = use;}
@ -62,7 +64,7 @@ public:
protected:
unsigned int m_sampleRate;
unsigned int m_aiSampleRate;
unsigned int m_dspSampleRate;
unsigned int m_dacSampleRate;
int m_bits;
int m_channels;

View File

@ -25,7 +25,7 @@ class NullMixer : public CMixer {
public:
virtual unsigned int Mix(short *samples, unsigned int numSamples) { return 0; }
virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate) {}
virtual void PushSamples(short* samples, unsigned int num_samples) {}
};
class NullSound : public SoundStream

View File

@ -35,9 +35,9 @@
#endif // WIN32
// 16 bit Stereo
#define SFX_MAX_SOURCE 1
#define OAL_NUM_BUFFERS 8
#define OAL_NUM_BUFFERS 16
#define OAL_MAX_SAMPLES 512 // AyuanX: Don't make it too large, as larger buffer means longer delay
#define OAL_THRESHOLD 128
#define OAL_THRESHOLD 128 // Some games are quite sensitive to delay
#endif
class OpenALStream: public SoundStream

View File

@ -27,7 +27,7 @@ typedef void (__cdecl* TDSP_WriteMailBox)(bool _CPUMailbox, unsigned short);
typedef unsigned short (__cdecl* TDSP_ReadMailBox)(bool _CPUMailbox);
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short);
typedef void (__cdecl *TDSP_SendAIBuffer)(unsigned int address, unsigned int num_samples, unsigned int sample_rate);
typedef void (__cdecl *TDSP_SendAIBuffer)(unsigned int address, unsigned int num_samples);
typedef void (__cdecl *TDSP_Update)(int cycles);
typedef void (__cdecl *TDSP_StopSoundStream)();
typedef void (__cdecl *TDSP_ClearAudioBuffer)();

View File

@ -700,7 +700,7 @@ void Callback_VideoCopiedToXFB(bool video_update)
while (Timer.GetTimeDifference() < wait_frametime * frames)
{
if (no_framelimit==0)
if (no_framelimit == 0)
Common::SleepCurrentThread(1);
}
}

View File

@ -54,13 +54,13 @@ union AICR
struct
{
unsigned PSTAT : 1; // sample counter/playback enable
unsigned AFR : 1; // AI Frequency (0=32khz 1=48khz)
unsigned AIFR : 1; // AI Frequency (0=32khz 1=48khz)
unsigned AIINTMSK : 1; // 0=interrupt masked 1=interrupt enabled
unsigned AIINT : 1; // audio interrupt status
unsigned AIINTVLD : 1; // This bit controls whether AIINT is affected by the AIIT register
// matching AISLRCNT. Once set, AIINT will hold
unsigned SCRESET : 1; // write to reset counter
unsigned DSPFR : 1; // DSP Frequency (0=48khz 1=32khz)
unsigned DACFR : 1; // DAC Frequency (0=48khz 1=32khz)
unsigned :25;
};
u32 hex;
@ -90,16 +90,16 @@ struct SAudioRegister
// STATE_TO_SAVE
static SAudioRegister g_AudioRegister;
static u64 g_LastCPUTime = 0;
static unsigned int g_SampleRate = 32000;
static unsigned int g_DSPSampleRate = 32000;
static unsigned int g_AISampleRate = 32000;
static unsigned int g_DACSampleRate = 32000;
static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL;
void DoState(PointerWrap &p)
{
p.Do(g_AudioRegister);
p.Do(g_LastCPUTime);
p.Do(g_SampleRate);
p.Do(g_DSPSampleRate);
p.Do(g_AISampleRate);
p.Do(g_DACSampleRate);
p.Do(g_CPUCyclesPerSample);
}
@ -111,7 +111,7 @@ void ReadStreamBlock(short* _pPCM);
void Init()
{
g_AudioRegister.m_SampleCounter = 0;
g_AudioRegister.m_Control.AFR = 1;
g_AudioRegister.m_Control.AIFR = 1;
}
void Shutdown()
@ -169,22 +169,22 @@ void Write32(const u32 _Value, const u32 _Address)
g_AudioRegister.m_Control.AIINTVLD = tmpAICtrl.AIINTVLD;
// Set frequency
if (tmpAICtrl.AFR != g_AudioRegister.m_Control.AFR)
if (tmpAICtrl.AIFR != g_AudioRegister.m_Control.AIFR)
{
INFO_LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AFR ? "48khz":"32khz");
g_AudioRegister.m_Control.AFR = tmpAICtrl.AFR;
INFO_LOG(AUDIO_INTERFACE, "Change Freq to %s", tmpAICtrl.AIFR ? "48khz":"32khz");
g_AudioRegister.m_Control.AIFR = tmpAICtrl.AIFR;
}
// Set DSP frequency
if (tmpAICtrl.DSPFR != g_AudioRegister.m_Control.DSPFR)
if (tmpAICtrl.DACFR != g_AudioRegister.m_Control.DACFR)
{
INFO_LOG(AUDIO_INTERFACE, "AI_CONTROL_REGISTER: Change DSPFR Freq to %s", tmpAICtrl.DSPFR ? "48khz":"32khz");
g_AudioRegister.m_Control.DSPFR = tmpAICtrl.DSPFR;
INFO_LOG(AUDIO_INTERFACE, "AI_CONTROL_REGISTER: Change DSPFR Freq to %s", tmpAICtrl.DACFR ? "48khz":"32khz");
g_AudioRegister.m_Control.DACFR = tmpAICtrl.DACFR;
}
g_SampleRate = tmpAICtrl.AFR ? 48000 : 32000;
g_DSPSampleRate = tmpAICtrl.DSPFR ? 32000 : 48000;
g_AISampleRate = tmpAICtrl.AIFR ? 48000 : 32000;
g_DACSampleRate = tmpAICtrl.DACFR ? 32000 : 48000;
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_SampleRate;
g_CPUCyclesPerSample = SystemTimers::GetTicksPerSecond() / g_AISampleRate;
// Streaming counter
if (tmpAICtrl.PSTAT != g_AudioRegister.m_Control.PSTAT)
@ -264,10 +264,10 @@ void GenerateAudioInterrupt()
UpdateInterrupts();
}
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate)
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate)
{
_AISampleRate = g_SampleRate;
_DSPSampleRate = g_DSPSampleRate;
_AISampleRate = g_AISampleRate;
_DACSampleRate = g_DACSampleRate;
}
// Callback for the disc streaming
@ -282,12 +282,12 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
const int rvolume = g_AudioRegister.m_Volume.rightVolume;
if (g_SampleRate == 48000 && _sampleRate == 32000)
if (g_AISampleRate == 48000 && _sampleRate == 32000)
{
_dbg_assert_msg_(AUDIO_INTERFACE, !(_numSamples % 2), "Number of Samples: %i must be even!", _numSamples);
_numSamples = _numSamples * 3 / 2;
}
else if (g_SampleRate == 32000 && _sampleRate == 48000)
else if (g_AISampleRate == 32000 && _sampleRate == 48000)
{
// AyuanX: Up-sampling is not implemented yet
PanicAlert("AUDIO_INTERFACE: Up-sampling is not implemented yet!");
@ -299,7 +299,7 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples
if (pos == 0)
ReadStreamBlock(pcm);
if (g_SampleRate == 48000 && _sampleRate == 32000)
if (g_AISampleRate == 48000 && _sampleRate == 32000)
{
if (i % 3)
{
@ -393,16 +393,6 @@ void IncreaseSampleCount(const u32 _iAmount)
}
}
unsigned int GetAISampleRate()
{
return g_SampleRate;
}
unsigned int GetDSPSampleRate()
{
return g_DSPSampleRate;
}
void Update()
{
// update timer

View File

@ -34,16 +34,12 @@ void DoState(PointerWrap &p);
void Update();
// Called by DSP plugin
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate);
void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate);
unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate = 48000);
void Read32(u32& _uReturnValue, const u32 _iAddress);
void Write32(const u32 _iValue, const u32 _iAddress);
// Get the audio rates (48000 or 32000 only)
unsigned int GetAISampleRate();
unsigned int GetDSPSampleRate();
} // namespace
#endif

View File

@ -484,17 +484,17 @@ void UpdateAudioDMA()
// AyuanX: let's do it in a bundle to speed up
if (g_audioDMA.BlocksLeft == g_audioDMA.AudioDMAControl.NumBlocks)
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8, AudioInterface::GetDSPSampleRate());
dsp_plugin->DSP_SendAIBuffer(g_audioDMA.SourceAddress, g_audioDMA.AudioDMAControl.NumBlocks * 8);
// g_audioDMA.ReadAddress += 32;
g_audioDMA.BlocksLeft--;
if (g_audioDMA.BlocksLeft == 0)
{
GenerateDSPInterrupt(DSP::INT_AID);
// g_audioDMA.ReadAddress = g_audioDMA.SourceAddress;
g_audioDMA.BlocksLeft = g_audioDMA.AudioDMAControl.NumBlocks;
// DEBUG_LOG(DSPLLE, "ADMA read addresses: %08x", g_audioDMA.ReadAddress);
GenerateDSPInterrupt(DSP::INT_AID);
}
}
else

View File

@ -112,7 +112,7 @@ int et_Dec;
int et_VI;
int et_SI;
int et_AI;
int et_AudioFifo;
int et_AudioDMA;
int et_DSP;
int et_IPC_HLE;
int et_FakeGPWD; // DC watchdog hack
@ -127,6 +127,9 @@ int
// These shouldn't be period controlled either, most likely.
DSP_PERIOD,
// This is a fixed value, don't change it
AUDIO_DMA_PERIOD,
// This is completely arbitrary. If we find that we need lower latency, we can just
// increase this number.
IPC_HLE_PERIOD,
@ -165,12 +168,10 @@ void DSPCallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(DSP_PERIOD - cyclesLate, et_DSP);
}
void AudioFifoCallback(u64 userdata, int cyclesLate)
void AudioDMACallback(u64 userdata, int cyclesLate)
{
int period = CPU_CORE_CLOCK / (AudioInterface::GetDSPSampleRate() * 4 / 32);
DSP::UpdateAudioDMA(); // Push audio to speakers.
CoreTiming::ScheduleEvent(period - cyclesLate, et_AudioFifo);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD - cyclesLate, et_AudioDMA);
}
void IPC_HLE_UpdateCallback(u64 userdata, int cyclesLate)
@ -275,6 +276,9 @@ void Init()
// This is the biggest question mark.
AI_PERIOD = GetTicksPerSecond() / 80;
// System internal sample rate is fixed at 32KHz
AUDIO_DMA_PERIOD = CPU_CORE_CLOCK / (32000 * 4 / 32);
Common::Timer::IncreaseResolution();
// store and convert localtime at boot to timebase ticks
startTimeBaseTicks = (u64)(CPU_CORE_CLOCK / TIMER_RATIO) * (u64)CEXIIPL::GetGCTime();
@ -284,7 +288,7 @@ void Init()
et_VI = CoreTiming::RegisterEvent("VICallback", VICallback);
et_SI = CoreTiming::RegisterEvent("SICallback", SICallback);
et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback);
et_AudioFifo = CoreTiming::RegisterEvent("AudioFifoCallback", AudioFifoCallback);
et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback);
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
// Always register this. Increases chances of DC/SC save state compatibility.
et_FakeGPWD = CoreTiming::RegisterEvent("FakeGPWatchdogCallback", FakeGPWatchdogCallback);
@ -294,7 +298,7 @@ void Init()
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
CoreTiming::ScheduleEvent(DSP_PERIOD, et_DSP);
CoreTiming::ScheduleEvent(GetTicksPerSecond() / 60, et_SI);
CoreTiming::ScheduleEvent(CPU_CORE_CLOCK / (32000 * 4 / 32), et_AudioFifo);
CoreTiming::ScheduleEvent(AUDIO_DMA_PERIOD, et_AudioDMA);
// For DC watchdog hack
if (Core::GetStartupParameter().bCPUThread)

View File

@ -141,6 +141,7 @@
// cr (Not g_dsp.r[CR]) bits
// See HW/DSP.cpp.
#define CR_HALT 0x0004
#define CR_INIT 0x0400
#define CR_EXTERNAL_INT 0x0002

View File

@ -286,7 +286,7 @@ void CConfigMain::CreateGUIControls()
wxT("\nIt can be convenient in a Wii game that already has a cursor."));
WiimoteStatusLEDs->SetToolTip(wxT("Show which wiimotes are connected in the statusbar."));
WiimoteStatusSpeakers->SetToolTip(wxT("Show wiimote speaker status in the statusbar."));
DSPThread->SetToolTip(wxT("This should be on when using HLE and off when using LLE."));
DSPThread->SetToolTip(wxT("Run DSPLLE on a dedicate thread, this has no affect on DSPHLE."));
CPUThread->SetToolTip(wxT("This splits the Video and CPU threads, so they can be run on separate cores.")
wxT("\nCauses major speed improvements on PCs with more than one core,")
wxT("\nbut can also cause occasional crashes/glitches."));