From 97ed78109c1a0e8501da4b594d944feeae441f85 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sat, 30 Jan 2021 02:42:55 +0000 Subject: [PATCH] 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 --- pcsx2/SPU2/defs.h | 2 +- pcsx2/SPU2/spu2sys.cpp | 65 ++++++++++++++++++++++++++---------------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/pcsx2/SPU2/defs.h b/pcsx2/SPU2/defs.h index 94f06955ad..17ec291f2f 100644 --- a/pcsx2/SPU2/defs.h +++ b/pcsx2/SPU2/defs.h @@ -193,7 +193,7 @@ struct V_Voice s32 SCurrent; // it takes a few ticks for voices to start on the real SPU2? - bool Start(); + void Start(); void Stop(); }; diff --git a/pcsx2/SPU2/spu2sys.cpp b/pcsx2/SPU2/spu2sys.cpp index 62c9cd13df..9b4ebc9e1f 100644 --- a/pcsx2/SPU2/spu2sys.cpp +++ b/pcsx2/SPU2/spu2sys.cpp @@ -336,32 +336,11 @@ void V_Core::UpdateEffectsBufferSize() 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; LoopCycle = Cycles - 1; // Get it out of the start range as to not confuse it - return true; + PendingLoopStart = false; } void V_Voice::Stop() @@ -374,6 +353,37 @@ uint TickInterval = 768; static const int SanityInterval = 4800; 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) { u32 dClocks = cClocks - lClocks; @@ -429,6 +439,12 @@ __forceinline void TimeUpdate(u32 cClocks) lClocks += TickInterval; 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. //SaveMMXRegs(); Mix(); @@ -1970,8 +1986,7 @@ void StartVoices(int core, u32 value) if (!((value >> vc) & 1)) continue; - if (Cores[core].Voices[vc].Start()) - Cores[core].KeyOn &= ~(1 << vc); + Cores[core].Voices[vc].Start(); if (IsDevBuild) {