suyu/src/audio_core/renderer/command/command_buffer.cpp
2022-07-22 01:11:32 +01:00

715 lines
30 KiB
C++

// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/renderer/behavior/behavior_info.h"
#include "audio_core/renderer/command/command_buffer.h"
#include "audio_core/renderer/command/command_list_header.h"
#include "audio_core/renderer/command/command_processing_time_estimator.h"
#include "audio_core/renderer/effect/biquad_filter.h"
#include "audio_core/renderer/effect/delay.h"
#include "audio_core/renderer/effect/reverb.h"
#include "audio_core/renderer/memory/memory_pool_info.h"
#include "audio_core/renderer/mix/mix_info.h"
#include "audio_core/renderer/sink/circular_buffer_sink_info.h"
#include "audio_core/renderer/sink/device_sink_info.h"
#include "audio_core/renderer/sink/sink_info_base.h"
#include "audio_core/renderer/voice/voice_info.h"
#include "audio_core/renderer/voice/voice_state.h"
namespace AudioCore::AudioRenderer {
template <typename T, CommandId Id>
T& CommandBuffer::GenerateStart(const s32 node_id) {
if (size + sizeof(T) >= command_list.size_bytes()) {
LOG_ERROR(
Service_Audio,
"Attempting to write commands beyond the end of allocated command buffer memory!");
UNREACHABLE();
}
auto& cmd{*std::construct_at<T>(reinterpret_cast<T*>(&command_list[size]))};
cmd.magic = CommandMagic;
cmd.enabled = true;
cmd.type = Id;
cmd.size = sizeof(T);
cmd.node_id = node_id;
return cmd;
}
template <typename T>
void CommandBuffer::GenerateEnd(T& cmd) {
cmd.estimated_process_time = time_estimator->Estimate(cmd);
estimated_process_time += cmd.estimated_process_time;
size += sizeof(T);
count++;
}
void CommandBuffer::GeneratePcmInt16Version1Command(const s32 node_id,
const MemoryPoolInfo& memory_pool_,
VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<PcmInt16DataSourceVersion1Command, CommandId::DataSourcePcmInt16Version1>(
node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
cmd.channel_index = channel;
cmd.channel_count = voice_info.channel_count;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool_.Translate(CpuAddr(&voice_state), sizeof(VoiceState));
GenerateEnd<PcmInt16DataSourceVersion1Command>(cmd);
}
void CommandBuffer::GeneratePcmInt16Version2Command(const s32 node_id, VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<PcmInt16DataSourceVersion2Command, CommandId::DataSourcePcmInt16Version2>(
node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
cmd.channel_index = channel;
cmd.channel_count = voice_info.channel_count;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool->Translate(CpuAddr(&voice_state), sizeof(VoiceState));
GenerateEnd<PcmInt16DataSourceVersion2Command>(cmd);
}
void CommandBuffer::GeneratePcmFloatVersion1Command(const s32 node_id,
const MemoryPoolInfo& memory_pool_,
VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<PcmFloatDataSourceVersion1Command, CommandId::DataSourcePcmFloatVersion1>(
node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
cmd.channel_index = channel;
cmd.channel_count = voice_info.channel_count;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool_.Translate(CpuAddr(&voice_state), sizeof(VoiceState));
GenerateEnd<PcmFloatDataSourceVersion1Command>(cmd);
}
void CommandBuffer::GeneratePcmFloatVersion2Command(const s32 node_id, VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<PcmFloatDataSourceVersion2Command, CommandId::DataSourcePcmFloatVersion2>(
node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
cmd.channel_index = channel;
cmd.channel_count = voice_info.channel_count;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool->Translate(CpuAddr(&voice_state), sizeof(VoiceState));
GenerateEnd<PcmFloatDataSourceVersion2Command>(cmd);
}
void CommandBuffer::GenerateAdpcmVersion1Command(const s32 node_id,
const MemoryPoolInfo& memory_pool_,
VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<AdpcmDataSourceVersion1Command, CommandId::DataSourceAdpcmVersion1>(node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool_.Translate(CpuAddr(&voice_state), sizeof(VoiceState));
cmd.data_address = voice_info.data_address.GetReference(true);
cmd.data_size = voice_info.data_address.GetSize();
GenerateEnd<AdpcmDataSourceVersion1Command>(cmd);
}
void CommandBuffer::GenerateAdpcmVersion2Command(const s32 node_id, VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{
GenerateStart<AdpcmDataSourceVersion2Command, CommandId::DataSourceAdpcmVersion2>(node_id)};
cmd.src_quality = voice_info.src_quality;
cmd.output_index = buffer_count + channel;
cmd.flags = voice_info.flags & 3;
cmd.sample_rate = voice_info.sample_rate;
cmd.pitch = voice_info.pitch;
cmd.channel_index = channel;
cmd.channel_count = voice_info.channel_count;
for (u32 i = 0; i < MaxWaveBuffers; i++) {
voice_info.wavebuffers[i].Copy(cmd.wave_buffers[i]);
}
cmd.voice_state = memory_pool->Translate(CpuAddr(&voice_state), sizeof(VoiceState));
cmd.data_address = voice_info.data_address.GetReference(true);
cmd.data_size = voice_info.data_address.GetSize();
GenerateEnd<AdpcmDataSourceVersion2Command>(cmd);
}
void CommandBuffer::GenerateVolumeCommand(const s32 node_id, const s16 buffer_offset,
const s16 input_index, const f32 volume,
const u8 precision) {
auto& cmd{GenerateStart<VolumeCommand, CommandId::Volume>(node_id)};
cmd.precision = precision;
cmd.input_index = buffer_offset + input_index;
cmd.output_index = buffer_offset + input_index;
cmd.volume = volume;
GenerateEnd<VolumeCommand>(cmd);
}
void CommandBuffer::GenerateVolumeRampCommand(const s32 node_id, VoiceInfo& voice_info,
const s16 buffer_count, const u8 precision) {
auto& cmd{GenerateStart<VolumeRampCommand, CommandId::VolumeRamp>(node_id)};
cmd.input_index = buffer_count;
cmd.output_index = buffer_count;
cmd.prev_volume = voice_info.prev_volume;
cmd.volume = voice_info.volume;
cmd.precision = precision;
GenerateEnd<VolumeRampCommand>(cmd);
}
void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel,
const u32 biquad_index,
const bool use_float_processing) {
auto& cmd{GenerateStart<BiquadFilterCommand, CommandId::BiquadFilter>(node_id)};
cmd.input = buffer_count + channel;
cmd.output = buffer_count + channel;
cmd.biquad = voice_info.biquads[biquad_index];
cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
cmd.needs_init = !voice_info.biquad_initialized[biquad_index];
cmd.use_float_processing = use_float_processing;
GenerateEnd<BiquadFilterCommand>(cmd);
}
void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 buffer_offset, const s8 channel,
const bool needs_init,
const bool use_float_processing) {
auto& cmd{GenerateStart<BiquadFilterCommand, CommandId::BiquadFilter>(node_id)};
const auto& parameter{
*reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
const auto state{
reinterpret_cast<VoiceState::BiquadFilterState*>(effect_info.GetStateBuffer())};
cmd.input = buffer_offset + parameter.inputs[channel];
cmd.output = buffer_offset + parameter.outputs[channel];
cmd.biquad.b = parameter.b;
cmd.biquad.a = parameter.a;
cmd.state = memory_pool->Translate(CpuAddr(state),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
cmd.needs_init = needs_init;
cmd.use_float_processing = use_float_processing;
GenerateEnd<BiquadFilterCommand>(cmd);
}
void CommandBuffer::GenerateMixCommand(const s32 node_id, const s16 input_index,
const s16 output_index, const s16 buffer_offset,
const f32 volume, const u8 precision) {
auto& cmd{GenerateStart<MixCommand, CommandId::Mix>(node_id)};
cmd.input_index = input_index;
cmd.output_index = output_index;
cmd.volume = volume;
cmd.precision = precision;
GenerateEnd<MixCommand>(cmd);
}
void CommandBuffer::GenerateMixRampCommand(const s32 node_id,
[[maybe_unused]] const s16 buffer_count,
const s16 input_index, const s16 output_index,
const f32 volume, const f32 prev_volume,
const CpuAddr prev_samples, const u8 precision) {
if (volume == 0.0f && prev_volume == 0.0f) {
return;
}
auto& cmd{GenerateStart<MixRampCommand, CommandId::MixRamp>(node_id)};
cmd.input_index = input_index;
cmd.output_index = output_index;
cmd.prev_volume = prev_volume;
cmd.volume = volume;
cmd.previous_sample = prev_samples;
cmd.precision = precision;
GenerateEnd<MixRampCommand>(cmd);
}
void CommandBuffer::GenerateMixRampGroupedCommand(const s32 node_id, const s16 buffer_count,
const s16 input_index, s16 output_index,
std::span<const f32> volumes,
std::span<const f32> prev_volumes,
const CpuAddr prev_samples, const u8 precision) {
auto& cmd{GenerateStart<MixRampGroupedCommand, CommandId::MixRampGrouped>(node_id)};
cmd.buffer_count = buffer_count;
for (s32 i = 0; i < buffer_count; i++) {
cmd.inputs[i] = input_index;
cmd.outputs[i] = output_index++;
cmd.prev_volumes[i] = prev_volumes[i];
cmd.volumes[i] = volumes[i];
}
cmd.previous_samples = prev_samples;
cmd.precision = precision;
GenerateEnd<MixRampGroupedCommand>(cmd);
}
void CommandBuffer::GenerateDepopPrepareCommand(const s32 node_id, const VoiceState& voice_state,
std::span<const s32> buffer, const s16 buffer_count,
s16 buffer_offset, const bool was_playing) {
auto& cmd{GenerateStart<DepopPrepareCommand, CommandId::DepopPrepare>(node_id)};
cmd.enabled = was_playing;
for (u32 i = 0; i < MaxMixBuffers; i++) {
cmd.inputs[i] = buffer_offset++;
}
cmd.previous_samples = memory_pool->Translate(CpuAddr(voice_state.previous_samples.data()),
MaxMixBuffers * sizeof(s32));
cmd.buffer_count = buffer_count;
cmd.depop_buffer = memory_pool->Translate(CpuAddr(buffer.data()), buffer_count * sizeof(s32));
GenerateEnd<DepopPrepareCommand>(cmd);
}
void CommandBuffer::GenerateDepopForMixBuffersCommand(const s32 node_id, const MixInfo& mix_info,
std::span<const s32> depop_buffer) {
auto& cmd{GenerateStart<DepopForMixBuffersCommand, CommandId::DepopForMixBuffers>(node_id)};
cmd.input = mix_info.buffer_offset;
cmd.count = mix_info.buffer_count;
cmd.decay = mix_info.sample_rate == TargetSampleRate ? 0.96218872f : 0.94369507f;
cmd.depop_buffer =
memory_pool->Translate(CpuAddr(depop_buffer.data()), mix_info.buffer_count * sizeof(s32));
GenerateEnd<DepopForMixBuffersCommand>(cmd);
}
void CommandBuffer::GenerateDelayCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 buffer_offset) {
auto& cmd{GenerateStart<DelayCommand, CommandId::Delay>(node_id)};
const auto& parameter{
*reinterpret_cast<DelayInfo::ParameterVersion1*>(effect_info.GetParameter())};
const auto state{effect_info.GetStateBuffer()};
if (IsChannelCountValid(parameter.channel_count)) {
const auto state_buffer{memory_pool->Translate(CpuAddr(state), sizeof(DelayInfo::State))};
if (state_buffer) {
for (s16 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
if (!behavior->IsDelayChannelMappingChanged() && parameter.channel_count == 6) {
UseOldChannelMapping(cmd.inputs, cmd.outputs);
}
cmd.parameter = parameter;
cmd.effect_enabled = effect_info.IsEnabled();
cmd.state = state_buffer;
cmd.workbuffer = effect_info.GetWorkbuffer(-1);
}
}
GenerateEnd<DelayCommand>(cmd);
}
void CommandBuffer::GenerateUpsampleCommand(const s32 node_id, const s16 buffer_offset,
UpsamplerInfo& upsampler_info, const u32 input_count,
std::span<const s8> inputs, const s16 buffer_count,
const u32 sample_count_, const u32 sample_rate_) {
auto& cmd{GenerateStart<UpsampleCommand, CommandId::Upsample>(node_id)};
cmd.samples_buffer = memory_pool->Translate(upsampler_info.samples_pos,
upsampler_info.sample_count * sizeof(s32));
cmd.inputs = memory_pool->Translate(CpuAddr(upsampler_info.inputs.data()), MaxChannels);
cmd.buffer_count = buffer_count;
cmd.unk_20 = 0;
cmd.source_sample_count = sample_count_;
cmd.source_sample_rate = sample_rate_;
upsampler_info.input_count = input_count;
for (u32 i = 0; i < input_count; i++) {
upsampler_info.inputs[i] = buffer_offset + inputs[i];
}
cmd.upsampler_info = memory_pool->Translate(CpuAddr(&upsampler_info), sizeof(UpsamplerInfo));
GenerateEnd<UpsampleCommand>(cmd);
}
void CommandBuffer::GenerateDownMix6chTo2chCommand(const s32 node_id, std::span<const s8> inputs,
const s16 buffer_offset,
std::span<const f32> downmix_coeff) {
auto& cmd{GenerateStart<DownMix6chTo2chCommand, CommandId::DownMix6chTo2ch>(node_id)};
for (u32 i = 0; i < MaxChannels; i++) {
cmd.inputs[i] = buffer_offset + inputs[i];
cmd.outputs[i] = buffer_offset + inputs[i];
}
for (u32 i = 0; i < 4; i++) {
cmd.down_mix_coeff[i] = downmix_coeff[i];
}
GenerateEnd<DownMix6chTo2chCommand>(cmd);
}
void CommandBuffer::GenerateAuxCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 input_index, const s16 output_index,
const s16 buffer_offset, const u32 update_count,
const u32 count_max, const u32 write_offset) {
auto& cmd{GenerateStart<AuxCommand, CommandId::Aux>(node_id)};
if (effect_info.GetSendBuffer() != 0 && effect_info.GetReturnBuffer() != 0) {
cmd.input = buffer_offset + input_index;
cmd.output = buffer_offset + output_index;
cmd.send_buffer_info = effect_info.GetSendBufferInfo();
cmd.send_buffer = effect_info.GetSendBuffer();
cmd.return_buffer_info = effect_info.GetReturnBufferInfo();
cmd.return_buffer = effect_info.GetReturnBuffer();
cmd.count_max = count_max;
cmd.write_offset = write_offset;
cmd.update_count = update_count;
cmd.effect_enabled = effect_info.IsEnabled();
}
GenerateEnd<AuxCommand>(cmd);
}
void CommandBuffer::GenerateDeviceSinkCommand(const s32 node_id, const s16 buffer_offset,
SinkInfoBase& sink_info, const u32 session_id,
std::span<s32> samples_buffer) {
auto& cmd{GenerateStart<DeviceSinkCommand, CommandId::DeviceSink>(node_id)};
const auto& parameter{
*reinterpret_cast<DeviceSinkInfo::DeviceInParameter*>(sink_info.GetParameter())};
auto state{*reinterpret_cast<DeviceSinkInfo::DeviceState*>(sink_info.GetState())};
cmd.session_id = session_id;
if (state.upsampler_info != nullptr) {
const auto size_{state.upsampler_info->sample_count * parameter.input_count};
const auto size_bytes{size_ * sizeof(s32)};
const auto addr{memory_pool->Translate(state.upsampler_info->samples_pos, size_bytes)};
cmd.sample_buffer = {reinterpret_cast<s32*>(addr),
parameter.input_count * state.upsampler_info->sample_count};
} else {
cmd.sample_buffer = samples_buffer;
}
cmd.input_count = parameter.input_count;
for (u32 i = 0; i < parameter.input_count; i++) {
cmd.inputs[i] = buffer_offset + parameter.inputs[i];
}
GenerateEnd<DeviceSinkCommand>(cmd);
}
void CommandBuffer::GenerateCircularBufferSinkCommand(const s32 node_id, SinkInfoBase& sink_info,
const s16 buffer_offset) {
auto& cmd{GenerateStart<CircularBufferSinkCommand, CommandId::CircularBufferSink>(node_id)};
const auto& parameter{*reinterpret_cast<CircularBufferSinkInfo::CircularBufferInParameter*>(
sink_info.GetParameter())};
auto state{
*reinterpret_cast<CircularBufferSinkInfo::CircularBufferState*>(sink_info.GetState())};
cmd.input_count = parameter.input_count;
for (u32 i = 0; i < parameter.input_count; i++) {
cmd.inputs[i] = buffer_offset + parameter.inputs[i];
}
cmd.address = state.address_info.GetReference(true);
cmd.size = parameter.size;
cmd.pos = state.current_pos;
GenerateEnd<CircularBufferSinkCommand>(cmd);
}
void CommandBuffer::GenerateReverbCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 buffer_offset,
const bool long_size_pre_delay_supported) {
auto& cmd{GenerateStart<ReverbCommand, CommandId::Reverb>(node_id)};
const auto& parameter{
*reinterpret_cast<ReverbInfo::ParameterVersion2*>(effect_info.GetParameter())};
const auto state{effect_info.GetStateBuffer()};
if (IsChannelCountValid(parameter.channel_count)) {
const auto state_buffer{memory_pool->Translate(CpuAddr(state), sizeof(ReverbInfo::State))};
if (state_buffer) {
for (s16 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
if (!behavior->IsReverbChannelMappingChanged() && parameter.channel_count == 6) {
UseOldChannelMapping(cmd.inputs, cmd.outputs);
}
cmd.parameter = parameter;
cmd.effect_enabled = effect_info.IsEnabled();
cmd.state = state_buffer;
cmd.workbuffer = effect_info.GetWorkbuffer(-1);
cmd.long_size_pre_delay_supported = long_size_pre_delay_supported;
}
}
GenerateEnd<ReverbCommand>(cmd);
}
void CommandBuffer::GenerateI3dl2ReverbCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 buffer_offset) {
auto& cmd{GenerateStart<I3dl2ReverbCommand, CommandId::I3dl2Reverb>(node_id)};
const auto& parameter{
*reinterpret_cast<I3dl2ReverbInfo::ParameterVersion1*>(effect_info.GetParameter())};
const auto state{effect_info.GetStateBuffer()};
if (IsChannelCountValid(parameter.channel_count)) {
const auto state_buffer{
memory_pool->Translate(CpuAddr(state), sizeof(I3dl2ReverbInfo::State))};
if (state_buffer) {
for (s16 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
if (!behavior->IsI3dl2ReverbChannelMappingChanged() && parameter.channel_count == 6) {
UseOldChannelMapping(cmd.inputs, cmd.outputs);
}
cmd.parameter = parameter;
cmd.effect_enabled = effect_info.IsEnabled();
cmd.state = state_buffer;
cmd.workbuffer = effect_info.GetWorkbuffer(-1);
}
}
GenerateEnd<I3dl2ReverbCommand>(cmd);
}
void CommandBuffer::GeneratePerformanceCommand(const s32 node_id, const PerformanceState state,
const PerformanceEntryAddresses& entry_addresses) {
auto& cmd{GenerateStart<PerformanceCommand, CommandId::Performance>(node_id)};
cmd.state = state;
cmd.entry_address = entry_addresses;
GenerateEnd<PerformanceCommand>(cmd);
}
void CommandBuffer::GenerateClearMixCommand(const s32 node_id) {
auto& cmd{GenerateStart<ClearMixBufferCommand, CommandId::ClearMixBuffer>(node_id)};
GenerateEnd<ClearMixBufferCommand>(cmd);
}
void CommandBuffer::GenerateCopyMixBufferCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 buffer_offset, const s8 channel) {
auto& cmd{GenerateStart<CopyMixBufferCommand, CommandId::CopyMixBuffer>(node_id)};
const auto& parameter{
*reinterpret_cast<BiquadFilterInfo::ParameterVersion1*>(effect_info.GetParameter())};
cmd.input_index = buffer_offset + parameter.inputs[channel];
cmd.output_index = buffer_offset + parameter.outputs[channel];
GenerateEnd<CopyMixBufferCommand>(cmd);
}
void CommandBuffer::GenerateLightLimiterCommand(
const s32 node_id, const s16 buffer_offset,
const LightLimiterInfo::ParameterVersion1& parameter, const LightLimiterInfo::State& state,
const bool enabled, const CpuAddr workbuffer) {
auto& cmd{GenerateStart<LightLimiterVersion1Command, CommandId::LightLimiterVersion1>(node_id)};
if (IsChannelCountValid(parameter.channel_count)) {
const auto state_buffer{
memory_pool->Translate(CpuAddr(&state), sizeof(LightLimiterInfo::State))};
if (state_buffer) {
for (s8 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
std::memcpy(&cmd.parameter, &parameter, sizeof(LightLimiterInfo::ParameterVersion1));
cmd.effect_enabled = enabled;
cmd.state = state_buffer;
cmd.workbuffer = workbuffer;
}
}
GenerateEnd<LightLimiterVersion1Command>(cmd);
}
void CommandBuffer::GenerateLightLimiterCommand(
const s32 node_id, const s16 buffer_offset,
const LightLimiterInfo::ParameterVersion2& parameter,
const LightLimiterInfo::StatisticsInternal& statistics, const LightLimiterInfo::State& state,
const bool enabled, const CpuAddr workbuffer) {
auto& cmd{GenerateStart<LightLimiterVersion2Command, CommandId::LightLimiterVersion2>(node_id)};
if (IsChannelCountValid(parameter.channel_count)) {
const auto state_buffer{
memory_pool->Translate(CpuAddr(&state), sizeof(LightLimiterInfo::State))};
if (state_buffer) {
for (s8 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
cmd.parameter = parameter;
cmd.effect_enabled = enabled;
cmd.state = state_buffer;
if (cmd.parameter.statistics_enabled) {
cmd.result_state = memory_pool->Translate(
CpuAddr(&statistics), sizeof(LightLimiterInfo::StatisticsInternal));
} else {
cmd.result_state = 0;
}
cmd.workbuffer = workbuffer;
}
}
GenerateEnd<LightLimiterVersion2Command>(cmd);
}
void CommandBuffer::GenerateMultitapBiquadFilterCommand(const s32 node_id, VoiceInfo& voice_info,
const VoiceState& voice_state,
const s16 buffer_count, const s8 channel) {
auto& cmd{GenerateStart<MultiTapBiquadFilterCommand, CommandId::MultiTapBiquadFilter>(node_id)};
cmd.input = buffer_count + channel;
cmd.output = buffer_count + channel;
cmd.biquads = voice_info.biquads;
cmd.states[0] =
memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
cmd.states[1] =
memory_pool->Translate(CpuAddr(voice_state.biquad_states[1].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
cmd.needs_init[0] = !voice_info.biquad_initialized[0];
cmd.needs_init[1] = !voice_info.biquad_initialized[1];
cmd.filter_tap_count = MaxBiquadFilters;
GenerateEnd<MultiTapBiquadFilterCommand>(cmd);
}
void CommandBuffer::GenerateCaptureCommand(const s32 node_id, EffectInfoBase& effect_info,
const s16 input_index, const s16 output_index,
const s16 buffer_offset, const u32 update_count,
const u32 count_max, const u32 write_offset) {
auto& cmd{GenerateStart<CaptureCommand, CommandId::Capture>(node_id)};
if (effect_info.GetSendBuffer()) {
cmd.input = buffer_offset + input_index;
cmd.output = buffer_offset + output_index;
cmd.send_buffer_info = effect_info.GetSendBufferInfo();
cmd.send_buffer = effect_info.GetSendBuffer();
cmd.count_max = count_max;
cmd.write_offset = write_offset;
cmd.update_count = update_count;
cmd.effect_enabled = effect_info.IsEnabled();
}
GenerateEnd<CaptureCommand>(cmd);
}
void CommandBuffer::GenerateCompressorCommand(s16 buffer_offset, EffectInfoBase& effect_info,
s32 node_id) {
auto& cmd{GenerateStart<CompressorCommand, CommandId::Compressor>(node_id)};
auto& parameter{
*reinterpret_cast<CompressorInfo::ParameterVersion2*>(effect_info.GetParameter())};
auto state{reinterpret_cast<CompressorInfo::State*>(effect_info.GetStateBuffer())};
if (IsChannelCountValid(parameter.channel_count)) {
auto state_buffer{memory_pool->Translate(CpuAddr(state), sizeof(CompressorInfo::State))};
if (state_buffer) {
for (u16 channel = 0; channel < parameter.channel_count; channel++) {
cmd.inputs[channel] = buffer_offset + parameter.inputs[channel];
cmd.outputs[channel] = buffer_offset + parameter.outputs[channel];
}
cmd.parameter = parameter;
cmd.workbuffer = state_buffer;
cmd.enabled = effect_info.IsEnabled();
}
}
GenerateEnd<CompressorCommand>(cmd);
}
} // namespace AudioCore::AudioRenderer