aboutsummaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/command
diff options
context:
space:
mode:
authorMaufeat <sahyno1996@gmail.com>2025-12-13 19:44:41 +0100
committercrueter <crueter@eden-emu.dev>2025-12-13 19:44:41 +0100
commit06b83a58a6d60063cd5fad934aa7f3a75f0ce040 (patch)
tree21f7d62f6940bd6cfe79ce60504884fb357ff1b6 /src/audio_core/renderer/command
parent1e06c6f752c3b257783347a705dbcae293f618db (diff)
[audio] correct biquad filter v2 parameters (#3142)
We had the same struct for v1 and v2 - this was tested only with MP4, should output correct sounds now and boot it. Co-authored-by: MaranBr <maranbr@outlook.com> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3142 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: crueter <crueter@eden-emu.dev> Co-authored-by: Maufeat <sahyno1996@gmail.com> Co-committed-by: Maufeat <sahyno1996@gmail.com>
Diffstat (limited to 'src/audio_core/renderer/command')
-rw-r--r--src/audio_core/renderer/command/command_buffer.cpp56
-rw-r--r--src/audio_core/renderer/command/command_generator.cpp54
2 files changed, 92 insertions, 18 deletions
diff --git a/src/audio_core/renderer/command/command_buffer.cpp b/src/audio_core/renderer/command/command_buffer.cpp
index a0a574fc64..804aba438d 100644
--- a/src/audio_core/renderer/command/command_buffer.cpp
+++ b/src/audio_core/renderer/command/command_buffer.cpp
@@ -21,6 +21,15 @@
namespace AudioCore::Renderer {
+namespace {
+constexpr f32 BiquadParameterFixedScaleQ14 = 16384.0f; // 1 << 14
+
+[[nodiscard]] inline s16 ToQ14Clamped(f32 v) {
+ const f32 scaled = std::clamp(v * BiquadParameterFixedScaleQ14, -32768.0f, 32767.0f);
+ return static_cast<s16>(scaled);
+}
+} // namespace
+
template <typename T, CommandId Id>
T& CommandBuffer::GenerateStart(const s32 node_id) {
if (size + sizeof(T) >= command_list.size_bytes()) {
@@ -259,18 +268,42 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, EffectInfoBas
const bool use_float_processing) {
auto& cmd{GenerateStart<BiquadFilterCommand, CommandId::BiquadFilter>(node_id)};
- const auto& parameter{
- *reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
const auto state{reinterpret_cast<VoiceState::BiquadFilterState*>(
effect_info.GetStateBuffer() + channel * sizeof(VoiceState::BiquadFilterState))};
- cmd.input = buffer_offset + parameter.inputs[channel];
- cmd.output = buffer_offset + parameter.outputs[channel];
+ if (behavior->IsEffectInfoVersion2Supported()) {
+ const auto& p{
+ *reinterpret_cast<BiquadFilterInfo::ParameterVersion2*>(effect_info.GetParameter())};
- cmd.biquad.b = parameter.b;
- cmd.biquad.a = parameter.a;
+ if (!IsChannelCountValid(p.channel_count) || channel < 0 || channel >= p.channel_count) {
+ return;
+ }
+
+ cmd.input = buffer_offset + p.inputs[channel];
+ cmd.output = buffer_offset + p.outputs[channel];
+
+ // Convert float coefficients to Q2.14 fixed-point as expected by the legacy DSP path.
+ cmd.biquad.b[0] = ToQ14Clamped(p.b[0]);
+ cmd.biquad.b[1] = ToQ14Clamped(p.b[1]);
+ cmd.biquad.b[2] = ToQ14Clamped(p.b[2]);
+ cmd.biquad.a[0] = ToQ14Clamped(p.a[0]);
+ cmd.biquad.a[1] = ToQ14Clamped(p.a[1]);
+ } else {
+ const auto& p{
+ *reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
- // Effects use legacy fixed-point format
+ if (!IsChannelCountValid(p.channel_count) || channel < 0 || channel >= p.channel_count) {
+ return;
+ }
+
+ cmd.input = buffer_offset + p.inputs[channel];
+ cmd.output = buffer_offset + p.outputs[channel];
+
+ cmd.biquad.b = p.b;
+ cmd.biquad.a = p.a;
+ }
+
+ // Effects always use the fixed-point coefficient path on the DSP.
cmd.use_float_coefficients = false;
cmd.state = memory_pool->Translate(CpuAddr(state),
@@ -595,6 +628,15 @@ void CommandBuffer::GenerateCopyMixBufferCommand(const s32 node_id, EffectInfoBa
const s16 buffer_offset, const s8 channel) {
auto& cmd{GenerateStart<CopyMixBufferCommand, CommandId::CopyMixBuffer>(node_id)};
+ if (behavior->IsEffectInfoVersion2Supported()) {
+ const auto& parameter_v2{
+ *reinterpret_cast<BiquadFilterInfo::ParameterVersion2*>(effect_info.GetParameter())};
+ cmd.input_index = buffer_offset + parameter_v2.inputs[channel];
+ cmd.output_index = buffer_offset + parameter_v2.outputs[channel];
+ GenerateEnd<CopyMixBufferCommand>(cmd);
+ return;
+ }
+
const auto& parameter{
*reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
cmd.input_index = buffer_offset + parameter.inputs[channel];
diff --git a/src/audio_core/renderer/command/command_generator.cpp b/src/audio_core/renderer/command/command_generator.cpp
index f97db5899e..bec6abbaf9 100644
--- a/src/audio_core/renderer/command/command_generator.cpp
+++ b/src/audio_core/renderer/command/command_generator.cpp
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -361,12 +364,37 @@ void CommandGenerator::GenerateAuxCommand(const s16 buffer_offset, EffectInfoBas
void CommandGenerator::GenerateBiquadFilterEffectCommand(const s16 buffer_offset,
EffectInfoBase& effect_info,
const s32 node_id) {
- const auto& parameter{
- *reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
+ EffectInfoBase::ParameterState param_state{};
+ s8 channel_count = 0;
+
+ if (render_context.behavior->IsEffectInfoVersion2Supported()) {
+ const auto* parameter =
+ reinterpret_cast<const BiquadFilterInfo::ParameterVersion2*>(effect_info.GetParameter());
+ if (!parameter) {
+ LOG_ERROR(Service_Audio, "Biquad filter parameter is null");
+ return;
+ }
+ param_state = parameter->state;
+ channel_count = parameter->channel_count;
+ } else {
+ const auto* parameter =
+ reinterpret_cast<const BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter());
+ if (!parameter) {
+ LOG_ERROR(Service_Audio, "Biquad filter parameter is null");
+ return;
+ }
+ param_state = parameter->state;
+ channel_count = parameter->channel_count;
+ }
+
+ if (channel_count <= 0) {
+ return;
+ }
+
if (effect_info.IsEnabled()) {
bool needs_init{false};
- switch (parameter.state) {
+ switch (param_state) {
case EffectInfoBase::ParameterState::Initialized:
needs_init = true;
break;
@@ -375,22 +403,26 @@ void CommandGenerator::GenerateBiquadFilterEffectCommand(const s16 buffer_offset
if (render_context.behavior->IsBiquadFilterEffectStateClearBugFixed()) {
needs_init = false;
} else {
- needs_init = parameter.state == EffectInfoBase::ParameterState::Updating;
+ needs_init = param_state == EffectInfoBase::ParameterState::Updating;
}
break;
default:
- LOG_ERROR(Service_Audio, "Invalid biquad parameter state {}",
- static_cast<u32>(parameter.state));
+ LOG_ERROR(Service_Audio,
+ "Invalid biquad parameter state {}, treating as uninitialized",
+ static_cast<u32>(param_state));
+ needs_init = true;
break;
}
- for (s8 channel = 0; channel < parameter.channel_count; channel++) {
- command_buffer.GenerateBiquadFilterCommand(
- node_id, effect_info, buffer_offset, channel, needs_init,
- render_context.behavior->UseBiquadFilterFloatProcessing());
+ const bool use_float_processing =
+ render_context.behavior->UseBiquadFilterFloatProcessing();
+
+ for (s8 channel = 0; channel < channel_count; channel++) {
+ command_buffer.GenerateBiquadFilterCommand(node_id, effect_info, buffer_offset, channel,
+ needs_init, use_float_processing);
}
} else {
- for (s8 channel = 0; channel < parameter.channel_count; channel++) {
+ for (s8 channel = 0; channel < channel_count; channel++) {
command_buffer.GenerateCopyMixBufferCommand(node_id, effect_info, buffer_offset,
channel);
}