From 62e1f5015d067c766f8879d4153f93de9fb82ad9 Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Sat, 1 Nov 2008 19:27:35 +0000 Subject: [PATCH] SPU2ghz: Fixed DMA memory corruption bug introduced in r264 (and made the DMA code even faster!), and expanded SoundTouch's working buffer by ~15ms (seems to help improve voice audio breakups when games slow down below 40 fps). XAudio2 problems are still up in the air, as they may be related to version differences in DXSDK installations of people building the DLL. Note to compilers: please update your DX SDK to the most recent version (Aug 2008) if you haven't already. git-svn-id: http://pcsx2-playground.googlecode.com/svn/trunk@266 a6443dda-0b58-4228-96e9-037be469359c --- plugins/spu2ghz/SoundTouch/FIRFilter.cpp | 2 +- plugins/spu2ghz/SoundTouch/TDStretch.h | 6 +- plugins/spu2ghz/dma.cpp | 70 ++++++++++++------- plugins/spu2ghz/sndout.cpp | 87 ++++++++++++++---------- plugins/spu2ghz/spu2.cpp | 2 +- plugins/spu2ghz/xaudio2out.cpp | 7 +- 6 files changed, 105 insertions(+), 69 deletions(-) diff --git a/plugins/spu2ghz/SoundTouch/FIRFilter.cpp b/plugins/spu2ghz/SoundTouch/FIRFilter.cpp index 5c3c3a58fa..10a0bb0299 100644 --- a/plugins/spu2ghz/SoundTouch/FIRFilter.cpp +++ b/plugins/spu2ghz/SoundTouch/FIRFilter.cpp @@ -180,7 +180,7 @@ void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint u #ifdef INTEGER_SAMPLES resultDivider = (SAMPLETYPE)(1< 0 ) + buff1end = 0xfffff; + { - u32 nexta = Cores[core].TDA >> 3; - u32 flagbitmask = 1ul << ( nexta & 31 ); + u32 nexta = Cores[core].TDA >> 3; // next address in 8 word blocks + const u32 leftsidebit = nexta & 31; + u32 rightsidebit; // assigned later nexta >>= 5; - // Traverse from start to finish in 8 word blocks, - // and clear the pcm cache flag for each block. - u32 stmp = ( size + 7 ) >> 3; // round up - for( i=0; i>= (3+5); // 8 words per block, 32 blocks per int. + memset( &pcm_cache_flags[nexta], 0, sizeof( u32 ) * (buff1end-nexta) ); + + if( buff2end > 0 ) + { + // second branch needs cleared: + // It starts at the beginning of memory and moves forward to buff2end + + const u32 endpt2 = buff2end >> (3+5); // 8 words per block, 32 blocks per int. + memset( pcm_cache_flags, 0, sizeof( u32 ) * endpt2 ); + + for(Cores[core].TDA=0; Cores[core].TDA<(u32)buff2end; ++Cores[core].TDA, ++pMem) + *GetMemPtr( Cores[core].TDA ) = *pMem; + + rightsidebit = ( buff2end >> 3 ); + nexta = endpt2; + } + else + { + rightsidebit = (Cores[core].TDA >> 3); + nexta = buff1end; + } + + // clear the right-side remainder: + pcm_cache_flags[nexta] &= ~((1ul << (32-(rightsidebit&31)))-1); } i=Cores[core].TSA; diff --git a/plugins/spu2ghz/sndout.cpp b/plugins/spu2ghz/sndout.cpp index 334456e045..ea89d65115 100644 --- a/plugins/spu2ghz/sndout.cpp +++ b/plugins/spu2ghz/sndout.cpp @@ -19,6 +19,8 @@ #include "SoundTouch/SoundTouch.h" #include "SoundTouch/WavFile.h" +#include + static int ts_stats_stretchblocks = 0; static int ts_stats_normalblocks = 0; static int ts_stats_logcounter = 0; @@ -432,11 +434,6 @@ s32* sndTempBuffer=NULL; s32 sndTempProgress=NULL; s16* sndTempBuffer16=NULL; -void ResetTempoChange() -{ - pSoundTouch->setTempo(1); -} - void UpdateTempoChange() { if( --freezeTempo > 0 ) @@ -581,49 +578,71 @@ void UpdateTempoChange() } -void soundtouchInit() { +void soundtouchInit() +{ pSoundTouch = new soundtouch::SoundTouch(); pSoundTouch->setSampleRate(SampleRate); pSoundTouch->setChannels(2); pSoundTouch->setSetting(SETTING_USE_QUICKSEEK, 0); pSoundTouch->setSetting(SETTING_USE_AA_FILTER, 0); -} + pSoundTouch->setTempo(1); -s32 SndInit() -{ - if( mods[OutputModule] == NULL ) - { - // force us to the NullOut module if nothing assigned. - OutputModule = FindOutputModuleById( NullOut.GetIdent() ); - } - - // initialize sound buffer - // Buffer actually attempts to run ~50%, so allocate near double what - // the requested latency is: - - sndBuffer = new SndBufferImpl( SndOutLatencyMS * (timeStretchEnabled ? 2.0 : 1.5) ); - sndTempProgress = 0; - sndTempBuffer = new s32[SndOutPacketSize]; - sndTempBuffer16 = new s16[SndOutPacketSize]; - - // clear buffers! - // Fixes loopy sounds on emu resets. - memset( sndTempBuffer, 0, sizeof(s32) * SndOutPacketSize ); - memset( sndTempBuffer16, 0, sizeof(s16) * SndOutPacketSize ); + // some timestretch management vars: cTempo = 1.0; eTempo = 1.0; - lastPct = 0; lastEmergencyAdj = 0; // just freeze tempo changes for a while at startup. // the driver buffers are bogus anyway. freezeTempo = 8; - soundtouchInit(); +} - ResetTempoChange(); +static void _sndInitFail() +{ + // If a failure occurs, just initialize the NoSound driver. This'll allow + // the game to emulate properly (hopefully), albeit without sound. + OutputModule = FindOutputModuleById( NullOut.GetIdent() ); + mods[OutputModule]->Init( sndBuffer ); +} + +s32 SndInit() +{ + if( mods[OutputModule] == NULL ) + { + _sndInitFail(); + return 0; + } + + // initialize sound buffer + // Buffer actually attempts to run ~50%, so allocate near double what + // the requested latency is: + + try + { + sndBuffer = new SndBufferImpl( SndOutLatencyMS * (timeStretchEnabled ? 2.0 : 1.5) ); + sndTempBuffer = new s32[SndOutPacketSize]; + sndTempBuffer16 = new s16[SndOutPacketSize]; + } + catch( std::bad_alloc& ) + { + // out of memory exception (most likely) + + SysMessage( "Out of memory error occured while initializing SPU2." ); + _sndInitFail(); + return 0; + } + + // clear buffers! + // Fixes loopy sounds on emu resets. + memset( sndTempBuffer, 0, sizeof(s32) * SndOutPacketSize ); + memset( sndTempBuffer16, 0, sizeof(s16) * SndOutPacketSize ); + + sndTempProgress = 0; + + soundtouchInit(); // initializes the timestretching if(LimitMode!=0) { @@ -636,9 +655,9 @@ s32 SndInit() // initialize module if( mods[OutputModule]->Init(sndBuffer) == -1 ) { - OutputModule = FindOutputModuleById( NullOut.GetIdent() ); - return mods[OutputModule]->Init( sndBuffer ); + _sndInitFail(); } + return 0; } @@ -685,8 +704,6 @@ s32 SndWrite(s32 ValL, s32 ValR) if(mods[OutputModule] == &NullOut) // null output doesn't need buffering or stretching! :p return 0; - //inputSamples+=2; - sndTempBuffer[sndTempProgress++] = ValL; sndTempBuffer[sndTempProgress++] = ValR; diff --git a/plugins/spu2ghz/spu2.cpp b/plugins/spu2ghz/spu2.cpp index c43b9342fa..56a509748e 100644 --- a/plugins/spu2ghz/spu2.cpp +++ b/plugins/spu2ghz/spu2.cpp @@ -413,7 +413,7 @@ s32 CALLBACK SPU2open(void *pDsp) }*/ spu2open=1; - if (!SndInit()) + if (!SndInit()) { srate_pv=(double)SampleRate/48000.0; diff --git a/plugins/spu2ghz/xaudio2out.cpp b/plugins/spu2ghz/xaudio2out.cpp index d16216f1a8..730bf218a3 100644 --- a/plugins/spu2ghz/xaudio2out.cpp +++ b/plugins/spu2ghz/xaudio2out.cpp @@ -24,9 +24,6 @@ #include #include -// turn off warning C4355: 'this' : used in base member initializer list -#pragma warning( disable: 4355 ) - class XAudio2Mod: public SndOutModule { private: @@ -133,7 +130,7 @@ public: // Create an XAudio2 voice to stream this wave // if( FAILED(hr = pXAudio2->CreateSourceVoice( &pSourceVoice, &wfx, - XAUDIO2_VOICE_NOSRC, 1.0f, &voiceContext ) ) ) + XAUDIO2_VOICE_NOPITCH, 1.0f, &voiceContext ) ) ) { SysMessage( "Error %#X creating source voice\n", hr ); SAFE_RELEASE( pXAudio2 ); @@ -183,7 +180,7 @@ public: pSourceVoice = NULL; } - Sleep(50); + Sleep(50); // give the engine some time to stop voices // // Cleanup XAudio2