audio_core: Fix reverb effect causing extreme noise on Windows

Fixed multiple bugs in reverb processing:
- Early gains for stereo channels not being assigned (missing *=)
- Incorrect TapOut pointer arithmetic (extra +1 offset)
- Uninitialized input pointer causing crashes
- Missing state initialization check
- SetDelay not called during parameter updates

Co-authored-by: MaranBr <maranbr@outlook.com>
Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
Zephyron
2025-12-17 16:41:59 +10:00
parent b1192de0c4
commit 5fbfc6693b
2 changed files with 18 additions and 15 deletions

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <numbers> #include <numbers>
@@ -101,8 +102,8 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par
} }
if (params.channel_count == 2) { if (params.channel_count == 2) {
state.early_gains[4] * 0.5f; state.early_gains[4] *= 0.5f;
state.early_gains[5] * 0.5f; state.early_gains[5] *= 0.5f;
} }
auto pre_time{ auto pre_time{
@@ -116,16 +117,12 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par
for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) { for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) {
const auto fdn_delay{(FdnDelayTimes[params.late_mode][i] * sample_rate).to_int()}; const auto fdn_delay{(FdnDelayTimes[params.late_mode][i] * sample_rate).to_int()};
state.fdn_delay_lines[i].sample_count = state.fdn_delay_lines[i].SetDelay(
std::min(fdn_delay, state.fdn_delay_lines[i].sample_count_max); std::min(fdn_delay, state.fdn_delay_lines[i].sample_count_max));
state.fdn_delay_lines[i].buffer_end =
&state.fdn_delay_lines[i].buffer[state.fdn_delay_lines[i].sample_count - 1];
const auto decay_delay{(DecayDelayTimes[params.late_mode][i] * sample_rate).to_int()}; const auto decay_delay{(DecayDelayTimes[params.late_mode][i] * sample_rate).to_int()};
state.decay_delay_lines[i].sample_count = state.decay_delay_lines[i].SetDelay(
std::min(decay_delay, state.decay_delay_lines[i].sample_count_max); std::min(decay_delay, state.decay_delay_lines[i].sample_count_max));
state.decay_delay_lines[i].buffer_end =
&state.decay_delay_lines[i].buffer[state.decay_delay_lines[i].sample_count - 1];
state.decay_delay_lines[i].decay = state.decay_delay_lines[i].decay =
0.5999755859375f * (1.0f - Common::FixedPoint<50, 14>::from_base(params.colouration)); 0.5999755859375f * (1.0f - Common::FixedPoint<50, 14>::from_base(params.colouration));
@@ -425,10 +422,12 @@ void ReverbCommand::Process(const AudioRenderer::CommandListProcessor& processor
auto state_{reinterpret_cast<ReverbInfo::State*>(state)}; auto state_{reinterpret_cast<ReverbInfo::State*>(state)};
if (effect_enabled) { if (effect_enabled) {
if (parameter.state == ReverbInfo::ParameterState::Updating) { bool needs_init = state_->pre_delay_line.buffer.empty();
UpdateReverbEffectParameter(parameter, *state_);
} else if (parameter.state == ReverbInfo::ParameterState::Initialized) { if (needs_init || parameter.state == ReverbInfo::ParameterState::Initialized) {
InitializeReverbEffect(parameter, *state_, workbuffer, long_size_pre_delay_supported); InitializeReverbEffect(parameter, *state_, workbuffer, long_size_pre_delay_supported);
} else if (parameter.state == ReverbInfo::ParameterState::Updating) {
UpdateReverbEffectParameter(parameter, *state_);
} }
} }
ApplyReverbEffect(parameter, *state_, effect_enabled, input_buffers, output_buffers, ApplyReverbEffect(parameter, *state_, effect_enabled, input_buffers, output_buffers,

View File

@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#pragma once #pragma once
@@ -69,6 +70,7 @@ public:
buffer.resize(delay_time + 1, 0); buffer.resize(delay_time + 1, 0);
buffer_end = &buffer[delay_time]; buffer_end = &buffer[delay_time];
output = &buffer[0]; output = &buffer[0];
input = &buffer[0];
decay = decay_rate; decay = decay_rate;
sample_count_max = delay_time; sample_count_max = delay_time;
SetDelay(delay_time); SetDelay(delay_time);
@@ -79,7 +81,6 @@ public:
return; return;
} }
sample_count = delay_time; sample_count = delay_time;
input = &buffer[0];
} }
Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) { Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) {
@@ -107,10 +108,13 @@ public:
} }
Common::FixedPoint<50, 14> TapOut(const s32 index) const { Common::FixedPoint<50, 14> TapOut(const s32 index) const {
auto out{input - (index + 1)}; const Common::FixedPoint<50, 14>* out{input - index};
if (out < buffer.data()) { if (out < buffer.data()) {
out += sample_count; out += sample_count;
} }
if (out >= buffer_end) {
out = buffer.data() + ((out - buffer.data()) % (sample_count_max + 1));
}
return *out; return *out;
} }