mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-01-18 06:25:37 +00:00
SPU: Fix off-by-one-sampling-error causing noise in output
This commit is contained in:
parent
6f7b9c8e28
commit
40eb157d77
|
@ -677,19 +677,20 @@ void SPU::Voice::DecodeBlock(const ADPCMBlock& block)
|
||||||
for (u32 i = 0; i < NUM_SAMPLES_PER_ADPCM_BLOCK; i++)
|
for (u32 i = 0; i < NUM_SAMPLES_PER_ADPCM_BLOCK; i++)
|
||||||
{
|
{
|
||||||
// extend 4-bit to 16-bit, apply shift from header and mix in previous samples
|
// extend 4-bit to 16-bit, apply shift from header and mix in previous samples
|
||||||
const s16 sample = static_cast<s16>(ZeroExtend16(block.GetNibble(i)) << 12) >> shift;
|
s32 sample = s32(static_cast<s16>(ZeroExtend16(block.GetNibble(i)) << 12) >> shift);
|
||||||
const s32 interp_sample = s32(sample) + ((last_samples[0] * filter_pos) + (last_samples[1] * filter_neg) + 32) / 64;
|
sample += (last_samples[0] * filter_pos) >> 6;
|
||||||
|
sample += (last_samples[1] * filter_neg) >> 6;
|
||||||
|
|
||||||
current_block_samples[i] = Clamp16(interp_sample);
|
current_block_samples[i] = Clamp16(sample);
|
||||||
last_samples[1] = last_samples[0];
|
last_samples[1] = last_samples[0];
|
||||||
last_samples[0] = interp_sample;
|
last_samples[0] = sample;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::copy(last_samples, last_samples + countof(last_samples), adpcm_last_samples.begin());
|
std::copy(last_samples, last_samples + countof(last_samples), adpcm_last_samples.begin());
|
||||||
current_block_flags.bits = block.flags.bits;
|
current_block_flags.bits = block.flags.bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
SPU::SampleFormat SPU::Voice::SampleBlock(s32 index) const
|
s16 SPU::Voice::SampleBlock(s32 index) const
|
||||||
{
|
{
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
{
|
{
|
||||||
|
@ -832,6 +833,10 @@ std::tuple<s32, s32> SPU::SampleVoice(u32 voice_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolate/sample and apply ADSR volume
|
||||||
|
const s32 sample = ApplyVolume(voice.Interpolate(), voice.regs.adsr_volume);
|
||||||
|
voice.TickADSR();
|
||||||
|
|
||||||
// TODO: Pulse modulation
|
// TODO: Pulse modulation
|
||||||
u16 step = voice.regs.adpcm_sample_rate;
|
u16 step = voice.regs.adpcm_sample_rate;
|
||||||
step = std::min<u16>(step, 0x4000);
|
step = std::min<u16>(step, 0x4000);
|
||||||
|
@ -864,10 +869,6 @@ std::tuple<s32, s32> SPU::SampleVoice(u32 voice_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// interpolate/sample and apply ADSR volume
|
|
||||||
const s32 sample = ApplyVolume(voice.Interpolate(), voice.regs.adsr_volume);
|
|
||||||
voice.TickADSR();
|
|
||||||
|
|
||||||
// apply per-channel volume
|
// apply per-channel volume
|
||||||
const s32 left = ApplyVolume(sample, voice.regs.volume_left.GetVolume());
|
const s32 left = ApplyVolume(sample, voice.regs.volume_left.GetVolume());
|
||||||
const s32 right = ApplyVolume(sample, voice.regs.volume_right.GetVolume());
|
const s32 right = ApplyVolume(sample, voice.regs.volume_right.GetVolume());
|
||||||
|
|
|
@ -14,8 +14,6 @@ class InterruptController;
|
||||||
class SPU
|
class SPU
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using SampleFormat = s16;
|
|
||||||
|
|
||||||
SPU();
|
SPU();
|
||||||
~SPU();
|
~SPU();
|
||||||
|
|
||||||
|
@ -221,8 +219,8 @@ private:
|
||||||
VoiceRegisters regs;
|
VoiceRegisters regs;
|
||||||
VoiceCounter counter;
|
VoiceCounter counter;
|
||||||
ADPCMFlags current_block_flags;
|
ADPCMFlags current_block_flags;
|
||||||
std::array<SampleFormat, NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples;
|
std::array<s16, NUM_SAMPLES_PER_ADPCM_BLOCK> current_block_samples;
|
||||||
std::array<SampleFormat, 3> previous_block_last_samples;
|
std::array<s16, 3> previous_block_last_samples;
|
||||||
std::array<s32, 2> adpcm_last_samples;
|
std::array<s32, 2> adpcm_last_samples;
|
||||||
|
|
||||||
ADSRPhase adsr_phase;
|
ADSRPhase adsr_phase;
|
||||||
|
@ -238,7 +236,7 @@ private:
|
||||||
void KeyOff();
|
void KeyOff();
|
||||||
|
|
||||||
void DecodeBlock(const ADPCMBlock& block);
|
void DecodeBlock(const ADPCMBlock& block);
|
||||||
SampleFormat SampleBlock(s32 index) const;
|
s16 SampleBlock(s32 index) const;
|
||||||
s16 Interpolate() const;
|
s16 Interpolate() const;
|
||||||
|
|
||||||
// Switches to the specified phase, filling in target.
|
// Switches to the specified phase, filling in target.
|
||||||
|
|
Loading…
Reference in a new issue