summaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/effect
diff options
context:
space:
mode:
authorGravatar Kelebek12022-07-16 23:48:45 +0100
committerGravatar Kelebek12022-07-22 01:11:32 +0100
commit458da8a94877677f086f06cdeecf959ec4283a33 (patch)
tree583166d77602ad90a0d552f37de8729ad80fd6c1 /src/audio_core/renderer/effect
parentMerge pull request #8598 from Link4565/recv-dontwait (diff)
downloadyuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.gz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.tar.xz
yuzu-458da8a94877677f086f06cdeecf959ec4283a33.zip
Project Andio
Diffstat (limited to 'src/audio_core/renderer/effect')
-rw-r--r--src/audio_core/renderer/effect/aux_.cpp93
-rw-r--r--src/audio_core/renderer/effect/aux_.h123
-rw-r--r--src/audio_core/renderer/effect/biquad_filter.cpp52
-rw-r--r--src/audio_core/renderer/effect/biquad_filter.h79
-rw-r--r--src/audio_core/renderer/effect/buffer_mixer.cpp49
-rw-r--r--src/audio_core/renderer/effect/buffer_mixer.h75
-rw-r--r--src/audio_core/renderer/effect/capture.cpp82
-rw-r--r--src/audio_core/renderer/effect/capture.h65
-rw-r--r--src/audio_core/renderer/effect/compressor.cpp40
-rw-r--r--src/audio_core/renderer/effect/compressor.h106
-rw-r--r--src/audio_core/renderer/effect/delay.cpp93
-rw-r--r--src/audio_core/renderer/effect/delay.h135
-rw-r--r--src/audio_core/renderer/effect/effect_context.cpp41
-rw-r--r--src/audio_core/renderer/effect/effect_context.h75
-rw-r--r--src/audio_core/renderer/effect/effect_info_base.h435
-rw-r--r--src/audio_core/renderer/effect/effect_reset.h71
-rw-r--r--src/audio_core/renderer/effect/effect_result_state.h16
-rw-r--r--src/audio_core/renderer/effect/i3dl2.cpp94
-rw-r--r--src/audio_core/renderer/effect/i3dl2.h200
-rw-r--r--src/audio_core/renderer/effect/light_limiter.cpp81
-rw-r--r--src/audio_core/renderer/effect/light_limiter.h138
-rw-r--r--src/audio_core/renderer/effect/reverb.cpp93
-rw-r--r--src/audio_core/renderer/effect/reverb.h190
23 files changed, 2426 insertions, 0 deletions
diff --git a/src/audio_core/renderer/effect/aux_.cpp b/src/audio_core/renderer/effect/aux_.cpp
new file mode 100644
index 000000000..51e780ef1
--- /dev/null
+++ b/src/audio_core/renderer/effect/aux_.cpp
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/aux_.h"
5
6namespace AudioCore::AudioRenderer {
7
8void AuxInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
9 const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
14 mix_id = in_params.mix_id;
15 process_order = in_params.process_order;
16 enabled = in_params.enabled;
17 if (buffer_unmapped || in_params.is_new) {
18 const bool send_unmapped{!pool_mapper.TryAttachBuffer(
19 error_info, workbuffers[0], in_specific->send_buffer_info_address,
20 sizeof(AuxBufferInfo) + in_specific->count_max * sizeof(s32))};
21 const bool return_unmapped{!pool_mapper.TryAttachBuffer(
22 error_info, workbuffers[1], in_specific->return_buffer_info_address,
23 sizeof(AuxBufferInfo) + in_specific->count_max * sizeof(s32))};
24
25 buffer_unmapped = send_unmapped || return_unmapped;
26
27 if (!buffer_unmapped) {
28 auto send{workbuffers[0].GetReference(false)};
29 send_buffer_info = send + sizeof(AuxInfoDsp);
30 send_buffer = send + sizeof(AuxBufferInfo);
31
32 auto ret{workbuffers[1].GetReference(false)};
33 return_buffer_info = ret + sizeof(AuxInfoDsp);
34 return_buffer = ret + sizeof(AuxBufferInfo);
35 }
36 } else {
37 error_info.error_code = ResultSuccess;
38 error_info.address = CpuAddr(0);
39 }
40}
41
42void AuxInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
43 const PoolMapper& pool_mapper) {
44 auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
45 auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
46
47 std::memcpy(params, in_specific, sizeof(ParameterVersion2));
48 mix_id = in_params.mix_id;
49 process_order = in_params.process_order;
50 enabled = in_params.enabled;
51
52 if (buffer_unmapped || in_params.is_new) {
53 const bool send_unmapped{!pool_mapper.TryAttachBuffer(
54 error_info, workbuffers[0], params->send_buffer_info_address,
55 sizeof(AuxBufferInfo) + params->count_max * sizeof(s32))};
56 const bool return_unmapped{!pool_mapper.TryAttachBuffer(
57 error_info, workbuffers[1], params->return_buffer_info_address,
58 sizeof(AuxBufferInfo) + params->count_max * sizeof(s32))};
59
60 buffer_unmapped = send_unmapped || return_unmapped;
61
62 if (!buffer_unmapped) {
63 auto send{workbuffers[0].GetReference(false)};
64 send_buffer_info = send + sizeof(AuxInfoDsp);
65 send_buffer = send + sizeof(AuxBufferInfo);
66
67 auto ret{workbuffers[1].GetReference(false)};
68 return_buffer_info = ret + sizeof(AuxInfoDsp);
69 return_buffer = ret + sizeof(AuxBufferInfo);
70 }
71 } else {
72 error_info.error_code = ResultSuccess;
73 error_info.address = CpuAddr(0);
74 }
75}
76
77void AuxInfo::UpdateForCommandGeneration() {
78 if (enabled) {
79 usage_state = UsageState::Enabled;
80 } else {
81 usage_state = UsageState::Disabled;
82 }
83}
84
85void AuxInfo::InitializeResultState(EffectResultState& result_state) {}
86
87void AuxInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
88
89CpuAddr AuxInfo::GetWorkbuffer(s32 index) {
90 return workbuffers[index].GetReference(true);
91}
92
93} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/aux_.h b/src/audio_core/renderer/effect/aux_.h
new file mode 100644
index 000000000..4d3d9e3d9
--- /dev/null
+++ b/src/audio_core/renderer/effect/aux_.h
@@ -0,0 +1,123 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/effect/effect_info_base.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13/**
14 * Auxiliary Buffer used for Aux commands.
15 * Send and return buffers are available (names from the game's perspective).
16 * Send is read by the host, containing a buffer of samples to be used for whatever purpose.
17 * Return is written by the host, writing a mix buffer back to the game.
18 * This allows the game to use pre-processed samples skipping the other render processing,
19 * and to examine or modify what the audio renderer has generated.
20 */
21class AuxInfo : public EffectInfoBase {
22public:
23 struct ParameterVersion1 {
24 /* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
25 /* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
26 /* 0x30 */ u32 mix_buffer_count;
27 /* 0x34 */ u32 sample_rate;
28 /* 0x38 */ u32 count_max;
29 /* 0x3C */ u32 mix_buffer_count_max;
30 /* 0x40 */ CpuAddr send_buffer_info_address;
31 /* 0x48 */ CpuAddr send_buffer_address;
32 /* 0x50 */ CpuAddr return_buffer_info_address;
33 /* 0x58 */ CpuAddr return_buffer_address;
34 /* 0x60 */ u32 mix_buffer_sample_size;
35 /* 0x64 */ u32 sample_count;
36 /* 0x68 */ u32 mix_buffer_sample_count;
37 };
38 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
39 "AuxInfo::ParameterVersion1 has the wrong size!");
40
41 struct ParameterVersion2 {
42 /* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
43 /* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
44 /* 0x30 */ u32 mix_buffer_count;
45 /* 0x34 */ u32 sample_rate;
46 /* 0x38 */ u32 count_max;
47 /* 0x3C */ u32 mix_buffer_count_max;
48 /* 0x40 */ CpuAddr send_buffer_info_address;
49 /* 0x48 */ CpuAddr send_buffer_address;
50 /* 0x50 */ CpuAddr return_buffer_info_address;
51 /* 0x58 */ CpuAddr return_buffer_address;
52 /* 0x60 */ u32 mix_buffer_sample_size;
53 /* 0x64 */ u32 sample_count;
54 /* 0x68 */ u32 mix_buffer_sample_count;
55 };
56 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
57 "AuxInfo::ParameterVersion2 has the wrong size!");
58
59 struct AuxInfoDsp {
60 /* 0x00 */ u32 read_offset;
61 /* 0x04 */ u32 write_offset;
62 /* 0x08 */ u32 lost_sample_count;
63 /* 0x0C */ u32 total_sample_count;
64 /* 0x10 */ char unk10[0x30];
65 };
66 static_assert(sizeof(AuxInfoDsp) == 0x40, "AuxInfo::AuxInfoDsp has the wrong size!");
67
68 struct AuxBufferInfo {
69 /* 0x00 */ AuxInfoDsp cpu_info;
70 /* 0x40 */ AuxInfoDsp dsp_info;
71 };
72 static_assert(sizeof(AuxBufferInfo) == 0x80, "AuxInfo::AuxBufferInfo has the wrong size!");
73
74 /**
75 * Update the info with new parameters, version 1.
76 *
77 * @param error_info - Used to write call result code.
78 * @param in_params - New parameters to update the info with.
79 * @param pool_mapper - Pool for mapping buffers.
80 */
81 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
82 const PoolMapper& pool_mapper) override;
83
84 /**
85 * Update the info with new parameters, version 2.
86 *
87 * @param error_info - Used to write call result code.
88 * @param in_params - New parameters to update the info with.
89 * @param pool_mapper - Pool for mapping buffers.
90 */
91 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
92 const PoolMapper& pool_mapper) override;
93
94 /**
95 * Update the info after command generation. Usually only changes its state.
96 */
97 void UpdateForCommandGeneration() override;
98
99 /**
100 * Initialize a new result state. Version 2 only, unused.
101 *
102 * @param result_state - Result state to initialize.
103 */
104 void InitializeResultState(EffectResultState& result_state) override;
105
106 /**
107 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
108 *
109 * @param cpu_state - Host-side result state to update.
110 * @param dsp_state - AudioRenderer-side result state to update from.
111 */
112 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
113
114 /**
115 * Get a workbuffer assigned to this effect with the given index.
116 *
117 * @param index - Workbuffer index.
118 * @return Address of the buffer.
119 */
120 CpuAddr GetWorkbuffer(s32 index) override;
121};
122
123} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/biquad_filter.cpp b/src/audio_core/renderer/effect/biquad_filter.cpp
new file mode 100644
index 000000000..a1efb3231
--- /dev/null
+++ b/src/audio_core/renderer/effect/biquad_filter.cpp
@@ -0,0 +1,52 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/biquad_filter.h"
5
6namespace AudioCore::AudioRenderer {
7
8void BiquadFilterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
9 const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
14 mix_id = in_params.mix_id;
15 process_order = in_params.process_order;
16 enabled = in_params.enabled;
17
18 error_info.error_code = ResultSuccess;
19 error_info.address = CpuAddr(0);
20}
21
22void BiquadFilterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
23 const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
24 auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
25 auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
26
27 std::memcpy(params, in_specific, sizeof(ParameterVersion2));
28 mix_id = in_params.mix_id;
29 process_order = in_params.process_order;
30 enabled = in_params.enabled;
31
32 error_info.error_code = ResultSuccess;
33 error_info.address = CpuAddr(0);
34}
35
36void BiquadFilterInfo::UpdateForCommandGeneration() {
37 if (enabled) {
38 usage_state = UsageState::Enabled;
39 } else {
40 usage_state = UsageState::Disabled;
41 }
42
43 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
44 params->state = ParameterState::Updated;
45}
46
47void BiquadFilterInfo::InitializeResultState(EffectResultState& result_state) {}
48
49void BiquadFilterInfo::UpdateResultState(EffectResultState& cpu_state,
50 EffectResultState& dsp_state) {}
51
52} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/biquad_filter.h b/src/audio_core/renderer/effect/biquad_filter.h
new file mode 100644
index 000000000..f53fd5bab
--- /dev/null
+++ b/src/audio_core/renderer/effect/biquad_filter.h
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/effect/effect_info_base.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13
14class BiquadFilterInfo : public EffectInfoBase {
15public:
16 struct ParameterVersion1 {
17 /* 0x00 */ std::array<s8, MaxChannels> inputs;
18 /* 0x06 */ std::array<s8, MaxChannels> outputs;
19 /* 0x0C */ std::array<s16, 3> b;
20 /* 0x12 */ std::array<s16, 2> a;
21 /* 0x16 */ s8 channel_count;
22 /* 0x17 */ ParameterState state;
23 };
24 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
25 "BiquadFilterInfo::ParameterVersion1 has the wrong size!");
26
27 struct ParameterVersion2 {
28 /* 0x00 */ std::array<s8, MaxChannels> inputs;
29 /* 0x06 */ std::array<s8, MaxChannels> outputs;
30 /* 0x0C */ std::array<s16, 3> b;
31 /* 0x12 */ std::array<s16, 2> a;
32 /* 0x16 */ s8 channel_count;
33 /* 0x17 */ ParameterState state;
34 };
35 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
36 "BiquadFilterInfo::ParameterVersion2 has the wrong size!");
37
38 /**
39 * Update the info with new parameters, version 1.
40 *
41 * @param error_info - Used to write call result code.
42 * @param in_params - New parameters to update the info with.
43 * @param pool_mapper - Pool for mapping buffers.
44 */
45 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
46 const PoolMapper& pool_mapper) override;
47
48 /**
49 * Update the info with new parameters, version 2.
50 *
51 * @param error_info - Used to write call result code.
52 * @param in_params - New parameters to update the info with.
53 * @param pool_mapper - Pool for mapping buffers.
54 */
55 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
56 const PoolMapper& pool_mapper) override;
57
58 /**
59 * Update the info after command generation. Usually only changes its state.
60 */
61 void UpdateForCommandGeneration() override;
62
63 /**
64 * Initialize a new result state. Version 2 only, unused.
65 *
66 * @param result_state - Result state to initialize.
67 */
68 void InitializeResultState(EffectResultState& result_state) override;
69
70 /**
71 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
72 *
73 * @param cpu_state - Host-side result state to update.
74 * @param dsp_state - AudioRenderer-side result state to update from.
75 */
76 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
77};
78
79} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/buffer_mixer.cpp b/src/audio_core/renderer/effect/buffer_mixer.cpp
new file mode 100644
index 000000000..9c8877f01
--- /dev/null
+++ b/src/audio_core/renderer/effect/buffer_mixer.cpp
@@ -0,0 +1,49 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/buffer_mixer.h"
5
6namespace AudioCore::AudioRenderer {
7
8void BufferMixerInfo::Update(BehaviorInfo::ErrorInfo& error_info,
9 const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
14 mix_id = in_params.mix_id;
15 process_order = in_params.process_order;
16 enabled = in_params.enabled;
17
18 error_info.error_code = ResultSuccess;
19 error_info.address = CpuAddr(0);
20}
21
22void BufferMixerInfo::Update(BehaviorInfo::ErrorInfo& error_info,
23 const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
24 auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
25 auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
26
27 std::memcpy(params, in_specific, sizeof(ParameterVersion2));
28 mix_id = in_params.mix_id;
29 process_order = in_params.process_order;
30 enabled = in_params.enabled;
31
32 error_info.error_code = ResultSuccess;
33 error_info.address = CpuAddr(0);
34}
35
36void BufferMixerInfo::UpdateForCommandGeneration() {
37 if (enabled) {
38 usage_state = UsageState::Enabled;
39 } else {
40 usage_state = UsageState::Disabled;
41 }
42}
43
44void BufferMixerInfo::InitializeResultState(EffectResultState& result_state) {}
45
46void BufferMixerInfo::UpdateResultState(EffectResultState& cpu_state,
47 EffectResultState& dsp_state) {}
48
49} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/buffer_mixer.h b/src/audio_core/renderer/effect/buffer_mixer.h
new file mode 100644
index 000000000..23eed4a8b
--- /dev/null
+++ b/src/audio_core/renderer/effect/buffer_mixer.h
@@ -0,0 +1,75 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/effect/effect_info_base.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13
14class BufferMixerInfo : public EffectInfoBase {
15public:
16 struct ParameterVersion1 {
17 /* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
18 /* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
19 /* 0x30 */ std::array<f32, MaxMixBuffers> volumes;
20 /* 0x90 */ u32 mix_count;
21 };
22 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
23 "BufferMixerInfo::ParameterVersion1 has the wrong size!");
24
25 struct ParameterVersion2 {
26 /* 0x00 */ std::array<s8, MaxMixBuffers> inputs;
27 /* 0x18 */ std::array<s8, MaxMixBuffers> outputs;
28 /* 0x30 */ std::array<f32, MaxMixBuffers> volumes;
29 /* 0x90 */ u32 mix_count;
30 };
31 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
32 "BufferMixerInfo::ParameterVersion2 has the wrong size!");
33
34 /**
35 * Update the info with new parameters, version 1.
36 *
37 * @param error_info - Used to write call result code.
38 * @param in_params - New parameters to update the info with.
39 * @param pool_mapper - Pool for mapping buffers.
40 */
41 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
42 const PoolMapper& pool_mapper) override;
43
44 /**
45 * Update the info with new parameters, version 2.
46 *
47 * @param error_info - Used to write call result code.
48 * @param in_params - New parameters to update the info with.
49 * @param pool_mapper - Pool for mapping buffers.
50 */
51 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
52 const PoolMapper& pool_mapper) override;
53
54 /**
55 * Update the info after command generation. Usually only changes its state.
56 */
57 void UpdateForCommandGeneration() override;
58
59 /**
60 * Initialize a new result state. Version 2 only, unused.
61 *
62 * @param result_state - Result state to initialize.
63 */
64 void InitializeResultState(EffectResultState& result_state) override;
65
66 /**
67 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
68 *
69 * @param cpu_state - Host-side result state to update.
70 * @param dsp_state - AudioRenderer-side result state to update from.
71 */
72 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
73};
74
75} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/capture.cpp b/src/audio_core/renderer/effect/capture.cpp
new file mode 100644
index 000000000..3f038efdb
--- /dev/null
+++ b/src/audio_core/renderer/effect/capture.cpp
@@ -0,0 +1,82 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/aux_.h"
5#include "audio_core/renderer/effect/capture.h"
6
7namespace AudioCore::AudioRenderer {
8
9void CaptureInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
10 const PoolMapper& pool_mapper) {
11 auto in_specific{
12 reinterpret_cast<const AuxInfo::ParameterVersion1*>(in_params.specific.data())};
13 auto params{reinterpret_cast<AuxInfo::ParameterVersion1*>(parameter.data())};
14
15 std::memcpy(params, in_specific, sizeof(AuxInfo::ParameterVersion1));
16 mix_id = in_params.mix_id;
17 process_order = in_params.process_order;
18 enabled = in_params.enabled;
19 if (buffer_unmapped || in_params.is_new) {
20 buffer_unmapped = !pool_mapper.TryAttachBuffer(
21 error_info, workbuffers[0], in_specific->send_buffer_info_address,
22 in_specific->count_max * sizeof(s32) + sizeof(AuxInfo::AuxBufferInfo));
23
24 if (!buffer_unmapped) {
25 const auto send_address{workbuffers[0].GetReference(false)};
26 send_buffer_info = send_address + sizeof(AuxInfo::AuxInfoDsp);
27 send_buffer = send_address + sizeof(AuxInfo::AuxBufferInfo);
28 return_buffer_info = 0;
29 return_buffer = 0;
30 }
31 } else {
32 error_info.error_code = ResultSuccess;
33 error_info.address = CpuAddr(0);
34 }
35}
36
37void CaptureInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
38 const PoolMapper& pool_mapper) {
39 auto in_specific{
40 reinterpret_cast<const AuxInfo::ParameterVersion2*>(in_params.specific.data())};
41 auto params{reinterpret_cast<AuxInfo::ParameterVersion2*>(parameter.data())};
42
43 std::memcpy(params, in_specific, sizeof(AuxInfo::ParameterVersion2));
44 mix_id = in_params.mix_id;
45 process_order = in_params.process_order;
46 enabled = in_params.enabled;
47
48 if (buffer_unmapped || in_params.is_new) {
49 buffer_unmapped = !pool_mapper.TryAttachBuffer(
50 error_info, workbuffers[0], params->send_buffer_info_address,
51 params->count_max * sizeof(s32) + sizeof(AuxInfo::AuxBufferInfo));
52
53 if (!buffer_unmapped) {
54 const auto send_address{workbuffers[0].GetReference(false)};
55 send_buffer_info = send_address + sizeof(AuxInfo::AuxInfoDsp);
56 send_buffer = send_address + sizeof(AuxInfo::AuxBufferInfo);
57 return_buffer_info = 0;
58 return_buffer = 0;
59 }
60 } else {
61 error_info.error_code = ResultSuccess;
62 error_info.address = CpuAddr(0);
63 }
64}
65
66void CaptureInfo::UpdateForCommandGeneration() {
67 if (enabled) {
68 usage_state = UsageState::Enabled;
69 } else {
70 usage_state = UsageState::Disabled;
71 }
72}
73
74void CaptureInfo::InitializeResultState(EffectResultState& result_state) {}
75
76void CaptureInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
77
78CpuAddr CaptureInfo::GetWorkbuffer(s32 index) {
79 return workbuffers[index].GetReference(true);
80}
81
82} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/capture.h b/src/audio_core/renderer/effect/capture.h
new file mode 100644
index 000000000..6fbed8e6b
--- /dev/null
+++ b/src/audio_core/renderer/effect/capture.h
@@ -0,0 +1,65 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/effect/effect_info_base.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13
14class CaptureInfo : public EffectInfoBase {
15public:
16 /**
17 * Update the info with new parameters, version 1.
18 *
19 * @param error_info - Used to write call result code.
20 * @param in_params - New parameters to update the info with.
21 * @param pool_mapper - Pool for mapping buffers.
22 */
23 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
24 const PoolMapper& pool_mapper) override;
25
26 /**
27 * Update the info with new parameters, version 2.
28 *
29 * @param error_info - Used to write call result code.
30 * @param in_params - New parameters to update the info with.
31 * @param pool_mapper - Pool for mapping buffers.
32 */
33 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
34 const PoolMapper& pool_mapper) override;
35
36 /**
37 * Update the info after command generation. Usually only changes its state.
38 */
39 void UpdateForCommandGeneration() override;
40
41 /**
42 * Initialize a new result state. Version 2 only, unused.
43 *
44 * @param result_state - Result state to initialize.
45 */
46 void InitializeResultState(EffectResultState& result_state) override;
47
48 /**
49 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
50 *
51 * @param cpu_state - Host-side result state to update.
52 * @param dsp_state - AudioRenderer-side result state to update from.
53 */
54 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
55
56 /**
57 * Get a workbuffer assigned to this effect with the given index.
58 *
59 * @param index - Workbuffer index.
60 * @return Address of the buffer.
61 */
62 CpuAddr GetWorkbuffer(s32 index) override;
63};
64
65} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/compressor.cpp b/src/audio_core/renderer/effect/compressor.cpp
new file mode 100644
index 000000000..220ae02f9
--- /dev/null
+++ b/src/audio_core/renderer/effect/compressor.cpp
@@ -0,0 +1,40 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/compressor.h"
5
6namespace AudioCore::AudioRenderer {
7
8void CompressorInfo::Update(BehaviorInfo::ErrorInfo& error_info,
9 const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {}
10
11void CompressorInfo::Update(BehaviorInfo::ErrorInfo& error_info,
12 const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
13 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
14 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
15
16 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
17 mix_id = in_params.mix_id;
18 process_order = in_params.process_order;
19 enabled = in_params.enabled;
20
21 error_info.error_code = ResultSuccess;
22 error_info.address = CpuAddr(0);
23}
24
25void CompressorInfo::UpdateForCommandGeneration() {
26 if (enabled) {
27 usage_state = UsageState::Enabled;
28 } else {
29 usage_state = UsageState::Disabled;
30 }
31
32 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
33 params->state = ParameterState::Updated;
34}
35
36CpuAddr CompressorInfo::GetWorkbuffer(s32 index) {
37 return GetSingleBuffer(index);
38}
39
40} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/compressor.h b/src/audio_core/renderer/effect/compressor.h
new file mode 100644
index 000000000..019a5ae58
--- /dev/null
+++ b/src/audio_core/renderer/effect/compressor.h
@@ -0,0 +1,106 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/effect/effect_info_base.h"
10#include "common/common_types.h"
11#include "common/fixed_point.h"
12
13namespace AudioCore::AudioRenderer {
14
15class CompressorInfo : public EffectInfoBase {
16public:
17 struct ParameterVersion1 {
18 /* 0x00 */ std::array<s8, MaxChannels> inputs;
19 /* 0x06 */ std::array<s8, MaxChannels> outputs;
20 /* 0x0C */ s16 channel_count_max;
21 /* 0x0E */ s16 channel_count;
22 /* 0x10 */ s32 sample_rate;
23 /* 0x14 */ f32 threshold;
24 /* 0x18 */ f32 compressor_ratio;
25 /* 0x1C */ s32 attack_time;
26 /* 0x20 */ s32 release_time;
27 /* 0x24 */ f32 unk_24;
28 /* 0x28 */ f32 unk_28;
29 /* 0x2C */ f32 unk_2C;
30 /* 0x30 */ f32 out_gain;
31 /* 0x34 */ ParameterState state;
32 /* 0x35 */ bool makeup_gain_enabled;
33 };
34 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
35 "CompressorInfo::ParameterVersion1 has the wrong size!");
36
37 struct ParameterVersion2 {
38 /* 0x00 */ std::array<s8, MaxChannels> inputs;
39 /* 0x06 */ std::array<s8, MaxChannels> outputs;
40 /* 0x0C */ s16 channel_count_max;
41 /* 0x0E */ s16 channel_count;
42 /* 0x10 */ s32 sample_rate;
43 /* 0x14 */ f32 threshold;
44 /* 0x18 */ f32 compressor_ratio;
45 /* 0x1C */ s32 attack_time;
46 /* 0x20 */ s32 release_time;
47 /* 0x24 */ f32 unk_24;
48 /* 0x28 */ f32 unk_28;
49 /* 0x2C */ f32 unk_2C;
50 /* 0x30 */ f32 out_gain;
51 /* 0x34 */ ParameterState state;
52 /* 0x35 */ bool makeup_gain_enabled;
53 };
54 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
55 "CompressorInfo::ParameterVersion2 has the wrong size!");
56
57 struct State {
58 f32 unk_00;
59 f32 unk_04;
60 f32 unk_08;
61 f32 unk_0C;
62 f32 unk_10;
63 f32 unk_14;
64 f32 unk_18;
65 f32 makeup_gain;
66 f32 unk_20;
67 char unk_24[0x1C];
68 };
69 static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
70 "CompressorInfo::State has the wrong size!");
71
72 /**
73 * Update the info with new parameters, version 1.
74 *
75 * @param error_info - Used to write call result code.
76 * @param in_params - New parameters to update the info with.
77 * @param pool_mapper - Pool for mapping buffers.
78 */
79 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
80 const PoolMapper& pool_mapper) override;
81
82 /**
83 * Update the info with new parameters, version 2.
84 *
85 * @param error_info - Used to write call result code.
86 * @param in_params - New parameters to update the info with.
87 * @param pool_mapper - Pool for mapping buffers.
88 */
89 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
90 const PoolMapper& pool_mapper) override;
91
92 /**
93 * Update the info after command generation. Usually only changes its state.
94 */
95 void UpdateForCommandGeneration() override;
96
97 /**
98 * Get a workbuffer assigned to this effect with the given index.
99 *
100 * @param index - Workbuffer index.
101 * @return Address of the buffer.
102 */
103 CpuAddr GetWorkbuffer(s32 index) override;
104};
105
106} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/delay.cpp b/src/audio_core/renderer/effect/delay.cpp
new file mode 100644
index 000000000..d9853efd9
--- /dev/null
+++ b/src/audio_core/renderer/effect/delay.cpp
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/delay.h"
5
6namespace AudioCore::AudioRenderer {
7
8void DelayInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
9 const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 if (IsChannelCountValid(in_specific->channel_count_max)) {
14 const auto old_state{params->state};
15 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
16 mix_id = in_params.mix_id;
17 process_order = in_params.process_order;
18 enabled = in_params.enabled;
19
20 if (!IsChannelCountValid(in_specific->channel_count)) {
21 params->channel_count = params->channel_count_max;
22 }
23
24 if (!IsChannelCountValid(in_specific->channel_count) ||
25 old_state != ParameterState::Updated) {
26 params->state = old_state;
27 }
28
29 if (buffer_unmapped || in_params.is_new) {
30 usage_state = UsageState::New;
31 params->state = ParameterState::Initialized;
32 buffer_unmapped = !pool_mapper.TryAttachBuffer(
33 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
34 return;
35 }
36 }
37 error_info.error_code = ResultSuccess;
38 error_info.address = CpuAddr(0);
39}
40
41void DelayInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
42 const PoolMapper& pool_mapper) {
43 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
44 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
45
46 if (IsChannelCountValid(in_specific->channel_count_max)) {
47 const auto old_state{params->state};
48 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
49 mix_id = in_params.mix_id;
50 process_order = in_params.process_order;
51 enabled = in_params.enabled;
52
53 if (!IsChannelCountValid(in_specific->channel_count)) {
54 params->channel_count = params->channel_count_max;
55 }
56
57 if (!IsChannelCountValid(in_specific->channel_count) ||
58 old_state != ParameterState::Updated) {
59 params->state = old_state;
60 }
61
62 if (buffer_unmapped || in_params.is_new) {
63 usage_state = UsageState::New;
64 params->state = ParameterState::Initialized;
65 buffer_unmapped = !pool_mapper.TryAttachBuffer(
66 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
67 return;
68 }
69 }
70 error_info.error_code = ResultSuccess;
71 error_info.address = CpuAddr(0);
72}
73
74void DelayInfo::UpdateForCommandGeneration() {
75 if (enabled) {
76 usage_state = UsageState::Enabled;
77 } else {
78 usage_state = UsageState::Disabled;
79 }
80
81 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
82 params->state = ParameterState::Updated;
83}
84
85void DelayInfo::InitializeResultState(EffectResultState& result_state) {}
86
87void DelayInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
88
89CpuAddr DelayInfo::GetWorkbuffer(s32 index) {
90 return GetSingleBuffer(index);
91}
92
93} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/delay.h b/src/audio_core/renderer/effect/delay.h
new file mode 100644
index 000000000..accc42a06
--- /dev/null
+++ b/src/audio_core/renderer/effect/delay.h
@@ -0,0 +1,135 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <vector>
8
9#include "audio_core/common/common.h"
10#include "audio_core/renderer/effect/effect_info_base.h"
11#include "common/common_types.h"
12#include "common/fixed_point.h"
13
14namespace AudioCore::AudioRenderer {
15
16class DelayInfo : public EffectInfoBase {
17public:
18 struct ParameterVersion1 {
19 /* 0x00 */ std::array<s8, MaxChannels> inputs;
20 /* 0x06 */ std::array<s8, MaxChannels> outputs;
21 /* 0x0C */ u16 channel_count_max;
22 /* 0x0E */ u16 channel_count;
23 /* 0x10 */ u32 delay_time_max;
24 /* 0x14 */ u32 delay_time;
25 /* 0x18 */ Common::FixedPoint<18, 14> sample_rate;
26 /* 0x1C */ Common::FixedPoint<18, 14> in_gain;
27 /* 0x20 */ Common::FixedPoint<18, 14> feedback_gain;
28 /* 0x24 */ Common::FixedPoint<18, 14> wet_gain;
29 /* 0x28 */ Common::FixedPoint<18, 14> dry_gain;
30 /* 0x2C */ Common::FixedPoint<18, 14> channel_spread;
31 /* 0x30 */ Common::FixedPoint<18, 14> lowpass_amount;
32 /* 0x34 */ ParameterState state;
33 };
34 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
35 "DelayInfo::ParameterVersion1 has the wrong size!");
36
37 struct ParameterVersion2 {
38 /* 0x00 */ std::array<s8, MaxChannels> inputs;
39 /* 0x06 */ std::array<s8, MaxChannels> outputs;
40 /* 0x0C */ s16 channel_count_max;
41 /* 0x0E */ s16 channel_count;
42 /* 0x10 */ s32 delay_time_max;
43 /* 0x14 */ s32 delay_time;
44 /* 0x18 */ s32 sample_rate;
45 /* 0x1C */ s32 in_gain;
46 /* 0x20 */ s32 feedback_gain;
47 /* 0x24 */ s32 wet_gain;
48 /* 0x28 */ s32 dry_gain;
49 /* 0x2C */ s32 channel_spread;
50 /* 0x30 */ s32 lowpass_amount;
51 /* 0x34 */ ParameterState state;
52 };
53 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
54 "DelayInfo::ParameterVersion2 has the wrong size!");
55
56 struct DelayLine {
57 Common::FixedPoint<50, 14> Read() const {
58 return buffer[buffer_pos];
59 }
60
61 void Write(const Common::FixedPoint<50, 14> value) {
62 buffer[buffer_pos] = value;
63 buffer_pos = static_cast<u32>((buffer_pos + 1) % buffer.size());
64 }
65
66 s32 sample_count_max{};
67 s32 sample_count{};
68 std::vector<Common::FixedPoint<50, 14>> buffer{};
69 u32 buffer_pos{};
70 Common::FixedPoint<18, 14> decay_rate{};
71 };
72
73 struct State {
74 /* 0x000 */ std::array<s32, 8> unk_000;
75 /* 0x020 */ std::array<DelayLine, MaxChannels> delay_lines;
76 /* 0x0B0 */ Common::FixedPoint<18, 14> feedback_gain;
77 /* 0x0B4 */ Common::FixedPoint<18, 14> delay_feedback_gain;
78 /* 0x0B8 */ Common::FixedPoint<18, 14> delay_feedback_cross_gain;
79 /* 0x0BC */ Common::FixedPoint<18, 14> lowpass_gain;
80 /* 0x0C0 */ Common::FixedPoint<18, 14> lowpass_feedback_gain;
81 /* 0x0C4 */ std::array<Common::FixedPoint<50, 14>, MaxChannels> lowpass_z;
82 };
83 static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
84 "DelayInfo::State has the wrong size!");
85
86 /**
87 * Update the info with new parameters, version 1.
88 *
89 * @param error_info - Used to write call result code.
90 * @param in_params - New parameters to update the info with.
91 * @param pool_mapper - Pool for mapping buffers.
92 */
93 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
94 const PoolMapper& pool_mapper) override;
95
96 /**
97 * Update the info with new parameters, version 2.
98 *
99 * @param error_info - Used to write call result code.
100 * @param in_params - New parameters to update the info with.
101 * @param pool_mapper - Pool for mapping buffers.
102 */
103 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
104 const PoolMapper& pool_mapper) override;
105
106 /**
107 * Update the info after command generation. Usually only changes its state.
108 */
109 void UpdateForCommandGeneration() override;
110
111 /**
112 * Initialize a new result state. Version 2 only, unused.
113 *
114 * @param result_state - Result state to initialize.
115 */
116 void InitializeResultState(EffectResultState& result_state) override;
117
118 /**
119 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
120 *
121 * @param cpu_state - Host-side result state to update.
122 * @param dsp_state - AudioRenderer-side result state to update from.
123 */
124 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
125
126 /**
127 * Get a workbuffer assigned to this effect with the given index.
128 *
129 * @param index - Workbuffer index.
130 * @return Address of the buffer.
131 */
132 CpuAddr GetWorkbuffer(s32 index) override;
133};
134
135} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/effect_context.cpp b/src/audio_core/renderer/effect/effect_context.cpp
new file mode 100644
index 000000000..74c7801c9
--- /dev/null
+++ b/src/audio_core/renderer/effect/effect_context.cpp
@@ -0,0 +1,41 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/effect_context.h"
5
6namespace AudioCore::AudioRenderer {
7
8void EffectContext::Initialize(std::span<EffectInfoBase> effect_infos_, const u32 effect_count_,
9 std::span<EffectResultState> result_states_cpu_,
10 std::span<EffectResultState> result_states_dsp_,
11 const size_t dsp_state_count_) {
12 effect_infos = effect_infos_;
13 effect_count = effect_count_;
14 result_states_cpu = result_states_cpu_;
15 result_states_dsp = result_states_dsp_;
16 dsp_state_count = dsp_state_count_;
17}
18
19EffectInfoBase& EffectContext::GetInfo(const u32 index) {
20 return effect_infos[index];
21}
22
23EffectResultState& EffectContext::GetResultState(const u32 index) {
24 return result_states_cpu[index];
25}
26
27EffectResultState& EffectContext::GetDspSharedResultState(const u32 index) {
28 return result_states_dsp[index];
29}
30
31u32 EffectContext::GetCount() const {
32 return effect_count;
33}
34
35void EffectContext::UpdateStateByDspShared() {
36 for (size_t i = 0; i < dsp_state_count; i++) {
37 effect_infos[i].UpdateResultState(result_states_cpu[i], result_states_dsp[i]);
38 }
39}
40
41} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/effect_context.h b/src/audio_core/renderer/effect/effect_context.h
new file mode 100644
index 000000000..85955bd9c
--- /dev/null
+++ b/src/audio_core/renderer/effect/effect_context.h
@@ -0,0 +1,75 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <span>
7
8#include "audio_core/renderer/effect/effect_info_base.h"
9#include "audio_core/renderer/effect/effect_result_state.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13
14class EffectContext {
15public:
16 /**
17 * Initialize the effect context
18 * @param effect_infos List of effect infos for this context
19 * @param effect_count The number of effects in the list
20 * @param result_states_cpu The workbuffer of result states for the CPU for this context
21 * @param result_states_dsp The workbuffer of result states for the DSP for this context
22 * @param state_count The number of result states
23 */
24 void Initialize(std::span<EffectInfoBase> effect_infos_, const u32 effect_count_,
25 std::span<EffectResultState> result_states_cpu_,
26 std::span<EffectResultState> result_states_dsp_, const size_t dsp_state_count);
27
28 /**
29 * Get the EffectInfo for a given index
30 * @param index Which effect to return
31 * @return Pointer to the effect
32 */
33 EffectInfoBase& GetInfo(const u32 index);
34
35 /**
36 * Get the CPU result state for a given index
37 * @param index Which result to return
38 * @return Pointer to the effect result state
39 */
40 EffectResultState& GetResultState(const u32 index);
41
42 /**
43 * Get the DSP result state for a given index
44 * @param index Which result to return
45 * @return Pointer to the effect result state
46 */
47 EffectResultState& GetDspSharedResultState(const u32 index);
48
49 /**
50 * Get the number of effects in this context
51 * @return The number of effects
52 */
53 u32 GetCount() const;
54
55 /**
56 * Update the CPU and DSP result states for all effects
57 */
58 void UpdateStateByDspShared();
59
60private:
61 /// Workbuffer for all of the effects
62 std::span<EffectInfoBase> effect_infos{};
63 /// Number of effects in the workbuffer
64 u32 effect_count{};
65 /// Workbuffer of states for all effects, kept host-side and not directly modified, dsp states
66 /// are copied here on the next render frame
67 std::span<EffectResultState> result_states_cpu{};
68 /// Workbuffer of states for all effects, used by the AudioRenderer to track effect state
69 /// between calls
70 std::span<EffectResultState> result_states_dsp{};
71 /// Number of result states in the workbuffers
72 size_t dsp_state_count{};
73};
74
75} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/effect_info_base.h b/src/audio_core/renderer/effect/effect_info_base.h
new file mode 100644
index 000000000..43d0589cc
--- /dev/null
+++ b/src/audio_core/renderer/effect/effect_info_base.h
@@ -0,0 +1,435 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "audio_core/common/common.h"
9#include "audio_core/renderer/behavior/behavior_info.h"
10#include "audio_core/renderer/effect/effect_result_state.h"
11#include "audio_core/renderer/memory/address_info.h"
12#include "audio_core/renderer/memory/pool_mapper.h"
13#include "common/common_types.h"
14
15namespace AudioCore::AudioRenderer {
16/**
17 * Base of all effects. Holds various data and functions used for all derived effects.
18 * Should not be used directly.
19 */
20class EffectInfoBase {
21public:
22 enum class Type : u8 {
23 Invalid,
24 Mix,
25 Aux,
26 Delay,
27 Reverb,
28 I3dl2Reverb,
29 BiquadFilter,
30 LightLimiter,
31 Capture,
32 Compressor,
33 };
34
35 enum class UsageState {
36 Invalid,
37 New,
38 Enabled,
39 Disabled,
40 };
41
42 enum class OutStatus : u8 {
43 Invalid,
44 New,
45 Initialized,
46 Used,
47 Removed,
48 };
49
50 enum class ParameterState : u8 {
51 Initialized,
52 Updating,
53 Updated,
54 };
55
56 struct InParameterVersion1 {
57 /* 0x00 */ Type type;
58 /* 0x01 */ bool is_new;
59 /* 0x02 */ bool enabled;
60 /* 0x04 */ u32 mix_id;
61 /* 0x08 */ CpuAddr workbuffer;
62 /* 0x10 */ CpuAddr workbuffer_size;
63 /* 0x18 */ u32 process_order;
64 /* 0x1C */ char unk1C[0x4];
65 /* 0x20 */ std::array<u8, 0xA0> specific;
66 };
67 static_assert(sizeof(InParameterVersion1) == 0xC0,
68 "EffectInfoBase::InParameterVersion1 has the wrong size!");
69
70 struct InParameterVersion2 {
71 /* 0x00 */ Type type;
72 /* 0x01 */ bool is_new;
73 /* 0x02 */ bool enabled;
74 /* 0x04 */ u32 mix_id;
75 /* 0x08 */ CpuAddr workbuffer;
76 /* 0x10 */ CpuAddr workbuffer_size;
77 /* 0x18 */ u32 process_order;
78 /* 0x1C */ char unk1C[0x4];
79 /* 0x20 */ std::array<u8, 0xA0> specific;
80 };
81 static_assert(sizeof(InParameterVersion2) == 0xC0,
82 "EffectInfoBase::InParameterVersion2 has the wrong size!");
83
84 struct OutStatusVersion1 {
85 /* 0x00 */ OutStatus state;
86 /* 0x01 */ char unk01[0xF];
87 };
88 static_assert(sizeof(OutStatusVersion1) == 0x10,
89 "EffectInfoBase::OutStatusVersion1 has the wrong size!");
90
91 struct OutStatusVersion2 {
92 /* 0x00 */ OutStatus state;
93 /* 0x01 */ char unk01[0xF];
94 /* 0x10 */ EffectResultState result_state;
95 };
96 static_assert(sizeof(OutStatusVersion2) == 0x90,
97 "EffectInfoBase::OutStatusVersion2 has the wrong size!");
98
99 struct State {
100 std::array<u8, 0x500> buffer;
101 };
102 static_assert(sizeof(State) == 0x500, "EffectInfoBase::State has the wrong size!");
103
104 EffectInfoBase() {
105 Cleanup();
106 }
107
108 virtual ~EffectInfoBase() = default;
109
110 /**
111 * Cleanup this effect, resetting it to a starting state.
112 */
113 void Cleanup() {
114 type = Type::Invalid;
115 enabled = false;
116 mix_id = UnusedMixId;
117 process_order = InvalidProcessOrder;
118 buffer_unmapped = false;
119 parameter = {};
120 for (auto& workbuffer : workbuffers) {
121 workbuffer.Setup(CpuAddr(0), 0);
122 }
123 }
124
125 /**
126 * Forcibly unmap all assigned workbuffers from the AudioRenderer.
127 *
128 * @param pool_mapper - Mapper to unmap the buffers.
129 */
130 void ForceUnmapBuffers(const PoolMapper& pool_mapper) {
131 for (auto& workbuffer : workbuffers) {
132 if (workbuffer.GetReference(false) != 0) {
133 pool_mapper.ForceUnmapPointer(workbuffer);
134 }
135 }
136 }
137
138 /**
139 * Check if this effect is enabled.
140 *
141 * @return True if effect is enabled, otherwise false.
142 */
143 bool IsEnabled() const {
144 return enabled;
145 }
146
147 /**
148 * Check if this effect should not be generated.
149 *
150 * @return True if effect should be skipped, otherwise false.
151 */
152 bool ShouldSkip() const {
153 return buffer_unmapped;
154 }
155
156 /**
157 * Get the type of this effect.
158 *
159 * @return The type of this effect. See EffectInfoBase::Type
160 */
161 Type GetType() const {
162 return type;
163 }
164
165 /**
166 * Set the type of this effect.
167 *
168 * @param type_ - The new type of this effect.
169 */
170 void SetType(const Type type_) {
171 type = type_;
172 }
173
174 /**
175 * Get the mix id of this effect.
176 *
177 * @return Mix id of this effect.
178 */
179 s32 GetMixId() const {
180 return mix_id;
181 }
182
183 /**
184 * Get the processing order of this effect.
185 *
186 * @return Process order of this effect.
187 */
188 s32 GetProcessingOrder() const {
189 return process_order;
190 }
191
192 /**
193 * Get this effect's parameter data.
194 *
195 * @return Pointer to the parametter, must be cast to the correct type.
196 */
197 u8* GetParameter() {
198 return parameter.data();
199 }
200
201 /**
202 * Get this effect's parameter data.
203 *
204 * @return Pointer to the parametter, must be cast to the correct type.
205 */
206 u8* GetStateBuffer() {
207 return state.data();
208 }
209
210 /**
211 * Set this effect's usage state.
212 *
213 * @param usage - new usage state of this effect.
214 */
215 void SetUsage(const UsageState usage) {
216 usage_state = usage;
217 }
218
219 /**
220 * Check if this effects need to have its workbuffer information updated.
221 * Version 1.
222 *
223 * @param params - Input parameters.
224 * @return True if workbuffers need updating, otherwise false.
225 */
226 bool ShouldUpdateWorkBufferInfo(const InParameterVersion1& params) const {
227 return buffer_unmapped || params.is_new;
228 }
229
230 /**
231 * Check if this effects need to have its workbuffer information updated.
232 * Version 2.
233 *
234 * @param params - Input parameters.
235 * @return True if workbuffers need updating, otherwise false.
236 */
237 bool ShouldUpdateWorkBufferInfo(const InParameterVersion2& params) const {
238 return buffer_unmapped || params.is_new;
239 }
240
241 /**
242 * Get the current usage state of this effect.
243 *
244 * @return The current usage state.
245 */
246 UsageState GetUsage() const {
247 return usage_state;
248 }
249
250 /**
251 * Write the current state. Version 1.
252 *
253 * @param out_status - Status to write.
254 * @param renderer_active - Is the AudioRenderer active?
255 */
256 void StoreStatus(OutStatusVersion1& out_status, const bool renderer_active) const {
257 if (renderer_active) {
258 if (usage_state != UsageState::Disabled) {
259 out_status.state = OutStatus::Used;
260 } else {
261 out_status.state = OutStatus::Removed;
262 }
263 } else if (usage_state == UsageState::New) {
264 out_status.state = OutStatus::Used;
265 } else {
266 out_status.state = OutStatus::Removed;
267 }
268 }
269
270 /**
271 * Write the current state. Version 2.
272 *
273 * @param out_status - Status to write.
274 * @param renderer_active - Is the AudioRenderer active?
275 */
276 void StoreStatus(OutStatusVersion2& out_status, const bool renderer_active) const {
277 if (renderer_active) {
278 if (usage_state != UsageState::Disabled) {
279 out_status.state = OutStatus::Used;
280 } else {
281 out_status.state = OutStatus::Removed;
282 }
283 } else if (usage_state == UsageState::New) {
284 out_status.state = OutStatus::Used;
285 } else {
286 out_status.state = OutStatus::Removed;
287 }
288 }
289
290 /**
291 * Update the info with new parameters, version 1.
292 *
293 * @param error_info - Used to write call result code.
294 * @param in_params - New parameters to update the info with.
295 * @param pool_mapper - Pool for mapping buffers.
296 */
297 virtual void Update(BehaviorInfo::ErrorInfo& error_info,
298 [[maybe_unused]] const InParameterVersion1& params,
299 [[maybe_unused]] const PoolMapper& pool_mapper) {
300 error_info.error_code = ResultSuccess;
301 error_info.address = CpuAddr(0);
302 }
303
304 /**
305 * Update the info with new parameters, version 2.
306 *
307 * @param error_info - Used to write call result code.
308 * @param in_params - New parameters to update the info with.
309 * @param pool_mapper - Pool for mapping buffers.
310 */
311 virtual void Update(BehaviorInfo::ErrorInfo& error_info,
312 [[maybe_unused]] const InParameterVersion2& params,
313 [[maybe_unused]] const PoolMapper& pool_mapper) {
314 error_info.error_code = ResultSuccess;
315 error_info.address = CpuAddr(0);
316 }
317
318 /**
319 * Update the info after command generation. Usually only changes its state.
320 */
321 virtual void UpdateForCommandGeneration() {}
322
323 /**
324 * Initialize a new result state. Version 2 only, unused.
325 *
326 * @param result_state - Result state to initialize.
327 */
328 virtual void InitializeResultState([[maybe_unused]] EffectResultState& result_state) {}
329
330 /**
331 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
332 *
333 * @param cpu_state - Host-side result state to update.
334 * @param dsp_state - AudioRenderer-side result state to update from.
335 */
336 virtual void UpdateResultState([[maybe_unused]] EffectResultState& cpu_state,
337 [[maybe_unused]] EffectResultState& dsp_state) {}
338
339 /**
340 * Get a workbuffer assigned to this effect with the given index.
341 *
342 * @param index - Workbuffer index.
343 * @return Address of the buffer.
344 */
345 virtual CpuAddr GetWorkbuffer([[maybe_unused]] s32 index) {
346 return 0;
347 }
348
349 /**
350 * Get the first workbuffer assigned to this effect.
351 *
352 * @param index - Workbuffer index. Unused.
353 * @return Address of the buffer.
354 */
355 CpuAddr GetSingleBuffer([[maybe_unused]] const s32 index) {
356 if (enabled) {
357 return workbuffers[0].GetReference(true);
358 }
359
360 if (usage_state != UsageState::Disabled) {
361 const auto ref{workbuffers[0].GetReference(false)};
362 const auto size{workbuffers[0].GetSize()};
363 if (ref != 0 && size > 0) {
364 // Invalidate DSP cache
365 }
366 }
367 return 0;
368 }
369
370 /**
371 * Get the send buffer info, used by Aux and Capture.
372 *
373 * @return Address of the buffer info.
374 */
375 CpuAddr GetSendBufferInfo() const {
376 return send_buffer_info;
377 }
378
379 /**
380 * Get the send buffer, used by Aux and Capture.
381 *
382 * @return Address of the buffer.
383 */
384 CpuAddr GetSendBuffer() const {
385 return send_buffer;
386 }
387
388 /**
389 * Get the return buffer info, used by Aux and Capture.
390 *
391 * @return Address of the buffer info.
392 */
393 CpuAddr GetReturnBufferInfo() const {
394 return return_buffer_info;
395 }
396
397 /**
398 * Get the return buffer, used by Aux and Capture.
399 *
400 * @return Address of the buffer.
401 */
402 CpuAddr GetReturnBuffer() const {
403 return return_buffer;
404 }
405
406protected:
407 /// Type of this effect. May be changed
408 Type type{Type::Invalid};
409 /// Is this effect enabled?
410 bool enabled{};
411 /// Are this effect's buffers unmapped?
412 bool buffer_unmapped{};
413 /// Current usage state
414 UsageState usage_state{UsageState::Invalid};
415 /// Mix id of this effect
416 s32 mix_id{UnusedMixId};
417 /// Process order of this effect
418 s32 process_order{InvalidProcessOrder};
419 /// Workbuffers assigned to this effect
420 std::array<AddressInfo, 2> workbuffers{AddressInfo(CpuAddr(0), 0), AddressInfo(CpuAddr(0), 0)};
421 /// Aux/Capture buffer info for reading
422 CpuAddr send_buffer_info;
423 /// Aux/Capture buffer for reading
424 CpuAddr send_buffer;
425 /// Aux/Capture buffer info for writing
426 CpuAddr return_buffer_info;
427 /// Aux/Capture buffer for writing
428 CpuAddr return_buffer;
429 /// Parameters of this effect
430 std::array<u8, sizeof(InParameterVersion2)> parameter{};
431 /// State of this effect used by the AudioRenderer across calls
432 std::array<u8, sizeof(State)> state{};
433};
434
435} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/effect_reset.h b/src/audio_core/renderer/effect/effect_reset.h
new file mode 100644
index 000000000..1ea67e334
--- /dev/null
+++ b/src/audio_core/renderer/effect/effect_reset.h
@@ -0,0 +1,71 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include "audio_core/renderer/effect/aux_.h"
7#include "audio_core/renderer/effect/biquad_filter.h"
8#include "audio_core/renderer/effect/buffer_mixer.h"
9#include "audio_core/renderer/effect/capture.h"
10#include "audio_core/renderer/effect/compressor.h"
11#include "audio_core/renderer/effect/delay.h"
12#include "audio_core/renderer/effect/i3dl2.h"
13#include "audio_core/renderer/effect/light_limiter.h"
14#include "audio_core/renderer/effect/reverb.h"
15#include "common/common_types.h"
16
17namespace AudioCore::AudioRenderer {
18/**
19 * Reset an effect, and create a new one of the given type.
20 *
21 * @param effect - Effect to reset and re-construct.
22 * @param type - Type of the new effect to create.
23 */
24static void ResetEffect(EffectInfoBase* effect, const EffectInfoBase::Type type) {
25 *effect = {};
26
27 switch (type) {
28 case EffectInfoBase::Type::Invalid:
29 std::construct_at<EffectInfoBase>(effect);
30 effect->SetType(EffectInfoBase::Type::Invalid);
31 break;
32 case EffectInfoBase::Type::Mix:
33 std::construct_at<BufferMixerInfo>(reinterpret_cast<BufferMixerInfo*>(effect));
34 effect->SetType(EffectInfoBase::Type::Mix);
35 break;
36 case EffectInfoBase::Type::Aux:
37 std::construct_at<AuxInfo>(reinterpret_cast<AuxInfo*>(effect));
38 effect->SetType(EffectInfoBase::Type::Aux);
39 break;
40 case EffectInfoBase::Type::Delay:
41 std::construct_at<DelayInfo>(reinterpret_cast<DelayInfo*>(effect));
42 effect->SetType(EffectInfoBase::Type::Delay);
43 break;
44 case EffectInfoBase::Type::Reverb:
45 std::construct_at<ReverbInfo>(reinterpret_cast<ReverbInfo*>(effect));
46 effect->SetType(EffectInfoBase::Type::Reverb);
47 break;
48 case EffectInfoBase::Type::I3dl2Reverb:
49 std::construct_at<I3dl2ReverbInfo>(reinterpret_cast<I3dl2ReverbInfo*>(effect));
50 effect->SetType(EffectInfoBase::Type::I3dl2Reverb);
51 break;
52 case EffectInfoBase::Type::BiquadFilter:
53 std::construct_at<BiquadFilterInfo>(reinterpret_cast<BiquadFilterInfo*>(effect));
54 effect->SetType(EffectInfoBase::Type::BiquadFilter);
55 break;
56 case EffectInfoBase::Type::LightLimiter:
57 std::construct_at<LightLimiterInfo>(reinterpret_cast<LightLimiterInfo*>(effect));
58 effect->SetType(EffectInfoBase::Type::LightLimiter);
59 break;
60 case EffectInfoBase::Type::Capture:
61 std::construct_at<CaptureInfo>(reinterpret_cast<CaptureInfo*>(effect));
62 effect->SetType(EffectInfoBase::Type::Capture);
63 break;
64 case EffectInfoBase::Type::Compressor:
65 std::construct_at<CompressorInfo>(reinterpret_cast<CompressorInfo*>(effect));
66 effect->SetType(EffectInfoBase::Type::Compressor);
67 break;
68 }
69}
70
71} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/effect_result_state.h b/src/audio_core/renderer/effect/effect_result_state.h
new file mode 100644
index 000000000..ae096ad69
--- /dev/null
+++ b/src/audio_core/renderer/effect/effect_result_state.h
@@ -0,0 +1,16 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7
8#include "common/common_types.h"
9
10namespace AudioCore::AudioRenderer {
11
12struct EffectResultState {
13 std::array<u8, 0x80> state;
14};
15
16} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/i3dl2.cpp b/src/audio_core/renderer/effect/i3dl2.cpp
new file mode 100644
index 000000000..960b29cfc
--- /dev/null
+++ b/src/audio_core/renderer/effect/i3dl2.cpp
@@ -0,0 +1,94 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/i3dl2.h"
5
6namespace AudioCore::AudioRenderer {
7
8void I3dl2ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info,
9 const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 if (IsChannelCountValid(in_specific->channel_count_max)) {
14 const auto old_state{params->state};
15 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
16 mix_id = in_params.mix_id;
17 process_order = in_params.process_order;
18 enabled = in_params.enabled;
19
20 if (!IsChannelCountValid(in_specific->channel_count)) {
21 params->channel_count = params->channel_count_max;
22 }
23
24 if (!IsChannelCountValid(in_specific->channel_count) ||
25 old_state != ParameterState::Updated) {
26 params->state = old_state;
27 }
28
29 if (buffer_unmapped || in_params.is_new) {
30 usage_state = UsageState::New;
31 params->state = ParameterState::Initialized;
32 buffer_unmapped = !pool_mapper.TryAttachBuffer(
33 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
34 return;
35 }
36 }
37 error_info.error_code = ResultSuccess;
38 error_info.address = CpuAddr(0);
39}
40
41void I3dl2ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info,
42 const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
43 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
44 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
45
46 if (IsChannelCountValid(in_specific->channel_count_max)) {
47 const auto old_state{params->state};
48 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
49 mix_id = in_params.mix_id;
50 process_order = in_params.process_order;
51 enabled = in_params.enabled;
52
53 if (!IsChannelCountValid(in_specific->channel_count)) {
54 params->channel_count = params->channel_count_max;
55 }
56
57 if (!IsChannelCountValid(in_specific->channel_count) ||
58 old_state != ParameterState::Updated) {
59 params->state = old_state;
60 }
61
62 if (buffer_unmapped || in_params.is_new) {
63 usage_state = UsageState::New;
64 params->state = ParameterState::Initialized;
65 buffer_unmapped = !pool_mapper.TryAttachBuffer(
66 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
67 return;
68 }
69 }
70 error_info.error_code = ResultSuccess;
71 error_info.address = CpuAddr(0);
72}
73
74void I3dl2ReverbInfo::UpdateForCommandGeneration() {
75 if (enabled) {
76 usage_state = UsageState::Enabled;
77 } else {
78 usage_state = UsageState::Disabled;
79 }
80
81 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
82 params->state = ParameterState::Updated;
83}
84
85void I3dl2ReverbInfo::InitializeResultState(EffectResultState& result_state) {}
86
87void I3dl2ReverbInfo::UpdateResultState(EffectResultState& cpu_state,
88 EffectResultState& dsp_state) {}
89
90CpuAddr I3dl2ReverbInfo::GetWorkbuffer(s32 index) {
91 return GetSingleBuffer(index);
92}
93
94} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/i3dl2.h b/src/audio_core/renderer/effect/i3dl2.h
new file mode 100644
index 000000000..7a088a627
--- /dev/null
+++ b/src/audio_core/renderer/effect/i3dl2.h
@@ -0,0 +1,200 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <vector>
8
9#include "audio_core/common/common.h"
10#include "audio_core/renderer/effect/effect_info_base.h"
11#include "common/common_types.h"
12#include "common/fixed_point.h"
13
14namespace AudioCore::AudioRenderer {
15
16class I3dl2ReverbInfo : public EffectInfoBase {
17public:
18 struct ParameterVersion1 {
19 /* 0x00 */ std::array<s8, MaxChannels> inputs;
20 /* 0x06 */ std::array<s8, MaxChannels> outputs;
21 /* 0x0C */ u16 channel_count_max;
22 /* 0x0E */ u16 channel_count;
23 /* 0x10 */ char unk10[0x4];
24 /* 0x14 */ u32 sample_rate;
25 /* 0x18 */ f32 room_HF_gain;
26 /* 0x1C */ f32 reference_HF;
27 /* 0x20 */ f32 late_reverb_decay_time;
28 /* 0x24 */ f32 late_reverb_HF_decay_ratio;
29 /* 0x28 */ f32 room_gain;
30 /* 0x2C */ f32 reflection_gain;
31 /* 0x30 */ f32 reverb_gain;
32 /* 0x34 */ f32 late_reverb_diffusion;
33 /* 0x38 */ f32 reflection_delay;
34 /* 0x3C */ f32 late_reverb_delay_time;
35 /* 0x40 */ f32 late_reverb_density;
36 /* 0x44 */ f32 dry_gain;
37 /* 0x48 */ ParameterState state;
38 /* 0x49 */ char unk49[0x3];
39 };
40 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
41 "I3dl2ReverbInfo::ParameterVersion1 has the wrong size!");
42
43 struct ParameterVersion2 {
44 /* 0x00 */ std::array<s8, MaxChannels> inputs;
45 /* 0x06 */ std::array<s8, MaxChannels> outputs;
46 /* 0x0C */ u16 channel_count_max;
47 /* 0x0E */ u16 channel_count;
48 /* 0x10 */ char unk10[0x4];
49 /* 0x14 */ u32 sample_rate;
50 /* 0x18 */ f32 room_HF_gain;
51 /* 0x1C */ f32 reference_HF;
52 /* 0x20 */ f32 late_reverb_decay_time;
53 /* 0x24 */ f32 late_reverb_HF_decay_ratio;
54 /* 0x28 */ f32 room_gain;
55 /* 0x2C */ f32 reflection_gain;
56 /* 0x30 */ f32 reverb_gain;
57 /* 0x34 */ f32 late_reverb_diffusion;
58 /* 0x38 */ f32 reflection_delay;
59 /* 0x3C */ f32 late_reverb_delay_time;
60 /* 0x40 */ f32 late_reverb_density;
61 /* 0x44 */ f32 dry_gain;
62 /* 0x48 */ ParameterState state;
63 /* 0x49 */ char unk49[0x3];
64 };
65 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
66 "I3dl2ReverbInfo::ParameterVersion2 has the wrong size!");
67
68 static constexpr u32 MaxDelayLines = 4;
69 static constexpr u32 MaxDelayTaps = 20;
70
71 struct I3dl2DelayLine {
72 void Initialize(const s32 delay_time) {
73 max_delay = delay_time;
74 buffer.resize(delay_time + 1, 0);
75 buffer_end = &buffer[delay_time];
76 output = &buffer[0];
77 SetDelay(delay_time);
78 wet_gain = 0.0f;
79 }
80
81 void SetDelay(const s32 delay_time) {
82 if (max_delay < delay_time) {
83 return;
84 }
85 delay = delay_time;
86 input = &buffer[(output - buffer.data() + delay) % (max_delay + 1)];
87 }
88
89 Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) {
90 Write(sample);
91
92 auto out_sample{Read()};
93
94 output++;
95 if (output >= buffer_end) {
96 output = buffer.data();
97 }
98
99 return out_sample;
100 }
101
102 Common::FixedPoint<50, 14> Read() {
103 return *output;
104 }
105
106 void Write(const Common::FixedPoint<50, 14> sample) {
107 *(input++) = sample;
108 if (input >= buffer_end) {
109 input = buffer.data();
110 }
111 }
112
113 Common::FixedPoint<50, 14> TapOut(const s32 index) {
114 auto out{input - (index + 1)};
115 if (out < buffer.data()) {
116 out += max_delay + 1;
117 }
118 return *out;
119 }
120
121 std::vector<Common::FixedPoint<50, 14>> buffer{};
122 Common::FixedPoint<50, 14>* buffer_end{};
123 s32 max_delay{};
124 Common::FixedPoint<50, 14>* input{};
125 Common::FixedPoint<50, 14>* output{};
126 s32 delay{};
127 f32 wet_gain{};
128 };
129
130 struct State {
131 f32 lowpass_0;
132 f32 lowpass_1;
133 f32 lowpass_2;
134 I3dl2DelayLine early_delay_line;
135 std::array<s32, MaxDelayTaps> early_tap_steps;
136 f32 early_gain;
137 f32 late_gain;
138 s32 early_to_late_taps;
139 std::array<I3dl2DelayLine, MaxDelayLines> fdn_delay_lines;
140 std::array<I3dl2DelayLine, MaxDelayLines> decay_delay_lines0;
141 std::array<I3dl2DelayLine, MaxDelayLines> decay_delay_lines1;
142 f32 last_reverb_echo;
143 I3dl2DelayLine center_delay_line;
144 std::array<std::array<f32, 3>, MaxDelayLines> lowpass_coeff;
145 std::array<f32, MaxDelayLines> shelf_filter;
146 f32 dry_gain;
147 };
148 static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
149 "I3dl2ReverbInfo::State is too large!");
150
151 /**
152 * Update the info with new parameters, version 1.
153 *
154 * @param error_info - Used to write call result code.
155 * @param in_params - New parameters to update the info with.
156 * @param pool_mapper - Pool for mapping buffers.
157 */
158 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
159 const PoolMapper& pool_mapper) override;
160
161 /**
162 * Update the info with new parameters, version 2.
163 *
164 * @param error_info - Used to write call result code.
165 * @param in_params - New parameters to update the info with.
166 * @param pool_mapper - Pool for mapping buffers.
167 */
168 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
169 const PoolMapper& pool_mapper) override;
170
171 /**
172 * Update the info after command generation. Usually only changes its state.
173 */
174 void UpdateForCommandGeneration() override;
175
176 /**
177 * Initialize a new result state. Version 2 only, unused.
178 *
179 * @param result_state - Result state to initialize.
180 */
181 void InitializeResultState(EffectResultState& result_state) override;
182
183 /**
184 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
185 *
186 * @param cpu_state - Host-side result state to update.
187 * @param dsp_state - AudioRenderer-side result state to update from.
188 */
189 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
190
191 /**
192 * Get a workbuffer assigned to this effect with the given index.
193 *
194 * @param index - Workbuffer index.
195 * @return Address of the buffer.
196 */
197 CpuAddr GetWorkbuffer(s32 index) override;
198};
199
200} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/light_limiter.cpp b/src/audio_core/renderer/effect/light_limiter.cpp
new file mode 100644
index 000000000..1635a952d
--- /dev/null
+++ b/src/audio_core/renderer/effect/light_limiter.cpp
@@ -0,0 +1,81 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/light_limiter.h"
5
6namespace AudioCore::AudioRenderer {
7
8void LightLimiterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
9 const InParameterVersion1& in_params, const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
14 mix_id = in_params.mix_id;
15 process_order = in_params.process_order;
16 enabled = in_params.enabled;
17
18 if (buffer_unmapped || in_params.is_new) {
19 usage_state = UsageState::New;
20 params->state = ParameterState::Initialized;
21 buffer_unmapped = !pool_mapper.TryAttachBuffer(
22 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
23 } else {
24 error_info.error_code = ResultSuccess;
25 error_info.address = CpuAddr(0);
26 }
27}
28
29void LightLimiterInfo::Update(BehaviorInfo::ErrorInfo& error_info,
30 const InParameterVersion2& in_params, const PoolMapper& pool_mapper) {
31 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
32 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
33
34 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
35 mix_id = in_params.mix_id;
36 process_order = in_params.process_order;
37 enabled = in_params.enabled;
38
39 if (buffer_unmapped || in_params.is_new) {
40 usage_state = UsageState::New;
41 params->state = ParameterState::Initialized;
42 buffer_unmapped = !pool_mapper.TryAttachBuffer(
43 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
44 } else {
45 error_info.error_code = ResultSuccess;
46 error_info.address = CpuAddr(0);
47 }
48}
49
50void LightLimiterInfo::UpdateForCommandGeneration() {
51 if (enabled) {
52 usage_state = UsageState::Enabled;
53 } else {
54 usage_state = UsageState::Disabled;
55 }
56
57 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
58 params->state = ParameterState::Updated;
59 params->statistics_reset_required = false;
60}
61
62void LightLimiterInfo::InitializeResultState(EffectResultState& result_state) {
63 auto result_state_{reinterpret_cast<StatisticsInternal*>(result_state.state.data())};
64
65 result_state_->channel_max_sample.fill(0);
66 result_state_->channel_compression_gain_min.fill(1.0f);
67}
68
69void LightLimiterInfo::UpdateResultState(EffectResultState& cpu_state,
70 EffectResultState& dsp_state) {
71 auto cpu_statistics{reinterpret_cast<StatisticsInternal*>(cpu_state.state.data())};
72 auto dsp_statistics{reinterpret_cast<StatisticsInternal*>(dsp_state.state.data())};
73
74 *cpu_statistics = *dsp_statistics;
75}
76
77CpuAddr LightLimiterInfo::GetWorkbuffer(s32 index) {
78 return GetSingleBuffer(index);
79}
80
81} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/light_limiter.h b/src/audio_core/renderer/effect/light_limiter.h
new file mode 100644
index 000000000..338d67bbc
--- /dev/null
+++ b/src/audio_core/renderer/effect/light_limiter.h
@@ -0,0 +1,138 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <vector>
8
9#include "audio_core/common/common.h"
10#include "audio_core/renderer/effect/effect_info_base.h"
11#include "common/common_types.h"
12#include "common/fixed_point.h"
13
14namespace AudioCore::AudioRenderer {
15
16class LightLimiterInfo : public EffectInfoBase {
17public:
18 enum class ProcessingMode {
19 Mode0,
20 Mode1,
21 };
22
23 struct ParameterVersion1 {
24 /* 0x00 */ std::array<s8, MaxChannels> inputs;
25 /* 0x06 */ std::array<s8, MaxChannels> outputs;
26 /* 0x0C */ u16 channel_count_max;
27 /* 0x0E */ u16 channel_count;
28 /* 0x0C */ u32 sample_rate;
29 /* 0x14 */ s32 look_ahead_time_max;
30 /* 0x18 */ s32 attack_time;
31 /* 0x1C */ s32 release_time;
32 /* 0x20 */ s32 look_ahead_time;
33 /* 0x24 */ f32 attack_coeff;
34 /* 0x28 */ f32 release_coeff;
35 /* 0x2C */ f32 threshold;
36 /* 0x30 */ f32 input_gain;
37 /* 0x34 */ f32 output_gain;
38 /* 0x38 */ s32 look_ahead_samples_min;
39 /* 0x3C */ s32 look_ahead_samples_max;
40 /* 0x40 */ ParameterState state;
41 /* 0x41 */ bool statistics_enabled;
42 /* 0x42 */ bool statistics_reset_required;
43 /* 0x43 */ ProcessingMode processing_mode;
44 };
45 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
46 "LightLimiterInfo::ParameterVersion1 has the wrong size!");
47
48 struct ParameterVersion2 {
49 /* 0x00 */ std::array<s8, MaxChannels> inputs;
50 /* 0x06 */ std::array<s8, MaxChannels> outputs;
51 /* 0x0C */ u16 channel_count_max;
52 /* 0x0E */ u16 channel_count;
53 /* 0x0C */ u32 sample_rate;
54 /* 0x14 */ s32 look_ahead_time_max;
55 /* 0x18 */ s32 attack_time;
56 /* 0x1C */ s32 release_time;
57 /* 0x20 */ s32 look_ahead_time;
58 /* 0x24 */ f32 attack_coeff;
59 /* 0x28 */ f32 release_coeff;
60 /* 0x2C */ f32 threshold;
61 /* 0x30 */ f32 input_gain;
62 /* 0x34 */ f32 output_gain;
63 /* 0x38 */ s32 look_ahead_samples_min;
64 /* 0x3C */ s32 look_ahead_samples_max;
65 /* 0x40 */ ParameterState state;
66 /* 0x41 */ bool statistics_enabled;
67 /* 0x42 */ bool statistics_reset_required;
68 /* 0x43 */ ProcessingMode processing_mode;
69 };
70 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
71 "LightLimiterInfo::ParameterVersion2 has the wrong size!");
72
73 struct State {
74 std::array<Common::FixedPoint<49, 15>, MaxChannels> samples_average;
75 std::array<Common::FixedPoint<49, 15>, MaxChannels> compression_gain;
76 std::array<s32, MaxChannels> look_ahead_sample_offsets;
77 std::array<std::vector<Common::FixedPoint<49, 15>>, MaxChannels> look_ahead_sample_buffers;
78 };
79 static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
80 "LightLimiterInfo::State has the wrong size!");
81
82 struct StatisticsInternal {
83 /* 0x00 */ std::array<f32, MaxChannels> channel_max_sample;
84 /* 0x18 */ std::array<f32, MaxChannels> channel_compression_gain_min;
85 };
86 static_assert(sizeof(StatisticsInternal) == 0x30,
87 "LightLimiterInfo::StatisticsInternal has the wrong size!");
88
89 /**
90 * Update the info with new parameters, version 1.
91 *
92 * @param error_info - Used to write call result code.
93 * @param in_params - New parameters to update the info with.
94 * @param pool_mapper - Pool for mapping buffers.
95 */
96 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
97 const PoolMapper& pool_mapper) override;
98
99 /**
100 * Update the info with new parameters, version 2.
101 *
102 * @param error_info - Used to write call result code.
103 * @param in_params - New parameters to update the info with.
104 * @param pool_mapper - Pool for mapping buffers.
105 */
106 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
107 const PoolMapper& pool_mapper) override;
108
109 /**
110 * Update the info after command generation. Usually only changes its state.
111 */
112 void UpdateForCommandGeneration() override;
113
114 /**
115 * Initialize a new limiter statistics result state. Version 2 only.
116 *
117 * @param result_state - Result state to initialize.
118 */
119 void InitializeResultState(EffectResultState& result_state) override;
120
121 /**
122 * Update the host-side limiter statistics with the ADSP-side one. Version 2 only.
123 *
124 * @param cpu_state - Host-side result state to update.
125 * @param dsp_state - AudioRenderer-side result state to update from.
126 */
127 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
128
129 /**
130 * Get a workbuffer assigned to this effect with the given index.
131 *
132 * @param index - Workbuffer index.
133 * @return Address of the buffer.
134 */
135 CpuAddr GetWorkbuffer(s32 index) override;
136};
137
138} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/reverb.cpp b/src/audio_core/renderer/effect/reverb.cpp
new file mode 100644
index 000000000..2d32383d0
--- /dev/null
+++ b/src/audio_core/renderer/effect/reverb.cpp
@@ -0,0 +1,93 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/effect/reverb.h"
5
6namespace AudioCore::AudioRenderer {
7
8void ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
9 const PoolMapper& pool_mapper) {
10 auto in_specific{reinterpret_cast<const ParameterVersion1*>(in_params.specific.data())};
11 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
12
13 if (IsChannelCountValid(in_specific->channel_count_max)) {
14 const auto old_state{params->state};
15 std::memcpy(params, in_specific, sizeof(ParameterVersion1));
16 mix_id = in_params.mix_id;
17 process_order = in_params.process_order;
18 enabled = in_params.enabled;
19
20 if (!IsChannelCountValid(in_specific->channel_count)) {
21 params->channel_count = params->channel_count_max;
22 }
23
24 if (!IsChannelCountValid(in_specific->channel_count) ||
25 old_state != ParameterState::Updated) {
26 params->state = old_state;
27 }
28
29 if (buffer_unmapped || in_params.is_new) {
30 usage_state = UsageState::New;
31 params->state = ParameterState::Initialized;
32 buffer_unmapped = !pool_mapper.TryAttachBuffer(
33 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
34 return;
35 }
36 }
37 error_info.error_code = ResultSuccess;
38 error_info.address = CpuAddr(0);
39}
40
41void ReverbInfo::Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
42 const PoolMapper& pool_mapper) {
43 auto in_specific{reinterpret_cast<const ParameterVersion2*>(in_params.specific.data())};
44 auto params{reinterpret_cast<ParameterVersion2*>(parameter.data())};
45
46 if (IsChannelCountValid(in_specific->channel_count_max)) {
47 const auto old_state{params->state};
48 std::memcpy(params, in_specific, sizeof(ParameterVersion2));
49 mix_id = in_params.mix_id;
50 process_order = in_params.process_order;
51 enabled = in_params.enabled;
52
53 if (!IsChannelCountValid(in_specific->channel_count)) {
54 params->channel_count = params->channel_count_max;
55 }
56
57 if (!IsChannelCountValid(in_specific->channel_count) ||
58 old_state != ParameterState::Updated) {
59 params->state = old_state;
60 }
61
62 if (buffer_unmapped || in_params.is_new) {
63 usage_state = UsageState::New;
64 params->state = ParameterState::Initialized;
65 buffer_unmapped = !pool_mapper.TryAttachBuffer(
66 error_info, workbuffers[0], in_params.workbuffer, in_params.workbuffer_size);
67 return;
68 }
69 }
70 error_info.error_code = ResultSuccess;
71 error_info.address = CpuAddr(0);
72}
73
74void ReverbInfo::UpdateForCommandGeneration() {
75 if (enabled) {
76 usage_state = UsageState::Enabled;
77 } else {
78 usage_state = UsageState::Disabled;
79 }
80
81 auto params{reinterpret_cast<ParameterVersion1*>(parameter.data())};
82 params->state = ParameterState::Updated;
83}
84
85void ReverbInfo::InitializeResultState(EffectResultState& result_state) {}
86
87void ReverbInfo::UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) {}
88
89CpuAddr ReverbInfo::GetWorkbuffer(s32 index) {
90 return GetSingleBuffer(index);
91}
92
93} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/effect/reverb.h b/src/audio_core/renderer/effect/reverb.h
new file mode 100644
index 000000000..b4df9f6ef
--- /dev/null
+++ b/src/audio_core/renderer/effect/reverb.h
@@ -0,0 +1,190 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#pragma once
5
6#include <array>
7#include <vector>
8
9#include "audio_core/common/common.h"
10#include "audio_core/renderer/effect/effect_info_base.h"
11#include "common/common_types.h"
12#include "common/fixed_point.h"
13
14namespace AudioCore::AudioRenderer {
15
16class ReverbInfo : public EffectInfoBase {
17public:
18 struct ParameterVersion1 {
19 /* 0x00 */ std::array<s8, MaxChannels> inputs;
20 /* 0x06 */ std::array<s8, MaxChannels> outputs;
21 /* 0x0C */ u16 channel_count_max;
22 /* 0x0E */ u16 channel_count;
23 /* 0x10 */ u32 sample_rate;
24 /* 0x14 */ u32 early_mode;
25 /* 0x18 */ s32 early_gain;
26 /* 0x1C */ s32 pre_delay;
27 /* 0x20 */ s32 late_mode;
28 /* 0x24 */ s32 late_gain;
29 /* 0x28 */ s32 decay_time;
30 /* 0x2C */ s32 high_freq_Decay_ratio;
31 /* 0x30 */ s32 colouration;
32 /* 0x34 */ s32 base_gain;
33 /* 0x38 */ s32 wet_gain;
34 /* 0x3C */ s32 dry_gain;
35 /* 0x40 */ ParameterState state;
36 };
37 static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
38 "ReverbInfo::ParameterVersion1 has the wrong size!");
39
40 struct ParameterVersion2 {
41 /* 0x00 */ std::array<s8, MaxChannels> inputs;
42 /* 0x06 */ std::array<s8, MaxChannels> outputs;
43 /* 0x0C */ u16 channel_count_max;
44 /* 0x0E */ u16 channel_count;
45 /* 0x10 */ u32 sample_rate;
46 /* 0x14 */ u32 early_mode;
47 /* 0x18 */ s32 early_gain;
48 /* 0x1C */ s32 pre_delay;
49 /* 0x20 */ s32 late_mode;
50 /* 0x24 */ s32 late_gain;
51 /* 0x28 */ s32 decay_time;
52 /* 0x2C */ s32 high_freq_decay_ratio;
53 /* 0x30 */ s32 colouration;
54 /* 0x34 */ s32 base_gain;
55 /* 0x38 */ s32 wet_gain;
56 /* 0x3C */ s32 dry_gain;
57 /* 0x40 */ ParameterState state;
58 };
59 static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
60 "ReverbInfo::ParameterVersion2 has the wrong size!");
61
62 static constexpr u32 MaxDelayLines = 4;
63 static constexpr u32 MaxDelayTaps = 10;
64 static constexpr u32 NumEarlyModes = 5;
65 static constexpr u32 NumLateModes = 5;
66
67 struct ReverbDelayLine {
68 void Initialize(const s32 delay_time, const f32 decay_rate) {
69 buffer.resize(delay_time + 1, 0);
70 buffer_end = &buffer[delay_time];
71 output = &buffer[0];
72 decay = decay_rate;
73 sample_count_max = delay_time;
74 SetDelay(delay_time);
75 }
76
77 void SetDelay(const s32 delay_time) {
78 if (sample_count_max < delay_time) {
79 return;
80 }
81 sample_count = delay_time;
82 input = &buffer[(output - buffer.data() + sample_count) % (sample_count_max + 1)];
83 }
84
85 Common::FixedPoint<50, 14> Tick(const Common::FixedPoint<50, 14> sample) {
86 Write(sample);
87
88 auto out_sample{Read()};
89
90 output++;
91 if (output >= buffer_end) {
92 output = buffer.data();
93 }
94
95 return out_sample;
96 }
97
98 Common::FixedPoint<50, 14> Read() {
99 return *output;
100 }
101
102 void Write(const Common::FixedPoint<50, 14> sample) {
103 *(input++) = sample;
104 if (input >= buffer_end) {
105 input = buffer.data();
106 }
107 }
108
109 Common::FixedPoint<50, 14> TapOut(const s32 index) {
110 auto out{input - (index + 1)};
111 if (out < buffer.data()) {
112 out += sample_count;
113 }
114 return *out;
115 }
116
117 s32 sample_count{};
118 s32 sample_count_max{};
119 std::vector<Common::FixedPoint<50, 14>> buffer{};
120 Common::FixedPoint<50, 14>* buffer_end;
121 Common::FixedPoint<50, 14>* input{};
122 Common::FixedPoint<50, 14>* output{};
123 Common::FixedPoint<50, 14> decay{};
124 };
125
126 struct State {
127 ReverbDelayLine pre_delay_line;
128 ReverbDelayLine center_delay_line;
129 std::array<s32, MaxDelayTaps> early_delay_times;
130 std::array<Common::FixedPoint<50, 14>, MaxDelayTaps> early_gains;
131 s32 pre_delay_time;
132 std::array<ReverbDelayLine, MaxDelayLines> decay_delay_lines;
133 std::array<ReverbDelayLine, MaxDelayLines> fdn_delay_lines;
134 std::array<Common::FixedPoint<50, 14>, MaxDelayLines> hf_decay_gain;
135 std::array<Common::FixedPoint<50, 14>, MaxDelayLines> hf_decay_prev_gain;
136 std::array<Common::FixedPoint<50, 14>, MaxDelayLines> prev_feedback_output;
137 };
138 static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
139 "ReverbInfo::State is too large!");
140
141 /**
142 * Update the info with new parameters, version 1.
143 *
144 * @param error_info - Used to write call result code.
145 * @param in_params - New parameters to update the info with.
146 * @param pool_mapper - Pool for mapping buffers.
147 */
148 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
149 const PoolMapper& pool_mapper) override;
150
151 /**
152 * Update the info with new parameters, version 2.
153 *
154 * @param error_info - Used to write call result code.
155 * @param in_params - New parameters to update the info with.
156 * @param pool_mapper - Pool for mapping buffers.
157 */
158 void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
159 const PoolMapper& pool_mapper) override;
160
161 /**
162 * Update the info after command generation. Usually only changes its state.
163 */
164 void UpdateForCommandGeneration() override;
165
166 /**
167 * Initialize a new result state. Version 2 only, unused.
168 *
169 * @param result_state - Result state to initialize.
170 */
171 void InitializeResultState(EffectResultState& result_state) override;
172
173 /**
174 * Update the host-side state with the ADSP-side state. Version 2 only, unused.
175 *
176 * @param cpu_state - Host-side result state to update.
177 * @param dsp_state - AudioRenderer-side result state to update from.
178 */
179 void UpdateResultState(EffectResultState& cpu_state, EffectResultState& dsp_state) override;
180
181 /**
182 * Get a workbuffer assigned to this effect with the given index.
183 *
184 * @param index - Workbuffer index.
185 * @return Address of the buffer.
186 */
187 CpuAddr GetWorkbuffer(s32 index) override;
188};
189
190} // namespace AudioCore::AudioRenderer