mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-10-27 08:10:52 +01:00
[audio_core/hid] Audio REV12+15 support + HID fixes (#2719)
This fixes newer updates / games. Implements partial audio rev15, rev13, rev12 and HID issues on SDK20+ games. Credits to LotP (Ryubing) and Zephyron (Citron) for their research and implementation. Co-authored-by: Zephyron <zephyron@citron-emu.org> Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2719 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: CamilleLaVey <camillelavey99@gmail.com> Co-authored-by: unknown <sahyno1996@gmail.com> Co-committed-by: unknown <sahyno1996@gmail.com>
This commit is contained in:
parent
1e1b8ad33f
commit
a3ef2cc183
27 changed files with 727 additions and 36 deletions
|
|
@ -237,6 +237,13 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, VoiceInfo& vo
|
|||
|
||||
cmd.biquad = voice_info.biquads[biquad_index];
|
||||
|
||||
if (voice_info.use_float_biquads) {
|
||||
cmd.biquad_float = voice_info.biquads_float[biquad_index];
|
||||
cmd.use_float_coefficients = true;
|
||||
} else {
|
||||
cmd.use_float_coefficients = false;
|
||||
}
|
||||
|
||||
cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()),
|
||||
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
|
||||
|
||||
|
|
@ -263,6 +270,9 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, EffectInfoBas
|
|||
cmd.biquad.b = parameter.b;
|
||||
cmd.biquad.a = parameter.a;
|
||||
|
||||
// Effects use legacy fixed-point format
|
||||
cmd.use_float_coefficients = false;
|
||||
|
||||
cmd.state = memory_pool->Translate(CpuAddr(state),
|
||||
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
|
||||
|
||||
|
|
@ -658,6 +668,13 @@ void CommandBuffer::GenerateMultitapBiquadFilterCommand(const s32 node_id, Voice
|
|||
cmd.output = buffer_count + channel;
|
||||
cmd.biquads = voice_info.biquads;
|
||||
|
||||
if (voice_info.use_float_biquads) {
|
||||
cmd.biquads_float = voice_info.biquads_float;
|
||||
cmd.use_float_coefficients = true;
|
||||
} else {
|
||||
cmd.use_float_coefficients = false;
|
||||
}
|
||||
|
||||
cmd.states[0] =
|
||||
memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()),
|
||||
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
|
||||
|
|
|
|||
|
|
@ -51,6 +51,40 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
|
|||
state.s3 = Common::BitCast<s64>(s[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Biquad filter float implementation with native float coefficients.
|
||||
*/
|
||||
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
|
||||
std::array<f32, 3>& b, std::array<f32, 2>& a,
|
||||
VoiceState::BiquadFilterState& state, const u32 sample_count) {
|
||||
constexpr f64 min{std::numeric_limits<s32>::min()};
|
||||
constexpr f64 max{std::numeric_limits<s32>::max()};
|
||||
|
||||
std::array<f64, 3> b_double{static_cast<f64>(b[0]), static_cast<f64>(b[1]),
|
||||
static_cast<f64>(b[2])};
|
||||
std::array<f64, 2> a_double{static_cast<f64>(a[0]), static_cast<f64>(a[1])};
|
||||
std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1),
|
||||
Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)};
|
||||
|
||||
for (u32 i = 0; i < sample_count; i++) {
|
||||
f64 in_sample{static_cast<f64>(input[i])};
|
||||
auto sample{in_sample * b_double[0] + s[0] * b_double[1] + s[1] * b_double[2] +
|
||||
s[2] * a_double[0] + s[3] * a_double[1]};
|
||||
|
||||
output[i] = static_cast<s32>(std::clamp(sample, min, max));
|
||||
|
||||
s[1] = s[0];
|
||||
s[0] = in_sample;
|
||||
s[3] = s[2];
|
||||
s[2] = sample;
|
||||
}
|
||||
|
||||
state.s0 = Common::BitCast<s64>(s[0]);
|
||||
state.s1 = Common::BitCast<s64>(s[1]);
|
||||
state.s2 = Common::BitCast<s64>(s[2]);
|
||||
state.s3 = Common::BitCast<s64>(s[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Biquad filter s32 implementation.
|
||||
*
|
||||
|
|
@ -98,8 +132,14 @@ void BiquadFilterCommand::Process(const AudioRenderer::CommandListProcessor& pro
|
|||
processor.mix_buffers.subspan(output * processor.sample_count, processor.sample_count)};
|
||||
|
||||
if (use_float_processing) {
|
||||
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
|
||||
processor.sample_count);
|
||||
// REV15+: Use native float coefficients if available
|
||||
if (use_float_coefficients) {
|
||||
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquad_float.numerator,
|
||||
biquad_float.denominator, *state_, processor.sample_count);
|
||||
} else {
|
||||
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
|
||||
processor.sample_count);
|
||||
}
|
||||
} else {
|
||||
ApplyBiquadFilterInt(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
|
||||
processor.sample_count);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -50,12 +53,16 @@ struct BiquadFilterCommand : ICommand {
|
|||
s16 output;
|
||||
/// Input parameters for biquad
|
||||
VoiceInfo::BiquadFilterParameter biquad;
|
||||
/// Input parameters for biquad (REV15+ native float)
|
||||
VoiceInfo::BiquadFilterParameter2 biquad_float;
|
||||
/// Biquad state, updated each call
|
||||
CpuAddr state;
|
||||
/// If true, reset the state
|
||||
bool needs_init;
|
||||
/// If true, use float processing rather than int
|
||||
bool use_float_processing;
|
||||
/// If true, use native float coefficients (REV15+)
|
||||
bool use_float_coefficients;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -72,4 +79,18 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
|
|||
std::array<s16, 3>& b, std::array<s16, 2>& a,
|
||||
VoiceState::BiquadFilterState& state, const u32 sample_count);
|
||||
|
||||
/**
|
||||
* Biquad filter float implementation with native float coefficients (SDK REV15+).
|
||||
*
|
||||
* @param output - Output container for filtered samples.
|
||||
* @param input - Input container for samples to be filtered.
|
||||
* @param b - Feedforward coefficients (float).
|
||||
* @param a - Feedback coefficients (float).
|
||||
* @param state - State to track previous samples.
|
||||
* @param sample_count - Number of samples to process.
|
||||
*/
|
||||
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
|
||||
std::array<f32, 3>& b, std::array<f32, 2>& a,
|
||||
VoiceState::BiquadFilterState& state, const u32 sample_count);
|
||||
|
||||
} // namespace AudioCore::Renderer
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -33,8 +36,14 @@ void MultiTapBiquadFilterCommand::Process(const AudioRenderer::CommandListProces
|
|||
*state = {};
|
||||
}
|
||||
|
||||
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state,
|
||||
processor.sample_count);
|
||||
// REV15+: Use native float coefficients if available
|
||||
if (use_float_coefficients) {
|
||||
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquads_float[i].numerator,
|
||||
biquads_float[i].denominator, *state, processor.sample_count);
|
||||
} else {
|
||||
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state,
|
||||
processor.sample_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
@ -49,12 +52,16 @@ struct MultiTapBiquadFilterCommand : ICommand {
|
|||
s16 output;
|
||||
/// Biquad parameters
|
||||
std::array<VoiceInfo::BiquadFilterParameter, MaxBiquadFilters> biquads;
|
||||
/// Biquad parameters (REV15+ native float)
|
||||
std::array<VoiceInfo::BiquadFilterParameter2, MaxBiquadFilters> biquads_float;
|
||||
/// Biquad states, updated each call
|
||||
std::array<CpuAddr, MaxBiquadFilters> states;
|
||||
/// If each biquad needs initialisation
|
||||
std::array<bool, MaxBiquadFilters> needs_init;
|
||||
/// Number of active biquads
|
||||
u8 filter_tap_count;
|
||||
/// If true, use native float coefficients (REV15+)
|
||||
bool use_float_coefficients;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::Renderer
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue