From 40eb157d774986dd4f316b563e1e2219b54483d9 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Tue, 29 Oct 2019 13:33:19 +1000 Subject: [PATCH] SPU: Fix off-by-one-sampling-error causing noise in output --- src/core/spu.cpp | 19 ++++++++++--------- src/core/spu.h | 8 +++----- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core/spu.cpp b/src/core/spu.cpp index db73350c6..1cc6bfe61 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -677,19 +677,20 @@ void SPU::Voice::DecodeBlock(const ADPCMBlock& block) 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 - const s16 sample = static_cast(ZeroExtend16(block.GetNibble(i)) << 12) >> shift; - const s32 interp_sample = s32(sample) + ((last_samples[0] * filter_pos) + (last_samples[1] * filter_neg) + 32) / 64; + s32 sample = s32(static_cast(ZeroExtend16(block.GetNibble(i)) << 12) >> shift); + 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[0] = interp_sample; + last_samples[0] = sample; } std::copy(last_samples, last_samples + countof(last_samples), adpcm_last_samples.begin()); 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) { @@ -832,6 +833,10 @@ std::tuple 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 u16 step = voice.regs.adpcm_sample_rate; step = std::min(step, 0x4000); @@ -864,10 +869,6 @@ std::tuple 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 const s32 left = ApplyVolume(sample, voice.regs.volume_left.GetVolume()); const s32 right = ApplyVolume(sample, voice.regs.volume_right.GetVolume()); diff --git a/src/core/spu.h b/src/core/spu.h index aa8f0b085..94af22d04 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -14,8 +14,6 @@ class InterruptController; class SPU { public: - using SampleFormat = s16; - SPU(); ~SPU(); @@ -221,8 +219,8 @@ private: VoiceRegisters regs; VoiceCounter counter; ADPCMFlags current_block_flags; - std::array current_block_samples; - std::array previous_block_last_samples; + std::array current_block_samples; + std::array previous_block_last_samples; std::array adpcm_last_samples; ADSRPhase adsr_phase; @@ -238,7 +236,7 @@ private: void KeyOff(); void DecodeBlock(const ADPCMBlock& block); - SampleFormat SampleBlock(s32 index) const; + s16 SampleBlock(s32 index) const; s16 Interpolate() const; // Switches to the specified phase, filling in target.