diff options
| author | 2023-02-11 10:28:42 -0500 | |
|---|---|---|
| committer | 2023-02-11 10:28:42 -0500 | |
| commit | 89c09d639ae92d0df40c68a962fe0683f1a1cd21 (patch) | |
| tree | 8bcaac4af953518fd3a72c6c07b3048ec884ba13 | |
| parent | Merge pull request #9744 from behunin/quick-release (diff) | |
| parent | biquad_filter: Clamp f64 in ApplyBiquadFilterFloat (diff) | |
| download | yuzu-89c09d639ae92d0df40c68a962fe0683f1a1cd21.tar.gz yuzu-89c09d639ae92d0df40c68a962fe0683f1a1cd21.tar.xz yuzu-89c09d639ae92d0df40c68a962fe0683f1a1cd21.zip | |
Merge pull request #9768 from merryhime/biquad-rounding
biquad_filter: Fix rounding in ApplyBiquadFilterInt
| -rw-r--r-- | src/audio_core/renderer/command/effect/biquad_filter.cpp | 38 | ||||
| -rw-r--r-- | src/audio_core/renderer/voice/voice_state.h | 8 |
2 files changed, 19 insertions, 27 deletions
diff --git a/src/audio_core/renderer/command/effect/biquad_filter.cpp b/src/audio_core/renderer/command/effect/biquad_filter.cpp index edb30ce72..dea6423dc 100644 --- a/src/audio_core/renderer/command/effect/biquad_filter.cpp +++ b/src/audio_core/renderer/command/effect/biquad_filter.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | #include "audio_core/renderer/adsp/command_list_processor.h" | 4 | #include "audio_core/renderer/adsp/command_list_processor.h" |
| 5 | #include "audio_core/renderer/command/effect/biquad_filter.h" | 5 | #include "audio_core/renderer/command/effect/biquad_filter.h" |
| 6 | #include "audio_core/renderer/voice/voice_state.h" | 6 | #include "audio_core/renderer/voice/voice_state.h" |
| 7 | #include "common/bit_cast.h" | ||
| 7 | 8 | ||
| 8 | namespace AudioCore::AudioRenderer { | 9 | namespace AudioCore::AudioRenderer { |
| 9 | /** | 10 | /** |
| @@ -19,21 +20,21 @@ namespace AudioCore::AudioRenderer { | |||
| 19 | void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input, | 20 | void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input, |
| 20 | std::array<s16, 3>& b_, std::array<s16, 2>& a_, | 21 | std::array<s16, 3>& b_, std::array<s16, 2>& a_, |
| 21 | VoiceState::BiquadFilterState& state, const u32 sample_count) { | 22 | VoiceState::BiquadFilterState& state, const u32 sample_count) { |
| 22 | constexpr s64 min{std::numeric_limits<s32>::min()}; | 23 | constexpr f64 min{std::numeric_limits<s32>::min()}; |
| 23 | constexpr s64 max{std::numeric_limits<s32>::max()}; | 24 | constexpr f64 max{std::numeric_limits<s32>::max()}; |
| 24 | std::array<f64, 3> b{Common::FixedPoint<50, 14>::from_base(b_[0]).to_double(), | 25 | std::array<f64, 3> b{Common::FixedPoint<50, 14>::from_base(b_[0]).to_double(), |
| 25 | Common::FixedPoint<50, 14>::from_base(b_[1]).to_double(), | 26 | Common::FixedPoint<50, 14>::from_base(b_[1]).to_double(), |
| 26 | Common::FixedPoint<50, 14>::from_base(b_[2]).to_double()}; | 27 | Common::FixedPoint<50, 14>::from_base(b_[2]).to_double()}; |
| 27 | std::array<f64, 2> a{Common::FixedPoint<50, 14>::from_base(a_[0]).to_double(), | 28 | std::array<f64, 2> a{Common::FixedPoint<50, 14>::from_base(a_[0]).to_double(), |
| 28 | Common::FixedPoint<50, 14>::from_base(a_[1]).to_double()}; | 29 | Common::FixedPoint<50, 14>::from_base(a_[1]).to_double()}; |
| 29 | std::array<f64, 4> s{state.s0.to_double(), state.s1.to_double(), state.s2.to_double(), | 30 | std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1), |
| 30 | state.s3.to_double()}; | 31 | Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)}; |
| 31 | 32 | ||
| 32 | for (u32 i = 0; i < sample_count; i++) { | 33 | for (u32 i = 0; i < sample_count; i++) { |
| 33 | f64 in_sample{static_cast<f64>(input[i])}; | 34 | f64 in_sample{static_cast<f64>(input[i])}; |
| 34 | auto sample{in_sample * b[0] + s[0] * b[1] + s[1] * b[2] + s[2] * a[0] + s[3] * a[1]}; | 35 | auto sample{in_sample * b[0] + s[0] * b[1] + s[1] * b[2] + s[2] * a[0] + s[3] * a[1]}; |
| 35 | 36 | ||
| 36 | output[i] = static_cast<s32>(std::clamp(static_cast<s64>(sample), min, max)); | 37 | output[i] = static_cast<s32>(std::clamp(sample, min, max)); |
| 37 | 38 | ||
| 38 | s[1] = s[0]; | 39 | s[1] = s[0]; |
| 39 | s[0] = in_sample; | 40 | s[0] = in_sample; |
| @@ -41,10 +42,10 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input, | |||
| 41 | s[2] = sample; | 42 | s[2] = sample; |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | state.s0 = s[0]; | 45 | state.s0 = Common::BitCast<s64>(s[0]); |
| 45 | state.s1 = s[1]; | 46 | state.s1 = Common::BitCast<s64>(s[1]); |
| 46 | state.s2 = s[2]; | 47 | state.s2 = Common::BitCast<s64>(s[2]); |
| 47 | state.s3 = s[3]; | 48 | state.s3 = Common::BitCast<s64>(s[3]); |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 50 | /** | 51 | /** |
| @@ -58,29 +59,20 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input, | |||
| 58 | * @param sample_count - Number of samples to process. | 59 | * @param sample_count - Number of samples to process. |
| 59 | */ | 60 | */ |
| 60 | static void ApplyBiquadFilterInt(std::span<s32> output, std::span<const s32> input, | 61 | static void ApplyBiquadFilterInt(std::span<s32> output, std::span<const s32> input, |
| 61 | std::array<s16, 3>& b_, std::array<s16, 2>& a_, | 62 | std::array<s16, 3>& b, std::array<s16, 2>& a, |
| 62 | VoiceState::BiquadFilterState& state, const u32 sample_count) { | 63 | VoiceState::BiquadFilterState& state, const u32 sample_count) { |
| 63 | constexpr s64 min{std::numeric_limits<s32>::min()}; | 64 | constexpr s64 min{std::numeric_limits<s32>::min()}; |
| 64 | constexpr s64 max{std::numeric_limits<s32>::max()}; | 65 | constexpr s64 max{std::numeric_limits<s32>::max()}; |
| 65 | std::array<Common::FixedPoint<50, 14>, 3> b{ | ||
| 66 | Common::FixedPoint<50, 14>::from_base(b_[0]), | ||
| 67 | Common::FixedPoint<50, 14>::from_base(b_[1]), | ||
| 68 | Common::FixedPoint<50, 14>::from_base(b_[2]), | ||
| 69 | }; | ||
| 70 | std::array<Common::FixedPoint<50, 14>, 3> a{ | ||
| 71 | Common::FixedPoint<50, 14>::from_base(a_[0]), | ||
| 72 | Common::FixedPoint<50, 14>::from_base(a_[1]), | ||
| 73 | }; | ||
| 74 | 66 | ||
| 75 | for (u32 i = 0; i < sample_count; i++) { | 67 | for (u32 i = 0; i < sample_count; i++) { |
| 76 | s64 in_sample{input[i]}; | 68 | const s64 in_sample{input[i]}; |
| 77 | auto sample{in_sample * b[0] + state.s0}; | 69 | const s64 sample{in_sample * b[0] + state.s0}; |
| 78 | const auto out_sample{std::clamp(sample.to_long(), min, max)}; | 70 | const s64 out_sample{std::clamp<s64>((sample + (1 << 13)) >> 14, min, max)}; |
| 79 | 71 | ||
| 80 | output[i] = static_cast<s32>(out_sample); | 72 | output[i] = static_cast<s32>(out_sample); |
| 81 | 73 | ||
| 82 | state.s0 = state.s1 + b[1] * in_sample + a[0] * out_sample; | 74 | state.s0 = state.s1 + b[1] * in_sample + a[0] * out_sample; |
| 83 | state.s1 = 0 + b[2] * in_sample + a[1] * out_sample; | 75 | state.s1 = b[2] * in_sample + a[1] * out_sample; |
| 84 | } | 76 | } |
| 85 | } | 77 | } |
| 86 | 78 | ||
diff --git a/src/audio_core/renderer/voice/voice_state.h b/src/audio_core/renderer/voice/voice_state.h index d5497e2fb..ce947233f 100644 --- a/src/audio_core/renderer/voice/voice_state.h +++ b/src/audio_core/renderer/voice/voice_state.h | |||
| @@ -19,10 +19,10 @@ struct VoiceState { | |||
| 19 | * State of the voice's biquad filter. | 19 | * State of the voice's biquad filter. |
| 20 | */ | 20 | */ |
| 21 | struct BiquadFilterState { | 21 | struct BiquadFilterState { |
| 22 | Common::FixedPoint<50, 14> s0; | 22 | s64 s0; |
| 23 | Common::FixedPoint<50, 14> s1; | 23 | s64 s1; |
| 24 | Common::FixedPoint<50, 14> s2; | 24 | s64 s2; |
| 25 | Common::FixedPoint<50, 14> s3; | 25 | s64 s3; |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | /** | 28 | /** |