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)); int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos));
if (numBytesToRender >= 256) if (numBytesToRender >= 256)
{ {
if (numBytesToRender > sizeof(realtimeBuffer) * sizeof(short)) if (numBytesToRender > sizeof(realtimeBuffer))
PanicAlert("soundThread: too big render call"); PanicAlert("soundThread: too big render call");
m_mixer->Mix(realtimeBuffer, numBytesToRender / 4); m_mixer->Mix(realtimeBuffer, numBytesToRender / 4);
WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender); WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender);

View File

@ -17,7 +17,6 @@
#include "Atomic.h" #include "Atomic.h"
#include "Mixer.h" #include "Mixer.h"
#include "AudioCommon.h" #include "AudioCommon.h"
@ -41,37 +40,13 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
numLeft = (numLeft > numSamples) ? numSamples : numLeft; numLeft = (numLeft > numSamples) ? numSamples : numLeft;
// Do re-sampling if needed // Do re-sampling if needed
if (m_sampleRate == m_dspSampleRate) if (m_sampleRate == 32000)
{ {
for (unsigned int i = 0; i < numLeft * 2; i++) for (unsigned int i = 0; i < numLeft * 2; i++)
samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]); samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]);
m_indexR += numLeft * 2; m_indexR += numLeft * 2;
} }
else if (m_sampleRate < m_dspSampleRate) // If down-sampling needed else
{
_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)
{ {
// AyuanX: Up-sampling is not implemented yet // AyuanX: Up-sampling is not implemented yet
PanicAlert("Mixer: 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) if (numSamples > numLeft)
memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4); memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4);
// Add the HLE sound // Add the DSPHLE sound, re-sampling is done inside
if (m_sampleRate < m_dspSampleRate) Premix(samples, numSamples);
{
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 // Add the DTK Music
if (m_EnableDTKMusic) if (m_EnableDTKMusic)
@ -161,19 +128,17 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate); g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate);
} }
Common::AtomicAdd(m_numSamples, -(int)numLeft); Common::AtomicAdd(m_numSamples, -(s32)numLeft);
return numSamples; 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. // The auto throttle function. This loop will put a ceiling on the CPU MHz.
if (m_throttle) 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) while (Common::AtomicLoad(m_numSamples) >= MAX_SAMPLES - RESERVED_SAMPLES)
{ {
if (g_dspInitialize.pEmulatorState) if (g_dspInitialize.pEmulatorState)
@ -181,8 +146,12 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
if (*g_dspInitialize.pEmulatorState != 0) if (*g_dspInitialize.pEmulatorState != 0)
break; break;
} }
soundStream->Update(); // Shortcut key for Throttle Skipping
#ifdef _WIN32
if (GetAsyncKeyState(VK_TAB)) break;;
#endif
SLEEP(1); SLEEP(1);
soundStream->Update();
} }
} }
@ -191,7 +160,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
return; return;
// AyuanX: Actual re-sampling work has been moved to sound thread // 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 // 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); int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (m_indexW & INDEX_MASK)) * sizeof(short);
if (over_bytes > 0) if (over_bytes > 0)
@ -206,12 +175,7 @@ void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int
m_indexW += num_samples * 2; m_indexW += num_samples * 2;
if (m_sampleRate < m_dspSampleRate) if (m_sampleRate != 32000)
{
// 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!"); PanicAlert("Mixer: Up-sampling is not implemented yet!");
} }

View File

@ -19,16 +19,16 @@
#define _MIXER_H_ #define _MIXER_H_
// 16 bit Stereo // 16 bit Stereo
#define MAX_SAMPLES (1024 * 4) #define MAX_SAMPLES (1024 * 8)
#define INDEX_MASK (MAX_SAMPLES * 2 - 1) #define INDEX_MASK (MAX_SAMPLES * 2 - 1)
#define RESERVED_SAMPLES (MAX_SAMPLES / 8) #define RESERVED_SAMPLES (256)
class CMixer { class CMixer {
public: public:
CMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000) CMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000)
: m_aiSampleRate(AISampleRate) : m_aiSampleRate(AISampleRate)
, m_dspSampleRate(DSPSampleRate) , m_dacSampleRate(DACSampleRate)
, m_bits(16) , m_bits(16)
, m_channels(2) , m_channels(2)
, m_HLEready(false) , m_HLEready(false)
@ -36,19 +36,21 @@ public:
, m_indexW(0) , m_indexW(0)
, m_indexR(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 // 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 // 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 // Called from audio threads
virtual unsigned int Mix(short* samples, unsigned int numSamples); 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(); unsigned int GetNumSamples();
// Called from main thread // 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;} unsigned int GetSampleRate() {return m_sampleRate;}
void SetThrottle(bool use) { m_throttle = use;} void SetThrottle(bool use) { m_throttle = use;}
@ -62,7 +64,7 @@ public:
protected: protected:
unsigned int m_sampleRate; unsigned int m_sampleRate;
unsigned int m_aiSampleRate; unsigned int m_aiSampleRate;
unsigned int m_dspSampleRate; unsigned int m_dacSampleRate;
int m_bits; int m_bits;
int m_channels; int m_channels;

View File

@ -25,7 +25,7 @@ class NullMixer : public CMixer {
public: public:
virtual unsigned int Mix(short *samples, unsigned int numSamples) { return 0; } 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 class NullSound : public SoundStream

View File

@ -35,9 +35,9 @@
#endif // WIN32 #endif // WIN32
// 16 bit Stereo // 16 bit Stereo
#define SFX_MAX_SOURCE 1 #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_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 #endif
class OpenALStream: public SoundStream 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_ReadMailBox)(bool _CPUMailbox);
typedef unsigned short (__cdecl* TDSP_ReadControlRegister)(); typedef unsigned short (__cdecl* TDSP_ReadControlRegister)();
typedef unsigned short (__cdecl* TDSP_WriteControlRegister)(unsigned short); 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_Update)(int cycles);
typedef void (__cdecl *TDSP_StopSoundStream)(); typedef void (__cdecl *TDSP_StopSoundStream)();
typedef void (__cdecl *TDSP_ClearAudioBuffer)(); typedef void (__cdecl *TDSP_ClearAudioBuffer)();

View File

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

View File

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

View File

@ -34,16 +34,12 @@ void DoState(PointerWrap &p);
void Update(); void Update();
// Called by DSP plugin // 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); unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate = 48000);
void Read32(u32& _uReturnValue, const u32 _iAddress); void Read32(u32& _uReturnValue, const u32 _iAddress);
void Write32(const u32 _iValue, 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 } // namespace
#endif #endif

View File

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

View File

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

View File

@ -141,6 +141,7 @@
// cr (Not g_dsp.r[CR]) bits // cr (Not g_dsp.r[CR]) bits
// See HW/DSP.cpp. // See HW/DSP.cpp.
#define CR_HALT 0x0004 #define CR_HALT 0x0004
#define CR_INIT 0x0400
#define CR_EXTERNAL_INT 0x0002 #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.")); 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.")); WiimoteStatusLEDs->SetToolTip(wxT("Show which wiimotes are connected in the statusbar."));
WiimoteStatusSpeakers->SetToolTip(wxT("Show wiimote speaker status 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.") 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("\nCauses major speed improvements on PCs with more than one core,")
wxT("\nbut can also cause occasional crashes/glitches.")); wxT("\nbut can also cause occasional crashes/glitches."));

View File

@ -17,7 +17,7 @@ typedef const char* (*TName)(void);
typedef void (*TDebuggerBreak)(void); typedef void (*TDebuggerBreak)(void);
typedef void (*TGenerateDSPInt)(void); typedef void (*TGenerateDSPInt)(void);
typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate); typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate);
typedef void (*TGetSampleRate)(unsigned int &AISampleRate, unsigned int &DSPSampleRate); typedef void (*TGetSampleRate)(unsigned int &AISampleRate, unsigned int &DACSampleRate);
typedef struct typedef struct
{ {
@ -98,9 +98,8 @@ EXPORT void CALL DSP_Update(int cycles);
// Purpose: This function sends the current AI Buffer to the DSP plugin // Purpose: This function sends the current AI Buffer to the DSP plugin
// input: _Address : Memory-Address // input: _Address : Memory-Address
// input: _Number : Number of the Samples // input: _Number : Number of the Samples
// input: _Rate : Sample Rate 32000/48000
// //
EXPORT void CALL DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate); EXPORT void CALL DSP_SendAIBuffer(unsigned int address, unsigned int num_samples);
// __________________________________________________________________________________________________ // __________________________________________________________________________________________________
// Function: DSP_StopSoundStream // Function: DSP_StopSoundStream

View File

@ -58,10 +58,9 @@ DSPConfigDialogHLE::DSPConfigDialogHLE(wxWindow *parent, wxWindowID id, const wx
m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM.")); m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM."));
m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n") m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n")
wxT("Disabling this could cause abnormal game speed, such as too fast.\n") wxT("Disabling this could cause abnormal game speed, such as too fast.\n")
wxT("But sometimes enabling this causes constant noise.")); wxT("But sometimes enabling this could cause constant noise.\n")
wxT("\nKeyboard Shortcut <TAB>: Hold down to instantly disable Throttle."));
m_buttonEnableRE0Fix->SetToolTip(wxT("This fixes audio in Resident Evil Zero and maybe some other games.")); m_buttonEnableRE0Fix->SetToolTip(wxT("This fixes audio in Resident Evil Zero and maybe some other games."));
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!")); m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
// Create sizer and add items to dialog // Create sizer and add items to dialog

View File

@ -20,7 +20,7 @@
#include "DSPHandler.h" #include "DSPHandler.h"
#include "HLEMixer.h" #include "HLEMixer.h"
void HLEMixer::Premix(short *samples, unsigned int numSamples, unsigned int sampleRate) void HLEMixer::Premix(short *samples, unsigned int numSamples)
{ {
// if this was called directly from the HLE // if this was called directly from the HLE
if (g_Config.m_EnableHLEAudio && IsHLEReady()) if (g_Config.m_EnableHLEAudio && IsHLEReady())

View File

@ -6,10 +6,10 @@
class HLEMixer : public CMixer class HLEMixer : public CMixer
{ {
public: public:
HLEMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000) HLEMixer(unsigned int AISampleRate = 48000, unsigned int DACSampleRate = 48000)
: CMixer(AISampleRate, DSPSampleRate) {}; : CMixer(AISampleRate, DACSampleRate) {};
virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate); virtual void Premix(short *samples, unsigned int numSamples);
}; };
#endif // HLEMIXER_H #endif // HLEMIXER_H

View File

@ -307,9 +307,9 @@ unsigned short DSP_WriteControlRegister(unsigned short _Value)
{ {
if (!Temp.DSPHalt && Temp.DSPInit) if (!Temp.DSPHalt && Temp.DSPInit)
{ {
unsigned int AISampleRate, DSPSampleRate; unsigned int AISampleRate, DACSampleRate;
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate); g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate);
soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DSPSampleRate)); soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DACSampleRate));
if(!soundStream) PanicAlert("Error starting up sound stream"); if(!soundStream) PanicAlert("Error starting up sound stream");
// Mixer is initialized // Mixer is initialized
g_InitMixer = true; g_InitMixer = true;
@ -334,7 +334,7 @@ void DSP_Update(int cycles)
inside Mixer_PushSamples(), the reason that we don't disable this entire inside Mixer_PushSamples(), the reason that we don't disable this entire
function when Other Audio is disabled is that then we can't turn it back on function when Other Audio is disabled is that then we can't turn it back on
again once the game has started. */ again once the game has started. */
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate) void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
{ {
if (!soundStream) if (!soundStream)
return; return;
@ -344,9 +344,8 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned i
if (pMixer && address) if (pMixer && address)
{ {
short* samples = (short*)Memory_Get_Pointer(address); short* samples = (short*)Memory_Get_Pointer(address);
// sample_rate could be 32khz/48khz here, // Internal sample rate is always 32khz
// see Core/DSP/DSP.cpp for better information pMixer->PushSamples(samples, num_samples);
pMixer->PushSamples(samples, num_samples, sample_rate);
// FIXME: Write the audio to a file // FIXME: Write the audio to a file
//if (log_ai) //if (log_ai)

View File

@ -39,7 +39,7 @@ DSPConfigDialogLLE::DSPConfigDialogLLE(wxWindow *parent, wxWindowID id, const wx
// Create items // Create items
m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_buttonEnableDTKMusic = new wxCheckBox(this, ID_ENABLE_DTK_MUSIC, wxT("Enable DTK Music"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Other Audio (Throttle)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_buttonEnableThrottle = new wxCheckBox(this, ID_ENABLE_THROTTLE, wxT("Enable Audio Throttle"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator);
wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0); wxStaticText *BackendText = new wxStaticText(this, wxID_ANY, wxT("Audio Backend"), wxDefaultPosition, wxDefaultSize, 0);
m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxSize(90, 20), wxArrayBackends, wxCB_READONLY, wxDefaultValidator); m_BackendSelection = new wxComboBox(this, ID_BACKEND, wxEmptyString, wxDefaultPosition, wxSize(90, 20), wxArrayBackends, wxCB_READONLY, wxDefaultValidator);
@ -51,10 +51,11 @@ DSPConfigDialogLLE::DSPConfigDialogLLE(wxWindow *parent, wxWindowID id, const wx
m_buttonEnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false); m_buttonEnableThrottle->SetValue(ac_Config.m_EnableThrottle ? true : false);
// Add tooltips // Add tooltips
m_buttonEnableDTKMusic->SetToolTip(wxT("This is sometimes used to play music tracks from the disc")); m_buttonEnableDTKMusic->SetToolTip(wxT("This is used to play music tracks, like BGM."));
m_buttonEnableThrottle->SetToolTip(wxT("This is sometimes used together with pre-rendered movies.\n") m_buttonEnableThrottle->SetToolTip(wxT("This is used to control game speed by sound throttle.\n")
wxT("Disabling this also disables the speed throttle which this causes,\n") wxT("Disabling this could cause abnormal game speed, such as too fast.\n")
wxT("meaning that there will be no upper limit on your FPS.")); wxT("But sometimes enabling this could cause constant noise.\n")
wxT("\nKeyboard Shortcut <TAB>: Hold down to instantly disable Throttle."));
m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!")); m_BackendSelection->SetToolTip(wxT("Changing this will have no effect while the emulator is running!"));
// Create sizer and add items to dialog // Create sizer and add items to dialog

View File

@ -263,9 +263,9 @@ u16 DSP_WriteControlRegister(u16 _uFlag)
{ {
if (!Temp.DSPHalt && Temp.DSPInit) if (!Temp.DSPHalt && Temp.DSPInit)
{ {
unsigned int AISampleRate, DSPSampleRate; unsigned int AISampleRate, DACSampleRate;
g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate); g_dspInitialize.pGetSampleRate(AISampleRate, DACSampleRate);
soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DSPSampleRate)); soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DACSampleRate));
if(!soundStream) PanicAlert("Error starting up sound stream"); if(!soundStream) PanicAlert("Error starting up sound stream");
// Mixer is initialized // Mixer is initialized
g_InitMixer = true; g_InitMixer = true;
@ -334,6 +334,8 @@ void DSP_WriteMailboxLow(bool _CPUMailbox, u16 _uLowMail)
void DSP_Update(int cycles) void DSP_Update(int cycles)
{ {
// Sound stream update job has been handled by AudioDMA routine, which is more efficient
/*
// This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something. // This gets called VERY OFTEN. The soundstream update might be expensive so only do it 200 times per second or something.
int cycles_between_ss_update; int cycles_between_ss_update;
@ -350,7 +352,7 @@ void DSP_Update(int cycles)
cycle_count -= cycles_between_ss_update; cycle_count -= cycles_between_ss_update;
soundStream->Update(); soundStream->Update();
} }
*/
// If we're not on a thread, run cycles here. // If we're not on a thread, run cycles here.
if (!g_dspInitialize.bOnThread) if (!g_dspInitialize.bOnThread)
{ {
@ -358,7 +360,7 @@ void DSP_Update(int cycles)
} }
} }
void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate) void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples)
{ {
if (!soundStream) if (!soundStream)
return; return;
@ -369,7 +371,7 @@ void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned i
{ {
short* samples = (short*)Memory_Get_Pointer(address); short* samples = (short*)Memory_Get_Pointer(address);
pMixer->PushSamples(samples, num_samples, sample_rate); pMixer->PushSamples(samples, num_samples);
} }
soundStream->Update(); soundStream->Update();