SPU2-X: Resorted the mixer so that it's a little faster, and will be easier to apply some SSE2 opts in the future.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@680 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-03-04 21:32:48 +00:00
parent 1492382253
commit 7d00eb7ec6
6 changed files with 166 additions and 141 deletions

View File

@ -135,18 +135,18 @@ void DoFullDump()
fprintf(dump,"Interrupt Address: %x\n",Cores[c].IRQA);
fprintf(dump,"DMA Transfer Start Address: %x\n",Cores[c].TSA);
fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].ExtDryL?"Yes":"No");
fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].ExtDryR?"Yes":"No");
fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].ExtWetL?"Yes":"No");
fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].ExtWetR?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].SndDryL?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].SndDryR?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].SndWetL?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].SndWetR?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].InpDryL?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].InpDryR?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].InpWetL?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].InpWetR?"Yes":"No");
fprintf(dump,"External Input to Direct Output (Left): %s\n",Cores[c].DryGate.ExtL?"Yes":"No");
fprintf(dump,"External Input to Direct Output (Right): %s\n",Cores[c].DryGate.ExtR?"Yes":"No");
fprintf(dump,"External Input to Effects (Left): %s\n",Cores[c].WetGate.ExtL?"Yes":"No");
fprintf(dump,"External Input to Effects (Right): %s\n",Cores[c].WetGate.ExtR?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Left): %s\n",Cores[c].DryGate.SndL?"Yes":"No");
fprintf(dump,"Sound Data Input to Direct Output (Right): %s\n",Cores[c].DryGate.SndR?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Left): %s\n",Cores[c].WetGate.SndL?"Yes":"No");
fprintf(dump,"Sound Data Input to Effects (Right): %s\n",Cores[c].WetGate.SndR?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Left): %s\n",Cores[c].DryGate.InpL?"Yes":"No");
fprintf(dump,"Voice Data Input to Direct Output (Right): %s\n",Cores[c].DryGate.InpR?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Left): %s\n",Cores[c].WetGate.InpL?"Yes":"No");
fprintf(dump,"Voice Data Input to Effects (Right): %s\n",Cores[c].WetGate.InpR?"Yes":"No");
fprintf(dump,"IRQ Enabled: %s\n",Cores[c].IRQEnable?"Yes":"No");
fprintf(dump,"Effects Enabled: %s\n",Cores[c].FxEnable?"Yes":"No");
fprintf(dump,"Mute Enabled: %s\n",Cores[c].Mute?"Yes":"No");
@ -197,10 +197,10 @@ void DoFullDump()
fprintf(dump," - Pitch: %x\n",Cores[c].Voices[v].Pitch);
fprintf(dump," - Modulated: %s\n",Cores[c].Voices[v].Modulated?"Yes":"No");
fprintf(dump," - Source: %s\n",Cores[c].Voices[v].Noise?"Noise":"Wave");
fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].Voices[v].DryL?"Yes":"No");
fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].Voices[v].DryR?"Yes":"No");
fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].Voices[v].WetL?"Yes":"No");
fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].Voices[v].WetR?"Yes":"No");
fprintf(dump," - Direct Output for Left Channel: %s\n",Cores[c].VoiceGates[v].DryL?"Yes":"No");
fprintf(dump," - Direct Output for Right Channel: %s\n",Cores[c].VoiceGates[v].DryR?"Yes":"No");
fprintf(dump," - Effects Output for Left Channel: %s\n",Cores[c].VoiceGates[v].WetL?"Yes":"No");
fprintf(dump," - Effects Output for Right Channel: %s\n",Cores[c].VoiceGates[v].WetR?"Yes":"No");
fprintf(dump," - Loop Start Address: %x\n",Cores[c].Voices[v].LoopStartA);
fprintf(dump," - Sound Start Address: %x\n",Cores[c].Voices[v].StartA);
fprintf(dump," - Next Data Address: %x\n",Cores[c].Voices[v].NextA);

View File

@ -64,10 +64,12 @@ __forceinline s32 clamp_mix( s32 x, u8 bitshift )
return GetClamped( x, -0x8000<<bitshift, 0x7fff<<bitshift );
}
__forceinline void clamp_mix( StereoOut32& sample, u8 bitshift )
__forceinline StereoOut32 clamp_mix( const StereoOut32& sample, u8 bitshift )
{
Clampify( sample.Left, -0x8000<<bitshift, 0x7fff<<bitshift );
Clampify( sample.Right, -0x8000<<bitshift, 0x7fff<<bitshift );
return StereoOut32(
GetClamped( sample.Left, -0x8000<<bitshift, 0x7fff<<bitshift ),
GetClamped( sample.Right, -0x8000<<bitshift, 0x7fff<<bitshift )
);
}
static void __forceinline XA_decode_block(s16* buffer, const s16* block, s32& prev1, s32& prev2)
@ -562,56 +564,71 @@ static __forceinline StereoOut32 MixVoice( uint coreidx, uint voiceidx )
}
}
struct VoiceMixSet
{
static const VoiceMixSet Empty;
StereoOut32 Dry, Wet;
static StereoOut32 __fastcall MixCore( uint coreidx, const StereoOut32& Input, const StereoOut32& Ext )
VoiceMixSet() {}
VoiceMixSet( const StereoOut32& dry, const StereoOut32& wet ) :
Dry( dry ),
Wet( wet )
{
}
};
const VoiceMixSet VoiceMixSet::Empty( StereoOut32::Empty, StereoOut32::Empty );
static void __fastcall MixCoreVoices( VoiceMixSet& dest, const uint coreidx )
{
V_Core& thiscore( Cores[coreidx] );
thiscore.MasterVol.Update();
StereoOut32 Dry(0,0), Wet(0,0);
for( uint voiceidx=0; voiceidx<24; ++voiceidx )
for( uint voiceidx=0; voiceidx<V_Core::NumVoices; ++voiceidx )
{
StereoOut32 VVal( MixVoice( coreidx, voiceidx ) );
// Note: Results from MixVoice are ranged at 16 bits.
V_Voice& vc( thiscore.Voices[voiceidx] );
Dry.Left += VVal.Left & vc.DryL;
Dry.Right += VVal.Right & vc.DryR;
Wet.Left += VVal.Left & vc.WetL;
Wet.Right += VVal.Right & vc.WetR;
dest.Dry.Left += VVal.Left & thiscore.VoiceGates[voiceidx].DryL;
dest.Dry.Right += VVal.Right & thiscore.VoiceGates[voiceidx].DryR;
dest.Wet.Left += VVal.Left & thiscore.VoiceGates[voiceidx].WetL;
dest.Wet.Right += VVal.Right & thiscore.VoiceGates[voiceidx].WetR;
}
}
static StereoOut32 __fastcall MixCore( const uint coreidx, const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext )
{
V_Core& thiscore( Cores[coreidx] );
thiscore.MasterVol.Update();
// Saturate final result to standard 16 bit range.
clamp_mix( Dry );
clamp_mix( Wet );
const VoiceMixSet Voices( clamp_mix( inVoices.Dry ), clamp_mix( inVoices.Wet ) );
// Write Mixed results To Output Area
spu2M_WriteFast( 0x1000 + (coreidx<<12) + OutPos, Dry.Left );
spu2M_WriteFast( 0x1200 + (coreidx<<12) + OutPos, Dry.Right );
spu2M_WriteFast( 0x1400 + (coreidx<<12) + OutPos, Wet.Left );
spu2M_WriteFast( 0x1600 + (coreidx<<12) + OutPos, Wet.Right );
spu2M_WriteFast( 0x1000 + (coreidx<<12) + OutPos, Voices.Dry.Left );
spu2M_WriteFast( 0x1200 + (coreidx<<12) + OutPos, Voices.Dry.Right );
spu2M_WriteFast( 0x1400 + (coreidx<<12) + OutPos, Voices.Wet.Left );
spu2M_WriteFast( 0x1600 + (coreidx<<12) + OutPos, Voices.Wet.Right );
// Write mixed results to logfile (if enabled)
WaveDump::WriteCore( coreidx, CoreSrc_DryVoiceMix, Dry );
WaveDump::WriteCore( coreidx, CoreSrc_WetVoiceMix, Wet );
WaveDump::WriteCore( coreidx, CoreSrc_DryVoiceMix, Voices.Dry );
WaveDump::WriteCore( coreidx, CoreSrc_WetVoiceMix, Voices.Wet );
// Mix in the Input data
StereoOut32 TD(
Input.Left & thiscore.InpDryL,
Input.Right & thiscore.InpDryR
Input.Left & thiscore.DryGate.InpL,
Input.Right & thiscore.DryGate.InpR
);
// Mix in the Voice data
TD.Left += Dry.Left & thiscore.SndDryL;
TD.Right += Dry.Right & thiscore.SndDryR;
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL;
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR;
// Mix in the External (nothing/core0) data
TD.Left += Ext.Left & thiscore.ExtDryL;
TD.Right += Ext.Right & thiscore.ExtDryR;
TD.Left += Ext.Left & thiscore.DryGate.ExtL;
TD.Right += Ext.Right & thiscore.DryGate.ExtR;
if( !EffectsDisabled )
{
@ -622,14 +639,14 @@ static StereoOut32 __fastcall MixCore( uint coreidx, const StereoOut32& Input, c
{
// Mix Input, Voice, and External data:
StereoOut32 TW(
Input.Left & thiscore.InpWetL,
Input.Right & thiscore.InpWetR
Input.Left & thiscore.WetGate.InpL,
Input.Right & thiscore.WetGate.InpR
);
TW.Left += Wet.Left & thiscore.SndWetL;
TW.Right += Wet.Right & thiscore.SndWetR;
TW.Left += Ext.Left & thiscore.ExtWetL;
TW.Right += Ext.Right & thiscore.ExtWetR;
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL;
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR;
TW.Left += Ext.Left & thiscore.WetGate.ExtL;
TW.Right += Ext.Right & thiscore.WetGate.ExtR;
WaveDump::WriteCore( coreidx, CoreSrc_PreReverb, TW );
@ -646,7 +663,7 @@ static StereoOut32 __fastcall MixCore( uint coreidx, const StereoOut32& Input, c
WaveDump::WriteCore( coreidx, CoreSrc_PostReverb, RV );
// Mix Dry+Wet
return StereoOut32( TD + ApplyVolume( RV, thiscore.FxVol ) );
return TD + ApplyVolume( RV, thiscore.FxVol );
}
else
{
@ -662,15 +679,25 @@ static int p_cachestat_counter=0;
__forceinline void Mix()
{
// **** CORE ZERO ****
// Note: Playmode 4 is SPDIF, which overrides other inputs.
StereoOut32 Ext( (PlayMode&4) ? StereoOut32::Empty : ReadInputPV( 0 ) );
WaveDump::WriteCore( 0, CoreSrc_Input, Ext );
StereoOut32 InputData[2] =
{
(PlayMode&4) ? StereoOut32::Empty : ReadInputPV( 0 ),
(PlayMode&8) ? StereoOut32::Empty : ReadInputPV( 1 )
};
Ext = MixCore( 0, Ext, StereoOut32::Empty );
WaveDump::WriteCore( 0, CoreSrc_Input, InputData[0] );
WaveDump::WriteCore( 1, CoreSrc_Input, InputData[1] );
// Todo: Replace me with memzero initializer!
VoiceMixSet VoiceData[2] = { VoiceMixSet::Empty, VoiceMixSet::Empty }; // mixed voice data for each core.
MixCoreVoices( VoiceData[0], 0 );
MixCoreVoices( VoiceData[1], 1 );
StereoOut32 Ext( MixCore( 0, VoiceData[0], InputData[0], StereoOut32::Empty ) );
if( (PlayMode & 4) || (Cores[0].Mute!=0) )
Ext = StereoOut32( 0, 0 );
Ext = StereoOut32::Empty;
else
{
Ext = ApplyVolume( Ext, Cores[0].MasterVol );
@ -683,13 +710,8 @@ __forceinline void Mix()
spu2M_WriteFast( 0xA00 + OutPos, Ext.Right );
WaveDump::WriteCore( 0, CoreSrc_External, Ext );
// **** CORE ONE ****
StereoOut32 Out( (PlayMode&8) ? StereoOut32::Empty : ReadInputPV( 1 ) );
WaveDump::WriteCore( 1, CoreSrc_Input, Out );
ApplyVolume( Ext, Cores[1].ExtVol );
Out = MixCore( 1, Out, Ext );
StereoOut32 Out( MixCore( 1, VoiceData[1], InputData[1], Ext ) );
if( PlayMode & 8 )
{

View File

@ -47,7 +47,7 @@ static const u32 SAVE_ID = 0x1227521;
// versioning for saves.
// Increment this when changes to the savestate system are made.
static const u32 SAVE_VERSION = 0x0003;
static const u32 SAVE_VERSION = 0x0004;
static void wipe_the_cache()
{

View File

@ -163,18 +163,19 @@ void V_Core::Reset()
MasterVol = V_VolumeSlideLR::Max;
ExtWetR = -1;
ExtWetL = -1;
ExtDryR = -1;
ExtDryL = -1;
InpWetR = -1;
InpWetL = -1;
InpDryR = -1;
InpDryL = -1;
SndWetR = -1;
SndWetL = -1;
SndDryR = -1;
SndDryL = -1;
DryGate.ExtL = -1;
DryGate.ExtR = -1;
WetGate.ExtL = -1;
WetGate.ExtR = -1;
DryGate.InpL = -1;
DryGate.InpR = -1;
WetGate.InpR = -1;
WetGate.InpL = -1;
DryGate.SndL = -1;
DryGate.SndR = -1;
WetGate.SndL = -1;
WetGate.SndR = -1;
Regs.MMIX = 0xFFCF;
Regs.VMIXL = 0xFFFFFF;
Regs.VMIXR = 0xFFFFFF;
@ -186,17 +187,18 @@ void V_Core::Reset()
IRQA=0xFFFF0;
IRQEnable=1;
for( uint v=0; v<24; ++v )
for( uint v=0; v<NumVoices; ++v )
{
VoiceGates[v].DryL = -1;
VoiceGates[v].DryR = -1;
VoiceGates[v].WetL = -1;
VoiceGates[v].WetR = -1;
Voices[v].Volume = V_VolumeSlideLR::Max;
Voices[v].ADSR.Value = 0;
Voices[v].ADSR.Phase = 0;
Voices[v].Pitch = 0x3FFF;
Voices[v].DryL = -1;
Voices[v].DryR = -1;
Voices[v].WetL = -1;
Voices[v].WetR = -1;
Voices[v].NextA = 2800;
Voices[v].StartA = 2800;
Voices[v].LoopStartA = 2800;
@ -461,10 +463,10 @@ void __fastcall TimeUpdate(u32 cClocks)
lClocks+=TickInterval;
Cycles++;
SaveMMXRegs();
// Note: IPU does not use MMX regs, so no need to save them.
//SaveMMXRegs();
Mix();
RestoreMMXRegs();
//RestoreMMXRegs();
}
}
@ -1016,7 +1018,7 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
const uint start_bit = hiword ? 16 : 0; \
const uint end_bit = hiword ? 24 : 16; \
for (uint vc=start_bit, vx=1; vc<end_bit; ++vc, vx<<=1) \
thiscore.Voices[vc].mask_out = (value & vx) ? -1 : 0; \
thiscore.VoiceGates[vc].mask_out = (value & vx) ? -1 : 0; \
}
case REG_S_VMIXL:
@ -1058,18 +1060,18 @@ __forceinline void SPU2_FastWrite( u32 rmem, u16 value )
vx = value;
if (core == 0) vx&=0xFF0;
thiscore.ExtWetR = (vx & 0x001) ? -1 : 0;
thiscore.ExtWetL = (vx & 0x002) ? -1 : 0;
thiscore.ExtDryR = (vx & 0x004) ? -1 : 0;
thiscore.ExtDryL = (vx & 0x008) ? -1 : 0;
thiscore.InpWetR = (vx & 0x010) ? -1 : 0;
thiscore.InpWetL = (vx & 0x020) ? -1 : 0;
thiscore.InpDryR = (vx & 0x040) ? -1 : 0;
thiscore.InpDryL = (vx & 0x080) ? -1 : 0;
thiscore.SndWetR = (vx & 0x100) ? -1 : 0;
thiscore.SndWetL = (vx & 0x200) ? -1 : 0;
thiscore.SndDryR = (vx & 0x400) ? -1 : 0;
thiscore.SndDryL = (vx & 0x800) ? -1 : 0;
thiscore.WetGate.ExtR = (vx & 0x001) ? -1 : 0;
thiscore.WetGate.ExtL = (vx & 0x002) ? -1 : 0;
thiscore.DryGate.ExtR = (vx & 0x004) ? -1 : 0;
thiscore.DryGate.ExtL = (vx & 0x008) ? -1 : 0;
thiscore.WetGate.InpR = (vx & 0x010) ? -1 : 0;
thiscore.WetGate.InpL = (vx & 0x020) ? -1 : 0;
thiscore.DryGate.InpR = (vx & 0x040) ? -1 : 0;
thiscore.DryGate.InpL = (vx & 0x080) ? -1 : 0;
thiscore.WetGate.SndR = (vx & 0x100) ? -1 : 0;
thiscore.WetGate.SndL = (vx & 0x200) ? -1 : 0;
thiscore.DryGate.SndR = (vx & 0x400) ? -1 : 0;
thiscore.DryGate.SndL = (vx & 0x800) ? -1 : 0;
thiscore.Regs.MMIX = value;
break;
@ -1199,7 +1201,7 @@ void StartVoices(int core, u32 value)
Cores[core].Regs.ENDX &= ~value;
for( u8 vc=0; vc<24; vc++ )
for( u8 vc=0; vc<V_Core::NumVoices; vc++ )
{
if ((value>>vc) & 1)
{
@ -1211,8 +1213,8 @@ void StartVoices(int core, u32 value)
if(MsgKeyOnOff()) ConLog(" * SPU2: KeyOn: C%dV%02d: SSA: %8x; M: %s%s%s%s; H: %02x%02x; P: %04x V: %04x/%04x; ADSR: %04x%04x\n",
core,vc,thisvc.StartA,
(thisvc.DryL)?"+":"-",(thisvc.DryR)?"+":"-",
(thisvc.WetL)?"+":"-",(thisvc.WetR)?"+":"-",
(Cores[core].VoiceGates[vc].DryL)?"+":"-",(Cores[core].VoiceGates[vc].DryR)?"+":"-",
(Cores[core].VoiceGates[vc].WetL)?"+":"-",(Cores[core].VoiceGates[vc].WetR)?"+":"-",
*(u8*)GetMemPtr(thisvc.StartA),*(u8 *)GetMemPtr((thisvc.StartA)+1),
thisvc.Pitch,
thisvc.Volume.Left.Value>>16,thisvc.Volume.Right.Value>>16,
@ -1225,7 +1227,7 @@ void StartVoices(int core, u32 value)
void StopVoices(int core, u32 value)
{
if( value == 0 ) return;
for( u8 vc=0; vc<24; vc++ )
for( u8 vc=0; vc<V_Core::NumVoices; vc++ )
{
if ((value>>vc) & 1)
{

View File

@ -210,7 +210,7 @@ extern void __fastcall ReadInput( uint core, StereoOut32& PData );
extern void Mix();
extern s32 clamp_mix( s32 x, u8 bitshift=0 );
extern void clamp_mix( StereoOut32& sample, u8 bitshift=0 );
extern StereoOut32 clamp_mix( const StereoOut32& sample, u8 bitshift=0 );
extern void Reverb_AdvanceBuffer( V_Core& thiscore );
extern StereoOut32 DoReverb( V_Core& thiscore, const StereoOut32& Input );
extern s32 MulShr32( s32 srcval, s32 mulval );

View File

@ -128,14 +128,6 @@ struct V_Voice
s8 Modulated;
// Source (Wave/Noise)
s8 Noise;
// Direct Output for Left Channel
s32 DryL;
// Direct Output for Right Channel
s32 DryR;
// Effect Output for Left Channel
s32 WetL;
// Effect Output for Right Channel
s32 WetR;
// Loop Start address (also Reg_LSAH/L)
u32 LoopStartA;
// Sound Start address (also Reg_SSAH/L)
@ -309,11 +301,40 @@ struct V_CoreRegs
u16 _1AC;
};
struct V_VoiceGates
{
s16 DryL; // 'AND Gate' for Direct Output to Left Channel
s16 DryR; // 'AND Gate' for Direct Output for Right Channel
s16 WetL; // 'AND Gate' for Effect Output for Left Channel
s16 WetR; // 'AND Gate' for Effect Output for Right Channel
};
union V_CoreGates
{
struct
{
u64 lo;
u64 hi;
} v128;
struct
{
s16 InpL; // Sound Data Input to Direct Output (Left)
s16 InpR; // Sound Data Input to Direct Output (Right)
s16 SndL; // Voice Data to Direct Output (Left)
s16 SndR; // Voice Data to Direct Output (Right)
s16 ExtL; // External Input to Direct Output (Left)
s16 ExtR; // External Input to Direct Output (Right)
};
};
struct V_Core
{
// Core Voices
V_Voice Voices[24];
static const uint NumVoices = 24;
// Core Voices
V_Voice Voices[NumVoices];
V_VoiceGates VoiceGates[NumVoices];
V_VolumeSlideLR MasterVol;// Master Volume
@ -321,36 +342,16 @@ struct V_Core
V_VolumeLR InpVol; // Volume for Sound Data Input
V_VolumeLR FxVol; // Volume for Output from Effects
V_CoreGates DryGate;
V_CoreGates WetGate;
// Interrupt Address
u32 IRQA;
// DMA Transfer Start Address
u32 TSA;
// DMA Transfer Data Address (Internal...)
u32 TDA;
// External Input to Direct Output (Left)
s32 ExtDryL;
// External Input to Direct Output (Right)
s32 ExtDryR;
// External Input to Effects (Left)
s32 ExtWetL;
// External Input to Effects (Right)
s32 ExtWetR;
// Sound Data Input to Direct Output (Left)
s32 InpDryL;
// Sound Data Input to Direct Output (Right)
s32 InpDryR;
// Sound Data Input to Effects (Left)
s32 InpWetL;
// Sound Data Input to Effects (Right)
s32 InpWetR;
// Voice Data to Direct Output (Left)
s32 SndDryL;
// Voice Data to Direct Output (Right)
s32 SndDryR;
// Voice Data to Effects (Left)
s32 SndWetL;
// Voice Data to Effects (Right)
s32 SndWetR;
// Interrupt Enable
s8 IRQEnable;
// DMA related?