SPU2ghz: Corrected another ADSR bug that muted audio in Shadow of the Colossus; implemented some minor speedups.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@473 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-02-11 09:47:31 +00:00
parent 3476172c49
commit 8630529f8e
4 changed files with 122 additions and 118 deletions

View File

@ -72,13 +72,13 @@ typedef struct {
// Source (Wave/Noise)
s8 Noise;
// Direct Output for Left Channel
s8 DryL;
s32 DryL;
// Direct Output for Right Channel
s8 DryR;
s32 DryR;
// Effect Output for Left Channel
s8 WetL;
s32 WetL;
// Effect Output for Right Channel
s8 WetR;
s32 WetR;
// Loop Start Adress (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start Adress (also Reg_SSAH/L)
@ -237,29 +237,29 @@ typedef struct {
// DMA Transfer Data Address (Internal...)
u32 TDA;
// External Input to Direct Output (Left)
s8 ExtDryL;
s32 ExtDryL;
// External Input to Direct Output (Right)
s8 ExtDryR;
s32 ExtDryR;
// External Input to Effects (Left)
s8 ExtWetL;
s32 ExtWetL;
// External Input to Effects (Right)
s8 ExtWetR;
s32 ExtWetR;
// Sound Data Input to Direct Output (Left)
s8 InpDryL;
s32 InpDryL;
// Sound Data Input to Direct Output (Right)
s8 InpDryR;
s32 InpDryR;
// Sound Data Input to Effects (Left)
s8 InpWetL;
s32 InpWetL;
// Sound Data Input to Effects (Right)
s8 InpWetR;
s32 InpWetR;
// Voice Data to Direct Output (Left)
s8 SndDryL;
s32 SndDryL;
// Voice Data to Direct Output (Right)
s8 SndDryR;
s32 SndDryR;
// Voice Data to Effects (Left)
s8 SndWetL;
s32 SndWetL;
// Voice Data to Effects (Right)
s8 SndWetR;
s32 SndWetR;
// Interrupt Enable
s8 IRQEnable;
// DMA related?

View File

@ -389,22 +389,20 @@ static void __forceinline CalculateADSR( V_Voice& vc )
u32 off = InvExpOffsets[(env.Value>>28)&7];
env.Value-=PsxRates[((env.Dr^0x1f)*4)-0x18+off+32];
// Clamp decay to SLevel or Zero
if (env.Value < 0)
env.Value = 0;
else
{
// calculate sustain level by mirroring the bits
// of the sustain var into the lower bits as we shift up
// (total shift, 27 bits)
u32 suslev = (env.Sl << 4) | env.Sl;
suslev = (suslev << 8) | suslev; // brings us to 12 bits!
suslev = (suslev << 12) | suslev; // 24 bits!
// calculate sustain level by mirroring the bits
// of the sustain var into the lower bits as we shift up
// (total shift, 27 bits)
s32 suslev = (env.Sl << 4) | env.Sl;
suslev = (suslev << 8) | suslev; // brings us to 12 bits!
suslev = (suslev << 12) | suslev; // 24 bits!
if( env.Value <= (suslev<<3) )
env.Phase++;
}
if( env.Value <= (suslev<<3) )
{
if (env.Value < 0)
env.Value = 0;
env.Phase++;
}
}
break;
@ -1090,10 +1088,10 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
// Note: Results from MixVoice are ranged at 16 bits.
// Following muls are toggles only (0 or 1)
SDL += VValL * vc.DryL;
SDR += VValR * vc.DryR;
SWL += VValL * vc.WetL;
SWR += VValR * vc.WetR;
SDL += VValL & vc.DryL;
SDR += VValR & vc.DryR;
SWL += VValL & vc.WetL;
SWR += VValR & vc.WetR;
}
// Saturate final result to standard 16 bit range.
@ -1116,28 +1114,28 @@ static void __fastcall MixCore(s32& OutL, s32& OutR, s32 ExtL, s32 ExtR)
s32 TDL,TDR;
// Mix in the Input data
TDL = OutL * thiscore.InpDryL;
TDR = OutR * thiscore.InpDryR;
TDL = OutL & thiscore.InpDryL;
TDR = OutR & thiscore.InpDryR;
// Mix in the Voice data
TDL += SDL * thiscore.SndDryL;
TDR += SDR * thiscore.SndDryR;
TDL += SDL & thiscore.SndDryL;
TDR += SDR & thiscore.SndDryR;
// Mix in the External (nothing/core0) data
TDL += ExtL * thiscore.ExtDryL;
TDR += ExtR * thiscore.ExtDryR;
TDL += ExtL & thiscore.ExtDryL;
TDR += ExtR & thiscore.ExtDryR;
if(EffectsEnabled)
{
s32 TWL,TWR;
// Mix Input, Voice, and External data:
TWL = OutL * thiscore.InpWetL;
TWR = OutR * thiscore.InpWetR;
TWL += SWL * thiscore.SndWetL;
TWR += SWR * thiscore.SndWetR;
TWL += ExtL * thiscore.ExtWetL;
TWR += ExtR * thiscore.ExtWetR;
TWL = OutL & thiscore.InpWetL;
TWR = OutR & thiscore.InpWetR;
TWL += SWL & thiscore.SndWetL;
TWR += SWR & thiscore.SndWetR;
TWL += ExtL & thiscore.ExtWetL;
TWR += ExtR & thiscore.ExtWetR;
WaveDump::WriteCore( core, CoreSrc_PreReverb, TWL, TWR );

View File

@ -48,7 +48,7 @@ struct SPU2freezeData
// Increment this if changes to V_Core or V_Voice structs are made.
// Chances are we'll never explicitly support older save versions,
// but might as well version them anyway. Could come in handly someday!
#define SAVE_VERSION 0x0101
#define SAVE_VERSION 0x0102
static int getFreezeSize()
{
@ -81,12 +81,20 @@ EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
{
const SPU2freezeData *spud = (SPU2freezeData*)data->data;
if( spud->id != SAVE_ID || spud->version < 0x100 )
if( spud->id != SAVE_ID || spud->version < SAVE_VERSION )
{
printf("\n*** SPU2Ghz Warning:\n");
printf(" The savestate you are trying to load was not made with this plugin.\n");
printf(" The emulator will not be stable! Find a memorycard savespot to save your\n");
printf(" game, reset, and then continue from there.\n\n");
if( spud->id == SAVE_ID )
{
printf("\tSavestate version is from an older version of this plugin.\n");
printf("\tAudio may not recover correctly.\n\n");
}
else
{
printf(" The savestate you are trying to load was not made with this plugin.\n");
printf(" The emulator will not be stable! Find a memorycard savespot to save your\n");
printf(" game, reset, and then continue from there.\n\n");
}
disableFreezes=true;
lClocks = 0;
@ -127,39 +135,34 @@ EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
// Load the ADPCM cache:
wipe_the_cache();
if( spud->version == 0x100 ) // don't support 0x100 cache anymore.
const PcmCacheEntry* pcmSrc = &spud->cacheData;
int blksLoaded=0;
for( int bidx=0; bidx<pcm_BlockCount; bidx++ )
{
printf("\n*** SPU2Ghz Warning:\n");
printf("\tSavestate version is from an older version of this plugin.\n");
printf("\tAudio may not recover correctly.\n\n");
const PcmCacheEntry* pcmSrc = &spud->cacheData;
int blksLoaded=0;
for( int bidx=0; bidx<pcm_BlockCount; bidx++ )
if( pcm_cache_data[bidx].Validated )
{
if( pcm_cache_data[bidx].Validated )
{
// load a cache block!
memcpy( &pcm_cache_data[bidx], pcmSrc, sizeof(PcmCacheEntry) );
pcmSrc++;
blksLoaded++;
}
}
// Go through the V_Voice structs and recalculate SBuffer pointer from
// the NextA setting.
for( int c=0; c<2; c++ )
{
for( int v=0; v<24; v++ )
{
const int cacheIdx = Cores[c].Voices[v].NextA / pcm_WordsPerBlock;
Cores[c].Voices[v].SBuffer = pcm_cache_data[cacheIdx].Sampledata;
}
// load a cache block!
memcpy( &pcm_cache_data[bidx], pcmSrc, sizeof(PcmCacheEntry) );
pcmSrc++;
blksLoaded++;
}
}
else
// Go through the V_Voice structs and recalculate SBuffer pointer from
// the NextA setting.
for( int c=0; c<2; c++ )
{
for( int v=0; v<24; v++ )
{
const int cacheIdx = Cores[c].Voices[v].NextA / pcm_WordsPerBlock;
Cores[c].Voices[v].SBuffer = pcm_cache_data[cacheIdx].Sampledata;
}
}
/*else
{
// We don't support the cache, so make sure the SBuffer pointers
// are safe (don't want any GPFs reading bad data)
@ -169,7 +172,7 @@ EXPORT_C_(s32) SPU2freeze(int mode, freezeData *data)
for( int v=0; v<24; v++ )
Cores[c].Voices[v].SBuffer = old_state_sBuffer;
}
}
}*/
//printf( " * SPU2 > FreezeLoad > Loaded %d cache blocks.\n", blksLoaded++ );

View File

@ -180,18 +180,18 @@ void CoreReset(int c)
Cores[c].MasterL.Value=0x7FFF;
Cores[c].MasterR.Reg_VOL=0x3FFF;
Cores[c].MasterR.Value=0x7FFF;
Cores[c].ExtWetR=1;
Cores[c].ExtWetL=1;
Cores[c].ExtDryR=1;
Cores[c].ExtDryL=1;
Cores[c].InpWetR=1;
Cores[c].InpWetL=1;
Cores[c].InpDryR=1;
Cores[c].InpDryL=1;
Cores[c].SndWetR=1;
Cores[c].SndWetL=1;
Cores[c].SndDryR=1;
Cores[c].SndDryL=1;
Cores[c].ExtWetR = -1;
Cores[c].ExtWetL = -1;
Cores[c].ExtDryR = -1;
Cores[c].ExtDryL = -1;
Cores[c].InpWetR = -1;
Cores[c].InpWetL = -1;
Cores[c].InpDryR = -1;
Cores[c].InpDryL = -1;
Cores[c].SndWetR = -1;
Cores[c].SndWetL = -1;
Cores[c].SndDryR = -1;
Cores[c].SndDryL = -1;
Cores[c].Regs.MMIX = 0xFFCF;
Cores[c].Regs.VMIXL = 0xFFFFFF;
Cores[c].Regs.VMIXR = 0xFFFFFF;
@ -209,10 +209,10 @@ void CoreReset(int c)
Cores[c].Voices[v].ADSR.Value=0;
Cores[c].Voices[v].ADSR.Phase=0;
Cores[c].Voices[v].Pitch=0x3FFF;
Cores[c].Voices[v].DryL=1;
Cores[c].Voices[v].DryR=1;
Cores[c].Voices[v].WetL=1;
Cores[c].Voices[v].WetR=1;
Cores[c].Voices[v].DryL = -1;
Cores[c].Voices[v].DryR = -1;
Cores[c].Voices[v].WetL = -1;
Cores[c].Voices[v].WetR = -1;
Cores[c].Voices[v].NextA=2800;
Cores[c].Voices[v].StartA=2800;
Cores[c].Voices[v].LoopStartA=2800;
@ -1111,6 +1111,9 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
}
return;
#define vx_SetSomeBits( varname, start, done ) \
{ for (uint vc=start, vx=1;vc<done;vc++) { Cores[core].Voices[vc].varname = (value & vx) ? -1 : 0; vx<<=1; } }
case REG_S_PMON:
vx=2; for (vc=1;vc<16;vc++) { Cores[core].Voices[vc].Modulated=(s8)((value & vx)/vx); vx<<=1; }
Cores[core].Regs.PMON = (Cores[core].Regs.PMON & 0xFFFF0000) | value;
@ -1132,60 +1135,60 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
return;
case REG_S_VMIXL:
vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( DryL, 0, 16 );
Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF0000) | value;
return;
case (REG_S_VMIXL + 2):
vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryL=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( DryL, 16, 24 );
Cores[core].Regs.VMIXL = (Cores[core].Regs.VMIXL & 0xFFFF) | (value << 16);
return;
case REG_S_VMIXEL:
vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( WetL, 0, 16 );
Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF0000) | value;
return;
case (REG_S_VMIXEL + 2):
vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetL=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( WetL, 16, 24 );
Cores[core].Regs.VMIXEL = (Cores[core].Regs.VMIXEL & 0xFFFF) | (value << 16);
return;
case REG_S_VMIXR:
vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( DryR, 0, 16 );
Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF0000) | value;
return;
case (REG_S_VMIXR + 2):
vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].DryR=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( DryR, 16, 24 );
Cores[core].Regs.VMIXR = (Cores[core].Regs.VMIXR & 0xFFFF) | (value << 16);
return;
case REG_S_VMIXER:
vx=1; for (vc=0;vc<16;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( WetR, 0, 16 );
Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF0000) | value;
return;
case (REG_S_VMIXER + 2):
vx=1; for (vc=16;vc<24;vc++) { Cores[core].Voices[vc].WetR=(s8)((value & vx)/vx); vx<<=1; }
vx_SetSomeBits( WetR, 16, 24 );
Cores[core].Regs.VMIXER = (Cores[core].Regs.VMIXER & 0xFFFF) | (value << 16);
return;
case REG_P_MMIX:
vx=value;
if (core == 0) vx&=0xFF0;
Cores[core].ExtWetR=(vx & 0x001);
Cores[core].ExtWetL=(vx & 0x002)>>1;
Cores[core].ExtDryR=(vx & 0x004)>>2;
Cores[core].ExtDryL=(vx & 0x008)>>3;
Cores[core].InpWetR=(vx & 0x010)>>4;
Cores[core].InpWetL=(vx & 0x020)>>5;
Cores[core].InpDryR=(vx & 0x040)>>6;
Cores[core].InpDryL=(vx & 0x080)>>7;
Cores[core].SndWetR=(vx & 0x100)>>8;
Cores[core].SndWetL=(vx & 0x200)>>9;
Cores[core].SndDryR=(vx & 0x400)>>10;
Cores[core].SndDryL=(vx & 0x800)>>11;
Cores[core].ExtWetR = (vx & 0x001) ? -1 : 0;
Cores[core].ExtWetL = (vx & 0x002) ? -1 : 0;
Cores[core].ExtDryR = (vx & 0x004) ? -1 : 0;
Cores[core].ExtDryL = (vx & 0x008) ? -1 : 0;
Cores[core].InpWetR = (vx & 0x010) ? -1 : 0;
Cores[core].InpWetL = (vx & 0x020) ? -1 : 0;
Cores[core].InpDryR = (vx & 0x040) ? -1 : 0;
Cores[core].InpDryL = (vx & 0x080) ? -1 : 0;
Cores[core].SndWetR = (vx & 0x100) ? -1 : 0;
Cores[core].SndWetL = (vx & 0x200) ? -1 : 0;
Cores[core].SndDryR = (vx & 0x400) ? -1 : 0;
Cores[core].SndDryL = (vx & 0x800) ? -1 : 0;
Cores[core].Regs.MMIX = value;
return;