|
|
@ -43,6 +43,7 @@ void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 s |
|
|
destinations_count = destination_count_; |
|
|
destinations_count = destination_count_; |
|
|
splitter_bug_fixed = splitter_bug_fixed_; |
|
|
splitter_bug_fixed = splitter_bug_fixed_; |
|
|
splitter_prev_volume_reset_supported = behavior.IsSplitterPrevVolumeResetSupported(); |
|
|
splitter_prev_volume_reset_supported = behavior.IsSplitterPrevVolumeResetSupported(); |
|
|
|
|
|
splitter_biquad_param_supported = behavior.IsBiquadFilterParameterForSplitterEnabled(); |
|
|
splitter_float_coeff_supported = behavior.IsSplitterDestinationV2bSupported(); |
|
|
splitter_float_coeff_supported = behavior.IsSplitterDestinationV2bSupported(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -140,8 +141,11 @@ u32 SplitterContext::UpdateInfo(const u8* input, u32 offset, const u32 splitter_ |
|
|
|
|
|
|
|
|
u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) { |
|
|
u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) { |
|
|
for (u32 i = 0; i < count; i++) { |
|
|
for (u32 i = 0; i < count; i++) { |
|
|
// Version selection based on float coeff/biquad v2b support.
|
|
|
|
|
|
if (!splitter_float_coeff_supported) { |
|
|
|
|
|
|
|
|
// 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 = |
|
|
const auto* data_header = |
|
|
reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset); |
|
|
reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset); |
|
|
|
|
|
|
|
|
@ -158,8 +162,50 @@ u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) { |
|
|
} |
|
|
} |
|
|
splitter_destinations[data_header->id].Update(modified_params); |
|
|
splitter_destinations[data_header->id].Update(modified_params); |
|
|
offset += sizeof(SplitterDestinationData::InParameter); |
|
|
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 { |
|
|
} else { |
|
|
// Version 2b: struct contains extra biquad filter fields
|
|
|
|
|
|
|
|
|
// Version 2b: struct contains extra biquad filter fields with float coeffs
|
|
|
const auto* data_header_v2b = |
|
|
const auto* data_header_v2b = |
|
|
reinterpret_cast<const SplitterDestinationData::InParameterVersion2b*>(input + |
|
|
reinterpret_cast<const SplitterDestinationData::InParameterVersion2b*>(input + |
|
|
offset); |
|
|
offset); |
|
|
|