From f3cd100b16f0593492c8714a5e94cdb605621fae Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sun, 20 Oct 2019 16:27:30 +1000 Subject: [PATCH] SPU: Float-less volume application --- src/core/spu.cpp | 43 ++++++++----------------------------------- src/core/spu.h | 16 ++++++++++++---- 2 files changed, 20 insertions(+), 39 deletions(-) diff --git a/src/core/spu.cpp b/src/core/spu.cpp index 2309cd683..2b3193cd9 100644 --- a/src/core/spu.cpp +++ b/src/core/spu.cpp @@ -9,23 +9,6 @@ #include Log_SetChannel(SPU); -static s16 Clamp16(s32 value) -{ - return static_cast(std::clamp(value, -32768, 32767)); -} - -static constexpr float S16ToFloat(s16 value) -{ - return (value >= 0) ? (static_cast(value) / static_cast(std::numeric_limits::max())) : - (static_cast(value) / -static_cast(std::numeric_limits::min())); -} - -static constexpr s16 FloatToS16(float value) -{ - return (value >= 0.0f) ? (static_cast(value * static_cast(std::numeric_limits::max()))) : - (static_cast(value * -static_cast(std::numeric_limits::min()))); -} - SPU::SPU() = default; SPU::~SPU() = default; @@ -754,11 +737,11 @@ void SPU::ReadADPCMBlock(u16 address, ADPCMBlock* block) } } -std::tuple SPU::SampleVoice(u32 voice_index) +std::tuple SPU::SampleVoice(u32 voice_index) { Voice& voice = m_voices[voice_index]; if (!voice.IsOn()) - return std::make_tuple(0, 0); + return {}; if (!voice.has_samples) { @@ -806,24 +789,14 @@ std::tuple SPU::SampleVoice(u32 voice_inde } } - // TODO: Volume - const float adsr_volume = S16ToFloat(voice.regs.adsr_volume); + // interpolate/sample and apply ADSR volume + const s32 sample = ApplyVolumeUnsaturated(voice.Interpolate(), voice.regs.adsr_volume); voice.TickADSR(); - const s32 sample = voice.Interpolate(); - // s32 sample = voice.SampleBlock(voice.counter.sample_index); - const s16 sample16 = Clamp16(sample); - const float samplef = S16ToFloat(sample16) * adsr_volume; - - // apply volume - const float volume_left = S16ToFloat(voice.regs.volume_left.GetVolume()); - const float volume_right = S16ToFloat(voice.regs.volume_right.GetVolume()); - const float final_left = volume_left * samplef; - const float final_right = volume_right * samplef; - - return std::make_tuple(FloatToS16(final_left), FloatToS16(final_right)); - // return std::make_tuple(FloatToS16(samplef), FloatToS16(samplef)); - // return std::make_tuple(sample16, sample16); + // apply per-channel volume + const s16 left = ApplyVolumeUnsaturated(sample, voice.regs.volume_left.GetVolume()); + const s16 right = ApplyVolumeUnsaturated(sample, voice.regs.volume_right.GetVolume()); + return std::make_tuple(left, right); } void SPU::EnsureCDAudioSpace(u32 num_samples) diff --git a/src/core/spu.h b/src/core/spu.h index 9a370cfcf..fa8b8d6fb 100644 --- a/src/core/spu.h +++ b/src/core/spu.h @@ -233,8 +233,8 @@ private: TickCount adsr_ticks; TickCount adsr_ticks_remaining; s16 adsr_step; - bool has_samples; - + bool has_samples; + bool IsOn() const { return adsr_phase != ADSRPhase::Off; } void KeyOn(); @@ -243,7 +243,7 @@ private: void DecodeBlock(const ADPCMBlock& block); SampleFormat SampleBlock(s32 index) const; s16 Interpolate() const; - + // Switches to the specified phase, filling in target. void SetADSRPhase(ADSRPhase phase); @@ -251,6 +251,14 @@ private: void TickADSR(); }; + static constexpr s16 Clamp16(s32 value) + { + return (value < -0x8000) ? -0x8000 : (value > 0x7FFF) ? 0x7FFF : static_cast(value); + } + + static constexpr s16 ApplyVolume(s16 sample, s16 volume) { return Clamp16((s32(sample) * s32(volume)) >> 15); } + static constexpr s32 ApplyVolumeUnsaturated(s32 sample, s16 volume) { return (sample * s32(volume)) >> 15; } + static ADSRPhase GetNextADSRPhase(ADSRPhase phase); u16 ReadVoiceRegister(u32 offset); @@ -261,7 +269,7 @@ private: void RAMTransferWrite(u16 value); void ReadADPCMBlock(u16 address, ADPCMBlock* block); - std::tuple SampleVoice(u32 voice_index); + std::tuple SampleVoice(u32 voice_index); void GenerateSample(); System* m_system = nullptr;