mirror of https://github.com/PCSX2/pcsx2.git
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
This commit is contained in:
parent
5edca82eb3
commit
62e1f5015d
|
@ -180,7 +180,7 @@ void FIRFilter::setCoefficients(const SAMPLETYPE *coeffs, uint newLength, uint u
|
|||
#ifdef INTEGER_SAMPLES
|
||||
resultDivider = (SAMPLETYPE)(1<<resultDivFactor);
|
||||
#else
|
||||
resultDivider = (SAMPLETYPE)powf(2, resultDivFactor);
|
||||
resultDivider = (SAMPLETYPE)powf(2, (SAMPLETYPE)resultDivFactor);
|
||||
#endif
|
||||
|
||||
delete[] filterCoeffs;
|
||||
|
|
|
@ -61,11 +61,11 @@ namespace soundtouch
|
|||
/// and vice versa.
|
||||
///
|
||||
/// Increasing this value reduces computational burden & vice versa.
|
||||
#define DEFAULT_SEQUENCE_MS 54
|
||||
#define DEFAULT_SEQUENCE_MS 61
|
||||
|
||||
#define DEFAULT_SEEKWINDOW_MS 15
|
||||
#define DEFAULT_SEEKWINDOW_MS 18
|
||||
|
||||
#define DEFAULT_OVERLAP_MS 6
|
||||
#define DEFAULT_OVERLAP_MS 7
|
||||
|
||||
|
||||
/// Class that does the time-stretch (tempo change) effect for the processed
|
||||
|
|
|
@ -92,9 +92,9 @@ void DMALogClose() {
|
|||
|
||||
__forceinline u16 DmaRead(u32 core)
|
||||
{
|
||||
Cores[core].TDA&=0xfffff;
|
||||
const u16 ret = (u16)spu2M_Read(Cores[core].TDA);
|
||||
Cores[core].TDA++;
|
||||
Cores[core].TDA&=0xfffff;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -213,38 +213,60 @@ void DoDMAWrite(int core,u16 *pMem,u32 size)
|
|||
|
||||
if(MsgDMA()) ConLog(" * SPU2: DMA%c Transfer of %d bytes to %x (%02x %x %04x).\n",(core==0)?'4':'7',size<<1,Cores[core].TSA,Cores[core].DMABits,Cores[core].AutoDMACtrl,(~Cores[core].Regs.ATTR)&0x7fff);
|
||||
|
||||
// Optimized!
|
||||
// split the DMA copy into two chunks if needed.
|
||||
|
||||
// Instead of checking the adpcm cache for every word, we check for every block.
|
||||
// That way we can use the optimized fast write instruction to commit the memory.
|
||||
|
||||
Cores[core].TDA = Cores[core].TSA & 0xfffff;
|
||||
|
||||
u32 buff1end = Cores[core].TDA + size;
|
||||
s32 buff2end = buff1end - 0xfffff;
|
||||
if( buff2end > 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<stmp; i++ )
|
||||
// Left side remainder:
|
||||
// this produces a bitmask of the left side remainder of the cache flags:
|
||||
pcm_cache_flags[nexta] &= (1ul << leftsidebit)-1;
|
||||
|
||||
// middle run!
|
||||
// Traverse from start to finish in 8*32 word blocks,
|
||||
// and clear all the the pcm cache flags for each block.
|
||||
|
||||
for(; Cores[core].TDA<buff1end; ++Cores[core].TDA, ++pMem)
|
||||
*GetMemPtr( Cores[core].TDA ) = *pMem;
|
||||
|
||||
buff1end >>= (3+5); // 8 words per block, 32 blocks per int.
|
||||
memset( &pcm_cache_flags[nexta], 0, sizeof( u32 ) * (buff1end-nexta) );
|
||||
|
||||
if( buff2end > 0 )
|
||||
{
|
||||
pcm_cache_flags[nexta] &= ~flagbitmask;
|
||||
flagbitmask <<= 1;
|
||||
if( flagbitmask == 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
|
||||
{
|
||||
nexta++;
|
||||
flagbitmask = 1;
|
||||
}
|
||||
}
|
||||
rightsidebit = (Cores[core].TDA >> 3);
|
||||
nexta = buff1end;
|
||||
}
|
||||
|
||||
for(i=0;i<size;i++)
|
||||
{
|
||||
*GetMemPtr( Cores[core].TDA ) = pMem[i];
|
||||
//spu2M_Write( Cores[core].TDA, pMem[i] );
|
||||
Cores[core].TDA++;
|
||||
Cores[core].TDA&=0xfffff;
|
||||
// clear the right-side remainder:
|
||||
pcm_cache_flags[nexta] &= ~((1ul << (32-(rightsidebit&31)))-1);
|
||||
}
|
||||
|
||||
i=Cores[core].TSA;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "SoundTouch/SoundTouch.h"
|
||||
#include "SoundTouch/WavFile.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
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;
|
||||
|
||||
|
|
|
@ -24,9 +24,6 @@
|
|||
#include <mmsystem.h>
|
||||
#include <conio.h>
|
||||
|
||||
// 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
|
||||
|
|
Loading…
Reference in New Issue