mirror of https://github.com/PCSX2/pcsx2.git
SPU2-X: Improved (hopefully to perfection) the reporting of NAX by moving code around in the decoder. Fixes Magic Pengel, hopefully no regressions (but it does intentionally change when some IRQs fire a bit so there might be some, but if so this is a step towards fixing other finicky games).
git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4752 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
parent
d968362961
commit
9dd3cf8078
|
@ -133,8 +133,8 @@ int g_counter_cache_misses = 0;
|
||||||
int g_counter_cache_ignores = 0;
|
int g_counter_cache_ignores = 0;
|
||||||
|
|
||||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||||
// LOOP probably prevents SPU2 from muting the voice when the ENDX bit is set
|
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||||
// (which would explain the requirement that every block in a loop has the LOOP bit set, not just the last)
|
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||||
#define XAFLAG_LOOP_END (1ul<<0)
|
#define XAFLAG_LOOP_END (1ul<<0)
|
||||||
|
@ -145,27 +145,45 @@ static __forceinline s32 GetNextDataBuffered( V_Core& thiscore, uint voiceidx )
|
||||||
{
|
{
|
||||||
V_Voice& vc( thiscore.Voices[voiceidx] );
|
V_Voice& vc( thiscore.Voices[voiceidx] );
|
||||||
|
|
||||||
|
if( (vc.SCurrent&3) == 0 )
|
||||||
|
{
|
||||||
|
IncrementNextA( thiscore, voiceidx );
|
||||||
|
|
||||||
|
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
|
||||||
|
{
|
||||||
|
if(vc.LoopFlags & XAFLAG_LOOP_END)
|
||||||
|
{
|
||||||
|
thiscore.Regs.ENDX |= (1 << voiceidx);
|
||||||
|
vc.NextA = vc.LoopStartA | 1;
|
||||||
|
if (!(vc.LoopFlags & XAFLAG_LOOP))
|
||||||
|
vc.Stop();
|
||||||
|
|
||||||
|
if( IsDevBuild )
|
||||||
|
{
|
||||||
|
if(MsgVoiceOff()) ConLog("* SPU2-X: Voice Off by EndPoint: %d \n", voiceidx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if( vc.SCurrent == 28 )
|
if( vc.SCurrent == 28 )
|
||||||
{
|
{
|
||||||
if(vc.LoopFlags & XAFLAG_LOOP_END)
|
vc.SCurrent = 0;
|
||||||
{
|
|
||||||
thiscore.Regs.ENDX |= (1 << voiceidx);
|
|
||||||
if (!(vc.LoopFlags & XAFLAG_LOOP))
|
|
||||||
vc.Stop();
|
|
||||||
|
|
||||||
vc.NextA = vc.LoopStartA;
|
|
||||||
if( IsDevBuild )
|
|
||||||
{
|
|
||||||
if(MsgVoiceOff()) ConLog("* SPU2-X: Voice Off by EndPoint: %d \n", voiceidx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll need the loop flags and buffer pointers regardless of cache status:
|
// We'll need the loop flags and buffer pointers regardless of cache status:
|
||||||
// Note to Self : NextA addresses WORDS (not bytes).
|
|
||||||
|
|
||||||
s16* memptr = GetMemPtr(vc.NextA&0xFFFFF);
|
for (int i=0; i<2; i++)
|
||||||
|
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
|
||||||
|
SetIrqCall(i);
|
||||||
|
|
||||||
|
s16* memptr = GetMemPtr(vc.NextA & 0xFFFF8);
|
||||||
vc.LoopFlags = *memptr >> 8; // grab loop flags from the upper byte.
|
vc.LoopFlags = *memptr >> 8; // grab loop flags from the upper byte.
|
||||||
|
|
||||||
|
if( (vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode )
|
||||||
|
vc.LoopStartA = vc.NextA & 0xFFFF8;
|
||||||
|
|
||||||
const int cacheIdx = vc.NextA / pcm_WordsPerBlock;
|
const int cacheIdx = vc.NextA / pcm_WordsPerBlock;
|
||||||
PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx];
|
PcmCacheEntry& cacheLine = pcm_cache_data[cacheIdx];
|
||||||
vc.SBuffer = cacheLine.Sampledata;
|
vc.SBuffer = cacheLine.Sampledata;
|
||||||
|
@ -199,18 +217,6 @@ static __forceinline s32 GetNextDataBuffered( V_Core& thiscore, uint voiceidx )
|
||||||
|
|
||||||
XA_decode_block( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 );
|
XA_decode_block( vc.SBuffer, memptr, vc.Prev1, vc.Prev2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
vc.SCurrent = 0;
|
|
||||||
if( (vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode )
|
|
||||||
vc.LoopStartA = vc.NextA;
|
|
||||||
|
|
||||||
goto _Increment;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( (vc.SCurrent&3) == 3 )
|
|
||||||
{
|
|
||||||
_Increment:
|
|
||||||
IncrementNextA( thiscore, voiceidx );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return vc.SBuffer[vc.SCurrent++];
|
return vc.SBuffer[vc.SCurrent++];
|
||||||
|
@ -220,27 +226,35 @@ static __forceinline void GetNextDataDummy(V_Core& thiscore, uint voiceidx)
|
||||||
{
|
{
|
||||||
V_Voice& vc( thiscore.Voices[voiceidx] );
|
V_Voice& vc( thiscore.Voices[voiceidx] );
|
||||||
|
|
||||||
if (vc.SCurrent == 28)
|
IncrementNextA( thiscore, voiceidx );
|
||||||
|
|
||||||
|
if ((vc.NextA & 7) == 0) // vc.SCurrent == 24 equivalent
|
||||||
{
|
{
|
||||||
if(vc.LoopFlags & XAFLAG_LOOP_END)
|
if(vc.LoopFlags & XAFLAG_LOOP_END)
|
||||||
{
|
{
|
||||||
thiscore.Regs.ENDX |= (1 << voiceidx);
|
thiscore.Regs.ENDX |= (1 << voiceidx);
|
||||||
vc.NextA = vc.LoopStartA;
|
vc.NextA = vc.LoopStartA | 1;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
vc.NextA++; // no, don't IncrementNextA here. We haven't read the header yet.
|
||||||
|
}
|
||||||
|
|
||||||
vc.LoopFlags = *GetMemPtr(vc.NextA&0xFFFFF) >> 8; // grab loop flags from the upper byte.
|
if (vc.SCurrent == 28)
|
||||||
|
{
|
||||||
|
for (int i=0; i<2; i++)
|
||||||
|
if (Cores[i].IRQEnable && Cores[i].IRQA == (vc.NextA & 0xFFFF8))
|
||||||
|
SetIrqCall(i);
|
||||||
|
|
||||||
|
vc.LoopFlags = *GetMemPtr(vc.NextA&0xFFFF8) >> 8; // grab loop flags from the upper byte.
|
||||||
|
|
||||||
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
|
if ((vc.LoopFlags & XAFLAG_LOOP_START) && !vc.LoopMode)
|
||||||
vc.LoopStartA = vc.NextA;
|
vc.LoopStartA = vc.NextA;
|
||||||
|
|
||||||
IncrementNextA(thiscore, voiceidx);
|
|
||||||
|
|
||||||
vc.SCurrent = 0;
|
vc.SCurrent = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vc.SP -= 4096 * (4 - (vc.SCurrent & 3));
|
vc.SP -= 4096 * (4 - (vc.SCurrent & 3));
|
||||||
vc.SCurrent += 4 - (vc.SCurrent & 3);
|
vc.SCurrent += 4 - (vc.SCurrent & 3);
|
||||||
IncrementNextA(thiscore, voiceidx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -170,7 +170,7 @@ void V_Core::Init( int index )
|
||||||
Voices[v].ADSR.Value = 0;
|
Voices[v].ADSR.Value = 0;
|
||||||
Voices[v].ADSR.Phase = 0;
|
Voices[v].ADSR.Phase = 0;
|
||||||
Voices[v].Pitch = 0x3FFF;
|
Voices[v].Pitch = 0x3FFF;
|
||||||
Voices[v].NextA = 0x2800;
|
Voices[v].NextA = 0x2801;
|
||||||
Voices[v].StartA = 0x2800;
|
Voices[v].StartA = 0x2800;
|
||||||
Voices[v].LoopStartA = 0x2800;
|
Voices[v].LoopStartA = 0x2800;
|
||||||
}
|
}
|
||||||
|
@ -324,9 +324,7 @@ void V_Voice::Start()
|
||||||
SCurrent = 28;
|
SCurrent = 28;
|
||||||
LoopMode = 0;
|
LoopMode = 0;
|
||||||
LoopFlags = 0;
|
LoopFlags = 0;
|
||||||
// Setting the loopstart to NextA breaks Squaresoft games (KH2 intro gets crackly)
|
NextA = StartA | 1;
|
||||||
//LoopStartA = StartA;
|
|
||||||
NextA = StartA;
|
|
||||||
Prev1 = 0;
|
Prev1 = 0;
|
||||||
Prev2 = 0;
|
Prev2 = 0;
|
||||||
|
|
||||||
|
@ -862,12 +860,12 @@ static void __fastcall RegWrite_VoiceAddr( u16 value )
|
||||||
// reg, and see if they're buggy or not. --air
|
// reg, and see if they're buggy or not. --air
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8);
|
thisvoice.NextA = ((value & 0x0F) << 16) | (thisvoice.NextA & 0xFFF8) | 1;
|
||||||
thisvoice.SCurrent = 28;
|
thisvoice.SCurrent = 28;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8);
|
thisvoice.NextA = (thisvoice.NextA & 0x0F0000) | (value & 0xFFF8) | 1;
|
||||||
thisvoice.SCurrent = 28;
|
thisvoice.SCurrent = 28;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue