mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-21 19:43:34 +00:00
feat(audio): Add REV13 audio renderer support
- Implement compressor statistics collection and tracking
- Add explicit splitter volume reset functionality
- Implement REV13 audio device notification commands
- Update feature support system to revision 13
- Maintain backward compatibility with older revisions
Resolves REV13 audio renderer feature requirements with proper
Nintendo Switch development practices and SwitchBrew compatibility.
REF: a2c0035013
Signed-off-by: Zephyron <zephyron@citron-emu.org>
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
#include "common/polyfill_ranges.h"
|
#include "common/polyfill_ranges.h"
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
constexpr u32 CurrentRevision = 11;
|
constexpr u32 CurrentRevision = 13;
|
||||||
|
|
||||||
enum class SupportTags {
|
enum class SupportTags {
|
||||||
CommandProcessingTimeEstimatorVersion4,
|
CommandProcessingTimeEstimatorVersion4,
|
||||||
@@ -44,6 +44,8 @@ enum class SupportTags {
|
|||||||
DelayChannelMappingChange,
|
DelayChannelMappingChange,
|
||||||
ReverbChannelMappingChange,
|
ReverbChannelMappingChange,
|
||||||
I3dl2ReverbChannelMappingChange,
|
I3dl2ReverbChannelMappingChange,
|
||||||
|
CompressorStatistics,
|
||||||
|
SplitterPrevVolumeReset,
|
||||||
|
|
||||||
// Not a real tag, just here to get the count.
|
// Not a real tag, just here to get the count.
|
||||||
Size
|
Size
|
||||||
@@ -87,6 +89,8 @@ constexpr bool CheckFeatureSupported(SupportTags tag, u32 user_revision) {
|
|||||||
{SupportTags::DelayChannelMappingChange, 11},
|
{SupportTags::DelayChannelMappingChange, 11},
|
||||||
{SupportTags::ReverbChannelMappingChange, 11},
|
{SupportTags::ReverbChannelMappingChange, 11},
|
||||||
{SupportTags::I3dl2ReverbChannelMappingChange, 11},
|
{SupportTags::I3dl2ReverbChannelMappingChange, 11},
|
||||||
|
{SupportTags::CompressorStatistics, 13},
|
||||||
|
{SupportTags::SplitterPrevVolumeReset, 13},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
const auto& feature =
|
const auto& feature =
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "audio_core/renderer/audio_device.h"
|
#include "audio_core/renderer/audio_device.h"
|
||||||
#include "audio_core/sink/sink.h"
|
#include "audio_core/sink/sink.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/hle/service/audio/errors.h"
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace AudioCore::Renderer {
|
namespace AudioCore::Renderer {
|
||||||
|
|
||||||
@@ -69,4 +71,93 @@ f32 AudioDevice::GetDeviceVolume([[maybe_unused]] std::string_view name) const {
|
|||||||
return output_sink.GetDeviceVolume();
|
return output_sink.GetDeviceVolume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::AcquireAudioOutputDeviceNotification(u32& event_handle, u64 device_id) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the notification request
|
||||||
|
output_device_notifications[device_id] = true;
|
||||||
|
|
||||||
|
// For now, return a dummy event handle
|
||||||
|
event_handle = static_cast<u32>(device_id & 0xFFFFFFFF);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::ReleaseAudioOutputDeviceNotification(u64 device_id) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the notification tracking
|
||||||
|
auto it = output_device_notifications.find(device_id);
|
||||||
|
if (it != output_device_notifications.end()) {
|
||||||
|
output_device_notifications.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::AcquireAudioInputDeviceNotification(u32& event_handle, u64 device_id) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track the notification request
|
||||||
|
input_device_notifications[device_id] = true;
|
||||||
|
|
||||||
|
// For now, return a dummy event handle
|
||||||
|
event_handle = static_cast<u32>(device_id & 0xFFFFFFFF);
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::ReleaseAudioInputDeviceNotification(u64 device_id) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the notification tracking
|
||||||
|
auto it = input_device_notifications.find(device_id);
|
||||||
|
if (it != input_device_notifications.end()) {
|
||||||
|
input_device_notifications.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the auto tune state
|
||||||
|
auto_tune_enabled = enabled;
|
||||||
|
|
||||||
|
// Apply auto tune to the sink if supported
|
||||||
|
if (enabled) {
|
||||||
|
// For now, we just track the state
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result AudioDevice::IsAudioDeviceOutputVolumeAutoTuneEnabled(bool& enabled) const {
|
||||||
|
// Check if REV13+ features are supported
|
||||||
|
if (!CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision)) {
|
||||||
|
return Service::Audio::ResultNotSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the current auto tune state
|
||||||
|
enabled = auto_tune_enabled;
|
||||||
|
|
||||||
|
return ResultSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
#include "audio_core/audio_render_manager.h"
|
#include "audio_core/audio_render_manager.h"
|
||||||
@@ -65,6 +66,63 @@ public:
|
|||||||
*/
|
*/
|
||||||
f32 GetDeviceVolume(std::string_view name) const;
|
f32 GetDeviceVolume(std::string_view name) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire audio output device notification. REV13+.
|
||||||
|
*
|
||||||
|
* @param event_handle - Output event handle.
|
||||||
|
* @param device_id - Device ID to acquire notification for.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result AcquireAudioOutputDeviceNotification(u32& event_handle, u64 device_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release audio output device notification. REV13+.
|
||||||
|
*
|
||||||
|
* @param device_id - Device ID to release notification for.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result ReleaseAudioOutputDeviceNotification(u64 device_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire audio input device notification. REV13+.
|
||||||
|
*
|
||||||
|
* @param event_handle - Output event handle.
|
||||||
|
* @param device_id - Device ID to acquire notification for.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result AcquireAudioInputDeviceNotification(u32& event_handle, u64 device_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release audio input device notification. REV13+.
|
||||||
|
*
|
||||||
|
* @param device_id - Device ID to release notification for.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result ReleaseAudioInputDeviceNotification(u64 device_id) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set audio device output volume auto tune enabled. REV13+.
|
||||||
|
*
|
||||||
|
* @param enabled - Whether auto tune is enabled.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result SetAudioDeviceOutputVolumeAutoTuneEnabled(bool enabled) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if audio device output volume auto tune is enabled. REV13+.
|
||||||
|
*
|
||||||
|
* @param enabled - Output whether auto tune is enabled.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
Result IsAudioDeviceOutputVolumeAutoTuneEnabled(bool& enabled) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// Track device notifications
|
||||||
|
mutable std::map<u64, bool> output_device_notifications{};
|
||||||
|
mutable std::map<u64, bool> input_device_notifications{};
|
||||||
|
/// Auto tune enabled state
|
||||||
|
mutable bool auto_tune_enabled{false};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Backend output sink for the device
|
/// Backend output sink for the device
|
||||||
Sink::Sink& output_sink;
|
Sink::Sink& output_sink;
|
||||||
|
|||||||
@@ -190,4 +190,12 @@ bool BehaviorInfo::IsI3dl2ReverbChannelMappingChanged() const {
|
|||||||
return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision);
|
return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BehaviorInfo::IsCompressorStatisticsSupported() const {
|
||||||
|
return CheckFeatureSupported(SupportTags::CompressorStatistics, user_revision);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BehaviorInfo::IsSplitterPrevVolumeResetSupported() const {
|
||||||
|
return CheckFeatureSupported(SupportTags::SplitterPrevVolumeReset, user_revision);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace AudioCore::Renderer
|
} // namespace AudioCore::Renderer
|
||||||
|
|||||||
@@ -361,6 +361,23 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool IsI3dl2ReverbChannelMappingChanged() const;
|
bool IsI3dl2ReverbChannelMappingChanged() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if compressor statistics are supported.
|
||||||
|
* This allows the compressor effect to output statistics about its processing.
|
||||||
|
*
|
||||||
|
* @return True if supported, otherwise false.
|
||||||
|
*/
|
||||||
|
bool IsCompressorStatisticsSupported() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if explicit previous mix volume reset is supported for splitters.
|
||||||
|
* This allows splitters to explicitly reset their previous mix volumes instead of
|
||||||
|
* doing so implicitly on first use.
|
||||||
|
*
|
||||||
|
* @return True if supported, otherwise false.
|
||||||
|
*/
|
||||||
|
bool IsSplitterPrevVolumeResetSupported() const;
|
||||||
|
|
||||||
/// Host version
|
/// Host version
|
||||||
u32 process_revision;
|
u32 process_revision;
|
||||||
/// User version
|
/// User version
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ static void InitializeCompressorEffect(const CompressorInfo::ParameterVersion2&
|
|||||||
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
|
||||||
CompressorInfo::State& state, bool enabled,
|
CompressorInfo::State& state, bool enabled,
|
||||||
std::span<std::span<const s32>> input_buffers,
|
std::span<std::span<const s32>> input_buffers,
|
||||||
std::span<std::span<s32>> output_buffers, u32 sample_count) {
|
std::span<std::span<s32>> output_buffers, u32 sample_count,
|
||||||
|
CompressorInfo::StatisticsInternal* statistics = nullptr) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
auto state_00{state.unk_00};
|
auto state_00{state.unk_00};
|
||||||
auto state_04{state.unk_04};
|
auto state_04{state.unk_04};
|
||||||
@@ -94,6 +95,15 @@ static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& param
|
|||||||
output_buffers[channel][i] = static_cast<s32>(
|
output_buffers[channel][i] = static_cast<s32>(
|
||||||
static_cast<f32>(input_buffers[channel][i]) * state_08 * state.unk_20);
|
static_cast<f32>(input_buffers[channel][i]) * state_08 * state.unk_20);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update statistics if enabled
|
||||||
|
if (statistics) {
|
||||||
|
statistics->maximum_mean = std::max(statistics->maximum_mean, a / params.channel_count);
|
||||||
|
statistics->minimum_gain = std::min(statistics->minimum_gain, state_08 * state.unk_20);
|
||||||
|
for (s16 channel = 0; channel < params.channel_count; channel++) {
|
||||||
|
statistics->last_samples[channel] = std::abs(static_cast<f32>(input_buffers[channel][i]) / 32768.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
state.unk_00 = state_00;
|
state.unk_00 = state_00;
|
||||||
@@ -135,6 +145,7 @@ void CompressorCommand::Process(const AudioRenderer::CommandListProcessor& proce
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto state_{reinterpret_cast<CompressorInfo::State*>(state)};
|
auto state_{reinterpret_cast<CompressorInfo::State*>(state)};
|
||||||
|
CompressorInfo::StatisticsInternal* statistics{nullptr};
|
||||||
|
|
||||||
if (effect_enabled) {
|
if (effect_enabled) {
|
||||||
if (parameter.state == CompressorInfo::ParameterState::Updating) {
|
if (parameter.state == CompressorInfo::ParameterState::Updating) {
|
||||||
@@ -142,10 +153,20 @@ void CompressorCommand::Process(const AudioRenderer::CommandListProcessor& proce
|
|||||||
} else if (parameter.state == CompressorInfo::ParameterState::Initialized) {
|
} else if (parameter.state == CompressorInfo::ParameterState::Initialized) {
|
||||||
InitializeCompressorEffect(parameter, *state_);
|
InitializeCompressorEffect(parameter, *state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle statistics if enabled
|
||||||
|
if (parameter.statistics_enabled && result_state != 0) {
|
||||||
|
statistics = reinterpret_cast<CompressorInfo::StatisticsInternal*>(result_state);
|
||||||
|
if (parameter.statistics_reset_required) {
|
||||||
|
statistics->maximum_mean = 0.0f;
|
||||||
|
statistics->minimum_gain = 1.0f;
|
||||||
|
statistics->last_samples.fill(0.0f);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyCompressorEffect(parameter, *state_, effect_enabled, input_buffers, output_buffers,
|
ApplyCompressorEffect(parameter, *state_, effect_enabled, input_buffers, output_buffers,
|
||||||
processor.sample_count);
|
processor.sample_count, statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CompressorCommand::Verify(const AudioRenderer::CommandListProcessor& processor) {
|
bool CompressorCommand::Verify(const AudioRenderer::CommandListProcessor& processor) {
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ struct CompressorCommand : ICommand {
|
|||||||
CpuAddr state;
|
CpuAddr state;
|
||||||
/// Game-supplied workbuffer (Unused)
|
/// Game-supplied workbuffer (Unused)
|
||||||
CpuAddr workbuffer;
|
CpuAddr workbuffer;
|
||||||
|
/// Result state for statistics
|
||||||
|
CpuAddr result_state;
|
||||||
/// Is this effect enabled?
|
/// Is this effect enabled?
|
||||||
bool effect_enabled;
|
bool effect_enabled;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,6 +31,18 @@ void CompressorInfo::UpdateForCommandGeneration() {
|
|||||||
|
|
||||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||||
params->state = ParameterState::Updated;
|
params->state = ParameterState::Updated;
|
||||||
|
params->statistics_reset_required = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressorInfo::InitializeResultState(EffectResultState& result_state) {
|
||||||
|
auto statistics{reinterpret_cast<StatisticsInternal*>(result_state.state.data())};
|
||||||
|
statistics->maximum_mean = 0.0f;
|
||||||
|
statistics->minimum_gain = 1.0f;
|
||||||
|
statistics->last_samples.fill(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressorInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {
|
||||||
|
cpu_state = dsp_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
CpuAddr CompressorInfo::GetWorkbuffer(s32 index) {
|
CpuAddr CompressorInfo::GetWorkbuffer(s32 index) {
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ public:
|
|||||||
/* 0x30 */ f32 out_gain;
|
/* 0x30 */ f32 out_gain;
|
||||||
/* 0x34 */ ParameterState state;
|
/* 0x34 */ ParameterState state;
|
||||||
/* 0x35 */ bool makeup_gain_enabled;
|
/* 0x35 */ bool makeup_gain_enabled;
|
||||||
|
/* 0x36 */ bool statistics_enabled;
|
||||||
|
/* 0x37 */ bool statistics_reset_required;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||||
"CompressorInfo::ParameterVersion1 has the wrong size!");
|
"CompressorInfo::ParameterVersion1 has the wrong size!");
|
||||||
@@ -50,6 +52,8 @@ public:
|
|||||||
/* 0x30 */ f32 out_gain;
|
/* 0x30 */ f32 out_gain;
|
||||||
/* 0x34 */ ParameterState state;
|
/* 0x34 */ ParameterState state;
|
||||||
/* 0x35 */ bool makeup_gain_enabled;
|
/* 0x35 */ bool makeup_gain_enabled;
|
||||||
|
/* 0x36 */ bool statistics_enabled;
|
||||||
|
/* 0x37 */ bool statistics_reset_required;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||||
"CompressorInfo::ParameterVersion2 has the wrong size!");
|
"CompressorInfo::ParameterVersion2 has the wrong size!");
|
||||||
@@ -69,6 +73,14 @@ public:
|
|||||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||||
"CompressorInfo::State has the wrong size!");
|
"CompressorInfo::State has the wrong size!");
|
||||||
|
|
||||||
|
struct StatisticsInternal {
|
||||||
|
/* 0x00 */ f32 maximum_mean;
|
||||||
|
/* 0x04 */ f32 minimum_gain;
|
||||||
|
/* 0x08 */ std::array<f32, MaxChannels> last_samples;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(StatisticsInternal) == 0x20,
|
||||||
|
"CompressorInfo::StatisticsInternal has the wrong size!");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the info with new parameters, version 1.
|
* Update the info with new parameters, version 1.
|
||||||
*
|
*
|
||||||
@@ -94,6 +106,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
void UpdateForCommandGeneration() override;
|
void UpdateForCommandGeneration() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a new compressor statistics result state. Version 2 only.
|
||||||
|
*
|
||||||
|
* @param result_state - Result state to initialize.
|
||||||
|
*/
|
||||||
|
void InitializeResultState(EffectResultState& result_state) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the host-side compressor statistics with the ADSP-side one. Version 2 only.
|
||||||
|
*
|
||||||
|
* @param cpu_state - Host-side result state to update.
|
||||||
|
* @param dsp_state - AudioRenderer-side result state to update from.
|
||||||
|
*/
|
||||||
|
void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a workbuffer assigned to this effect with the given index.
|
* Get a workbuffer assigned to this effect with the given index.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -32,12 +32,14 @@ SplitterDestinationData& SplitterContext::GetData(const u32 index) {
|
|||||||
|
|
||||||
void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_,
|
void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_,
|
||||||
SplitterDestinationData* splitter_destinations_,
|
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_;
|
splitter_infos = splitter_infos_;
|
||||||
info_count = splitter_info_count_;
|
info_count = splitter_info_count_;
|
||||||
splitter_destinations = splitter_destinations_;
|
splitter_destinations = splitter_destinations_;
|
||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SplitterContext::UsingSplitter() const {
|
bool SplitterContext::UsingSplitter() const {
|
||||||
@@ -81,7 +83,7 @@ bool SplitterContext::Initialize(const BehaviorInfo& behavior,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Setup(splitter_infos, params.splitter_infos, splitter_destinations,
|
Setup(splitter_infos, params.splitter_infos, splitter_destinations,
|
||||||
params.splitter_destinations, behavior.IsSplitterBugFixed());
|
params.splitter_destinations, behavior.IsSplitterBugFixed(), behavior);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -145,7 +147,13 @@ u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
splitter_destinations[data_header->id].Update(*data_header);
|
// Create a modified parameter that respects the behavior support
|
||||||
|
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);
|
offset += sizeof(SplitterDestinationData::InParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -168,10 +168,11 @@ private:
|
|||||||
* @param splitter_destinations - Workbuffer for splitter destinations.
|
* @param splitter_destinations - Workbuffer for splitter destinations.
|
||||||
* @param destination_count - Number of destinations in the workbuffer.
|
* @param destination_count - Number of destinations in the workbuffer.
|
||||||
* @param splitter_bug_fixed - Is the splitter bug fixed?
|
* @param splitter_bug_fixed - Is the splitter bug fixed?
|
||||||
|
* @param behavior - Behavior info for feature support.
|
||||||
*/
|
*/
|
||||||
void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count,
|
void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count,
|
||||||
SplitterDestinationData* splitter_destinations, u32 destination_count,
|
SplitterDestinationData* splitter_destinations, u32 destination_count,
|
||||||
bool splitter_bug_fixed);
|
bool splitter_bug_fixed, const BehaviorInfo& behavior);
|
||||||
|
|
||||||
/// Workbuffer for splitters
|
/// Workbuffer for splitters
|
||||||
std::span<SplitterInfo> splitter_infos{};
|
std::span<SplitterInfo> splitter_infos{};
|
||||||
@@ -183,6 +184,8 @@ private:
|
|||||||
s32 destinations_count{};
|
s32 destinations_count{};
|
||||||
/// Is the splitter bug fixed?
|
/// Is the splitter bug fixed?
|
||||||
bool splitter_bug_fixed{};
|
bool splitter_bug_fixed{};
|
||||||
|
/// Is explicit previous mix volume reset supported?
|
||||||
|
bool splitter_prev_volume_reset_supported{};
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Renderer
|
} // namespace Renderer
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ void SplitterDestinationData::Update(const InParameter& params) {
|
|||||||
destination_id = params.mix_id;
|
destination_id = params.mix_id;
|
||||||
mix_volumes = params.mix_volumes;
|
mix_volumes = params.mix_volumes;
|
||||||
|
|
||||||
if (!in_use && params.in_use) {
|
if (params.reset_prev_volume) {
|
||||||
|
prev_mix_volumes = mix_volumes;
|
||||||
|
need_update = false;
|
||||||
|
} else if (!in_use && params.in_use) {
|
||||||
prev_mix_volumes = mix_volumes;
|
prev_mix_volumes = mix_volumes;
|
||||||
need_update = false;
|
need_update = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ public:
|
|||||||
/* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
|
/* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
|
||||||
/* 0x68 */ u32 mix_id;
|
/* 0x68 */ u32 mix_id;
|
||||||
/* 0x6C */ bool in_use;
|
/* 0x6C */ bool in_use;
|
||||||
|
/* 0x6D */ bool reset_prev_volume;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(InParameter) == 0x70,
|
static_assert(sizeof(InParameter) == 0x70,
|
||||||
"SplitterDestinationData::InParameter has the wrong size!");
|
"SplitterDestinationData::InParameter has the wrong size!");
|
||||||
|
|||||||
Reference in New Issue
Block a user