diff options
Diffstat (limited to 'src/audio_core/renderer/splitter/splitter_context.cpp')
| -rw-r--r-- | src/audio_core/renderer/splitter/splitter_context.cpp | 117 |
1 files changed, 103 insertions, 14 deletions
diff --git a/src/audio_core/renderer/splitter/splitter_context.cpp b/src/audio_core/renderer/splitter/splitter_context.cpp index fb118e981e..1ba5daebe9 100644 --- a/src/audio_core/renderer/splitter/splitter_context.cpp +++ b/src/audio_core/renderer/splitter/splitter_context.cpp @@ -35,12 +35,16 @@ SplitterDestinationData& SplitterContext::GetData(const u32 index) { void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_, SplitterDestinationData* splitter_destinations_, - const u32 destination_count_, const bool splitter_bug_fixed_) { + const u32 destination_count_, const bool splitter_bug_fixed_, + const BehaviorInfo& behavior) { splitter_infos = splitter_infos_; info_count = splitter_info_count_; splitter_destinations = splitter_destinations_; destinations_count = destination_count_; splitter_bug_fixed = splitter_bug_fixed_; + splitter_prev_volume_reset_supported = behavior.IsSplitterPrevVolumeResetSupported(); + splitter_biquad_param_supported = behavior.IsBiquadFilterParameterForSplitterEnabled(); + splitter_float_coeff_supported = behavior.IsSplitterDestinationV2bSupported(); } bool SplitterContext::UsingSplitter() const { @@ -84,7 +88,7 @@ bool SplitterContext::Initialize(const BehaviorInfo& behavior, } Setup(splitter_infos, params.splitter_infos, splitter_destinations, - params.splitter_destinations, behavior.IsSplitterBugFixed()); + params.splitter_destinations, behavior.IsSplitterBugFixed(), behavior); } return true; } @@ -137,19 +141,104 @@ u32 SplitterContext::UpdateInfo(const u8* input, u32 offset, const u32 splitter_ u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) { for (u32 i = 0; i < count; i++) { - auto data_header{ - reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset)}; - - if (data_header->magic != GetSplitterSendDataMagic()) { - continue; - } - - if (data_header->id < 0 || data_header->id > destinations_count) { - continue; + // Version selection based on feature flags: + // - REV12: integer biquad params (Version2a) + // - REV15: float coeff/biquad v2b + // - older: no biquad fields + if (!splitter_biquad_param_supported) { + const auto* data_header = + reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset); + + if (data_header->magic != GetSplitterSendDataMagic()) { + continue; + } + if (data_header->id < 0 || data_header->id > destinations_count) { + continue; + } + + auto modified_params = *data_header; + if (!splitter_prev_volume_reset_supported) { + modified_params.reset_prev_volume = false; + } + splitter_destinations[data_header->id].Update(modified_params); + offset += sizeof(SplitterDestinationData::InParameter); + } else if (!splitter_float_coeff_supported) { + // Version 2a: struct contains legacy fixed-point biquad filter fields (REV12+) + const auto* data_header_v2a = + reinterpret_cast<const SplitterDestinationData::InParameterVersion2a*>(input + + offset); + + if (data_header_v2a->magic != GetSplitterSendDataMagic()) { + continue; + } + if (data_header_v2a->id < 0 || data_header_v2a->id > destinations_count) { + continue; + } + + // Map common fields to the base format + SplitterDestinationData::InParameter mapped{}; + mapped.magic = data_header_v2a->magic; + mapped.id = data_header_v2a->id; + mapped.mix_volumes = data_header_v2a->mix_volumes; + mapped.mix_id = data_header_v2a->mix_id; + mapped.in_use = data_header_v2a->in_use; + mapped.reset_prev_volume = + splitter_prev_volume_reset_supported ? data_header_v2a->reset_prev_volume : false; + + auto& destination = splitter_destinations[data_header_v2a->id]; + destination.Update(mapped); + + // Convert legacy fixed-point biquad params into float representation + auto biquad_filters = destination.GetBiquadFilters(); + for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) { + const auto& legacy = data_header_v2a->biquad_filters[filter_idx]; + auto& out = biquad_filters[filter_idx]; + out.enabled = legacy.enabled; + // s16 fixed-point scale: use Q14 like voices (b and a are s16, 1.0 ~= 1<<14) + constexpr float scale = 1.0f / static_cast<float>(1 << 14); + out.numerator[0] = static_cast<float>(legacy.b[0]) * scale; + out.numerator[1] = static_cast<float>(legacy.b[1]) * scale; + out.numerator[2] = static_cast<float>(legacy.b[2]) * scale; + out.denominator[0] = static_cast<float>(legacy.a[0]) * scale; + out.denominator[1] = static_cast<float>(legacy.a[1]) * scale; + } + + offset += static_cast<u32>(sizeof(SplitterDestinationData::InParameterVersion2a)); + } else { + // Version 2b: struct contains extra biquad filter fields with float coeffs + const auto* data_header_v2b = + reinterpret_cast<const SplitterDestinationData::InParameterVersion2b*>(input + + offset); + + if (data_header_v2b->magic != GetSplitterSendDataMagic()) { + continue; + } + if (data_header_v2b->id < 0 || data_header_v2b->id > destinations_count) { + continue; + } + + // Map common fields to the old format + SplitterDestinationData::InParameter mapped{}; + mapped.magic = data_header_v2b->magic; + mapped.id = data_header_v2b->id; + mapped.mix_volumes = data_header_v2b->mix_volumes; + mapped.mix_id = data_header_v2b->mix_id; + mapped.in_use = data_header_v2b->in_use; + mapped.reset_prev_volume = + splitter_prev_volume_reset_supported ? data_header_v2b->reset_prev_volume : false; + + // Store biquad filters from V2b (REV15+) + auto& destination = splitter_destinations[data_header_v2b->id]; + destination.Update(mapped); + + // Copy biquad filter parameters + auto biquad_filters = destination.GetBiquadFilters(); + for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) { + biquad_filters[filter_idx] = data_header_v2b->biquad_filters[filter_idx]; + } + + offset += static_cast<u32>(sizeof(SplitterDestinationData::InParameterVersion2b)); } - - splitter_destinations[data_header->id].Update(*data_header); - offset += sizeof(SplitterDestinationData::InParameter); } return offset; |
