From 809b9f89ca0a24934ffa13c7901345ed0aa82eeb Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 11 Apr 2020 00:40:28 +1000 Subject: [PATCH] SPU: Use reverb formula from Mednafen-PSX --- src/core/spu.cpp | 193 +++++++++++++++++++++++------------------------ src/core/spu.h | 66 ++++++++-------- 2 files changed, 128 insertions(+), 131 deletions(-) diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 2b90ee2de..c5fb478c1 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -150,8 +150,8 @@ bool SPU::DoState(StateWrapper& sw) UpdateTransferEvent(); } - //for (u32 i = 0; i < NUM_REVERB_REGS; i++) - //Log_WarningPrintf("Reverb[%u] = 0x%04X", i, m_reverb_registers.rev[i]); + // for (u32 i = 0; i < NUM_REVERB_REGS; i++) + // Log_WarningPrintf("Reverb[%u] = 0x%04X", i, m_reverb_registers.rev[i]); return !sw.HasError(); } @@ -1525,9 +1525,9 @@ u32 SPU::ReverbMemoryAddress(u32 address) const return (mBASE + relative_address) & 0x7FFFEu; } -s16 SPU::ReverbRead(u32 address) +s16 SPU::ReverbRead(u32 address, s32 offset) { - const u32 real_address = ReverbMemoryAddress(m_reverb_current_address + address); + const u32 real_address = ReverbMemoryAddress(m_reverb_current_address + address + static_cast(offset)); // TODO: Should this check interrupts? s16 data; @@ -1537,123 +1537,107 @@ s16 SPU::ReverbRead(u32 address) void SPU::ReverbWrite(u32 address, s16 data) { - if (!m_SPUCNT.reverb_master_enable) - return; - // TODO: Should this check interrupts? const u32 real_address = ReverbMemoryAddress(m_reverb_current_address + address); std::memcpy(&m_ram[real_address & RAM_MASK], &data, sizeof(data)); } -// Implements saturated add, subtract and multiply for reverb computations. -struct ReverbSample +ALWAYS_INLINE static s16 ReverbSat(s32 val) { - s16 value; + return static_cast(std::clamp(val, -0x8000, 0x7FFF)); +} - static ALWAYS_INLINE s16 OpAdd(s16 lhs, s16 rhs) +ALWAYS_INLINE static s32 IIASM(const s16 IIR_ALPHA, const s16 insamp) +{ + if (IIR_ALPHA == -32768) { - s32 result = s32(lhs) + s32(rhs); - return s16((result < -32768) ? -32768 : ((result > 32767) ? 32767 : result)); + if (insamp == -32768) + return 0; + else + return insamp * -65536; } - - static ALWAYS_INLINE s16 OpSub(s16 lhs, s16 rhs) - { - s32 result = s32(lhs) - s32(rhs); - return s16((result < -32768) ? -32768 : ((result > 32767) ? 32767 : result)); - } - - static ALWAYS_INLINE s16 OpMul(s16 lhs, s16 rhs) { return s16((s32(lhs) * s32(rhs)) >> 15); } - - ALWAYS_INLINE ReverbSample operator+(ReverbSample rhs) const { return ReverbSample{OpAdd(value, rhs.value)}; } - - ALWAYS_INLINE ReverbSample operator-(ReverbSample rhs) const { return ReverbSample{OpSub(value, rhs.value)}; } - - ALWAYS_INLINE ReverbSample operator*(ReverbSample rhs) const { return ReverbSample{OpMul(value, rhs.value)}; } - - ALWAYS_INLINE ReverbSample& operator+=(ReverbSample rhs) - { - value = OpAdd(value, rhs.value); - return *this; - } - - ALWAYS_INLINE ReverbSample& operator-=(ReverbSample rhs) - { - value = OpSub(value, rhs.value); - return *this; - } - - ALWAYS_INLINE ReverbSample& operator*=(ReverbSample rhs) - { - value = OpMul(value, rhs.value); - return *this; - } -}; + else + return insamp * (32768 - IIR_ALPHA); +} void SPU::DoReverb() { - const ReverbSample Lin(ReverbSample{m_reverb_left_input} * ReverbSample{m_reverb_registers.vLIN}); - const ReverbSample Rin(ReverbSample{m_reverb_right_input} * ReverbSample{m_reverb_registers.vRIN}); + if (m_SPUCNT.reverb_master_enable) + { + const s16 IIR_INPUT_A0 = + ReverbSat(((ReverbRead(m_reverb_registers.IIR_SRC_A0) * m_reverb_registers.IIR_COEF) >> 15) + + ((m_reverb_left_input * m_reverb_registers.IN_COEF_L) >> 15)); + const s16 IIR_INPUT_A1 = + ReverbSat(((ReverbRead(m_reverb_registers.IIR_SRC_A1) * m_reverb_registers.IIR_COEF) >> 15) + + ((m_reverb_right_input * m_reverb_registers.IN_COEF_R) >> 15)); + const s16 IIR_INPUT_B0 = + ReverbSat(((ReverbRead(m_reverb_registers.IIR_SRC_B0) * m_reverb_registers.IIR_COEF) >> 15) + + ((m_reverb_left_input * m_reverb_registers.IN_COEF_L) >> 15)); + const s16 IIR_INPUT_B1 = + ReverbSat(((ReverbRead(m_reverb_registers.IIR_SRC_B1) * m_reverb_registers.IIR_COEF) >> 15) + + ((m_reverb_right_input * m_reverb_registers.IN_COEF_R) >> 15)); -#define R(name) \ - ReverbSample { m_reverb_registers.name } -#define Rm(name) (u32(m_reverb_registers.name) * 8u) -#define MR(addr) \ - ReverbSample { ReverbRead(addr) } -#define MW(addr, value_) ReverbWrite((addr), (value_).value) + const s16 IIR_A0 = + ReverbSat((((IIR_INPUT_A0 * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_A0, -1)) >> 14)) >> + 1); + const s16 IIR_A1 = + ReverbSat((((IIR_INPUT_A1 * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_A1, -1)) >> 14)) >> + 1); + const s16 IIR_B0 = + ReverbSat((((IIR_INPUT_B0 * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_B0, -1)) >> 14)) >> + 1); + const s16 IIR_B1 = + ReverbSat((((IIR_INPUT_B1 * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_B1, -1)) >> 14)) >> + 1); - // [mLSAME] = (Lin + [dLSAME]*vWALL - [mLSAME-2])*vIIR + [mLSAME-2] ;L-to-L - MW(Rm(mLSAME), ((Lin + (MR(Rm(dLSAME)) * R(vWALL)) - MR(Rm(mLSAME) - 2)) * R(vIIR)) + MR(Rm(mLSAME) - 2)); + ReverbWrite(m_reverb_registers.IIR_DEST_A0, IIR_A0); + ReverbWrite(m_reverb_registers.IIR_DEST_A1, IIR_A1); + ReverbWrite(m_reverb_registers.IIR_DEST_B0, IIR_B0); + ReverbWrite(m_reverb_registers.IIR_DEST_B1, IIR_B1); - // [mRSAME] = (Rin + [dRSAME]*vWALL - [mRSAME-2])*vIIR + [mRSAME-2] ;R-to-R - MW(Rm(mLSAME), ((Rin + (MR(Rm(dRSAME)) * R(vWALL)) - MR(Rm(mRSAME) - 2)) * R(vIIR)) + MR(Rm(mRSAME) - 2)); + const s16 ACC0 = ReverbSat((((ReverbRead(m_reverb_registers.ACC_SRC_A0) * m_reverb_registers.ACC_COEF_A) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_B0) * m_reverb_registers.ACC_COEF_B) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_C0) * m_reverb_registers.ACC_COEF_C) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_D0) * m_reverb_registers.ACC_COEF_D) >> 14)) >> + 1); - // [mLDIFF] = (Lin + [dRDIFF]*vWALL - [mLDIFF-2])*vIIR + [mLDIFF-2] ;R-to-L - MW(Rm(mLDIFF), ((Lin + (MR(Rm(dRDIFF)) * R(vWALL)) - MR(Rm(mLDIFF) - 2)) * R(vIIR)) + MR(Rm(mLDIFF) - 2)); + const s16 ACC1 = ReverbSat((((ReverbRead(m_reverb_registers.ACC_SRC_A1) * m_reverb_registers.ACC_COEF_A) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_B1) * m_reverb_registers.ACC_COEF_B) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_C1) * m_reverb_registers.ACC_COEF_C) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_D1) * m_reverb_registers.ACC_COEF_D) >> 14)) >> + 1); - // [mRDIFF] = (Rin + [dLDIFF]*vWALL - [mRDIFF-2])*vIIR + [mRDIFF-2] ;L-to-R - MW(Rm(mRDIFF), ((Rin + (MR(Rm(dLDIFF)) * R(vWALL)) - MR(Rm(mRDIFF) - 2)) * R(vIIR)) + MR(Rm(mRDIFF) - 2)); + const s16 FB_A0 = ReverbRead(m_reverb_registers.MIX_DEST_A0 - m_reverb_registers.FB_SRC_A); + const s16 FB_A1 = ReverbRead(m_reverb_registers.MIX_DEST_A1 - m_reverb_registers.FB_SRC_A); + const s16 FB_B0 = ReverbRead(m_reverb_registers.MIX_DEST_B0 - m_reverb_registers.FB_SRC_B); + const s16 FB_B1 = ReverbRead(m_reverb_registers.MIX_DEST_B1 - m_reverb_registers.FB_SRC_B); - // Lout = vCOMB1 * [mLCOMB1] + vCOMB2 * [mLCOMB2] + vCOMB3 * [mLCOMB3] + vCOMB4 * [mLCOMB4] - ReverbSample Lout{(R(vCOMB1) * MR(Rm(mLCOMB1))) + (R(vCOMB2) * MR(Rm(mLCOMB2))) + (R(vCOMB3) * MR(Rm(mLCOMB3))) + - (R(vCOMB4) * MR(Rm(mLCOMB4)))}; + ReverbWrite(m_reverb_registers.MIX_DEST_A0, ReverbSat(ACC0 - ((FB_A0 * m_reverb_registers.FB_ALPHA) >> 15))); + ReverbWrite(m_reverb_registers.MIX_DEST_A1, ReverbSat(ACC1 - ((FB_A1 * m_reverb_registers.FB_ALPHA) >> 15))); - // Rout = vCOMB1 * [mRCOMB1] + vCOMB2 * [mRCOMB2] + vCOMB3 * [mRCOMB3] + vCOMB4 * [mRCOMB4] - ReverbSample Rout{(R(vCOMB1) * MR(Rm(mRCOMB1))) + (R(vCOMB2) * MR(Rm(mRCOMB2))) + (R(vCOMB3) * MR(Rm(mRCOMB3))) + - (R(vCOMB4) * MR(Rm(mRCOMB4)))}; + ReverbWrite(m_reverb_registers.MIX_DEST_B0, + ReverbSat(((m_reverb_registers.FB_ALPHA * ACC0) >> 15) - + ((FB_A0 * (s16)(0x8000 ^ m_reverb_registers.FB_ALPHA)) >> 15) - + ((FB_B0 * m_reverb_registers.FB_X) >> 15))); + ReverbWrite(m_reverb_registers.MIX_DEST_B1, + ReverbSat(((m_reverb_registers.FB_ALPHA * ACC1) >> 15) - + ((FB_A1 * (s16)(0x8000 ^ m_reverb_registers.FB_ALPHA)) >> 15) - + ((FB_B1 * m_reverb_registers.FB_X) >> 15))); + } - // Lout = Lout - vAPF1 * [mLAPF1 - dAPF1], [mLAPF1] = Lout, Lout = Lout * vAPF1 + [mLAPF1 - dAPF1] - Lout = Lout - (R(vAPF1) * MR(Rm(mLAPF1) - Rm(dAPF1))); - MW(Rm(mLAPF1), Lout); - Lout = (Lout * R(vAPF1)) + MR(Rm(mLAPF1) - Rm(dAPF1)); - - // Rout = Rout - vAPF1 * [mRAPF1 - dAPF1], [mRAPF1] = Rout, Rout = Rout * vAPF1 + [mRAPF1 - dAPF1] - Rout = Rout - (R(vAPF1) * MR(Rm(mRAPF1) - Rm(dAPF1))); - MW(Rm(mRAPF1), Rout); - Rout = (Rout * R(vAPF1)) + MR(Rm(mRAPF1) - Rm(dAPF1)); - - // Lout = Lout - vAPF2 * [mLAPF2 - dAPF2], [mLAPF2] = Lout, Lout = Lout * vAPF2 + [mLAPF2 - dAPF2] - Lout = Lout - (R(vAPF2) * MR(Rm(mLAPF2) - Rm(dAPF2))); - MW(Rm(mLAPF2), Lout); - Lout = (Lout * R(vAPF2)) + MR(Rm(mLAPF2) - Rm(dAPF2)); - - // Rout = Rout - vAPF2 * [mRAPF2 - dAPF2], [mRAPF2] = Rout, Rout = Rout * vAPF2 + [mRAPF2 - dAPF2] - Rout = Rout - (R(vAPF2) * MR(Rm(mRAPF2) - Rm(dAPF2))); - MW(Rm(mRAPF2), Rout); - Rout = (Rout * R(vAPF2)) + MR(Rm(mRAPF2) - Rm(dAPF2)); - - // LeftOutput = Lout*vLOUT - m_reverb_left_output = (Lout * R(vLOUT)).value; - - // RightOutput = Rout*vROUT - m_reverb_right_output = (Rout * R(vROUT)).value; + m_reverb_left_output = ReverbSat( + ApplyVolume((ReverbRead(m_reverb_registers.MIX_DEST_A0) + ReverbRead(m_reverb_registers.MIX_DEST_B0)) >> 1, + m_reverb_registers.vLOUT)); + m_reverb_right_output = ReverbSat( + ApplyVolume((ReverbRead(m_reverb_registers.MIX_DEST_A1) + ReverbRead(m_reverb_registers.MIX_DEST_B1)) >> 1, + m_reverb_registers.vROUT)); // BufferAddress = MAX(mBASE, (BufferAddress+2) AND 7FFFEh) m_reverb_current_address = ReverbMemoryAddress(m_reverb_current_address + 2); - -#undef MW -#undef MR -#undef Rm -#undef R } void SPU::EnsureCDAudioSpace(u32 remaining_frames) @@ -1834,5 +1818,18 @@ void SPU::DrawDebugStateWindow() } } + if (ImGui::CollapsingHeader("Hacks", ImGuiTreeNodeFlags_DefaultOpen)) + { + if (ImGui::Button("Key Off All Voices")) + { + for (u32 i = 0; i < NUM_VOICES; i++) + { + m_voices[i].KeyOff(); + m_voices[i].adsr_envelope.counter = 0; + m_voices[i].regs.adsr_volume = 0; + } + } + } + ImGui::End(); } diff --git a/src/core/spu.h b/src/core/spu.h index 5e1c05d25..1cf5db64d 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -292,38 +292,38 @@ private: { struct { - u16 dAPF1; - u16 dAPF2; - s16 vIIR; - s16 vCOMB1; - s16 vCOMB2; - s16 vCOMB3; - s16 vCOMB4; - s16 vWALL; - s16 vAPF1; - s16 vAPF2; - u16 mLSAME; - u16 mRSAME; - u16 mLCOMB1; - u16 mRCOMB1; - u16 mLCOMB2; - u16 mRCOMB2; - u16 dLSAME; - u16 dRSAME; - u16 mLDIFF; - u16 mRDIFF; - u16 mLCOMB3; - u16 mRCOMB3; - u16 mLCOMB4; - u16 mRCOMB4; - u16 dLDIFF; - u16 dRDIFF; - u16 mLAPF1; - u16 mRAPF1; - u16 mLAPF2; - u16 mRAPF2; - s16 vLIN; - s16 vRIN; + u16 FB_SRC_A; + u16 FB_SRC_B; + s16 IIR_ALPHA; + s16 ACC_COEF_A; + s16 ACC_COEF_B; + s16 ACC_COEF_C; + s16 ACC_COEF_D; + s16 IIR_COEF; + s16 FB_ALPHA; + s16 FB_X; + u16 IIR_DEST_A0; + u16 IIR_DEST_A1; + u16 ACC_SRC_A0; + u16 ACC_SRC_A1; + u16 ACC_SRC_B0; + u16 ACC_SRC_B1; + u16 IIR_SRC_A0; + u16 IIR_SRC_A1; + u16 IIR_DEST_B0; + u16 IIR_DEST_B1; + u16 ACC_SRC_C0; + u16 ACC_SRC_C1; + u16 ACC_SRC_D0; + u16 ACC_SRC_D1; + u16 IIR_SRC_B1; + u16 IIR_SRC_B0; + u16 MIX_DEST_A0; + u16 MIX_DEST_A1; + u16 MIX_DEST_B0; + u16 MIX_DEST_B1; + s16 IN_COEF_L; + s16 IN_COEF_R; }; u16 rev[NUM_REVERB_REGS]; @@ -366,7 +366,7 @@ private: void UpdateNoise(); u32 ReverbMemoryAddress(u32 address) const; - s16 ReverbRead(u32 address); + s16 ReverbRead(u32 address, s32 offset = 0); void ReverbWrite(u32 address, s16 data); void DoReverb();