SPU: DC filter output

Some games leave paused voices hanging with volume turned on which
results in dc offset. Filter it out.
This commit is contained in:
Ziemas 2023-09-23 16:47:40 +02:00 committed by refractionpcsx2
parent 98eb006cdd
commit d91e3f568b
3 changed files with 19 additions and 1 deletions

View File

@ -603,6 +603,19 @@ StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, c
return TD + ApplyVolume(RV, 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;
}
// used to throttle the output rate of cache stat reports
static int p_cachestat_counter = 0;
@ -679,7 +692,7 @@ __forceinline
// output by design.
// Good thing though that this code gets the volume exactly right, as per tests :)
Out = clamp_mix(Out);
Out = DCFilter(Out);
SndBuffer::Write(StereoOut16(Out));
// Update AutoDMA output positioning

View File

@ -513,6 +513,8 @@ extern u16 OutPos;
extern u16 InputPos;
// SPU Mixing Cycles ("Ticks mixed" counter)
extern u32 Cycles;
// DC Filter state
extern StereoOut16 DCFilterIn, DCFilterOut;
extern s16 spu2regs[0x010000 / sizeof(s16)];
extern s16 _spu2mem[0x200000 / sizeof(s16)];

View File

@ -37,6 +37,7 @@ V_CoreDebug DebugCores[2];
V_Core Cores[2];
V_SPDIF Spdif;
StereoOut16 DCFilterIn, DCFilterOut;
u16 OutPos;
u16 InputPos;
u32 Cycles;
@ -149,6 +150,8 @@ void V_Core::Init(int index)
DMAPtr = nullptr;
KeyOn = 0;
OutPos = 0;
DCFilterIn = {};
DCFilterOut = {};
psxmode = false;
psxSoundDataTransferControl = 0;