From 3f937a2a392ba380b29720e31be0b2bce29623a2 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 12 Nov 2020 00:56:24 +1000 Subject: [PATCH] SPU: Port reverb algorithm changes from Mednafen --- src/core/spu.cpp | 159 ++++++++++++++++++++--------------------------- src/core/spu.h | 36 ++++------- 2 files changed, 81 insertions(+), 114 deletions(-) diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 94310a3dc..bb3ec4019 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -1501,6 +1501,14 @@ ALWAYS_INLINE static s16 ReverbSat(s32 val) return static_cast(std::clamp(val, -0x8000, 0x7FFF)); } +ALWAYS_INLINE static s16 ReverbNeg(s16 samp) +{ + if (samp == -32768) + return 0x7FFF; + + return -samp; +} + ALWAYS_INLINE static s32 IIASM(const s16 IIR_ALPHA, const s16 insamp) { if (IIR_ALPHA == -32768) @@ -1514,91 +1522,6 @@ ALWAYS_INLINE static s32 IIASM(const s16 IIR_ALPHA, const s16 insamp) return insamp * (32768 - IIR_ALPHA); } -void SPU::ComputeReverb() -{ - std::array downsampled; - for (unsigned lr = 0; lr < 2; lr++) - downsampled[lr] = Reverb4422(&m_reverb_downsample_buffer[lr][(m_reverb_resample_buffer_position - 39) & 0x3F]); - - 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) + - ((downsampled[0] * 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) + - ((downsampled[1] * 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) + - ((downsampled[0] * 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) + - ((downsampled[1] * m_reverb_registers.IN_COEF_R) >> 15)); - - 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); - - 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); - - 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); - - 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); - - 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); - - 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))); - - 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))); - } - - m_reverb_upsample_buffer[0][(m_reverb_resample_buffer_position >> 1) | 0x20] = - m_reverb_upsample_buffer[0][m_reverb_resample_buffer_position >> 1] = - (ReverbRead(m_reverb_registers.MIX_DEST_A0) + ReverbRead(m_reverb_registers.MIX_DEST_B0)) >> 1; - m_reverb_upsample_buffer[1][(m_reverb_resample_buffer_position >> 1) | 0x20] = - m_reverb_upsample_buffer[1][m_reverb_resample_buffer_position >> 1] = - (ReverbRead(m_reverb_registers.MIX_DEST_A1) + ReverbRead(m_reverb_registers.MIX_DEST_B1)) >> 1; - - m_reverb_current_address = (m_reverb_current_address + 1) & 0x3FFFFu; - if (m_reverb_current_address == 0) - m_reverb_current_address = m_reverb_base_address; -} - void SPU::ProcessReverb(s16 left_in, s16 right_in, s32* left_out, s32* right_out) { s_last_reverb_input[0] = left_in; @@ -1611,14 +1534,70 @@ void SPU::ProcessReverb(s16 left_in, s16 right_in, s32* left_out, s32* right_out s32 out[2]; if (m_reverb_resample_buffer_position & 1u) { - ComputeReverb(); - for (u32 i = 0; i < 2; i++) - out[i] = Reverb2244(&m_reverb_upsample_buffer[i][((m_reverb_resample_buffer_position - 39) & 0x3F) >> 1]); + std::array downsampled; + for (unsigned lr = 0; lr < 2; lr++) + downsampled[lr] = Reverb4422(&m_reverb_downsample_buffer[lr][(m_reverb_resample_buffer_position - 38) & 0x3F]); + + for (unsigned lr = 0; lr < 2; lr++) + { + if (m_SPUCNT.reverb_master_enable) + { + const s16 IIR_INPUT_A = + ReverbSat((((ReverbRead(m_reverb_registers.IIR_SRC_A[lr ^ 0]) * m_reverb_registers.IIR_COEF) >> 14) + + ((downsampled[lr] * m_reverb_registers.IN_COEF[lr]) >> 14)) >> + 1); + const s16 IIR_INPUT_B = + ReverbSat((((ReverbRead(m_reverb_registers.IIR_SRC_B[lr ^ 1]) * m_reverb_registers.IIR_COEF) >> 14) + + ((downsampled[lr] * m_reverb_registers.IN_COEF[lr]) >> 14)) >> + 1); + const s16 IIR_A = + ReverbSat((((IIR_INPUT_A * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_A[lr], -1)) >> 14)) >> + 1); + const s16 IIR_B = + ReverbSat((((IIR_INPUT_B * m_reverb_registers.IIR_ALPHA) >> 14) + + (IIASM(m_reverb_registers.IIR_ALPHA, ReverbRead(m_reverb_registers.IIR_DEST_B[lr], -1)) >> 14)) >> + 1); + + ReverbWrite(m_reverb_registers.IIR_DEST_A[lr], IIR_A); + ReverbWrite(m_reverb_registers.IIR_DEST_B[lr], IIR_B); + } + + const s32 ACC = ((ReverbRead(m_reverb_registers.ACC_SRC_A[lr]) * m_reverb_registers.ACC_COEF_A) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_B[lr]) * m_reverb_registers.ACC_COEF_B) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_C[lr]) * m_reverb_registers.ACC_COEF_C) >> 14) + + ((ReverbRead(m_reverb_registers.ACC_SRC_D[lr]) * m_reverb_registers.ACC_COEF_D) >> 14); + + const s16 FB_A = ReverbRead(m_reverb_registers.MIX_DEST_A[lr] - m_reverb_registers.FB_SRC_A); + const s16 FB_B = ReverbRead(m_reverb_registers.MIX_DEST_B[lr] - m_reverb_registers.FB_SRC_B); + const s16 MDA = ReverbSat((ACC + ((FB_A * ReverbNeg(m_reverb_registers.FB_ALPHA)) >> 14)) >> 1); + const s16 MDB = ReverbSat( + FB_A + + ((((MDA * m_reverb_registers.FB_ALPHA) >> 14) + ((FB_B * ReverbNeg(m_reverb_registers.FB_X)) >> 14)) >> 1)); + const s16 IVB = ReverbSat(FB_B + ((MDB * m_reverb_registers.FB_X) >> 15)); + + if (m_SPUCNT.reverb_master_enable) + { + ReverbWrite(m_reverb_registers.MIX_DEST_A[lr], MDA); + ReverbWrite(m_reverb_registers.MIX_DEST_B[lr], MDB); + } + + m_reverb_upsample_buffer[lr][(m_reverb_resample_buffer_position >> 1) | 0x20] = + m_reverb_upsample_buffer[lr][m_reverb_resample_buffer_position >> 1] = IVB; + } + + m_reverb_current_address = (m_reverb_current_address + 1) & 0x3FFFFu; + if (m_reverb_current_address == 0) + m_reverb_current_address = m_reverb_base_address; + + for (unsigned lr = 0; lr < 2; lr++) + out[lr] = + Reverb2244(&m_reverb_upsample_buffer[lr][((m_reverb_resample_buffer_position >> 1) - 19) & 0x1F]); } else { - for (u32 i = 0; i < 2; i++) - out[i] = Reverb2244(&m_reverb_upsample_buffer[i][((m_reverb_resample_buffer_position - 39) & 0x3F) >> 1]); + for (unsigned lr = 0; lr < 2; lr++) + out[lr] = Reverb2244(&m_reverb_upsample_buffer[lr][((m_reverb_resample_buffer_position >> 1) - 19) & 0x1F]); } m_reverb_resample_buffer_position = (m_reverb_resample_buffer_position + 1) & 0x3F; diff --git a/src/core/spu.h b/src/core/spu.h index b3c08b9cb..4c2fde1ce 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -1,8 +1,8 @@ #pragma once #include "common/bitfield.h" #include "common/fifo_queue.h" -#include "types.h" #include "system.h" +#include "types.h" #include #include @@ -293,28 +293,17 @@ private: 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 IIR_DEST_A[2]; + u16 ACC_SRC_A[2]; + u16 ACC_SRC_B[2]; + u16 IIR_SRC_A[2]; + u16 IIR_DEST_B[2]; + u16 ACC_SRC_C[2]; + u16 ACC_SRC_D[2]; + u16 IIR_SRC_B[2]; + u16 MIX_DEST_A[2]; + u16 MIX_DEST_B[2]; + s16 IN_COEF[2]; }; u16 rev[NUM_REVERB_REGS]; @@ -356,7 +345,6 @@ private: u32 ReverbMemoryAddress(u32 address) const; s16 ReverbRead(u32 address, s32 offset = 0); void ReverbWrite(u32 address, s16 data); - void ComputeReverb(); void ProcessReverb(s16 left_in, s16 right_in, s32* left_out, s32* right_out); void Execute(TickCount ticks);