mirror of
https://github.com/yuzu-emu/yuzu-android.git
synced 2025-06-20 02:27:52 -05:00
Project Andio
This commit is contained in:
93
src/audio_core/renderer/effect/aux_.cpp
Normal file
93
src/audio_core/renderer/effect/aux_.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/aux_.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void AuxInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
const bool send_unmapped{!pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_specific->send_buffer_info_address,
|
||||
sizeof(AuxBufferInfo) + in_specific->count_max * sizeof(s32))};
|
||||
const bool return_unmapped{!pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[1], in_specific->return_buffer_info_address,
|
||||
sizeof(AuxBufferInfo) + in_specific->count_max * sizeof(s32))};
|
||||
|
||||
buffer_unmapped = send_unmapped || return_unmapped;
|
||||
|
||||
if (!buffer_unmapped) {
|
||||
auto send{workbuffers[0].GetReference(false)};
|
||||
send_buffer_info = send + sizeof(AuxInfoDsp);
|
||||
send_buffer = send + sizeof(AuxBufferInfo);
|
||||
|
||||
auto ret{workbuffers[1].GetReference(false)};
|
||||
return_buffer_info = ret + sizeof(AuxInfoDsp);
|
||||
return_buffer = ret + sizeof(AuxBufferInfo);
|
||||
}
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AuxInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion2));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
const bool send_unmapped{!pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], params->send_buffer_info_address,
|
||||
sizeof(AuxBufferInfo) + params->count_max * sizeof(s32))};
|
||||
const bool return_unmapped{!pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[1], params->return_buffer_info_address,
|
||||
sizeof(AuxBufferInfo) + params->count_max * sizeof(s32))};
|
||||
|
||||
buffer_unmapped = send_unmapped || return_unmapped;
|
||||
|
||||
if (!buffer_unmapped) {
|
||||
auto send{workbuffers[0].GetReference(false)};
|
||||
send_buffer_info = send + sizeof(AuxInfoDsp);
|
||||
send_buffer = send + sizeof(AuxBufferInfo);
|
||||
|
||||
auto ret{workbuffers[1].GetReference(false)};
|
||||
return_buffer_info = ret + sizeof(AuxInfoDsp);
|
||||
return_buffer = ret + sizeof(AuxBufferInfo);
|
||||
}
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AuxInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
}
|
||||
|
||||
void AuxInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void AuxInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
|
||||
|
||||
CpuAddr AuxInfo::GetWorkbuffer(s32 index) {
|
||||
return workbuffers[index].GetReference(true);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
123
src/audio_core/renderer/effect/aux_.h
Normal file
123
src/audio_core/renderer/effect/aux_.h
Normal file
@ -0,0 +1,123 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
* Auxiliary Buffer used for Aux commands.
|
||||
* Send and return buffers are available (names from the game's perspective).
|
||||
* Send is read by the host, containing a buffer of samples to be used for whatever purpose.
|
||||
* Return is written by the host, writing a mix buffer back to the game.
|
||||
* This allows the game to use pre-processed samples skipping the other render processing,
|
||||
* and to examine or modify what the audio renderer has generated.
|
||||
*/
|
||||
class AuxInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
|
||||
/* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
|
||||
/* 0x30 */ u32 mix_buffer_count;
|
||||
/* 0x34 */ u32 sample_rate;
|
||||
/* 0x38 */ u32 count_max;
|
||||
/* 0x3C */ u32 mix_buffer_count_max;
|
||||
/* 0x40 */ CpuAddr send_buffer_info_address;
|
||||
/* 0x48 */ CpuAddr send_buffer_address;
|
||||
/* 0x50 */ CpuAddr return_buffer_info_address;
|
||||
/* 0x58 */ CpuAddr return_buffer_address;
|
||||
/* 0x60 */ u32 mix_buffer_sample_size;
|
||||
/* 0x64 */ u32 sample_count;
|
||||
/* 0x68 */ u32 mix_buffer_sample_count;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"AuxInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
|
||||
/* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
|
||||
/* 0x30 */ u32 mix_buffer_count;
|
||||
/* 0x34 */ u32 sample_rate;
|
||||
/* 0x38 */ u32 count_max;
|
||||
/* 0x3C */ u32 mix_buffer_count_max;
|
||||
/* 0x40 */ CpuAddr send_buffer_info_address;
|
||||
/* 0x48 */ CpuAddr send_buffer_address;
|
||||
/* 0x50 */ CpuAddr return_buffer_info_address;
|
||||
/* 0x58 */ CpuAddr return_buffer_address;
|
||||
/* 0x60 */ u32 mix_buffer_sample_size;
|
||||
/* 0x64 */ u32 sample_count;
|
||||
/* 0x68 */ u32 mix_buffer_sample_count;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"AuxInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
struct AuxInfoDsp {
|
||||
/* 0x00 */ u32 read_offset;
|
||||
/* 0x04 */ u32 write_offset;
|
||||
/* 0x08 */ u32 lost_sample_count;
|
||||
/* 0x0C */ u32 total_sample_count;
|
||||
/* 0x10 */ char unk10[0x30];
|
||||
};
|
||||
static_assert(sizeof(AuxInfoDsp) == 0x40, "AuxInfo::AuxInfoDsp has the wrong size!");
|
||||
|
||||
struct AuxBufferInfo {
|
||||
/* 0x00 */ AuxInfoDsp cpu_info;
|
||||
/* 0x40 */ AuxInfoDsp dsp_info;
|
||||
};
|
||||
static_assert(sizeof(AuxBufferInfo) == 0x80, "AuxInfo::AuxBufferInfo has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
52
src/audio_core/renderer/effect/biquad_filter.cpp
Normal file
52
src/audio_core/renderer/effect/biquad_filter.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/biquad_filter.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void BiquadFilterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void BiquadFilterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion2));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void BiquadFilterInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
}
|
||||
|
||||
void BiquadFilterInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void BiquadFilterInfo::UpdateResultState(EffectResultState& cpu_state,
|
||||
EffectResultState& dsp_state) {}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
79
src/audio_core/renderer/effect/biquad_filter.h
Normal file
79
src/audio_core/renderer/effect/biquad_filter.h
Normal file
@ -0,0 +1,79 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class BiquadFilterInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ std::array<s16, 3> b;
|
||||
/* 0x12 */ std::array<s16, 2> a;
|
||||
/* 0x16 */ s8 channel_count;
|
||||
/* 0x17 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"BiquadFilterInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ std::array<s16, 3> b;
|
||||
/* 0x12 */ std::array<s16, 2> a;
|
||||
/* 0x16 */ s8 channel_count;
|
||||
/* 0x17 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"BiquadFilterInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
49
src/audio_core/renderer/effect/buffer_mixer.cpp
Normal file
49
src/audio_core/renderer/effect/buffer_mixer.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/buffer_mixer.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void BufferMixerInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void BufferMixerInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion2));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void BufferMixerInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
}
|
||||
|
||||
void BufferMixerInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void BufferMixerInfo::UpdateResultState(EffectResultState& cpu_state,
|
||||
EffectResultState& dsp_state) {}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
75
src/audio_core/renderer/effect/buffer_mixer.h
Normal file
75
src/audio_core/renderer/effect/buffer_mixer.h
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class BufferMixerInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
|
||||
/* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
|
||||
/* 0x30 */ std::array<f32, MaxMixBuffers> volumes;
|
||||
/* 0x90 */ u32 mix_count;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"BufferMixerInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
|
||||
/* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
|
||||
/* 0x30 */ std::array<f32, MaxMixBuffers> volumes;
|
||||
/* 0x90 */ u32 mix_count;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"BufferMixerInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
82
src/audio_core/renderer/effect/capture.cpp
Normal file
82
src/audio_core/renderer/effect/capture.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/aux_.h"
|
||||
#include "audio_core/renderer/effect/capture.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void CaptureInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{
|
||||
reinterpret_cast<const AuxInfo::ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<AuxInfo::ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(AuxInfo::ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_specific->send_buffer_info_address,
|
||||
in_specific->count_max * sizeof(s32) + sizeof(AuxInfo::AuxBufferInfo));
|
||||
|
||||
if (!buffer_unmapped) {
|
||||
const auto send_address{workbuffers[0].GetReference(false)};
|
||||
send_buffer_info = send_address + sizeof(AuxInfo::AuxInfoDsp);
|
||||
send_buffer = send_address + sizeof(AuxInfo::AuxBufferInfo);
|
||||
return_buffer_info = 0;
|
||||
return_buffer = 0;
|
||||
}
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{
|
||||
reinterpret_cast<const AuxInfo::ParameterVersion2*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<AuxInfo::ParameterVersion2*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(AuxInfo::ParameterVersion2));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], params->send_buffer_info_address,
|
||||
params->count_max * sizeof(s32) + sizeof(AuxInfo::AuxBufferInfo));
|
||||
|
||||
if (!buffer_unmapped) {
|
||||
const auto send_address{workbuffers[0].GetReference(false)};
|
||||
send_buffer_info = send_address + sizeof(AuxInfo::AuxInfoDsp);
|
||||
send_buffer = send_address + sizeof(AuxInfo::AuxBufferInfo);
|
||||
return_buffer_info = 0;
|
||||
return_buffer = 0;
|
||||
}
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
}
|
||||
|
||||
void CaptureInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void CaptureInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
|
||||
|
||||
CpuAddr CaptureInfo::GetWorkbuffer(s32 index) {
|
||||
return workbuffers[index].GetReference(true);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
65
src/audio_core/renderer/effect/capture.h
Normal file
65
src/audio_core/renderer/effect/capture.h
Normal file
@ -0,0 +1,65 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class CaptureInfo : public EffectInfoBase {
|
||||
public:
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
40
src/audio_core/renderer/effect/compressor.cpp
Normal file
40
src/audio_core/renderer/effect/compressor.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/compressor.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void CompressorInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {}
|
||||
|
||||
void CompressorInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void CompressorInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
}
|
||||
|
||||
CpuAddr CompressorInfo::GetWorkbuffer(s32 index) {
|
||||
return GetSingleBuffer(index);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
106
src/audio_core/renderer/effect/compressor.h
Normal file
106
src/audio_core/renderer/effect/compressor.h
Normal file
@ -0,0 +1,106 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fixed_point.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class CompressorInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ s16 channel_count_max;
|
||||
/* 0x0E */ s16 channel_count;
|
||||
/* 0x10 */ s32 sample_rate;
|
||||
/* 0x14 */ f32 threshold;
|
||||
/* 0x18 */ f32 compressor_ratio;
|
||||
/* 0x1C */ s32 attack_time;
|
||||
/* 0x20 */ s32 release_time;
|
||||
/* 0x24 */ f32 unk_24;
|
||||
/* 0x28 */ f32 unk_28;
|
||||
/* 0x2C */ f32 unk_2C;
|
||||
/* 0x30 */ f32 out_gain;
|
||||
/* 0x34 */ ParameterState state;
|
||||
/* 0x35 */ bool makeup_gain_enabled;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"CompressorInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ s16 channel_count_max;
|
||||
/* 0x0E */ s16 channel_count;
|
||||
/* 0x10 */ s32 sample_rate;
|
||||
/* 0x14 */ f32 threshold;
|
||||
/* 0x18 */ f32 compressor_ratio;
|
||||
/* 0x1C */ s32 attack_time;
|
||||
/* 0x20 */ s32 release_time;
|
||||
/* 0x24 */ f32 unk_24;
|
||||
/* 0x28 */ f32 unk_28;
|
||||
/* 0x2C */ f32 unk_2C;
|
||||
/* 0x30 */ f32 out_gain;
|
||||
/* 0x34 */ ParameterState state;
|
||||
/* 0x35 */ bool makeup_gain_enabled;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"CompressorInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
struct State {
|
||||
f32 unk_00;
|
||||
f32 unk_04;
|
||||
f32 unk_08;
|
||||
f32 unk_0C;
|
||||
f32 unk_10;
|
||||
f32 unk_14;
|
||||
f32 unk_18;
|
||||
f32 makeup_gain;
|
||||
f32 unk_20;
|
||||
char unk_24[0x1C];
|
||||
};
|
||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||
"CompressorInfo::State has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Get a workbuffer assigned to this effect with the given index.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
93
src/audio_core/renderer/effect/delay.cpp
Normal file
93
src/audio_core/renderer/effect/delay.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/delay.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void DelayInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void DelayInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void DelayInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
}
|
||||
|
||||
void DelayInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void DelayInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
|
||||
|
||||
CpuAddr DelayInfo::GetWorkbuffer(s32 index) {
|
||||
return GetSingleBuffer(index);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
135
src/audio_core/renderer/effect/delay.h
Normal file
135
src/audio_core/renderer/effect/delay.h
Normal file
@ -0,0 +1,135 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fixed_point.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class DelayInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x10 */ u32 delay_time_max;
|
||||
/* 0x14 */ u32 delay_time;
|
||||
/* 0x18 */ Common::FixedPoint<18, 14> sample_rate;
|
||||
/* 0x1C */ Common::FixedPoint<18, 14> in_gain;
|
||||
/* 0x20 */ Common::FixedPoint<18, 14> feedback_gain;
|
||||
/* 0x24 */ Common::FixedPoint<18, 14> wet_gain;
|
||||
/* 0x28 */ Common::FixedPoint<18, 14> dry_gain;
|
||||
/* 0x2C */ Common::FixedPoint<18, 14> channel_spread;
|
||||
/* 0x30 */ Common::FixedPoint<18, 14> lowpass_amount;
|
||||
/* 0x34 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"DelayInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ s16 channel_count_max;
|
||||
/* 0x0E */ s16 channel_count;
|
||||
/* 0x10 */ s32 delay_time_max;
|
||||
/* 0x14 */ s32 delay_time;
|
||||
/* 0x18 */ s32 sample_rate;
|
||||
/* 0x1C */ s32 in_gain;
|
||||
/* 0x20 */ s32 feedback_gain;
|
||||
/* 0x24 */ s32 wet_gain;
|
||||
/* 0x28 */ s32 dry_gain;
|
||||
/* 0x2C */ s32 channel_spread;
|
||||
/* 0x30 */ s32 lowpass_amount;
|
||||
/* 0x34 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"DelayInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
struct DelayLine {
|
||||
Common::FixedPoint<50, 14> Read() const {
|
||||
return buffer[buffer_pos];
|
||||
}
|
||||
|
||||
void Write(const Common::FixedPoint<50, 14> value) {
|
||||
buffer[buffer_pos] = value;
|
||||
buffer_pos = static_cast<u32>((buffer_pos + 1) % buffer.size());
|
||||
}
|
||||
|
||||
s32 sample_count_max{};
|
||||
s32 sample_count{};
|
||||
std::vector<Common::FixedPoint<50, 14>> buffer{};
|
||||
u32 buffer_pos{};
|
||||
Common::FixedPoint<18, 14> decay_rate{};
|
||||
};
|
||||
|
||||
struct State {
|
||||
/* 0x000 */ std::array<s32, 8> unk_000;
|
||||
/* 0x020 */ std::array<DelayLine, MaxChannels> delay_lines;
|
||||
/* 0x0B0 */ Common::FixedPoint<18, 14> feedback_gain;
|
||||
/* 0x0B4 */ Common::FixedPoint<18, 14> delay_feedback_gain;
|
||||
/* 0x0B8 */ Common::FixedPoint<18, 14> delay_feedback_cross_gain;
|
||||
/* 0x0BC */ Common::FixedPoint<18, 14> lowpass_gain;
|
||||
/* 0x0C0 */ Common::FixedPoint<18, 14> lowpass_feedback_gain;
|
||||
/* 0x0C4 */ std::array<Common::FixedPoint<50, 14>, MaxChannels> lowpass_z;
|
||||
};
|
||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||
"DelayInfo::State has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
41
src/audio_core/renderer/effect/effect_context.cpp
Normal file
41
src/audio_core/renderer/effect/effect_context.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/effect_context.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void EffectContext::Initialize(std::span<EffectInfoBase> effect_infos_, const u32 effect_count_,
|
||||
std::span<EffectResultState> result_states_cpu_,
|
||||
std::span<EffectResultState> result_states_dsp_,
|
||||
const size_t dsp_state_count_) {
|
||||
effect_infos = effect_infos_;
|
||||
effect_count = effect_count_;
|
||||
result_states_cpu = result_states_cpu_;
|
||||
result_states_dsp = result_states_dsp_;
|
||||
dsp_state_count = dsp_state_count_;
|
||||
}
|
||||
|
||||
EffectInfoBase& EffectContext::GetInfo(const u32 index) {
|
||||
return effect_infos[index];
|
||||
}
|
||||
|
||||
EffectResultState& EffectContext::GetResultState(const u32 index) {
|
||||
return result_states_cpu[index];
|
||||
}
|
||||
|
||||
EffectResultState& EffectContext::GetDspSharedResultState(const u32 index) {
|
||||
return result_states_dsp[index];
|
||||
}
|
||||
|
||||
u32 EffectContext::GetCount() const {
|
||||
return effect_count;
|
||||
}
|
||||
|
||||
void EffectContext::UpdateStateByDspShared() {
|
||||
for (size_t i = 0; i < dsp_state_count; i++) {
|
||||
effect_infos[i].UpdateResultState(result_states_cpu[i], result_states_dsp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
75
src/audio_core/renderer/effect/effect_context.h
Normal file
75
src/audio_core/renderer/effect/effect_context.h
Normal file
@ -0,0 +1,75 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "audio_core/renderer/effect/effect_result_state.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class EffectContext {
|
||||
public:
|
||||
/**
|
||||
* Initialize the effect context
|
||||
* @param effect_infos List of effect infos for this context
|
||||
* @param effect_count The number of effects in the list
|
||||
* @param result_states_cpu The workbuffer of result states for the CPU for this context
|
||||
* @param result_states_dsp The workbuffer of result states for the DSP for this context
|
||||
* @param state_count The number of result states
|
||||
*/
|
||||
void Initialize(std::span<EffectInfoBase> effect_infos_, const u32 effect_count_,
|
||||
std::span<EffectResultState> result_states_cpu_,
|
||||
std::span<EffectResultState> result_states_dsp_, const size_t dsp_state_count);
|
||||
|
||||
/**
|
||||
* Get the EffectInfo for a given index
|
||||
* @param index Which effect to return
|
||||
* @return Pointer to the effect
|
||||
*/
|
||||
EffectInfoBase& GetInfo(const u32 index);
|
||||
|
||||
/**
|
||||
* Get the CPU result state for a given index
|
||||
* @param index Which result to return
|
||||
* @return Pointer to the effect result state
|
||||
*/
|
||||
EffectResultState& GetResultState(const u32 index);
|
||||
|
||||
/**
|
||||
* Get the DSP result state for a given index
|
||||
* @param index Which result to return
|
||||
* @return Pointer to the effect result state
|
||||
*/
|
||||
EffectResultState& GetDspSharedResultState(const u32 index);
|
||||
|
||||
/**
|
||||
* Get the number of effects in this context
|
||||
* @return The number of effects
|
||||
*/
|
||||
u32 GetCount() const;
|
||||
|
||||
/**
|
||||
* Update the CPU and DSP result states for all effects
|
||||
*/
|
||||
void UpdateStateByDspShared();
|
||||
|
||||
private:
|
||||
/// Workbuffer for all of the effects
|
||||
std::span<EffectInfoBase> effect_infos{};
|
||||
/// Number of effects in the workbuffer
|
||||
u32 effect_count{};
|
||||
/// Workbuffer of states for all effects, kept host-side and not directly modified, dsp states
|
||||
/// are copied here on the next render frame
|
||||
std::span<EffectResultState> result_states_cpu{};
|
||||
/// Workbuffer of states for all effects, used by the AudioRenderer to track effect state
|
||||
/// between calls
|
||||
std::span<EffectResultState> result_states_dsp{};
|
||||
/// Number of result states in the workbuffers
|
||||
size_t dsp_state_count{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
435
src/audio_core/renderer/effect/effect_info_base.h
Normal file
435
src/audio_core/renderer/effect/effect_info_base.h
Normal file
@ -0,0 +1,435 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/behavior/behavior_info.h"
|
||||
#include "audio_core/renderer/effect/effect_result_state.h"
|
||||
#include "audio_core/renderer/memory/address_info.h"
|
||||
#include "audio_core/renderer/memory/pool_mapper.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
* Base of all effects. Holds various data and functions used for all derived effects.
|
||||
* Should not be used directly.
|
||||
*/
|
||||
class EffectInfoBase {
|
||||
public:
|
||||
enum class Type : u8 {
|
||||
Invalid,
|
||||
Mix,
|
||||
Aux,
|
||||
Delay,
|
||||
Reverb,
|
||||
I3dl2Reverb,
|
||||
BiquadFilter,
|
||||
LightLimiter,
|
||||
Capture,
|
||||
Compressor,
|
||||
};
|
||||
|
||||
enum class UsageState {
|
||||
Invalid,
|
||||
New,
|
||||
Enabled,
|
||||
Disabled,
|
||||
};
|
||||
|
||||
enum class OutStatus : u8 {
|
||||
Invalid,
|
||||
New,
|
||||
Initialized,
|
||||
Used,
|
||||
Removed,
|
||||
};
|
||||
|
||||
enum class ParameterState : u8 {
|
||||
Initialized,
|
||||
Updating,
|
||||
Updated,
|
||||
};
|
||||
|
||||
struct InParameterVersion1 {
|
||||
/* 0x00 */ Type type;
|
||||
/* 0x01 */ bool is_new;
|
||||
/* 0x02 */ bool enabled;
|
||||
/* 0x04 */ u32 mix_id;
|
||||
/* 0x08 */ CpuAddr workbuffer;
|
||||
/* 0x10 */ CpuAddr workbuffer_size;
|
||||
/* 0x18 */ u32 process_order;
|
||||
/* 0x1C */ char unk1C[0x4];
|
||||
/* 0x20 */ std::array<u8, 0xA0> specific;
|
||||
};
|
||||
static_assert(sizeof(InParameterVersion1) == 0xC0,
|
||||
"EffectInfoBase::InParameterVersion1 has the wrong size!");
|
||||
|
||||
struct InParameterVersion2 {
|
||||
/* 0x00 */ Type type;
|
||||
/* 0x01 */ bool is_new;
|
||||
/* 0x02 */ bool enabled;
|
||||
/* 0x04 */ u32 mix_id;
|
||||
/* 0x08 */ CpuAddr workbuffer;
|
||||
/* 0x10 */ CpuAddr workbuffer_size;
|
||||
/* 0x18 */ u32 process_order;
|
||||
/* 0x1C */ char unk1C[0x4];
|
||||
/* 0x20 */ std::array<u8, 0xA0> specific;
|
||||
};
|
||||
static_assert(sizeof(InParameterVersion2) == 0xC0,
|
||||
"EffectInfoBase::InParameterVersion2 has the wrong size!");
|
||||
|
||||
struct OutStatusVersion1 {
|
||||
/* 0x00 */ OutStatus state;
|
||||
/* 0x01 */ char unk01[0xF];
|
||||
};
|
||||
static_assert(sizeof(OutStatusVersion1) == 0x10,
|
||||
"EffectInfoBase::OutStatusVersion1 has the wrong size!");
|
||||
|
||||
struct OutStatusVersion2 {
|
||||
/* 0x00 */ OutStatus state;
|
||||
/* 0x01 */ char unk01[0xF];
|
||||
/* 0x10 */ EffectResultState result_state;
|
||||
};
|
||||
static_assert(sizeof(OutStatusVersion2) == 0x90,
|
||||
"EffectInfoBase::OutStatusVersion2 has the wrong size!");
|
||||
|
||||
struct State {
|
||||
std::array<u8, 0x500> buffer;
|
||||
};
|
||||
static_assert(sizeof(State) == 0x500, "EffectInfoBase::State has the wrong size!");
|
||||
|
||||
EffectInfoBase() {
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
virtual ~EffectInfoBase() = default;
|
||||
|
||||
/**
|
||||
* Cleanup this effect, resetting it to a starting state.
|
||||
*/
|
||||
void Cleanup() {
|
||||
type = Type::Invalid;
|
||||
enabled = false;
|
||||
mix_id = UnusedMixId;
|
||||
process_order = InvalidProcessOrder;
|
||||
buffer_unmapped = false;
|
||||
parameter = {};
|
||||
for (auto& workbuffer : workbuffers) {
|
||||
workbuffer.Setup(CpuAddr(0), 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcibly unmap all assigned workbuffers from the AudioRenderer.
|
||||
*
|
||||
* @param pool_mapper - Mapper to unmap the buffers.
|
||||
*/
|
||||
void ForceUnmapBuffers(const PoolMapper& pool_mapper) {
|
||||
for (auto& workbuffer : workbuffers) {
|
||||
if (workbuffer.GetReference(false) != 0) {
|
||||
pool_mapper.ForceUnmapPointer(workbuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this effect is enabled.
|
||||
*
|
||||
* @return True if effect is enabled, otherwise false.
|
||||
*/
|
||||
bool IsEnabled() const {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this effect should not be generated.
|
||||
*
|
||||
* @return True if effect should be skipped, otherwise false.
|
||||
*/
|
||||
bool ShouldSkip() const {
|
||||
return buffer_unmapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type of this effect.
|
||||
*
|
||||
* @return The type of this effect. See EffectInfoBase::Type
|
||||
*/
|
||||
Type GetType() const {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of this effect.
|
||||
*
|
||||
* @param type_ - The new type of this effect.
|
||||
*/
|
||||
void SetType(const Type type_) {
|
||||
type = type_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mix id of this effect.
|
||||
*
|
||||
* @return Mix id of this effect.
|
||||
*/
|
||||
s32 GetMixId() const {
|
||||
return mix_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the processing order of this effect.
|
||||
*
|
||||
* @return Process order of this effect.
|
||||
*/
|
||||
s32 GetProcessingOrder() const {
|
||||
return process_order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this effect's parameter data.
|
||||
*
|
||||
* @return Pointer to the parametter, must be cast to the correct type.
|
||||
*/
|
||||
u8* GetParameter() {
|
||||
return parameter.data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this effect's parameter data.
|
||||
*
|
||||
* @return Pointer to the parametter, must be cast to the correct type.
|
||||
*/
|
||||
u8* GetStateBuffer() {
|
||||
return state.data();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this effect's usage state.
|
||||
*
|
||||
* @param usage - new usage state of this effect.
|
||||
*/
|
||||
void SetUsage(const UsageState usage) {
|
||||
usage_state = usage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this effects need to have its workbuffer information updated.
|
||||
* Version 1.
|
||||
*
|
||||
* @param params - Input parameters.
|
||||
* @return True if workbuffers need updating, otherwise false.
|
||||
*/
|
||||
bool ShouldUpdateWorkBufferInfo(const InParameterVersion1& params) const {
|
||||
return buffer_unmapped || params.is_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this effects need to have its workbuffer information updated.
|
||||
* Version 2.
|
||||
*
|
||||
* @param params - Input parameters.
|
||||
* @return True if workbuffers need updating, otherwise false.
|
||||
*/
|
||||
bool ShouldUpdateWorkBufferInfo(const InParameterVersion2& params) const {
|
||||
return buffer_unmapped || params.is_new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current usage state of this effect.
|
||||
*
|
||||
* @return The current usage state.
|
||||
*/
|
||||
UsageState GetUsage() const {
|
||||
return usage_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the current state. Version 1.
|
||||
*
|
||||
* @param out_status - Status to write.
|
||||
* @param renderer_active - Is the AudioRenderer active?
|
||||
*/
|
||||
void StoreStatus(OutStatusVersion1& out_status, const bool renderer_active) const {
|
||||
if (renderer_active) {
|
||||
if (usage_state != UsageState::Disabled) {
|
||||
out_status.state = OutStatus::Used;
|
||||
} else {
|
||||
out_status.state = OutStatus::Removed;
|
||||
}
|
||||
} else if (usage_state == UsageState::New) {
|
||||
out_status.state = OutStatus::Used;
|
||||
} else {
|
||||
out_status.state = OutStatus::Removed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the current state. Version 2.
|
||||
*
|
||||
* @param out_status - Status to write.
|
||||
* @param renderer_active - Is the AudioRenderer active?
|
||||
*/
|
||||
void StoreStatus(OutStatusVersion2& out_status, const bool renderer_active) const {
|
||||
if (renderer_active) {
|
||||
if (usage_state != UsageState::Disabled) {
|
||||
out_status.state = OutStatus::Used;
|
||||
} else {
|
||||
out_status.state = OutStatus::Removed;
|
||||
}
|
||||
} else if (usage_state == UsageState::New) {
|
||||
out_status.state = OutStatus::Used;
|
||||
} else {
|
||||
out_status.state = OutStatus::Removed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
virtual void Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
[[maybe_unused]] const InParameterVersion1& params,
|
||||
[[maybe_unused]] const PoolMapper& pool_mapper) {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
virtual void Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
[[maybe_unused]] const InParameterVersion2& params,
|
||||
[[maybe_unused]] const PoolMapper& pool_mapper) {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
virtual void UpdateForCommandGeneration() {}
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
virtual void InitializeResultState([[maybe_unused]] EffectResultState& result_state) {}
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @param cpu_state - Host-side result state to update.
|
||||
* @param dsp_state - AudioRenderer-side result state to update from.
|
||||
*/
|
||||
virtual void UpdateResultState([[maybe_unused]] EffectResultState& cpu_state,
|
||||
[[maybe_unused]] EffectResultState& dsp_state) {}
|
||||
|
||||
/**
|
||||
* Get a workbuffer assigned to this effect with the given index.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
virtual CpuAddr GetWorkbuffer([[maybe_unused]] s32 index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first workbuffer assigned to this effect.
|
||||
*
|
||||
* @param index - Workbuffer index. Unused.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetSingleBuffer([[maybe_unused]] const s32 index) {
|
||||
if (enabled) {
|
||||
return workbuffers[0].GetReference(true);
|
||||
}
|
||||
|
||||
if (usage_state != UsageState::Disabled) {
|
||||
const auto ref{workbuffers[0].GetReference(false)};
|
||||
const auto size{workbuffers[0].GetSize()};
|
||||
if (ref != 0 && size > 0) {
|
||||
// Invalidate DSP cache
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the send buffer info, used by Aux and Capture.
|
||||
*
|
||||
* @return Address of the buffer info.
|
||||
*/
|
||||
CpuAddr GetSendBufferInfo() const {
|
||||
return send_buffer_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the send buffer, used by Aux and Capture.
|
||||
*
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetSendBuffer() const {
|
||||
return send_buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the return buffer info, used by Aux and Capture.
|
||||
*
|
||||
* @return Address of the buffer info.
|
||||
*/
|
||||
CpuAddr GetReturnBufferInfo() const {
|
||||
return return_buffer_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the return buffer, used by Aux and Capture.
|
||||
*
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetReturnBuffer() const {
|
||||
return return_buffer;
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Type of this effect. May be changed
|
||||
Type type{Type::Invalid};
|
||||
/// Is this effect enabled?
|
||||
bool enabled{};
|
||||
/// Are this effect's buffers unmapped?
|
||||
bool buffer_unmapped{};
|
||||
/// Current usage state
|
||||
UsageState usage_state{UsageState::Invalid};
|
||||
/// Mix id of this effect
|
||||
s32 mix_id{UnusedMixId};
|
||||
/// Process order of this effect
|
||||
s32 process_order{InvalidProcessOrder};
|
||||
/// Workbuffers assigned to this effect
|
||||
std::array<AddressInfo, 2> workbuffers{AddressInfo(CpuAddr(0), 0), AddressInfo(CpuAddr(0), 0)};
|
||||
/// Aux/Capture buffer info for reading
|
||||
CpuAddr send_buffer_info;
|
||||
/// Aux/Capture buffer for reading
|
||||
CpuAddr send_buffer;
|
||||
/// Aux/Capture buffer info for writing
|
||||
CpuAddr return_buffer_info;
|
||||
/// Aux/Capture buffer for writing
|
||||
CpuAddr return_buffer;
|
||||
/// Parameters of this effect
|
||||
std::array<u8, sizeof(InParameterVersion2)> parameter{};
|
||||
/// State of this effect used by the AudioRenderer across calls
|
||||
std::array<u8, sizeof(State)> state{};
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
71
src/audio_core/renderer/effect/effect_reset.h
Normal file
71
src/audio_core/renderer/effect/effect_reset.h
Normal file
@ -0,0 +1,71 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "audio_core/renderer/effect/aux_.h"
|
||||
#include "audio_core/renderer/effect/biquad_filter.h"
|
||||
#include "audio_core/renderer/effect/buffer_mixer.h"
|
||||
#include "audio_core/renderer/effect/capture.h"
|
||||
#include "audio_core/renderer/effect/compressor.h"
|
||||
#include "audio_core/renderer/effect/delay.h"
|
||||
#include "audio_core/renderer/effect/i3dl2.h"
|
||||
#include "audio_core/renderer/effect/light_limiter.h"
|
||||
#include "audio_core/renderer/effect/reverb.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
/**
|
||||
* Reset an effect, and create a new one of the given type.
|
||||
*
|
||||
* @param effect - Effect to reset and re-construct.
|
||||
* @param type - Type of the new effect to create.
|
||||
*/
|
||||
static void ResetEffect(EffectInfoBase* effect, const EffectInfoBase::Type type) {
|
||||
*effect = {};
|
||||
|
||||
switch (type) {
|
||||
case EffectInfoBase::Type::Invalid:
|
||||
std::construct_at<EffectInfoBase>(effect);
|
||||
effect->SetType(EffectInfoBase::Type::Invalid);
|
||||
break;
|
||||
case EffectInfoBase::Type::Mix:
|
||||
std::construct_at<BufferMixerInfo>(reinterpret_cast<BufferMixerInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Mix);
|
||||
break;
|
||||
case EffectInfoBase::Type::Aux:
|
||||
std::construct_at<AuxInfo>(reinterpret_cast<AuxInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Aux);
|
||||
break;
|
||||
case EffectInfoBase::Type::Delay:
|
||||
std::construct_at<DelayInfo>(reinterpret_cast<DelayInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Delay);
|
||||
break;
|
||||
case EffectInfoBase::Type::Reverb:
|
||||
std::construct_at<ReverbInfo>(reinterpret_cast<ReverbInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Reverb);
|
||||
break;
|
||||
case EffectInfoBase::Type::I3dl2Reverb:
|
||||
std::construct_at<I3dl2ReverbInfo>(reinterpret_cast<I3dl2ReverbInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::I3dl2Reverb);
|
||||
break;
|
||||
case EffectInfoBase::Type::BiquadFilter:
|
||||
std::construct_at<BiquadFilterInfo>(reinterpret_cast<BiquadFilterInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::BiquadFilter);
|
||||
break;
|
||||
case EffectInfoBase::Type::LightLimiter:
|
||||
std::construct_at<LightLimiterInfo>(reinterpret_cast<LightLimiterInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::LightLimiter);
|
||||
break;
|
||||
case EffectInfoBase::Type::Capture:
|
||||
std::construct_at<CaptureInfo>(reinterpret_cast<CaptureInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Capture);
|
||||
break;
|
||||
case EffectInfoBase::Type::Compressor:
|
||||
std::construct_at<CompressorInfo>(reinterpret_cast<CompressorInfo*>(effect));
|
||||
effect->SetType(EffectInfoBase::Type::Compressor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
16
src/audio_core/renderer/effect/effect_result_state.h
Normal file
16
src/audio_core/renderer/effect/effect_result_state.h
Normal file
@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
struct EffectResultState {
|
||||
std::array<u8, 0x80> state;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
94
src/audio_core/renderer/effect/i3dl2.cpp
Normal file
94
src/audio_core/renderer/effect/i3dl2.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/i3dl2.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void I3dl2ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void I3dl2ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void I3dl2ReverbInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
}
|
||||
|
||||
void I3dl2ReverbInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void I3dl2ReverbInfo::UpdateResultState(EffectResultState& cpu_state,
|
||||
EffectResultState& dsp_state) {}
|
||||
|
||||
CpuAddr I3dl2ReverbInfo::GetWorkbuffer(s32 index) {
|
||||
return GetSingleBuffer(index);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
200
src/audio_core/renderer/effect/i3dl2.h
Normal file
200
src/audio_core/renderer/effect/i3dl2.h
Normal file
@ -0,0 +1,200 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fixed_point.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class I3dl2ReverbInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x10 */ char unk10[0x4];
|
||||
/* 0x14 */ u32 sample_rate;
|
||||
/* 0x18 */ f32 room_HF_gain;
|
||||
/* 0x1C */ f32 reference_HF;
|
||||
/* 0x20 */ f32 late_reverb_decay_time;
|
||||
/* 0x24 */ f32 late_reverb_HF_decay_ratio;
|
||||
/* 0x28 */ f32 room_gain;
|
||||
/* 0x2C */ f32 reflection_gain;
|
||||
/* 0x30 */ f32 reverb_gain;
|
||||
/* 0x34 */ f32 late_reverb_diffusion;
|
||||
/* 0x38 */ f32 reflection_delay;
|
||||
/* 0x3C */ f32 late_reverb_delay_time;
|
||||
/* 0x40 */ f32 late_reverb_density;
|
||||
/* 0x44 */ f32 dry_gain;
|
||||
/* 0x48 */ ParameterState state;
|
||||
/* 0x49 */ char unk49[0x3];
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"I3dl2ReverbInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x10 */ char unk10[0x4];
|
||||
/* 0x14 */ u32 sample_rate;
|
||||
/* 0x18 */ f32 room_HF_gain;
|
||||
/* 0x1C */ f32 reference_HF;
|
||||
/* 0x20 */ f32 late_reverb_decay_time;
|
||||
/* 0x24 */ f32 late_reverb_HF_decay_ratio;
|
||||
/* 0x28 */ f32 room_gain;
|
||||
/* 0x2C */ f32 reflection_gain;
|
||||
/* 0x30 */ f32 reverb_gain;
|
||||
/* 0x34 */ f32 late_reverb_diffusion;
|
||||
/* 0x38 */ f32 reflection_delay;
|
||||
/* 0x3C */ f32 late_reverb_delay_time;
|
||||
/* 0x40 */ f32 late_reverb_density;
|
||||
/* 0x44 */ f32 dry_gain;
|
||||
/* 0x48 */ ParameterState state;
|
||||
/* 0x49 */ char unk49[0x3];
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"I3dl2ReverbInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
static constexpr u32 MaxDelayLines = 4;
|
||||
static constexpr u32 MaxDelayTaps = 20;
|
||||
|
||||
struct I3dl2DelayLine {
|
||||
void Initialize(const s32 delay_time) {
|
||||
max_delay = delay_time;
|
||||
buffer.resize(delay_time + 1, 0);
|
||||
buffer_end = &buffer[delay_time];
|
||||
output = &buffer[0];
|
||||
SetDelay(delay_time);
|
||||
wet_gain = 0.0f;
|
||||
}
|
||||
|
||||
void SetDelay(const s32 delay_time) {
|
||||
if (max_delay < delay_time) {
|
||||
return;
|
||||
}
|
||||
delay = delay_time;
|
||||
input = &buffer[(output - buffer.data() + delay) % (max_delay + 1)];
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) {
|
||||
Write(sample);
|
||||
|
||||
auto out_sample{Read()};
|
||||
|
||||
output++;
|
||||
if (output >= buffer_end) {
|
||||
output = buffer.data();
|
||||
}
|
||||
|
||||
return out_sample;
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> Read() {
|
||||
return *output;
|
||||
}
|
||||
|
||||
void Write(const Common::FixedPoint<50, 14> sample) {
|
||||
*(input++) = sample;
|
||||
if (input >= buffer_end) {
|
||||
input = buffer.data();
|
||||
}
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> TapOut(const s32 index) {
|
||||
auto out{input - (index + 1)};
|
||||
if (out < buffer.data()) {
|
||||
out += max_delay + 1;
|
||||
}
|
||||
return *out;
|
||||
}
|
||||
|
||||
std::vector<Common::FixedPoint<50, 14>> buffer{};
|
||||
Common::FixedPoint<50, 14>* buffer_end{};
|
||||
s32 max_delay{};
|
||||
Common::FixedPoint<50, 14>* input{};
|
||||
Common::FixedPoint<50, 14>* output{};
|
||||
s32 delay{};
|
||||
f32 wet_gain{};
|
||||
};
|
||||
|
||||
struct State {
|
||||
f32 lowpass_0;
|
||||
f32 lowpass_1;
|
||||
f32 lowpass_2;
|
||||
I3dl2DelayLine early_delay_line;
|
||||
std::array<s32, MaxDelayTaps> early_tap_steps;
|
||||
f32 early_gain;
|
||||
f32 late_gain;
|
||||
s32 early_to_late_taps;
|
||||
std::array<I3dl2DelayLine, MaxDelayLines> fdn_delay_lines;
|
||||
std::array<I3dl2DelayLine, MaxDelayLines> decay_delay_lines0;
|
||||
std::array<I3dl2DelayLine, MaxDelayLines> decay_delay_lines1;
|
||||
f32 last_reverb_echo;
|
||||
I3dl2DelayLine center_delay_line;
|
||||
std::array<std::array<f32, 3>, MaxDelayLines> lowpass_coeff;
|
||||
std::array<f32, MaxDelayLines> shelf_filter;
|
||||
f32 dry_gain;
|
||||
};
|
||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||
"I3dl2ReverbInfo::State is too large!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
81
src/audio_core/renderer/effect/light_limiter.cpp
Normal file
81
src/audio_core/renderer/effect/light_limiter.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/light_limiter.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void LightLimiterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void LightLimiterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
|
||||
const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
} else {
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
}
|
||||
|
||||
void LightLimiterInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
params->statistics_reset_required = false;
|
||||
}
|
||||
|
||||
void LightLimiterInfo::InitializeResultState(EffectResultState& result_state) {
|
||||
auto result_state_{reinterpret_cast<StatisticsInternal*>(result_state.state.data())};
|
||||
|
||||
result_state_->channel_max_sample.fill(0);
|
||||
result_state_->channel_compression_gain_min.fill(1.0f);
|
||||
}
|
||||
|
||||
void LightLimiterInfo::UpdateResultState(EffectResultState& cpu_state,
|
||||
EffectResultState& dsp_state) {
|
||||
auto cpu_statistics{reinterpret_cast<StatisticsInternal*>(cpu_state.state.data())};
|
||||
auto dsp_statistics{reinterpret_cast<StatisticsInternal*>(dsp_state.state.data())};
|
||||
|
||||
*cpu_statistics = *dsp_statistics;
|
||||
}
|
||||
|
||||
CpuAddr LightLimiterInfo::GetWorkbuffer(s32 index) {
|
||||
return GetSingleBuffer(index);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
138
src/audio_core/renderer/effect/light_limiter.h
Normal file
138
src/audio_core/renderer/effect/light_limiter.h
Normal file
@ -0,0 +1,138 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fixed_point.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class LightLimiterInfo : public EffectInfoBase {
|
||||
public:
|
||||
enum class ProcessingMode {
|
||||
Mode0,
|
||||
Mode1,
|
||||
};
|
||||
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x0C */ u32 sample_rate;
|
||||
/* 0x14 */ s32 look_ahead_time_max;
|
||||
/* 0x18 */ s32 attack_time;
|
||||
/* 0x1C */ s32 release_time;
|
||||
/* 0x20 */ s32 look_ahead_time;
|
||||
/* 0x24 */ f32 attack_coeff;
|
||||
/* 0x28 */ f32 release_coeff;
|
||||
/* 0x2C */ f32 threshold;
|
||||
/* 0x30 */ f32 input_gain;
|
||||
/* 0x34 */ f32 output_gain;
|
||||
/* 0x38 */ s32 look_ahead_samples_min;
|
||||
/* 0x3C */ s32 look_ahead_samples_max;
|
||||
/* 0x40 */ ParameterState state;
|
||||
/* 0x41 */ bool statistics_enabled;
|
||||
/* 0x42 */ bool statistics_reset_required;
|
||||
/* 0x43 */ ProcessingMode processing_mode;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"LightLimiterInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x0C */ u32 sample_rate;
|
||||
/* 0x14 */ s32 look_ahead_time_max;
|
||||
/* 0x18 */ s32 attack_time;
|
||||
/* 0x1C */ s32 release_time;
|
||||
/* 0x20 */ s32 look_ahead_time;
|
||||
/* 0x24 */ f32 attack_coeff;
|
||||
/* 0x28 */ f32 release_coeff;
|
||||
/* 0x2C */ f32 threshold;
|
||||
/* 0x30 */ f32 input_gain;
|
||||
/* 0x34 */ f32 output_gain;
|
||||
/* 0x38 */ s32 look_ahead_samples_min;
|
||||
/* 0x3C */ s32 look_ahead_samples_max;
|
||||
/* 0x40 */ ParameterState state;
|
||||
/* 0x41 */ bool statistics_enabled;
|
||||
/* 0x42 */ bool statistics_reset_required;
|
||||
/* 0x43 */ ProcessingMode processing_mode;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"LightLimiterInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
struct State {
|
||||
std::array<Common::FixedPoint<49, 15>, MaxChannels> samples_average;
|
||||
std::array<Common::FixedPoint<49, 15>, MaxChannels> compression_gain;
|
||||
std::array<s32, MaxChannels> look_ahead_sample_offsets;
|
||||
std::array<std::vector<Common::FixedPoint<49, 15>>, MaxChannels> look_ahead_sample_buffers;
|
||||
};
|
||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||
"LightLimiterInfo::State has the wrong size!");
|
||||
|
||||
struct StatisticsInternal {
|
||||
/* 0x00 */ std::array<f32, MaxChannels> channel_max_sample;
|
||||
/* 0x18 */ std::array<f32, MaxChannels> channel_compression_gain_min;
|
||||
};
|
||||
static_assert(sizeof(StatisticsInternal) == 0x30,
|
||||
"LightLimiterInfo::StatisticsInternal has the wrong size!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new limiter statistics result state. Version 2 only.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side limiter 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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
93
src/audio_core/renderer/effect/reverb.cpp
Normal file
93
src/audio_core/renderer/effect/reverb.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "audio_core/renderer/effect/reverb.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
void ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion1));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) {
|
||||
auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
|
||||
auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
|
||||
|
||||
if (IsChannelCountValid(in_specific->channel_count_max)) {
|
||||
const auto old_state{params->state};
|
||||
std::memcpy(params, in_specific, sizeof(ParameterVersion2));
|
||||
mix_id = in_params.mix_id;
|
||||
process_order = in_params.process_order;
|
||||
enabled = in_params.enabled;
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count)) {
|
||||
params->channel_count = params->channel_count_max;
|
||||
}
|
||||
|
||||
if (!IsChannelCountValid(in_specific->channel_count) ||
|
||||
old_state != ParameterState::Updated) {
|
||||
params->state = old_state;
|
||||
}
|
||||
|
||||
if (buffer_unmapped || in_params.is_new) {
|
||||
usage_state = UsageState::New;
|
||||
params->state = ParameterState::Initialized;
|
||||
buffer_unmapped = !pool_mapper.TryAttachBuffer(
|
||||
error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
error_info.error_code = ResultSuccess;
|
||||
error_info.address = CpuAddr(0);
|
||||
}
|
||||
|
||||
void ReverbInfo::UpdateForCommandGeneration() {
|
||||
if (enabled) {
|
||||
usage_state = UsageState::Enabled;
|
||||
} else {
|
||||
usage_state = UsageState::Disabled;
|
||||
}
|
||||
|
||||
auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
|
||||
params->state = ParameterState::Updated;
|
||||
}
|
||||
|
||||
void ReverbInfo::InitializeResultState(EffectResultState& result_state) {}
|
||||
|
||||
void ReverbInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
|
||||
|
||||
CpuAddr ReverbInfo::GetWorkbuffer(s32 index) {
|
||||
return GetSingleBuffer(index);
|
||||
}
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
190
src/audio_core/renderer/effect/reverb.h
Normal file
190
src/audio_core/renderer/effect/reverb.h
Normal file
@ -0,0 +1,190 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "audio_core/common/common.h"
|
||||
#include "audio_core/renderer/effect/effect_info_base.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fixed_point.h"
|
||||
|
||||
namespace AudioCore::AudioRenderer {
|
||||
|
||||
class ReverbInfo : public EffectInfoBase {
|
||||
public:
|
||||
struct ParameterVersion1 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x10 */ u32 sample_rate;
|
||||
/* 0x14 */ u32 early_mode;
|
||||
/* 0x18 */ s32 early_gain;
|
||||
/* 0x1C */ s32 pre_delay;
|
||||
/* 0x20 */ s32 late_mode;
|
||||
/* 0x24 */ s32 late_gain;
|
||||
/* 0x28 */ s32 decay_time;
|
||||
/* 0x2C */ s32 high_freq_Decay_ratio;
|
||||
/* 0x30 */ s32 colouration;
|
||||
/* 0x34 */ s32 base_gain;
|
||||
/* 0x38 */ s32 wet_gain;
|
||||
/* 0x3C */ s32 dry_gain;
|
||||
/* 0x40 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
|
||||
"ReverbInfo::ParameterVersion1 has the wrong size!");
|
||||
|
||||
struct ParameterVersion2 {
|
||||
/* 0x00 */ std::array<s8, MaxChannels> inputs;
|
||||
/* 0x06 */ std::array<s8, MaxChannels> outputs;
|
||||
/* 0x0C */ u16 channel_count_max;
|
||||
/* 0x0E */ u16 channel_count;
|
||||
/* 0x10 */ u32 sample_rate;
|
||||
/* 0x14 */ u32 early_mode;
|
||||
/* 0x18 */ s32 early_gain;
|
||||
/* 0x1C */ s32 pre_delay;
|
||||
/* 0x20 */ s32 late_mode;
|
||||
/* 0x24 */ s32 late_gain;
|
||||
/* 0x28 */ s32 decay_time;
|
||||
/* 0x2C */ s32 high_freq_decay_ratio;
|
||||
/* 0x30 */ s32 colouration;
|
||||
/* 0x34 */ s32 base_gain;
|
||||
/* 0x38 */ s32 wet_gain;
|
||||
/* 0x3C */ s32 dry_gain;
|
||||
/* 0x40 */ ParameterState state;
|
||||
};
|
||||
static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
|
||||
"ReverbInfo::ParameterVersion2 has the wrong size!");
|
||||
|
||||
static constexpr u32 MaxDelayLines = 4;
|
||||
static constexpr u32 MaxDelayTaps = 10;
|
||||
static constexpr u32 NumEarlyModes = 5;
|
||||
static constexpr u32 NumLateModes = 5;
|
||||
|
||||
struct ReverbDelayLine {
|
||||
void Initialize(const s32 delay_time, const f32 decay_rate) {
|
||||
buffer.resize(delay_time + 1, 0);
|
||||
buffer_end = &buffer[delay_time];
|
||||
output = &buffer[0];
|
||||
decay = decay_rate;
|
||||
sample_count_max = delay_time;
|
||||
SetDelay(delay_time);
|
||||
}
|
||||
|
||||
void SetDelay(const s32 delay_time) {
|
||||
if (sample_count_max < delay_time) {
|
||||
return;
|
||||
}
|
||||
sample_count = delay_time;
|
||||
input = &buffer[(output - buffer.data() + sample_count) % (sample_count_max + 1)];
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) {
|
||||
Write(sample);
|
||||
|
||||
auto out_sample{Read()};
|
||||
|
||||
output++;
|
||||
if (output >= buffer_end) {
|
||||
output = buffer.data();
|
||||
}
|
||||
|
||||
return out_sample;
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> Read() {
|
||||
return *output;
|
||||
}
|
||||
|
||||
void Write(const Common::FixedPoint<50, 14> sample) {
|
||||
*(input++) = sample;
|
||||
if (input >= buffer_end) {
|
||||
input = buffer.data();
|
||||
}
|
||||
}
|
||||
|
||||
Common::FixedPoint<50, 14> TapOut(const s32 index) {
|
||||
auto out{input - (index + 1)};
|
||||
if (out < buffer.data()) {
|
||||
out += sample_count;
|
||||
}
|
||||
return *out;
|
||||
}
|
||||
|
||||
s32 sample_count{};
|
||||
s32 sample_count_max{};
|
||||
std::vector<Common::FixedPoint<50, 14>> buffer{};
|
||||
Common::FixedPoint<50, 14>* buffer_end;
|
||||
Common::FixedPoint<50, 14>* input{};
|
||||
Common::FixedPoint<50, 14>* output{};
|
||||
Common::FixedPoint<50, 14> decay{};
|
||||
};
|
||||
|
||||
struct State {
|
||||
ReverbDelayLine pre_delay_line;
|
||||
ReverbDelayLine center_delay_line;
|
||||
std::array<s32, MaxDelayTaps> early_delay_times;
|
||||
std::array<Common::FixedPoint<50, 14>, MaxDelayTaps> early_gains;
|
||||
s32 pre_delay_time;
|
||||
std::array<ReverbDelayLine, MaxDelayLines> decay_delay_lines;
|
||||
std::array<ReverbDelayLine, MaxDelayLines> fdn_delay_lines;
|
||||
std::array<Common::FixedPoint<50, 14>, MaxDelayLines> hf_decay_gain;
|
||||
std::array<Common::FixedPoint<50, 14>, MaxDelayLines> hf_decay_prev_gain;
|
||||
std::array<Common::FixedPoint<50, 14>, MaxDelayLines> prev_feedback_output;
|
||||
};
|
||||
static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
|
||||
"ReverbInfo::State is too large!");
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 1.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info with new parameters, version 2.
|
||||
*
|
||||
* @param error_info - Used to write call result code.
|
||||
* @param in_params - New parameters to update the info with.
|
||||
* @param pool_mapper - Pool for mapping buffers.
|
||||
*/
|
||||
void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
|
||||
const PoolMapper& pool_mapper) override;
|
||||
|
||||
/**
|
||||
* Update the info after command generation. Usually only changes its state.
|
||||
*/
|
||||
void UpdateForCommandGeneration() override;
|
||||
|
||||
/**
|
||||
* Initialize a new result state. Version 2 only, unused.
|
||||
*
|
||||
* @param result_state - Result state to initialize.
|
||||
*/
|
||||
void InitializeResultState(EffectResultState& result_state) override;
|
||||
|
||||
/**
|
||||
* Update the host-side state with the ADSP-side state. Version 2 only, unused.
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param index - Workbuffer index.
|
||||
* @return Address of the buffer.
|
||||
*/
|
||||
CpuAddr GetWorkbuffer(s32 index) override;
|
||||
};
|
||||
|
||||
} // namespace AudioCore::AudioRenderer
|
Reference in New Issue
Block a user