SPU2: Rewrite volume slides [SAVEVERSION+]

This commit is contained in:
Ziemas 2023-10-10 01:21:01 +02:00 committed by refractionpcsx2
parent 7bf8f6115f
commit 07d4a65a45
7 changed files with 71 additions and 118 deletions

View File

@ -19,34 +19,8 @@
#include "common/Assertions.h"
#include <array>
static constexpr s32 ADSR_MAX_VOL = 0x7fff;
static const int InvExpOffsets[] = {0, 4, 6, 8, 9, 10, 11, 12};
using PSXRateTable = std::array<u32, 160>;
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<u32>(1, counter_inc);
Counter += counter_inc;
if (Counter >= 0x8000)
{
Counter = 0;
Value = std::clamp<s32>(Value + level_inc, 0, INT16_MAX);
}
}

View File

@ -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)

View File

@ -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!

View File

@ -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), \

View File

@ -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);

View File

@ -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<s32>(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);
}
}

View File

@ -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