summaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/splitter
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/splitter
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/splitter')
-rw-r--r--src/audio_core/renderer/splitter/splitter_context.cpp217
-rw-r--r--src/audio_core/renderer/splitter/splitter_context.h189
-rw-r--r--src/audio_core/renderer/splitter/splitter_destinations_data.cpp87
-rw-r--r--src/audio_core/renderer/splitter/splitter_destinations_data.h135
-rw-r--r--src/audio_core/renderer/splitter/splitter_info.cpp79
-rw-r--r--src/audio_core/renderer/splitter/splitter_info.h107
6 files changed, 814 insertions, 0 deletions
diff --git a/src/audio_core/renderer/splitter/splitter_context.cpp b/src/audio_core/renderer/splitter/splitter_context.cpp
new file mode 100644
index 000000000..7a23ba43f
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_context.cpp
@@ -0,0 +1,217 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/common/audio_renderer_parameter.h"
5#include "audio_core/common/workbuffer_allocator.h"
6#include "audio_core/renderer/behavior/behavior_info.h"
7#include "audio_core/renderer/splitter/splitter_context.h"
8#include "common/alignment.h"
9
10namespace AudioCore::AudioRenderer {
11
12SplitterDestinationData* SplitterContext::GetDesintationData(const s32 splitter_id,
13 const s32 destination_id) {
14 return splitter_infos[splitter_id].GetData(destination_id);
15}
16
17SplitterInfo& SplitterContext::GetInfo(const s32 splitter_id) {
18 return splitter_infos[splitter_id];
19}
20
21u32 SplitterContext::GetDataCount() const {
22 return destinations_count;
23}
24
25u32 SplitterContext::GetInfoCount() const {
26 return info_count;
27}
28
29SplitterDestinationData& SplitterContext::GetData(const u32 index) {
30 return splitter_destinations[index];
31}
32
33void SplitterContext::Setup(std::span<SplitterInfo> splitter_infos_, const u32 splitter_info_count_,
34 SplitterDestinationData* splitter_destinations_,
35 const u32 destination_count_, const bool splitter_bug_fixed_) {
36 splitter_infos = splitter_infos_;
37 info_count = splitter_info_count_;
38 splitter_destinations = splitter_destinations_;
39 destinations_count = destination_count_;
40 splitter_bug_fixed = splitter_bug_fixed_;
41}
42
43bool SplitterContext::UsingSplitter() const {
44 return splitter_infos.size() > 0 && info_count > 0 && splitter_destinations != nullptr &&
45 destinations_count > 0;
46}
47
48void SplitterContext::ClearAllNewConnectionFlag() {
49 for (s32 i = 0; i < info_count; i++) {
50 splitter_infos[i].SetNewConnectionFlag();
51 }
52}
53
54bool SplitterContext::Initialize(const BehaviorInfo& behavior,
55 const AudioRendererParameterInternal& params,
56 WorkbufferAllocator& allocator) {
57 if (behavior.IsSplitterSupported() && params.splitter_infos > 0 &&
58 params.splitter_destinations > 0) {
59 splitter_infos = allocator.Allocate<SplitterInfo>(params.splitter_infos, 0x10);
60
61 for (u32 i = 0; i < params.splitter_infos; i++) {
62 std::construct_at<SplitterInfo>(&splitter_infos[i], static_cast<s32>(i));
63 }
64
65 if (splitter_infos.size() == 0) {
66 splitter_infos = {};
67 return false;
68 }
69
70 splitter_destinations =
71 allocator.Allocate<SplitterDestinationData>(params.splitter_destinations, 0x10).data();
72
73 for (s32 i = 0; i < params.splitter_destinations; i++) {
74 std::construct_at<SplitterDestinationData>(&splitter_destinations[i], i);
75 }
76
77 if (params.splitter_destinations <= 0) {
78 splitter_infos = {};
79 splitter_destinations = nullptr;
80 return false;
81 }
82
83 Setup(splitter_infos, params.splitter_infos, splitter_destinations,
84 params.splitter_destinations, behavior.IsSplitterBugFixed());
85 }
86 return true;
87}
88
89bool SplitterContext::Update(const u8* input, u32& consumed_size) {
90 auto in_params{reinterpret_cast<const InParameterHeader*>(input)};
91
92 if (destinations_count == 0 || info_count == 0) {
93 consumed_size = 0;
94 return true;
95 }
96
97 if (in_params->magic != GetSplitterInParamHeaderMagic()) {
98 consumed_size = 0;
99 return false;
100 }
101
102 for (auto& splitter_info : splitter_infos) {
103 splitter_info.ClearNewConnectionFlag();
104 }
105
106 u32 offset{sizeof(InParameterHeader)};
107 offset = UpdateInfo(input, offset, in_params->info_count);
108 offset = UpdateData(input, offset, in_params->destination_count);
109
110 consumed_size = Common::AlignUp(offset, 0x10);
111 return true;
112}
113
114u32 SplitterContext::UpdateInfo(const u8* input, u32 offset, const u32 splitter_count) {
115 for (u32 i = 0; i < splitter_count; i++) {
116 auto info_header{reinterpret_cast<const SplitterInfo::InParameter*>(input + offset)};
117
118 if (info_header->magic != GetSplitterInfoMagic()) {
119 continue;
120 }
121
122 if (info_header->id < 0 || info_header->id > info_count) {
123 break;
124 }
125
126 auto& info{splitter_infos[info_header->id]};
127 RecomposeDestination(info, info_header);
128
129 offset += info.Update(info_header);
130 }
131
132 return offset;
133}
134
135u32 SplitterContext::UpdateData(const u8* input, u32 offset, const u32 count) {
136 for (u32 i = 0; i < count; i++) {
137 auto data_header{
138 reinterpret_cast<const SplitterDestinationData::InParameter*>(input + offset)};
139
140 if (data_header->magic != GetSplitterSendDataMagic()) {
141 continue;
142 }
143
144 if (data_header->id < 0 || data_header->id > destinations_count) {
145 continue;
146 }
147
148 splitter_destinations[data_header->id].Update(*data_header);
149 offset += sizeof(SplitterDestinationData::InParameter);
150 }
151
152 return offset;
153}
154
155void SplitterContext::UpdateInternalState() {
156 for (s32 i = 0; i < info_count; i++) {
157 splitter_infos[i].UpdateInternalState();
158 }
159}
160
161void SplitterContext::RecomposeDestination(SplitterInfo& out_info,
162 const SplitterInfo::InParameter* info_header) {
163 auto destination{out_info.GetData(0)};
164 while (destination != nullptr) {
165 auto dest{destination->GetNext()};
166 destination->SetNext(nullptr);
167 destination = dest;
168 }
169 out_info.SetDestinations(nullptr);
170
171 auto dest_count{info_header->destination_count};
172 if (!splitter_bug_fixed) {
173 dest_count = std::min(dest_count, GetDestCountPerInfoForCompat());
174 }
175
176 if (dest_count == 0) {
177 return;
178 }
179
180 std::span<const u32> destination_ids{reinterpret_cast<const u32*>(&info_header[1]), dest_count};
181
182 auto head{&splitter_destinations[destination_ids[0]]};
183 auto current_destination{head};
184 for (u32 i = 1; i < dest_count; i++) {
185 auto next_destination{&splitter_destinations[destination_ids[i]]};
186 current_destination->SetNext(next_destination);
187 current_destination = next_destination;
188 }
189
190 out_info.SetDestinations(head);
191 out_info.SetDestinationCount(dest_count);
192}
193
194u32 SplitterContext::GetDestCountPerInfoForCompat() const {
195 if (info_count <= 0) {
196 return 0;
197 }
198 return static_cast<u32>(destinations_count / info_count);
199}
200
201u64 SplitterContext::CalcWorkBufferSize(const BehaviorInfo& behavior,
202 const AudioRendererParameterInternal& params) {
203 u64 size{0};
204 if (!behavior.IsSplitterSupported()) {
205 return size;
206 }
207
208 size += params.splitter_destinations * sizeof(SplitterDestinationData) +
209 params.splitter_infos * sizeof(SplitterInfo);
210
211 if (behavior.IsSplitterBugFixed()) {
212 size += Common::AlignUp(params.splitter_destinations * sizeof(u32), 0x10);
213 }
214 return size;
215}
216
217} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/splitter/splitter_context.h b/src/audio_core/renderer/splitter/splitter_context.h
new file mode 100644
index 000000000..cfd092b4f
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_context.h
@@ -0,0 +1,189 @@
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/splitter/splitter_destinations_data.h"
9#include "audio_core/renderer/splitter/splitter_info.h"
10#include "common/common_types.h"
11
12namespace AudioCore {
13struct AudioRendererParameterInternal;
14class WorkbufferAllocator;
15
16namespace AudioRenderer {
17class BehaviorInfo;
18
19/**
20 * The splitter allows much more control over how sound is mixed together.
21 * Previously, one mix can only connect to one other, and you may need
22 * more mixes (and duplicate processing) to achieve the same result.
23 * With the splitter, many-to-one and one-to-many mixing is possible.
24 * This was added in revision 2.
25 * Had a bug with incorrect numbers of destinations, fixed in revision 5.
26 */
27class SplitterContext {
28 struct InParameterHeader {
29 /* 0x00 */ u32 magic; // 'SNDH'
30 /* 0x04 */ s32 info_count;
31 /* 0x08 */ s32 destination_count;
32 /* 0x0C */ char unk0C[0x14];
33 };
34 static_assert(sizeof(InParameterHeader) == 0x20,
35 "SplitterContext::InParameterHeader has the wrong size!");
36
37public:
38 /**
39 * Get a destination mix from the given splitter and destination index.
40 *
41 * @param splitter_id - Splitter index to get from.
42 * @param destination_id - Destination index within the splitter.
43 * @return Pointer to the found destination. May be nullptr.
44 */
45 SplitterDestinationData* GetDesintationData(s32 splitter_id, s32 destination_id);
46
47 /**
48 * Get a splitter from the given index.
49 *
50 * @param index - Index of the desired splitter.
51 * @return Splitter requested.
52 */
53 SplitterInfo& GetInfo(s32 index);
54
55 /**
56 * Get the total number of splitter destinations.
57 *
58 * @return Number of destiantions.
59 */
60 u32 GetDataCount() const;
61
62 /**
63 * Get the total number of splitters.
64 *
65 * @return Number of splitters.
66 */
67 u32 GetInfoCount() const;
68
69 /**
70 * Get a specific global destination.
71 *
72 * @param index - Index of the desired destination.
73 * @return The requested destination.
74 */
75 SplitterDestinationData& GetData(u32 index);
76
77 /**
78 * Check if the splitter is in use.
79 *
80 * @return True if any splitter or destination is in use, otherwise false.
81 */
82 bool UsingSplitter() const;
83
84 /**
85 * Mark all splitters as having new connections.
86 */
87 void ClearAllNewConnectionFlag();
88
89 /**
90 * Initialize the context.
91 *
92 * @param behavior - Used to check for splitter support.
93 * @param params - Input parameters.
94 * @param allocator - Allocator used to allocate workbuffer memory.
95 */
96 bool Initialize(const BehaviorInfo& behavior, const AudioRendererParameterInternal& params,
97 WorkbufferAllocator& allocator);
98
99 /**
100 * Update the context.
101 *
102 * @param input - Input buffer with the new info,
103 * expected to point to a InParameterHeader.
104 * @param consumed_size - Output with the number of bytes consumed from input.
105 */
106 bool Update(const u8* input, u32& consumed_size);
107
108 /**
109 * Update the splitters.
110 *
111 * @param input - Input buffer with the new info.
112 * @param offset - Current offset within the input buffer,
113 * input + offset should point to a SplitterInfo::InParameter.
114 * @param splitter_count - Number of splitters in the input buffer.
115 * @return Number of bytes consumed in input.
116 */
117 u32 UpdateInfo(const u8* input, u32 offset, u32 splitter_count);
118
119 /**
120 * Update the splitters.
121 *
122 * @param input - Input buffer with the new info.
123 * @param offset - Current offset within the input buffer,
124 * input + offset should point to a
125 * SplitterDestinationData::InParameter.
126 * @param destination_count - Number of destinations in the input buffer.
127 * @return Number of bytes consumed in input.
128 */
129 u32 UpdateData(const u8* input, u32 offset, u32 destination_count);
130
131 /**
132 * Update the state of all destinations in all splitters.
133 */
134 void UpdateInternalState();
135
136 /**
137 * Replace the given splitter's destinations with new ones.
138 *
139 * @param out_info - Splitter to recompose.
140 * @param info_header - Input parameters containing new destination ids.
141 */
142 void RecomposeDestination(SplitterInfo& out_info, const SplitterInfo::InParameter* info_header);
143
144 /**
145 * Old calculation for destinations, this is the thing the splitter bug fixes.
146 * Left for compatibility, and now min'd with the actual count to not bug.
147 *
148 * @return Number of splitter destinations.
149 */
150 u32 GetDestCountPerInfoForCompat() const;
151
152 /**
153 * Calculate the size of the required workbuffer for splitters and destinations.
154 *
155 * @param behavior - Used to check splitter features.
156 * @param params - Input parameters with splitter/destination counts.
157 * @return Required buffer size.
158 */
159 static u64 CalcWorkBufferSize(const BehaviorInfo& behavior,
160 const AudioRendererParameterInternal& params);
161
162private:
163 /**
164 * Setup the context.
165 *
166 * @param splitter_infos - Workbuffer for splitters.
167 * @param splitter_info_count - Number of splitters in the workbuffer.
168 * @param splitter_destinations - Workbuffer for splitter destinations.
169 * @param destination_count - Number of destinations in the workbuffer.
170 * @param splitter_bug_fixed - Is the splitter bug fixed?
171 */
172 void Setup(std::span<SplitterInfo> splitter_infos, u32 splitter_info_count,
173 SplitterDestinationData* splitter_destinations, u32 destination_count,
174 bool splitter_bug_fixed);
175
176 /// Workbuffer for splitters
177 std::span<SplitterInfo> splitter_infos{};
178 /// Number of splitters in buffer
179 s32 info_count{};
180 /// Workbuffer for destinations
181 SplitterDestinationData* splitter_destinations{};
182 /// Number of destinations in buffer
183 s32 destinations_count{};
184 /// Is the splitter bug fixed?
185 bool splitter_bug_fixed{};
186};
187
188} // namespace AudioRenderer
189} // namespace AudioCore
diff --git a/src/audio_core/renderer/splitter/splitter_destinations_data.cpp b/src/audio_core/renderer/splitter/splitter_destinations_data.cpp
new file mode 100644
index 000000000..b27d44896
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_destinations_data.cpp
@@ -0,0 +1,87 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/splitter/splitter_destinations_data.h"
5
6namespace AudioCore::AudioRenderer {
7
8SplitterDestinationData::SplitterDestinationData(const s32 id_) : id{id_} {}
9
10void SplitterDestinationData::ClearMixVolume() {
11 mix_volumes.fill(0.0f);
12 prev_mix_volumes.fill(0.0f);
13}
14
15s32 SplitterDestinationData::GetId() const {
16 return id;
17}
18
19bool SplitterDestinationData::IsConfigured() const {
20 return in_use && destination_id != UnusedMixId;
21}
22
23s32 SplitterDestinationData::GetMixId() const {
24 return destination_id;
25}
26
27f32 SplitterDestinationData::GetMixVolume(const u32 index) const {
28 if (index >= mix_volumes.size()) {
29 LOG_ERROR(Service_Audio, "SplitterDestinationData::GetMixVolume Invalid index {}", index);
30 return 0.0f;
31 }
32 return mix_volumes[index];
33}
34
35std::span<f32> SplitterDestinationData::GetMixVolume() {
36 return mix_volumes;
37}
38
39f32 SplitterDestinationData::GetMixVolumePrev(const u32 index) const {
40 if (index >= prev_mix_volumes.size()) {
41 LOG_ERROR(Service_Audio, "SplitterDestinationData::GetMixVolumePrev Invalid index {}",
42 index);
43 return 0.0f;
44 }
45 return prev_mix_volumes[index];
46}
47
48std::span<f32> SplitterDestinationData::GetMixVolumePrev() {
49 return prev_mix_volumes;
50}
51
52void SplitterDestinationData::Update(const InParameter& params) {
53 if (params.id != id || params.magic != GetSplitterSendDataMagic()) {
54 return;
55 }
56
57 destination_id = params.mix_id;
58 mix_volumes = params.mix_volumes;
59
60 if (!in_use && params.in_use) {
61 prev_mix_volumes = mix_volumes;
62 need_update = false;
63 }
64
65 in_use = params.in_use;
66}
67
68void SplitterDestinationData::MarkAsNeedToUpdateInternalState() {
69 need_update = true;
70}
71
72void SplitterDestinationData::UpdateInternalState() {
73 if (in_use && need_update) {
74 prev_mix_volumes = mix_volumes;
75 }
76 need_update = false;
77}
78
79SplitterDestinationData* SplitterDestinationData::GetNext() const {
80 return next;
81}
82
83void SplitterDestinationData::SetNext(SplitterDestinationData* next_) {
84 next = next_;
85}
86
87} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/splitter/splitter_destinations_data.h b/src/audio_core/renderer/splitter/splitter_destinations_data.h
new file mode 100644
index 000000000..bd3d55748
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_destinations_data.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 <span>
8
9#include "audio_core/common/common.h"
10#include "common/common_types.h"
11
12namespace AudioCore::AudioRenderer {
13/**
14 * Represents a mixing node, can be connected to a previous and next destination forming a chain
15 * that a certain mix buffer will pass through to output.
16 */
17class SplitterDestinationData {
18public:
19 struct InParameter {
20 /* 0x00 */ u32 magic; // 'SNDD'
21 /* 0x04 */ s32 id;
22 /* 0x08 */ std::array<f32, MaxMixBuffers> mix_volumes;
23 /* 0x68 */ u32 mix_id;
24 /* 0x6C */ bool in_use;
25 };
26 static_assert(sizeof(InParameter) == 0x70,
27 "SplitterDestinationData::InParameter has the wrong size!");
28
29 SplitterDestinationData(s32 id);
30
31 /**
32 * Reset the mix volumes for this destination.
33 */
34 void ClearMixVolume();
35
36 /**
37 * Get the id of this destination.
38 *
39 * @return Id for this destination.
40 */
41 s32 GetId() const;
42
43 /**
44 * Check if this destination is correctly configured.
45 *
46 * @return True if configured, otherwise false.
47 */
48 bool IsConfigured() const;
49
50 /**
51 * Get the mix id for this destination.
52 *
53 * @return Mix id for this destination.
54 */
55 s32 GetMixId() const;
56
57 /**
58 * Get the current mix volume of a given index in this destination.
59 *
60 * @param index - Mix buffer index to get the volume for.
61 * @return Current volume of the specified mix.
62 */
63 f32 GetMixVolume(u32 index) const;
64
65 /**
66 * Get the current mix volumes for all mix buffers in this destination.
67 *
68 * @return Span of current mix buffer volumes.
69 */
70 std::span<f32> GetMixVolume();
71
72 /**
73 * Get the previous mix volume of a given index in this destination.
74 *
75 * @param index - Mix buffer index to get the volume for.
76 * @return Previous volume of the specified mix.
77 */
78 f32 GetMixVolumePrev(u32 index) const;
79
80 /**
81 * Get the previous mix volumes for all mix buffers in this destination.
82 *
83 * @return Span of previous mix buffer volumes.
84 */
85 std::span<f32> GetMixVolumePrev();
86
87 /**
88 * Update this destination.
89 *
90 * @param params - Inpout parameters to update the destination.
91 */
92 void Update(const InParameter& params);
93
94 /**
95 * Mark this destination as needing its volumes updated.
96 */
97 void MarkAsNeedToUpdateInternalState();
98
99 /**
100 * Copy current volumes to previous if an update is required.
101 */
102 void UpdateInternalState();
103
104 /**
105 * Get the next destination in the mix chain.
106 *
107 * @return The next splitter destination, may be nullptr if this is the last in the chain.
108 */
109 SplitterDestinationData* GetNext() const;
110
111 /**
112 * Set the next destination in the mix chain.
113 *
114 * @param next - Destination this one is to be connected to.
115 */
116 void SetNext(SplitterDestinationData* next);
117
118private:
119 /// Id of this destination
120 const s32 id;
121 /// Mix id this destination represents
122 s32 destination_id{UnusedMixId};
123 /// Current mix volumes
124 std::array<f32, MaxMixBuffers> mix_volumes{0.0f};
125 /// Previous mix volumes
126 std::array<f32, MaxMixBuffers> prev_mix_volumes{0.0f};
127 /// Next destination in the mix chain
128 SplitterDestinationData* next{};
129 /// Is this destiantion in use?
130 bool in_use{};
131 /// Does this destiantion need its volumes updated?
132 bool need_update{};
133};
134
135} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/splitter/splitter_info.cpp b/src/audio_core/renderer/splitter/splitter_info.cpp
new file mode 100644
index 000000000..1aee6720b
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_info.cpp
@@ -0,0 +1,79 @@
1// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
2// SPDX-License-Identifier: GPL-2.0-or-later
3
4#include "audio_core/renderer/splitter/splitter_info.h"
5
6namespace AudioCore::AudioRenderer {
7
8SplitterInfo::SplitterInfo(const s32 id_) : id{id_} {}
9
10void SplitterInfo::InitializeInfos(SplitterInfo* splitters, const u32 count) {
11 if (splitters == nullptr) {
12 return;
13 }
14
15 for (u32 i = 0; i < count; i++) {
16 auto& splitter{splitters[i]};
17 splitter.destinations = nullptr;
18 splitter.destination_count = 0;
19 splitter.has_new_connection = true;
20 }
21}
22
23u32 SplitterInfo::Update(const InParameter* params) {
24 if (params->id != id) {
25 return 0;
26 }
27 sample_rate = params->sample_rate;
28 has_new_connection = true;
29 return static_cast<u32>((sizeof(InParameter) + 3 * sizeof(s32)) +
30 params->destination_count * sizeof(s32));
31}
32
33SplitterDestinationData* SplitterInfo::GetData(const u32 destination_id) {
34 auto out_destination{destinations};
35 u32 i{0};
36 while (i < destination_id) {
37 if (out_destination == nullptr) {
38 break;
39 }
40 out_destination = out_destination->GetNext();
41 i++;
42 }
43
44 return out_destination;
45}
46
47u32 SplitterInfo::GetDestinationCount() const {
48 return destination_count;
49}
50
51void SplitterInfo::SetDestinationCount(const u32 count) {
52 destination_count = count;
53}
54
55bool SplitterInfo::HasNewConnection() const {
56 return has_new_connection;
57}
58
59void SplitterInfo::ClearNewConnectionFlag() {
60 has_new_connection = false;
61}
62
63void SplitterInfo::SetNewConnectionFlag() {
64 has_new_connection = true;
65}
66
67void SplitterInfo::UpdateInternalState() {
68 auto destination{destinations};
69 while (destination != nullptr) {
70 destination->UpdateInternalState();
71 destination = destination->GetNext();
72 }
73}
74
75void SplitterInfo::SetDestinations(SplitterDestinationData* destinations_) {
76 destinations = destinations_;
77}
78
79} // namespace AudioCore::AudioRenderer
diff --git a/src/audio_core/renderer/splitter/splitter_info.h b/src/audio_core/renderer/splitter/splitter_info.h
new file mode 100644
index 000000000..d1d75064c
--- /dev/null
+++ b/src/audio_core/renderer/splitter/splitter_info.h
@@ -0,0 +1,107 @@
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/splitter/splitter_destinations_data.h"
7#include "common/common_types.h"
8
9namespace AudioCore::AudioRenderer {
10/**
11 * Represents a splitter, wraps multiple output destinations to split an input mix into.
12 */
13class SplitterInfo {
14public:
15 struct InParameter {
16 /* 0x00 */ u32 magic; // 'SNDI'
17 /* 0x04 */ s32 id;
18 /* 0x08 */ u32 sample_rate;
19 /* 0x0C */ u32 destination_count;
20 };
21 static_assert(sizeof(InParameter) == 0x10, "SplitterInfo::InParameter has the wrong size!");
22
23 explicit SplitterInfo(s32 id);
24
25 /**
26 * Initialize the given splitters.
27 *
28 * @param splitters - Splitters to initialize.
29 * @param count - Number of splitters given.
30 */
31 static void InitializeInfos(SplitterInfo* splitters, u32 count);
32
33 /**
34 * Update this splitter.
35 *
36 * @param params - Input parameters to update with.
37 * @return The size in bytes of this splitter.
38 */
39 u32 Update(const InParameter* params);
40
41 /**
42 * Get a destination in this splitter.
43 *
44 * @param id - Destination id to get.
45 * @return Pointer to the destination, may be nullptr.
46 */
47 SplitterDestinationData* GetData(u32 id);
48
49 /**
50 * Get the number of destinations in this splitter.
51 *
52 * @return The number of destiantions.
53 */
54 u32 GetDestinationCount() const;
55
56 /**
57 * Set the number of destinations in this splitter.
58 *
59 * @param count - The new number of destiantions.
60 */
61 void SetDestinationCount(u32 count);
62
63 /**
64 * Check if the splitter has a new connection.
65 *
66 * @return True if there is a new connection, otherwise false.
67 */
68 bool HasNewConnection() const;
69
70 /**
71 * Reset the new connection flag.
72 */
73 void ClearNewConnectionFlag();
74
75 /**
76 * Mark as having a new connection.
77 */
78 void SetNewConnectionFlag();
79
80 /**
81 * Update the state of all destinations.
82 */
83 void UpdateInternalState();
84
85 /**
86 * Set this splitter's destinations.
87 *
88 * @param destinations - The new destination list for this splitter.
89 */
90 void SetDestinations(SplitterDestinationData* destinations);
91
92private:
93 /// Id of this splitter
94 s32 id;
95 /// Sample rate of this splitter
96 u32 sample_rate{};
97 /// Number of destinations in this splitter
98 u32 destination_count{};
99 /// Does this splitter have a new connection?
100 bool has_new_connection{true};
101 /// Pointer to the destinations of this splitter
102 SplitterDestinationData* destinations{};
103 /// Number of channels this splitter manages
104 u32 channel_count{};
105};
106
107} // namespace AudioCore::AudioRenderer