SPU: Wait 2T when keying on a voice

Just like Delay cycles used to do, but done better and tested on a PS2 to get the correct timings
This commit is contained in:
refractionpcsx2 2021-01-30 02:42:55 +00:00
parent 2415fd3415
commit 97ed78109c
2 changed files with 41 additions and 26 deletions

View File

@ -193,7 +193,7 @@ struct V_Voice
s32 SCurrent; s32 SCurrent;
// it takes a few ticks for voices to start on the real SPU2? // it takes a few ticks for voices to start on the real SPU2?
bool Start(); void Start();
void Stop(); void Stop();
}; };

View File

@ -336,32 +336,11 @@ void V_Core::UpdateEffectsBufferSize()
RevBuffers.APF2_R_SRC = EffectsBufferIndexer(Revb.APF2_R_DST - Revb.APF2_SIZE); RevBuffers.APF2_R_SRC = EffectsBufferIndexer(Revb.APF2_R_DST - Revb.APF2_SIZE);
} }
bool V_Voice::Start() void V_Voice::Start()
{ {
if (StartA & 7)
{
fprintf(stderr, " *** Misaligned StartA %05x!\n", StartA);
StartA = (StartA + 0xFFFF8) + 0x8;
}
ADSR.Releasing = false;
ADSR.Value = 1;
ADSR.Phase = 1;
SCurrent = 28;
LoopMode = 0;
SP = 0;
LoopFlags = 0;
NextA = StartA | 1;
Prev1 = 0;
Prev2 = 0;
PendingLoopStart = false;
PV1 = PV2 = 0;
PV3 = PV4 = 0;
NextCrest = -0x8000;
PlayCycle = Cycles; PlayCycle = Cycles;
LoopCycle = Cycles - 1; // Get it out of the start range as to not confuse it LoopCycle = Cycles - 1; // Get it out of the start range as to not confuse it
return true; PendingLoopStart = false;
} }
void V_Voice::Stop() void V_Voice::Stop()
@ -374,6 +353,37 @@ uint TickInterval = 768;
static const int SanityInterval = 4800; static const int SanityInterval = 4800;
extern void UpdateDebugDialog(); extern void UpdateDebugDialog();
__forceinline bool StartQueuedVoice(uint coreidx, uint voiceidx)
{
V_Voice& vc(Cores[coreidx].Voices[voiceidx]);
if ((Cycles - vc.PlayCycle) < 2)
return false;
if (vc.StartA & 7)
{
fprintf(stderr, " *** Misaligned StartA %05x!\n", vc.StartA);
vc.StartA = (vc.StartA + 0xFFFF8) + 0x8;
}
vc.ADSR.Releasing = false;
vc.ADSR.Value = 1;
vc.ADSR.Phase = 1;
vc.SCurrent = 28;
vc.LoopMode = 0;
vc.SP = 0;
vc.LoopFlags = 0;
vc.NextA = vc.StartA | 1;
vc.Prev1 = 0;
vc.Prev2 = 0;
vc.PV1 = vc.PV2 = 0;
vc.PV3 = vc.PV4 = 0;
vc.NextCrest = -0x8000;
return true;
}
__forceinline void TimeUpdate(u32 cClocks) __forceinline void TimeUpdate(u32 cClocks)
{ {
u32 dClocks = cClocks - lClocks; u32 dClocks = cClocks - lClocks;
@ -429,6 +439,12 @@ __forceinline void TimeUpdate(u32 cClocks)
lClocks += TickInterval; lClocks += TickInterval;
Cycles++; Cycles++;
// Start Queued Voices, they start after 2T (Tested on real HW)
for(int c = 0; c < 2; c++)
for (int v = 0; v < 24; v++)
if(Cores[c].KeyOn & (1 << v))
if(StartQueuedVoice(c, v))
Cores[c].KeyOn &= ~(1 << v);
// Note: IOP does not use MMX regs, so no need to save them. // Note: IOP does not use MMX regs, so no need to save them.
//SaveMMXRegs(); //SaveMMXRegs();
Mix(); Mix();
@ -1970,8 +1986,7 @@ void StartVoices(int core, u32 value)
if (!((value >> vc) & 1)) if (!((value >> vc) & 1))
continue; continue;
if (Cores[core].Voices[vc].Start()) Cores[core].Voices[vc].Start();
Cores[core].KeyOn &= ~(1 << vc);
if (IsDevBuild) if (IsDevBuild)
{ {