diff --git a/Source/Core/AudioCommon/Src/AudioCommon.h b/Source/Core/AudioCommon/Src/AudioCommon.h index 294fab1f72..6edb792004 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.h +++ b/Source/Core/AudioCommon/Src/AudioCommon.h @@ -30,6 +30,31 @@ extern DSPInitialize g_dspInitialize; extern SoundStream *soundStream; extern AudioCommonConfig ac_Config; +// UDSPControl +union UDSPControl +{ + u16 Hex; + struct + { + unsigned DSPReset : 1; // Write 1 to reset and waits for 0 + unsigned DSPAssertInt : 1; + unsigned DSPHalt : 1; + + unsigned AI : 1; + unsigned AI_mask : 1; + unsigned ARAM : 1; + unsigned ARAM_mask : 1; + unsigned DSP : 1; + unsigned DSP_mask : 1; + + unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag + unsigned DSPInitCode : 1; + unsigned DSPInit : 1; // DSPInit() writes to this flag + unsigned pad : 4; + }; + UDSPControl(u16 _Hex = 0) : Hex(_Hex) {} +}; + namespace AudioCommon { SoundStream *InitSoundStream(CMixer *mixer = NULL); diff --git a/Source/Core/AudioCommon/Src/DSoundStream.cpp b/Source/Core/AudioCommon/Src/DSoundStream.cpp index 61613dbd4a..dc451eddb7 100644 --- a/Source/Core/AudioCommon/Src/DSoundStream.cpp +++ b/Source/Core/AudioCommon/Src/DSoundStream.cpp @@ -111,13 +111,11 @@ void DSound::SoundLoop() int numBytesToRender = FIX128(ModBufferSize(currentPos - lastPos)); if (numBytesToRender >= 256) { - if (numBytesToRender > sizeof(realtimeBuffer)) + if (numBytesToRender > sizeof(realtimeBuffer) * sizeof(short)) PanicAlert("soundThread: too big render call"); - m_mixer->Mix(realtimeBuffer, numBytesToRender >> 2); + m_mixer->Mix(realtimeBuffer, numBytesToRender / 4); WriteDataToBuffer(lastPos, (char*)realtimeBuffer, numBytesToRender); - currentPos = ModBufferSize(lastPos + numBytesToRender); - totalRenderedBytes += numBytesToRender; - lastPos = currentPos; + lastPos = ModBufferSize(lastPos + numBytesToRender); } soundCriticalSection.Leave(); soundSyncEvent.Wait(); @@ -142,7 +140,6 @@ bool DSound::Start() dsBuffer->Lock(0, bufferSize, (void* *)&p1, &num1, 0, 0, 0); memset(p1, 0, num1); dsBuffer->Unlock(p1, num1, 0, 0); - totalRenderedBytes = -bufferSize; thread = new Common::Thread(soundThread, (void *)this); return true; } diff --git a/Source/Core/AudioCommon/Src/DSoundStream.h b/Source/Core/AudioCommon/Src/DSoundStream.h index 9fd2aaf8bb..fcf0413ee7 100644 --- a/Source/Core/AudioCommon/Src/DSoundStream.h +++ b/Source/Core/AudioCommon/Src/DSoundStream.h @@ -25,8 +25,7 @@ #include #include -#define BUFSIZE 32768 -#define MAXWAIT 70 // miliseconds +#define BUFSIZE (1024 * 8 * 4) #endif class DSound : public SoundStream @@ -41,31 +40,30 @@ class DSound : public SoundStream IDirectSoundBuffer* dsBuffer; int bufferSize; //i bytes - int totalRenderedBytes; int m_volume; // playback position int currentPos; int lastPos; - short realtimeBuffer[1024 * 1024]; + short realtimeBuffer[BUFSIZE / sizeof(short)]; - inline int FIX128(int x) { + inline int FIX128(int x) + { return x & (~127); } - inline int ModBufferSize(int x) { + inline int ModBufferSize(int x) + { return (x + bufferSize) % bufferSize; } bool CreateBuffer(); - bool WriteDataToBuffer(DWORD dwOffset, char* soundData, - DWORD dwSoundBytes); + bool WriteDataToBuffer(DWORD dwOffset, char* soundData, DWORD dwSoundBytes); public: DSound(CMixer *mixer, void *hWnd = NULL) : SoundStream(mixer) , bufferSize(0) - , totalRenderedBytes(0) , currentPos(0) , lastPos(0) , dsBuffer(0) diff --git a/Source/Core/AudioCommon/Src/Mixer.cpp b/Source/Core/AudioCommon/Src/Mixer.cpp index 63bc8c7088..00b3a2587b 100644 --- a/Source/Core/AudioCommon/Src/Mixer.cpp +++ b/Source/Core/AudioCommon/Src/Mixer.cpp @@ -16,112 +16,65 @@ // http://code.google.com/p/dolphin-emu/ -// This queue solution is temporary. I'll implement something more efficient later. -#include // System - -#include "Thread.h" // Common +#include "Atomic.h" #include "Mixer.h" -#include "FixedSizeQueue.h" #include "AudioCommon.h" -int CMixer::Mix(short *samples, int numSamples) +// Executed from sound stream thread +unsigned int CMixer::Mix(short* samples, unsigned int numSamples) { - if (! samples) { - Premix(NULL, 0); + if (!samples) return 0; - } - // silence - memset(samples, 0, numSamples * 2 * sizeof(short)); - if (g_dspInitialize.pEmulatorState) { + if (g_dspInitialize.pEmulatorState) + { if (*g_dspInitialize.pEmulatorState != 0) - return 0; - } - - // first get the DTK Music - if (m_EnableDTKMusic) { - g_dspInitialize.pGetAudioStreaming(samples, numSamples); - } - - Premix(samples, numSamples); - - int count = 0; - - push_sync.Enter(); - while (m_queueSize > queue_minlength && count < numSamples * 2) - { - int x = samples[count]; - x += sample_queue.front(); - if (x > 32767) x = 32767; - if (x < -32767) x = -32767; - samples[count++] = x; - sample_queue.pop(); - x = samples[count]; - x += sample_queue.front(); - if (x > 32767) x = 32767; - if (x < -32767) x = -32767; - samples[count++] = x; - sample_queue.pop(); - m_queueSize-=2; - } - push_sync.Leave(); - - return count; -} - - -void CMixer::PushSamples(short *samples, int num_stereo_samples, int core_sample_rate) -{ - push_sync.Enter(); - if (m_queueSize == 0) - { - m_queueSize = queue_minlength; - for (int i = 0; i < queue_minlength; i++) - sample_queue.push((s16)0); - } - push_sync.Leave(); - -#ifdef _WIN32 - if (GetAsyncKeyState(VK_TAB)) - return; -#endif - - // Write Other Audio - if (!m_throttle) - return; - - // ----------------------------------------------------------------------- - // The auto throttle function. This loop will put a ceiling on the CPU MHz. - // ---------------------------- - /* This is only needed for non-AX sound, currently directly - streamed and DTK sound. For AX we call SoundStream::Update in - AXTask() for example. */ - while (m_queueSize > queue_maxlength / 2) - { - // Urgh. - if (g_dspInitialize.pEmulatorState) { - if (*g_dspInitialize.pEmulatorState != 0) - return; + { + // Silence + memset(samples, 0, numSamples * 4); + return numSamples; } - soundStream->Update(); - SLEEP(1); } - // ----------------------------------------------------------------------- - push_sync.Enter(); - while (num_stereo_samples) + unsigned int numLeft = Common::AtomicLoad(m_numSamples); + numLeft = (numLeft > numSamples) ? numSamples : numLeft; + + // Do re-sampling if needed + if (m_sampleRate == m_dspSampleRate) { - sample_queue.push(Common::swap16(*samples)); - samples++; - sample_queue.push(Common::swap16(*samples)); - samples++; - m_queueSize += 2; - num_stereo_samples--; + for (unsigned int i = 0; i < numLeft * 2; i++) + samples[i] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]); + m_indexR += numLeft * 2; } - push_sync.Leave(); - return; + 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) + { + // AyuanX: Up-sampling is not implemented yet + PanicAlert("Mixer: Up-sampling is not implemented yet!"); /* static int PV1l=0,PV2l=0,PV3l=0,PV4l=0; static int PV1r=0,PV2r=0,PV3r=0,PV4r=0; @@ -183,16 +136,93 @@ void CMixer::PushSamples(short *samples, int num_stereo_samples, int core_sample sample_queue.push(r); m_queueSize += 2; } - push_sync.Leave(); */ + } + // Padding + 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 DTK Music + if (m_EnableDTKMusic) + { + // Re-sampling is done inside + g_dspInitialize.pGetAudioStreaming(samples, numSamples, m_sampleRate); + } + + Common::AtomicAdd(m_numSamples, -(int)numLeft); + + return numSamples; } -int CMixer::GetNumSamples() + +void CMixer::PushSamples(short *samples, unsigned int num_samples, unsigned int sample_rate) { - return m_queueSize / 2; - //int ret = (m_queueSize - queue_minlength) / 2; - //ret = (ret > 0) ? ret : 0; - //return ret; + // 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) + { + if (*g_dspInitialize.pEmulatorState != 0) + break; + } + soundStream->Update(); + SLEEP(1); + } + } + + // Check if we have enough free space + if (num_samples > MAX_SAMPLES - Common::AtomicLoad(m_numSamples)) + return; + + // AyuanX: Actual re-sampling work has been moved to sound thread + // to alleviates 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) + { + memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes); + memcpy(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes); + } + else + { + memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4); + } + + 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) + { + PanicAlert("Mixer: Up-sampling is not implemented yet!"); + } + + Common::AtomicAdd(m_numSamples, num_samples); + + return; +} + +unsigned int CMixer::GetNumSamples() +{ + return Common::AtomicLoad(m_numSamples); } diff --git a/Source/Core/AudioCommon/Src/Mixer.h b/Source/Core/AudioCommon/Src/Mixer.h index 4fcf1c7d16..c6e50c4839 100644 --- a/Source/Core/AudioCommon/Src/Mixer.h +++ b/Source/Core/AudioCommon/Src/Mixer.h @@ -18,39 +18,38 @@ #ifndef _MIXER_H_ #define _MIXER_H_ -#include "FixedSizeQueue.h" -#include "Thread.h" - -// On real hardware, this fifo is much, much smaller. But timing is also -// tighter than under Windows, so... -#define queue_minlength 1024 * 4 -#define queue_maxlength 1024 * 28 +// 16 bit Stereo +#define MAX_SAMPLES (1024 * 4) +#define INDEX_MASK (MAX_SAMPLES * 2 - 1) +#define RESERVED_SAMPLES (MAX_SAMPLES / 8) class CMixer { public: - // AyuanX: Mixer sample rate is fixed to 32khz for now - // if any game sets DSP sample rate to 48khz, we are doomed - // TODO: Fix this somehow! - CMixer(unsigned int SampleRate = 32000) - : m_sampleRate(SampleRate) + CMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000) + : m_aiSampleRate(AISampleRate) + , m_dspSampleRate(DSPSampleRate) , m_bits(16) , m_channels(2) - , m_mode(2) , m_HLEready(false) - , m_queueSize(0) - {} + , m_numSamples(0) + , m_indexW(0) + , m_indexR(0) + { + // AyuanX: When sample rate differs, 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; + } // Called from audio threads - virtual int Mix(short *sample, int numSamples); - virtual int GetNumSamples(); + virtual unsigned int Mix(short* samples, unsigned int numSamples); + virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate) {} + unsigned int GetNumSamples(); // Called from main thread - virtual void PushSamples(short* samples, int num_stereo_samples, int core_sample_rate); - - virtual void Premix(short *samples, int numSamples) {} - - int GetSampleRate() {return m_sampleRate;} + virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate); + unsigned int GetSampleRate() {return m_sampleRate;} void SetThrottle(bool use) { m_throttle = use;} void SetDTKMusic(bool use) { m_EnableDTKMusic = use;} @@ -61,19 +60,23 @@ public: // --------------------- protected: - int m_sampleRate; + unsigned int m_sampleRate; + unsigned int m_aiSampleRate; + unsigned int m_dspSampleRate; int m_bits; int m_channels; - int m_mode; bool m_HLEready; - int m_queueSize; bool m_EnableDTKMusic; bool m_throttle; + + short m_buffer[MAX_SAMPLES * 2]; + u32 m_indexW; + u32 m_indexR; + volatile u32 m_numSamples; + private: - Common::CriticalSection push_sync; - FixedSizeQueue sample_queue; }; diff --git a/Source/Core/AudioCommon/Src/NullSoundStream.h b/Source/Core/AudioCommon/Src/NullSoundStream.h index d73e6ccc01..7fc6aecd88 100644 --- a/Source/Core/AudioCommon/Src/NullSoundStream.h +++ b/Source/Core/AudioCommon/Src/NullSoundStream.h @@ -22,10 +22,10 @@ #include "Mixer.h" class NullMixer : public CMixer { + public: - virtual int Mix(short *sample, int numSamples) {return 0;} - virtual void PushSamples(short* samples, int num_stereo_samples, - int core_sample_rate) {} + virtual unsigned int Mix(short *samples, unsigned int numSamples) { return 0; } + virtual void PushSamples(short* samples, unsigned int num_samples, unsigned int sample_rate) {} }; class NullSound : public SoundStream @@ -35,7 +35,6 @@ public: { delete m_mixer; m_mixer = new NullMixer(); - } virtual ~NullSound() {} @@ -47,7 +46,7 @@ public: virtual bool Start() { return true; } virtual void Update() { - m_mixer->Mix(NULL, 256 >> 2); + //m_mixer->Mix(NULL, 256 >> 2); //(*callback)(NULL, 256 >> 2, 16, sampleRate, 2); } }; diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp index 1b2363888d..7945f44d86 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.cpp +++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp @@ -138,12 +138,13 @@ void OpenALStream::SoundLoop() // Generate a Source to playback the Buffers alGenSources(1, &uiSource); - memset(realtimeBuffer, 0, OAL_BUFFER_SIZE); + // Short Silence + memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4); for (int i = 0; i < OAL_NUM_BUFFERS; i++) - alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_BUFFER_SIZE, ulFrequency); - + alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, OAL_MAX_SAMPLES, ulFrequency); alSourceQueueBuffers(uiSource, OAL_NUM_BUFFERS, uiBuffers); alSourcePlay(uiSource); + err = alGetError(); // TODO: Error handling @@ -158,12 +159,12 @@ void OpenALStream::SoundLoop() alGetSourcei(uiSource, AL_BUFFERS_PROCESSED, &iBuffersProcessed); iBuffersFilled = 0; } - int numSamples = m_mixer->GetNumSamples(); - numSamples &= ~0x100; - if (iBuffersProcessed && numSamples) + unsigned int numSamples = m_mixer->GetNumSamples(); + + if (iBuffersProcessed && (numSamples >= OAL_THRESHOLD)) { - numSamples = (numSamples > OAL_BUFFER_SIZE / 4) ? OAL_BUFFER_SIZE / 4 : numSamples; + numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples; // Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer) if (iBuffersFilled == 0) alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp); @@ -176,11 +177,11 @@ void OpenALStream::SoundLoop() if (iBuffersFilled == OAL_NUM_BUFFERS) alSourcePlay(uiSource); } - else + else if (numSamples >= OAL_THRESHOLD) { ALint state = 0; alGetSourcei(uiSource, AL_SOURCE_STATE, &state); - if (state != AL_PLAYING) + if (state == AL_STOPPED) alSourcePlay(uiSource); } soundSyncEvent.Wait(); diff --git a/Source/Core/AudioCommon/Src/OpenALStream.h b/Source/Core/AudioCommon/Src/OpenALStream.h index fbeaadba60..9a469511b8 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.h +++ b/Source/Core/AudioCommon/Src/OpenALStream.h @@ -33,10 +33,11 @@ #include "AL/al.h" #include "AL/alc.h" #endif // WIN32 -// public use +// 16 bit Stereo #define SFX_MAX_SOURCE 1 #define OAL_NUM_BUFFERS 8 -#define OAL_BUFFER_SIZE (512 * 4) +#define OAL_MAX_SAMPLES 512 // AyuanX: Don't make it too large, as larger buffer means longer delay +#define OAL_THRESHOLD 128 #endif class OpenALStream: public SoundStream @@ -66,7 +67,7 @@ private: Common::CriticalSection soundCriticalSection; Common::Event soundSyncEvent; - short realtimeBuffer[OAL_BUFFER_SIZE/sizeof(short)]; + short realtimeBuffer[OAL_MAX_SAMPLES * 2]; ALuint uiBuffers[OAL_NUM_BUFFERS]; ALuint uiSource; ALfloat fVolume; diff --git a/Source/Core/Common/Src/PluginDSP.h b/Source/Core/Common/Src/PluginDSP.h index 6341771a3d..8427c32070 100644 --- a/Source/Core/Common/Src/PluginDSP.h +++ b/Source/Core/Common/Src/PluginDSP.h @@ -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, int sample_rate); +typedef void (__cdecl *TDSP_SendAIBuffer)(unsigned int address, unsigned int num_samples, unsigned int sample_rate); typedef void (__cdecl *TDSP_Update)(int cycles); typedef void (__cdecl *TDSP_StopSoundStream)(); typedef void (__cdecl *TDSP_ClearAudioBuffer)(); diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 485de6bfd5..2e26f72a23 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -234,7 +234,7 @@ void SConfig::LoadSettings() ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false); ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false); ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0); - ini.Get("Core", "FrameLimit", &m_Framelimit, 1); + ini.Get("Core", "FrameLimit", &m_Framelimit, 0); // auto frame limit by default // Plugins ini.Get("Core", "GFXPlugin", &m_LocalCoreStartupParameter.m_strVideoPlugin, m_DefaultGFXPlugin.c_str()); diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 4dd364599b..7f7aca9567 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -386,6 +386,7 @@ THREAD_RETURN EmuThread(void *pArg) dspInit.pDebuggerBreak = Callback_DebuggerBreak; dspInit.pGenerateDSPInterrupt = Callback_DSPInterrupt; dspInit.pGetAudioStreaming = AudioInterface::Callback_GetStreaming; + dspInit.pGetSampleRate = AudioInterface::Callback_GetSampleRate; dspInit.pEmulatorState = (int *)PowerPC::GetStatePtr(); dspInit.bWii = _CoreParameter.bWii; dspInit.bOnThread = _CoreParameter.bDSPThread; diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp index 5d4589bfd6..0452e1c670 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.cpp +++ b/Source/Core/Core/Src/HW/AudioInterface.cpp @@ -54,13 +54,13 @@ union AICR struct { unsigned PSTAT : 1; // sample counter/playback enable - unsigned AFR : 1; // 0=32khz 1=48khz + unsigned AFR : 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) WTF, who designed this? + unsigned DSPFR : 1; // DSP Frequency (0=48khz 1=32khz) unsigned :25; }; u32 hex; @@ -90,8 +90,8 @@ struct SAudioRegister // STATE_TO_SAVE static SAudioRegister g_AudioRegister; static u64 g_LastCPUTime = 0; -static int g_SampleRate = 32000; -static int g_DSPSampleRate = 32000; +static unsigned int g_SampleRate = 32000; +static unsigned int g_DSPSampleRate = 32000; static u64 g_CPUCyclesPerSample = 0xFFFFFFFFFFFULL; void DoState(PointerWrap &p) @@ -264,9 +264,15 @@ void GenerateAudioInterrupt() UpdateInterrupts(); } +void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate) +{ + _AISampleRate = g_SampleRate; + _DSPSampleRate = g_DSPSampleRate; +} + // Callback for the disc streaming // WARNING - called from audio thread -u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples) +unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate) { if (g_AudioRegister.m_Control.PSTAT && !CCPU::IsStepping()) { @@ -275,34 +281,60 @@ u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples) const int lvolume = g_AudioRegister.m_Volume.leftVolume; const int rvolume = g_AudioRegister.m_Volume.rightVolume; - // AyuanX: I hate this, but for now we have to do down-sampling to support 48khz - if (g_SampleRate == 48000) + + if (g_SampleRate == 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) + { + // AyuanX: Up-sampling is not implemented yet + PanicAlert("AUDIO_INTERFACE: Up-sampling is not implemented yet!"); + } - short pcm_l = 0; - short pcm_r = 0; + int pcm_l, pcm_r; for (unsigned int i = 0; i < _numSamples; i++) { if (pos == 0) ReadStreamBlock(pcm); - if (g_SampleRate == 48000) + if (g_SampleRate == 48000 && _sampleRate == 32000) { if (i % 3) { - *_pDestBuffer++ = ((pcm_l / 2 + pcm[pos*2] / 2) * lvolume) >> 8; - *_pDestBuffer++ = ((pcm_r / 2 + pcm[pos*2+1] / 2) * rvolume) >> 8; + pcm_l = (((pcm_l + (int)pcm[pos*2]) / 2 * lvolume) >> 8) + (int)(*_pDestBuffer); + if (pcm_l > 32767) + pcm_l = 32767; + else if (pcm_l < -32767) + pcm_l = -32767; + *_pDestBuffer++ = pcm_l; + + pcm_r = (((pcm_r + (int)pcm[pos*2+1]) / 2 * rvolume) >> 8) + (int)(*_pDestBuffer); + if (pcm_r > 32767) + pcm_r = 32767; + else if (pcm_r < -32767) + pcm_r = -32767; + *_pDestBuffer++ = pcm_r; } pcm_l = pcm[pos*2]; pcm_r = pcm[pos*2+1]; } else { - *_pDestBuffer++ = (pcm[pos*2] * lvolume) >> 8; - *_pDestBuffer++ = (pcm[pos*2+1] * rvolume) >> 8; + pcm_l = (((int)pcm[pos*2] * lvolume) >> 8) + (int)(*_pDestBuffer); + if (pcm_l > 32767) + pcm_l = 32767; + else if (pcm_l < -32767) + pcm_l = -32767; + *_pDestBuffer++ = pcm_l; + + pcm_r = (((int)pcm[pos*2+1] * rvolume) >> 8) + (int)(*_pDestBuffer); + if (pcm_r > 32767) + pcm_r = 32767; + else if (pcm_r < -32767) + pcm_r = -32767; + *_pDestBuffer++ = pcm_r; } if (++pos == 28) @@ -311,7 +343,7 @@ u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples) } else { - // AyuanX: We have already preset those bytes, no need to do this again + // Don't overwrite existed sample data /* for (unsigned int i = 0; i < _numSamples * 2; i++) { @@ -361,12 +393,12 @@ void IncreaseSampleCount(const u32 _iAmount) } } -u32 GetAISampleRate() +unsigned int GetAISampleRate() { return g_SampleRate; } -u32 GetDSPSampleRate() +unsigned int GetDSPSampleRate() { return g_DSPSampleRate; } diff --git a/Source/Core/Core/Src/HW/AudioInterface.h b/Source/Core/Core/Src/HW/AudioInterface.h index 1a0a871056..d37623f4f8 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.h +++ b/Source/Core/Core/Src/HW/AudioInterface.h @@ -34,14 +34,15 @@ void DoState(PointerWrap &p); void Update(); // Called by DSP plugin -u32 Callback_GetStreaming(short* _pDestBuffer, u32 _numSamples); +void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DSPSampleRate); +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) -u32 GetAISampleRate(); -u32 GetDSPSampleRate(); +unsigned int GetAISampleRate(); +unsigned int GetDSPSampleRate(); } // namespace diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp index aa864aeb17..ce1046d30c 100644 --- a/Source/Core/Core/Src/HW/DSP.cpp +++ b/Source/Core/Core/Src/HW/DSP.cpp @@ -197,7 +197,6 @@ static u16 g_AR_SIZE; static u16 g_AR_MODE; static u16 g_AR_REFRESH; - Common::PluginDSP *dsp_plugin; @@ -379,27 +378,6 @@ void Write16(const u16 _Value, const u32 _Address) g_dspState.DSPControl.DSPHalt = tmpControl.DSPHalt; g_dspState.DSPControl.DSPInit = tmpControl.DSPInit; - // AyuanX: WTF, sample rate between AI & DSP can be different? - // This is a big problem especially when our mixer is fixed to 32000 - // TODO: Try to support these! - // More info: AudioCommon/Mixer.h, HW/AudioInterface.cpp - static bool FirstTimeWarning = false; - if (!FirstTimeWarning) - { - if (!g_dspState.DSPControl.DSPHalt && g_dspState.DSPControl.DSPInit) - { - // It's time to check now, and we do this only once - FirstTimeWarning = true; - if (AudioInterface::GetAISampleRate() != 32000 || AudioInterface::GetDSPSampleRate() != 32000) - { - WARN_LOG(DSPINTERFACE, "Unsupported Sample Rate, AI:%i, DSP:%i", AudioInterface::GetAISampleRate(), AudioInterface::GetDSPSampleRate()); - if (AudioInterface::GetDSPSampleRate() != 32000) - PanicAlert("DSPINTERFACE: Unsupported Sample Rate, AI:%i, DSP:%i\n" - "You may get incorrect sound output, please report!", AudioInterface::GetAISampleRate(), AudioInterface::GetDSPSampleRate()); - } - } - } - // Interrupt (mask) g_dspState.DSPControl.AID_mask = tmpControl.AID_mask; g_dspState.DSPControl.ARAM_mask = tmpControl.ARAM_mask; @@ -503,12 +481,17 @@ void UpdateAudioDMA() // external audio fifo in the emulator, to be mixed with the disc // streaming output. If that audio queue fills up, we delay the // emulator. - dsp_plugin->DSP_SendAIBuffer(g_audioDMA.ReadAddress, AudioInterface::GetDSPSampleRate()); - g_audioDMA.ReadAddress += 32; + + // 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()); + +// g_audioDMA.ReadAddress += 32; g_audioDMA.BlocksLeft--; + if (g_audioDMA.BlocksLeft == 0) { - g_audioDMA.ReadAddress = g_audioDMA.SourceAddress; +// 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); diff --git a/Source/Core/Core/Src/HW/MemmapFunctions.cpp b/Source/Core/Core/Src/HW/MemmapFunctions.cpp index b21a81fc94..fdcc476588 100644 --- a/Source/Core/Core/Src/HW/MemmapFunctions.cpp +++ b/Source/Core/Core/Src/HW/MemmapFunctions.cpp @@ -590,7 +590,7 @@ void GenerateISIException() // segment (N bit set in segment descriptor), or to guarded memory // when MSR[IR] = 1. Otherwise, cleared. // Bit 4: Set if a memory access is not permitted by the page or IBAT protection - // mechanism, described in Chapter 7, “Memory Management”; otherwise cleared. + // mechanism, described in Chapter 7, "Memory Management" otherwise cleared. // Only one of 1,3, or 4 may be set at a time // For now let's just say that hash lookup failed diff --git a/Source/PluginSpecs/pluginspecs_dsp.h b/Source/PluginSpecs/pluginspecs_dsp.h index 6b63aa5886..feb4ec6b3f 100644 --- a/Source/PluginSpecs/pluginspecs_dsp.h +++ b/Source/PluginSpecs/pluginspecs_dsp.h @@ -16,7 +16,8 @@ typedef void (*TLogv)(const char* _szMessage, int _v); typedef const char* (*TName)(void); typedef void (*TDebuggerBreak)(void); typedef void (*TGenerateDSPInt)(void); -typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples); +typedef unsigned int (*TAudioGetStreaming)(short* _pDestBuffer, unsigned int _numSamples, unsigned int _sampleRate); +typedef void (*TGetSampleRate)(unsigned int &AISampleRate, unsigned int &DSPSampleRate); typedef struct { @@ -30,6 +31,7 @@ typedef struct TDebuggerBreak pDebuggerBreak; TGenerateDSPInt pGenerateDSPInterrupt; TAudioGetStreaming pGetAudioStreaming; + TGetSampleRate pGetSampleRate; int *pEmulatorState; bool bWii; bool bOnThread; @@ -95,9 +97,10 @@ EXPORT void CALL DSP_Update(int cycles); // Function: DSP_SendAIBuffer // Purpose: This function sends the current AI Buffer to the DSP plugin // input: _Address : Memory-Address -// input: _Size : Size of the Buffer (always 32) +// input: _Number : Number of the Samples +// input: _Rate : Sample Rate 32000/48000 // -EXPORT void CALL DSP_SendAIBuffer(unsigned int address, int sample_rate); +EXPORT void CALL DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate); // __________________________________________________________________________________________________ // Function: DSP_StopSoundStream diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/DSPHandler.h b/Source/Plugins/Plugin_DSP_HLE/Src/DSPHandler.h index 9a490a3f34..7af80dde15 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/DSPHandler.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/DSPHandler.h @@ -19,6 +19,7 @@ #define _DSPHANDLER_H #include "Common.h" +#include "AudioCommon.h" #include "MailHandler.h" #include "UCodes/UCodes.h" @@ -57,34 +58,6 @@ private: CDSPHandler(); ~CDSPHandler(); - // UDSPControl - union UDSPControl - { - u16 Hex; - struct - { - unsigned DSPReset : 1; // Write 1 to reset and waits for 0 - unsigned DSPAssertInt : 1; - unsigned DSPHalt : 1; - - unsigned AI : 1; - unsigned AI_mask : 1; - unsigned ARAM : 1; - unsigned ARAM_mask : 1; - unsigned DSP : 1; - unsigned DSP_mask : 1; - - unsigned ARAM_DMAState : 1; // DSPGetDMAStatus() uses this flag - unsigned DSPInitCode : 1; - unsigned DSPInit : 1; // DSPInit() writes to this flag - unsigned pad : 4; - }; - - UDSPControl(u16 _Hex = 0) - : Hex(_Hex) - {} - }; - // singleton instance static CDSPHandler* m_pInstance; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp index 1de4b34dab..d810467180 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.cpp @@ -20,23 +20,14 @@ #include "DSPHandler.h" #include "HLEMixer.h" -void HLEMixer::MixUCode(short *samples, int numSamples) { - // if this was called directly from the HLE, and not by timeout - if (g_Config.m_EnableHLEAudio && IsHLEReady()) { +void HLEMixer::Premix(short *samples, unsigned int numSamples, unsigned int sampleRate) +{ + // if this was called directly from the HLE + if (g_Config.m_EnableHLEAudio && IsHLEReady()) + { IUCode *pUCode = CDSPHandler::GetInstance().GetUCode(); if (pUCode && samples) pUCode->MixAdd(samples, numSamples); } } -void HLEMixer::Premix(short *samples, int numSamples) { - - // first get the DTK Music - // if (g_Config.m_EnableDTKMusic) { - // g_dspInitialize.pGetAudioStreaming(samples, numSamples); - // } - - MixUCode(samples, numSamples); -} - - diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h index ddbcfc317f..4687ac4ae4 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/HLEMixer.h @@ -6,9 +6,10 @@ class HLEMixer : public CMixer { public: - void MixUCode(short *samples, int numSamples); + HLEMixer(unsigned int AISampleRate = 48000, unsigned int DSPSampleRate = 48000) + : CMixer(AISampleRate, DSPSampleRate) {}; - virtual void Premix(short *samples, int numSamples); + virtual void Premix(short *samples, unsigned int numSamples, unsigned int sampleRate); }; #endif // HLEMIXER_H diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AX.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AX.cpp index dd5ac1ed21..43922cdfd4 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AX.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AX.cpp @@ -498,7 +498,7 @@ bool CUCode_AX::AXTask(u32& _uMail) SaveLog("%08x : AXLIST PB address: %08x", uAddress, m_addressPBs); SaveLog("Update the SoundThread to be in sync"); - soundStream->Update(); //do it in this thread to avoid sync problems +// soundStream->Update(); //do it in this thread to avoid sync problems } break; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXStructs.h b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXStructs.h index 6d194e69be..f3670c881a 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXStructs.h +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXStructs.h @@ -156,7 +156,7 @@ struct AXParamBlock /* 63 */ PBADPCMInfo adpcm; /* 83 */ PBSampleRateConverter src; /* 90 */ PBADPCMLoopInfo adpcm_loop_info; -/* 93 */ u16 unknown_maybe_padding[3]; +/* 93 */ //u16 unknown_maybe_padding[3]; // Comment this out to get some speedup }; struct PBLpf @@ -201,7 +201,7 @@ struct AXParamBlockWii /* 95 */ PBADPCMLoopInfo adpcm_loop_info; /* 98 */ PBLpf lpf; /* 102 */ PBHpf hpf; -/* 106 */ u16 pad[22]; +/* 106 */ //u16 pad[22]; // Comment this out to get some speedup }; struct AXParamBlockWii_ // new CRC version @@ -226,7 +226,7 @@ struct AXParamBlockWii_ // new CRC version /* 0x0B4 */ PBADPCMLoopInfo adpcm_loop_info; /* 0x0BA */ PBLpf lpf; /* 0x0C2 */ PBHpf hpf; -/* 0x0CA */ u16 pad[27]; +/* 0x0CA */ //u16 pad[27]; // Comment this out to get some speedup /* 0x100 */ }; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXWii.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXWii.cpp index a2b781da8c..1621f32dfe 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXWii.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_AXWii.cpp @@ -289,7 +289,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail) m_addressPBs = Memory_Read_U32(uAddress); lCUCode_AX->m_addressPBs = m_addressPBs; // for the sake of logging soundStream->GetMixer()->SetHLEReady(true); - soundStream->Update(); +// soundStream->Update(); uAddress += 4; break; diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp index 2fae11ca3c..75d160023c 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/UCodes/UCode_Zelda.cpp @@ -147,7 +147,7 @@ void CUCode_Zelda::HandleMail_LightVersion(u32 _uMail) soundStream->GetMixer()->SetHLEReady(true); DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync"); - soundStream->Update(); //do it in this thread to avoid sync problems +// soundStream->Update(); //do it in this thread to avoid sync problems m_bSyncCmdPending = false; } @@ -216,7 +216,7 @@ void CUCode_Zelda::HandleMail_SMSVersion(u32 _uMail) soundStream->GetMixer()->SetHLEReady(true); DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync"); - soundStream->Update(); //do it in this thread to avoid sync problems +// soundStream->Update(); //do it in this thread to avoid sync problems m_bSyncCmdPending = false; } @@ -339,7 +339,7 @@ void CUCode_Zelda::HandleMail_NormalVersion(u32 _uMail) soundStream->GetMixer()->SetHLEReady(true); DEBUG_LOG(DSPHLE, "Update the SoundThread to be in sync"); - soundStream->Update(); //do it in this thread to avoid sync problems +// soundStream->Update(); //do it in this thread to avoid sync problems m_bSyncCmdPending = false; } diff --git a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp index 77e2f24958..24936857dc 100644 --- a/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp +++ b/Source/Plugins/Plugin_DSP_HLE/Src/main.cpp @@ -33,7 +33,6 @@ DSPDebuggerHLE* m_DebuggerFrame = NULL; #include "Config.h" #include "Setup.h" #include "StringUtil.h" -#include "AudioCommon.h" #include "LogManager.h" @@ -42,8 +41,8 @@ PLUGIN_GLOBALS* globals = NULL; DSPInitialize g_dspInitialize; u8* g_pMemory; extern std::vector sMailLog, sMailTime; -bool g_bMuted = false; +bool g_InitMixer = false; SoundStream *soundStream = NULL; // Mailbox utility @@ -203,6 +202,7 @@ void DllConfig(HWND _hParent) void Initialize(void *init) { + g_InitMixer = false; g_dspInitialize = *(DSPInitialize*)init; g_Config.Load(); @@ -211,10 +211,6 @@ void Initialize(void *init) g_dspState.Reset(); CDSPHandler::CreateInstance(); - - soundStream = AudioCommon::InitSoundStream(new HLEMixer()); - if(!soundStream) - PanicAlert("Error starting up sound stream"); } void DSP_StopSoundStream() @@ -245,6 +241,7 @@ void Shutdown() void DoState(unsigned char **ptr, int mode) { PointerWrap p(ptr, mode); + p.Do(g_InitMixer); CDSPHandler::GetInstance().GetUCode()->DoState(p); } @@ -305,6 +302,19 @@ void DSP_WriteMailboxLow(bool _CPUMailbox, unsigned short _Value) // Other DSP fuctions unsigned short DSP_WriteControlRegister(unsigned short _Value) { + UDSPControl Temp(_Value); + if (!g_InitMixer) + { + if (!Temp.DSPHalt && Temp.DSPInit) + { + unsigned int AISampleRate, DSPSampleRate; + g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate); + soundStream = AudioCommon::InitSoundStream(new HLEMixer(AISampleRate, DSPSampleRate)); + if(!soundStream) PanicAlert("Error starting up sound stream"); + // Mixer is initialized + g_InitMixer = true; + } + } return CDSPHandler::GetInstance().WriteControlRegister(_Value); } @@ -324,44 +334,26 @@ void DSP_Update(int cycles) 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 again once the game has started. */ -void DSP_SendAIBuffer(unsigned int address, int sample_rate) +void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate) { - // TODO: This is not yet fully threadsafe. - if (!soundStream) { + if (!soundStream) return; - } CMixer* pMixer = soundStream->GetMixer(); + if (pMixer && address) { short* samples = (short*)Memory_Get_Pointer(address); -/* - short samples[16] = {0}; // interleaved stereo - if (address) - { - for (int i = 0; i < 16; i++) - { - samples[i] = Memory_Read_U16(address + i * 2); - } - - // FIXME: Write the audio to a file - //if (log_ai) - // g_wave_writer.AddStereoSamples(samples, 8); - } -*/ - // sample_rate is usually 32k here, + // sample_rate could be 32khz/48khz here, // see Core/DSP/DSP.cpp for better information - pMixer->PushSamples(samples, 32 / 4, sample_rate); + pMixer->PushSamples(samples, num_samples, sample_rate); + + // FIXME: Write the audio to a file + //if (log_ai) + // g_wave_writer.AddStereoSamples(samples, 8); } - // SoundStream is updated only when necessary (there is no 70 ms limit - // so each sample now triggers the sound stream) - - // TODO: think about this. - static int counter = 0; - counter++; - if ((counter & 31) == 0 && soundStream) - soundStream->Update(); + soundStream->Update(); } void DSP_ClearAudioBuffer() diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp index f0a94c92ce..d58c052cb7 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Globals.cpp @@ -40,6 +40,11 @@ u32 Memory_Read_U32(u32 _uAddress) return Common::swap32(*(u32*)&g_dsp.cpu_ram[_uAddress & RAM_MASK]); } +void* Memory_Get_Pointer(u32 _uAddress) +{ + return &g_dsp.cpu_ram[_uAddress & RAM_MASK]; +} + #if PROFILE #define PROFILE_MAP_SIZE 0x10000 diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/Globals.h b/Source/Plugins/Plugin_DSP_LLE/Src/Globals.h index 4b8ab1fcae..5e88747ca9 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/Globals.h +++ b/Source/Plugins/Plugin_DSP_LLE/Src/Globals.h @@ -26,6 +26,7 @@ u16 Memory_Read_U16(u32 _uAddress); // For PB address detection u32 Memory_Read_U32(u32 _uAddress); +void* Memory_Get_Pointer(u32 _uAddress); #if PROFILE void ProfilerDump(u64 _count); diff --git a/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp b/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp index 07b908ae4f..854e8e9f13 100644 --- a/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp +++ b/Source/Plugins/Plugin_DSP_LLE/Src/main.cpp @@ -47,6 +47,7 @@ PLUGIN_GLOBALS* globals = NULL; DSPInitialize g_dspInitialize; Common::Thread *g_hDSPThread = NULL; SoundStream *soundStream = NULL; +bool g_InitMixer = false; bool bIsRunning = false; @@ -166,6 +167,7 @@ void DllConfig(HWND _hParent) void DoState(unsigned char **ptr, int mode) { PointerWrap p(ptr, mode); + p.Do(g_InitMixer); } void DllDebugger(HWND _hParent, bool Show) @@ -202,6 +204,7 @@ void DSP_DebugBreak() void Initialize(void *init) { + g_InitMixer = false; bool bCanWork = true; g_dspInitialize = *(DSPInitialize*)init; @@ -229,7 +232,6 @@ void Initialize(void *init) { g_hDSPThread = new Common::Thread(dsp_thread, NULL); } - soundStream = AudioCommon::InitSoundStream(); #if defined(HAVE_WX) && HAVE_WX if (m_DebuggerFrame) @@ -256,6 +258,19 @@ void Shutdown() u16 DSP_WriteControlRegister(u16 _uFlag) { + UDSPControl Temp(_uFlag); + if (!g_InitMixer) + { + if (!Temp.DSPHalt && Temp.DSPInit) + { + unsigned int AISampleRate, DSPSampleRate; + g_dspInitialize.pGetSampleRate(AISampleRate, DSPSampleRate); + soundStream = AudioCommon::InitSoundStream(new CMixer(AISampleRate, DSPSampleRate)); + if(!soundStream) PanicAlert("Error starting up sound stream"); + // Mixer is initialized + g_InitMixer = true; + } + } DSPInterpreter::WriteCR(_uFlag); return DSPInterpreter::ReadCR(); } @@ -343,29 +358,21 @@ void DSP_Update(int cycles) } } -void DSP_SendAIBuffer(unsigned int address, int sample_rate) +void DSP_SendAIBuffer(unsigned int address, unsigned int num_samples, unsigned int sample_rate) { - if (soundStream->GetMixer()) + if (!soundStream) + return; + + CMixer* pMixer = soundStream->GetMixer(); + + if (pMixer && address) { - short samples[16] = {0}; // interleaved stereo - if (address) - { - for (int i = 0; i < 16; i++) - { - samples[i] = Memory_Read_U16(address + i * 2); - } - } - soundStream->GetMixer()->PushSamples(samples, 32 / 4, sample_rate); + short* samples = (short*)Memory_Get_Pointer(address); + + pMixer->PushSamples(samples, num_samples, sample_rate); } - // SoundStream is updated only when necessary (there is no 70 ms limit - // so each sample now triggers the sound stream) - - // TODO: think about this. - // static int counter = 0; - // counter++; - if (/*(counter & 31) == 0 &&*/ soundStream) - soundStream->Update(); + soundStream->Update(); } void DSP_ClearAudioBuffer()