SPU: Do DC filtering with float samples

This commit is contained in:
Ziemas
2026-03-10 10:39:02 +01:00
committed by lightningterror
parent ea304becf6
commit 58a4f1e5e9
4 changed files with 33 additions and 29 deletions
-21
View File
@@ -519,20 +519,6 @@ static __forceinline StereoOut32 MixCore(const uint coreidx, const VoiceMixSet&
return TD + ApplyVolume(RV, thiscore.FxVol);
}
static StereoOut32 DCFilter(StereoOut32 input)
{
// A simple DC blocking high-pass filter
// Implementation from http://peabody.sapp.org/class/dmp2/lab/dcblock/
// The magic number 0x7f5c is ceil(INT16_MAX * 0.995)
StereoOut32 output;
output.Left = (input.Left - DCFilterIn.Left + clamp_mix((0x7f5c * DCFilterOut.Left) >> 15));
output.Right = (input.Right - DCFilterIn.Right + clamp_mix((0x7f5c * DCFilterOut.Right) >> 15));
DCFilterIn = input;
DCFilterOut = output;
return output;
}
void spu2Mix()
{
// Note: Playmode 4 is SPDIF, which overrides other inputs.
@@ -591,13 +577,6 @@ void spu2Mix()
Out = ApplyVolume(clamp_mix(Out), Cores[1].MasterVol);
}
// For a long time PCSX2 has had its output volume halved by
// an incorrect function for applying the master volume above.
//
// Adjust volume here so it matches what people have come to expect.
Out = ApplyVolume(Out, {0x4fff, 0x4fff});
Out = DCFilter(Out);
#ifdef PCSX2_DEVBUILD
// Log final output to wavefile.
WaveDump::WriteCore(1, CoreSrc_External, Out);
-2
View File
@@ -569,8 +569,6 @@ extern u16 OutPos;
extern u16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
// DC Filter state
extern StereoOut32 DCFilterIn, DCFilterOut;
extern s16 spu2regs[0x010000 / sizeof(s16)];
extern s16 _spu2mem[0x200000 / sizeof(s16)];
+33 -3
View File
@@ -36,6 +36,8 @@ static u32 s_current_chunk_pos;
static u32 s_standard_volume = 0;
static u32 s_fast_forward_volume = 0;
float DCFilterIn[2], DCFilterOut[2];
u32 SPU2::GetConsoleSampleRate()
{
return s_psxmode ? PSX_SAMPLE_RATE : SAMPLE_RATE;
@@ -232,6 +234,9 @@ void SPU2::InternalReset(bool psxmode)
memset(_spu2mem + 0x2800, 7, 0x10); // from BIOS reversal. Locks the voices so they don't run free.
memset(_spu2mem + 0xe870, 7, 0x10); // Loop which gets left over by the BIOS, Megaman X7 relies on it being there.
memset(DCFilterIn, 0, sizeof(DCFilterIn));
memset(DCFilterOut, 0, sizeof(DCFilterOut));
Spdif.Info = 0; // Reset IRQ Status if it got set in a previously run game
Cores[0].Init(0);
@@ -484,11 +489,36 @@ s32 SPU2freeze(FreezeAction mode, freezeData* data)
return 0;
}
static void DCFilter(float *input)
{
// A simple DC blocking high-pass filter
// Implementation from http://peabody.sapp.org/class/dmp2/lab/dcblock/
float output[2];
output[0] = (input[0] - DCFilterIn[0] + ((0.995f * DCFilterOut[0])));
output[1] = (input[1] - DCFilterIn[1] + ((0.995f * DCFilterOut[1])));
DCFilterIn[0] = input[0];
DCFilterIn[1] = input[1];
DCFilterOut[0] = output[0];
DCFilterOut[1] = output[1];
input[0] = output[0];
input[1] = output[1];
}
__forceinline void spu2Output(StereoOut32 out)
{
// Final clamp, take care not to exceed 16 bits from here on
s_current_chunk[s_current_chunk_pos++] = static_cast<float>(clamp_mix(out.Left)) / INT16_MAX;
s_current_chunk[s_current_chunk_pos++] = static_cast<float>(clamp_mix(out.Right)) / INT16_MAX;
float conv[2];
conv[0] = static_cast<float>(clamp_mix(out.Left)) / INT16_MAX;
conv[1] = static_cast<float>(clamp_mix(out.Right)) / INT16_MAX;
/* Some games pause voices with the volume left on leaving us with
* significant DC offset, so we filter it out (e.x. SSX 3)*/
DCFilter(conv);
s_current_chunk[s_current_chunk_pos++] = conv[0];
s_current_chunk[s_current_chunk_pos++] = conv[1];
if (s_current_chunk_pos == s_current_chunk.size())
{
s_current_chunk_pos = 0;
-3
View File
@@ -26,7 +26,6 @@ V_CoreDebug DebugCores[2];
V_Core Cores[2];
V_SPDIF Spdif;
StereoOut32 DCFilterIn, DCFilterOut;
u16 OutPos;
u16 InputPos;
u32 Cycles;
@@ -127,8 +126,6 @@ void V_Core::Init(int index)
DMAPtr = nullptr;
KeyOn = 0;
OutPos = 0;
DCFilterIn = {};
DCFilterOut = {};
psxmode = false;
psxSoundDataTransferControl = 0;