From 07d4a65a45ed9994ba60693fa6afdcedf79d7a86 Mon Sep 17 00:00:00 2001 From: Ziemas Date: Tue, 10 Oct 2023 01:21:01 +0200 Subject: [PATCH] SPU2: Rewrite volume slides [SAVEVERSION+] --- pcsx2/SPU2/ADSR.cpp | 61 +++++++++++++++++---------------- pcsx2/SPU2/Debug.cpp | 6 ++-- pcsx2/SPU2/Mixer.cpp | 8 ++--- pcsx2/SPU2/RegTable.cpp | 9 +++-- pcsx2/SPU2/defs.h | 27 +++++++++++---- pcsx2/SPU2/spu2sys.cpp | 76 ++++------------------------------------- pcsx2/SaveState.h | 2 +- 7 files changed, 71 insertions(+), 118 deletions(-) diff --git a/pcsx2/SPU2/ADSR.cpp b/pcsx2/SPU2/ADSR.cpp index d69b29b9fb..f5130ebf38 100644 --- a/pcsx2/SPU2/ADSR.cpp +++ b/pcsx2/SPU2/ADSR.cpp @@ -19,34 +19,8 @@ #include "common/Assertions.h" -#include - static constexpr s32 ADSR_MAX_VOL = 0x7fff; -static const int InvExpOffsets[] = {0, 4, 6, 8, 9, 10, 11, 12}; - -using PSXRateTable = std::array; - -static constexpr PSXRateTable ComputePSXRates() -{ - PSXRateTable rates = {}; - for (int i = 0; i < (32 + 128); i++) - { - const int shift = (i - 32) >> 2; - s64 rate = (i & 3) + 4; - if (shift < 0) - rate >>= -shift; - else - rate <<= shift; - - // Maximum rate is 0x4000. - rates[i] = (int)std::min(rate, (s64)0x40000000LL); - } - return rates; -} - -static constexpr const PSXRateTable PsxRates = ComputePSXRates(); - void V_ADSR::UpdateCache() { CachedPhases[PHASE_ATTACK].Decr = false; @@ -152,15 +126,44 @@ void V_VolumeSlide::RegSet(u16 src) Reg_VOL = src; if (!Enable) { - // Shift and sign extend; - Value = (s16)(src << 1); + Value = SignExtend16(src << 1); } } void V_VolumeSlide::Update() { if (!Enable) - { return; + + s32 step_size = 7 - Step; + + if (Decr) + { + step_size = ~step_size; + } + + u32 counter_inc = 0x8000 >> std::max(0, Shift - 11); + s16 level_inc = (s16)(step_size << std::max(0, 11 - Shift)); + + if (Exp) + { + if (!Decr && Value > 0x6000) + { + counter_inc >>= 2; + } + + if (Decr) + { + level_inc = (s16)((level_inc * Value) >> 15); + } + } + + counter_inc = std::max(1, counter_inc); + Counter += counter_inc; + + if (Counter >= 0x8000) + { + Counter = 0; + Value = std::clamp(Value + level_inc, 0, INT16_MAX); } } diff --git a/pcsx2/SPU2/Debug.cpp b/pcsx2/SPU2/Debug.cpp index 5755586f28..47513c334d 100644 --- a/pcsx2/SPU2/Debug.cpp +++ b/pcsx2/SPU2/Debug.cpp @@ -82,10 +82,8 @@ void SPU2::ConLog(const char* fmt, ...) void V_VolumeSlide::DebugDump(FILE* dump, const char* title, const char* nameLR) { fprintf(dump, "%s Volume for %s Channel:\t%x\n" - " - Value: %x\n" - " - Mode: %x\n" - " - Increment: %x\n", - title, nameLR, Reg_VOL, Value, Mode, Increment); + " - Value: %x\n", + title, nameLR, Reg_VOL, Value); } void V_VolumeSlideLR::DebugDump(FILE* dump, const char* title) diff --git a/pcsx2/SPU2/Mixer.cpp b/pcsx2/SPU2/Mixer.cpp index 20831d63da..3ef5610f73 100644 --- a/pcsx2/SPU2/Mixer.cpp +++ b/pcsx2/SPU2/Mixer.cpp @@ -302,8 +302,8 @@ static __forceinline StereoOut32 ApplyVolume(const StereoOut32& data, const V_Vo static __forceinline StereoOut32 ApplyVolume(const StereoOut32& data, const V_VolumeSlideLR& volume) { return StereoOut32( - ApplyVolume(data.Left, volume.Left.Value), - ApplyVolume(data.Right, volume.Right.Value)); + ApplyVolume16(data.Left, volume.Left.Value), + ApplyVolume16(data.Right, volume.Right.Value)); } static void __forceinline UpdatePitch(uint coreidx, uint voiceidx) @@ -684,8 +684,8 @@ __forceinline } else { - Out.Left = MulShr32(Out.Left, Cores[1].MasterVol.Left.Value); - Out.Right = MulShr32(Out.Right, Cores[1].MasterVol.Right.Value); + Out.Left = ApplyVolume16(Out.Left, Cores[1].MasterVol.Left.Value); + Out.Right = ApplyVolume16(Out.Right, Cores[1].MasterVol.Right.Value); } // Final Clamp! diff --git a/pcsx2/SPU2/RegTable.cpp b/pcsx2/SPU2/RegTable.cpp index 5ac9321988..573149f250 100644 --- a/pcsx2/SPU2/RegTable.cpp +++ b/pcsx2/SPU2/RegTable.cpp @@ -28,18 +28,17 @@ PCORE(c, Voices[v].p) #define PVC(c, v) \ - PVCP(c, v, Volume.Left.Reg_VOL) \ - , \ + PVCP(c, v, Volume.Left.Reg_VOL), \ PVCP(c, v, Volume.Right.Reg_VOL), \ PVCP(c, v, Pitch), \ PVCP(c, v, ADSR.regADSR1), \ PVCP(c, v, ADSR.regADSR2), \ PVCP(c, v, ADSR.Value), \ - PVCP(c, v, Volume.Left.Value) + 1, \ - PVCP(c, v, Volume.Right.Value) + 1 + PVCP(c, v, Volume.Left.Value), \ + PVCP(c, v, Volume.Right.Value) #define PVCA(c, v) \ - PVCP(c, v, StartA) + 1, \ + PVCP(c, v, StartA) + 1, \ PVCP(c, v, StartA), \ PVCP(c, v, LoopStartA) + 1, \ PVCP(c, v, LoopStartA), \ diff --git a/pcsx2/SPU2/defs.h b/pcsx2/SPU2/defs.h index ff710d1799..ef516cde91 100644 --- a/pcsx2/SPU2/defs.h +++ b/pcsx2/SPU2/defs.h @@ -38,6 +38,10 @@ extern s16 spu2M_Read(u32 addr); extern void spu2M_Write(u32 addr, s16 value); extern void spu2M_Write(u32 addr, u16 value); +static inline s16 SignExtend16(u16 v) +{ + return (s16)v; +} struct V_VolumeLR { @@ -61,23 +65,34 @@ struct V_VolumeSlide // Holds the "original" value of the volume for this voice, prior to slides. // (ie, the volume as written to the register) - s16 Reg_VOL; + union + { + u16 Reg_VOL; + struct + { + u16 Step : 2; + u16 Shift : 5; + u16 : 5; + u16 Phase : 1; + u16 Decr : 1; + u16 Exp : 1; + u16 Enable : 1; + }; + }; + + u32 Counter; s32 Value; - s8 Increment; - s8 Mode; public: V_VolumeSlide() = default; V_VolumeSlide(s16 regval, s32 fullvol) : Reg_VOL(regval) , Value(fullvol) - , Increment(0) - , Mode(0) { } void Update(); - void RegSet(u16 src); // used to set the volume from a register source (16 bit signed) + void RegSet(u16 src); // used to set the volume from a register source #ifdef PCSX2_DEVBUILD void DebugDump(FILE* dump, const char* title, const char* nameLR); diff --git a/pcsx2/SPU2/spu2sys.cpp b/pcsx2/SPU2/spu2sys.cpp index 47ae2f8c68..0e1625f724 100644 --- a/pcsx2/SPU2/spu2sys.cpp +++ b/pcsx2/SPU2/spu2sys.cpp @@ -104,7 +104,7 @@ __forceinline void spu2M_Write(u32 addr, u16 value) } V_VolumeLR V_VolumeLR::Max(0x7FFFFFFF); -V_VolumeSlideLR V_VolumeSlideLR::Max(0x3FFF, 0x7FFFFFFF); +V_VolumeSlideLR V_VolumeSlideLR::Max(0x3FFF, 0x7FFF); V_Core::V_Core(int coreidx) : Index(coreidx) @@ -485,11 +485,6 @@ static s32 GetVol32(u16 src) return ((static_cast(src)) << 16) | ((src << 1) & 0xffff); } -void V_VolumeSlide::RegSet(u16 src) -{ - Value = GetVol32(src); -} - static u32 map_spu1to2(u32 addr) { return addr * 4 + (addr >= 0x200 ? 0xc0000 : 0); @@ -519,26 +514,7 @@ void V_Core::WriteRegPS1(u32 mem, u16 value) case 0x2: //VOLR (Volume R) { V_VolumeSlide& thisvol = vval == 0 ? Voices[voice].Volume.Left : Voices[voice].Volume.Right; - thisvol.Reg_VOL = value; - - if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp - { - thisvol.Mode = (value & 0xF000) >> 12; - thisvol.Increment = (value & 0x7F); - // We're not sure slides work 100% - if (SPU2::MsgToConsole()) - SPU2::ConLog("* SPU2: Voice uses Slides in Mode = %x, Increment = %x\n", thisvol.Mode, thisvol.Increment); - } - else - { - // Constant Volume mode (no slides or envelopes) - // Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as - // the "sign" bit, so a simple bitwise extension will do the trick: - - thisvol.RegSet(value << 1); - thisvol.Mode = 0; - thisvol.Increment = 0; - } + thisvol.RegSet(value); //ConLog("voice %x VOL%c write: %x\n", voice, vval == 0 ? 'L' : 'R', value); break; } @@ -581,12 +557,10 @@ void V_Core::WriteRegPS1(u32 mem, u16 value) switch (reg) { case 0x1d80: // Mainvolume left - MasterVol.Left.Mode = 0; MasterVol.Left.RegSet(value); break; case 0x1d82: // Mainvolume right - MasterVol.Right.Mode = 0; MasterVol.Right.RegSet(value); break; @@ -895,10 +869,10 @@ u16 V_Core::ReadRegPS1(u32 mem) switch (reg) { case 0x1d80: - value = MasterVol.Left.Value >> 16; + value = MasterVol.Left.Value; break; case 0x1d82: - value = MasterVol.Right.Value >> 16; + value = MasterVol.Right.Value; break; case 0x1d84: value = FxVol.Left >> 16; @@ -1007,26 +981,7 @@ static void RegWrite_VoiceParams(u16 value) case 1: //VOLR (Volume R) { V_VolumeSlide& thisvol = (param == 0) ? thisvoice.Volume.Left : thisvoice.Volume.Right; - thisvol.Reg_VOL = value; - - if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp - { - thisvol.Mode = (value & 0xF000) >> 12; - thisvol.Increment = (value & 0x7F); - // We're not sure slides work 100% - if (SPU2::MsgToConsole()) - SPU2::ConLog("* SPU2: Voice uses Slides in Mode = %x, Increment = %x\n", thisvol.Mode, thisvol.Increment); - } - else - { - // Constant Volume mode (no slides or envelopes) - // Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as - // the "sign" bit, so a simple bitwise extension will do the trick: - - thisvol.RegSet(value << 1); - thisvol.Mode = 0; - thisvol.Increment = 0; - } + thisvol.RegSet(value); } break; @@ -1429,24 +1384,7 @@ static void RegWrite_CoreExt(u16 value) case REG_P_MVOLR: { V_VolumeSlide& thisvol = (addr == REG_P_MVOLL) ? thiscore.MasterVol.Left : thiscore.MasterVol.Right; - - if (value & 0x8000) // +Lin/-Lin/+Exp/-Exp - { - thisvol.Mode = (value & 0xF000) >> 12; - thisvol.Increment = (value & 0x7F); - //printf("slides Mode = %x, Increment = %x\n",thisvol.Mode,thisvol.Increment); - } - else - { - // Constant Volume mode (no slides or envelopes) - // Volumes range from 0x3fff to 0x7fff, with 0x4000 serving as - // the "sign" bit, so a simple bitwise extension will do the trick: - - thisvol.Value = GetVol32(value << 1); - thisvol.Mode = 0; - thisvol.Increment = 0; - } - thisvol.Reg_VOL = value; + thisvol.RegSet(value); } break; @@ -1835,7 +1773,7 @@ void StartVoices(int core, u32 value) (Cores[core].VoiceGates[vc].WetL) ? "+" : "-", (Cores[core].VoiceGates[vc].WetR) ? "+" : "-", *(u16*)GetMemPtr(thisvc.StartA), thisvc.Pitch, - thisvc.Volume.Left.Value >> 16, thisvc.Volume.Right.Value >> 16, + thisvc.Volume.Left.Value, thisvc.Volume.Right.Value, thisvc.ADSR.regADSR1, thisvc.ADSR.regADSR2); } } diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 5f2997a13a..65e9744ee6 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -37,7 +37,7 @@ enum class FreezeAction // [SAVEVERSION+] // This informs the auto updater that the users savestates will be invalidated. -static const u32 g_SaveVersion = (0x9A44 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A45 << 16) | 0x0000; // the freezing data between submodules and core