diff options
Diffstat (limited to 'src/audio_core/mix_context.cpp')
| -rw-r--r-- | src/audio_core/mix_context.cpp | 297 |
1 files changed, 0 insertions, 297 deletions
diff --git a/src/audio_core/mix_context.cpp b/src/audio_core/mix_context.cpp deleted file mode 100644 index bcaa7afab..000000000 --- a/src/audio_core/mix_context.cpp +++ /dev/null | |||
| @@ -1,297 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <algorithm> | ||
| 5 | |||
| 6 | #include "audio_core/behavior_info.h" | ||
| 7 | #include "audio_core/common.h" | ||
| 8 | #include "audio_core/effect_context.h" | ||
| 9 | #include "audio_core/mix_context.h" | ||
| 10 | #include "audio_core/splitter_context.h" | ||
| 11 | |||
| 12 | namespace AudioCore { | ||
| 13 | MixContext::MixContext() = default; | ||
| 14 | MixContext::~MixContext() = default; | ||
| 15 | |||
| 16 | void MixContext::Initialize(const BehaviorInfo& behavior_info, std::size_t mix_count, | ||
| 17 | std::size_t effect_count) { | ||
| 18 | info_count = mix_count; | ||
| 19 | infos.resize(info_count); | ||
| 20 | auto& final_mix = GetInfo(AudioCommon::FINAL_MIX); | ||
| 21 | final_mix.GetInParams().mix_id = AudioCommon::FINAL_MIX; | ||
| 22 | sorted_info.reserve(infos.size()); | ||
| 23 | for (auto& info : infos) { | ||
| 24 | sorted_info.push_back(&info); | ||
| 25 | } | ||
| 26 | |||
| 27 | for (auto& info : infos) { | ||
| 28 | info.SetEffectCount(effect_count); | ||
| 29 | } | ||
| 30 | |||
| 31 | // Only initialize our edge matrix and node states if splitters are supported | ||
| 32 | if (behavior_info.IsSplitterSupported()) { | ||
| 33 | node_states.Initialize(mix_count); | ||
| 34 | edge_matrix.Initialize(mix_count); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | void MixContext::UpdateDistancesFromFinalMix() { | ||
| 39 | // Set all distances to be invalid | ||
| 40 | for (std::size_t i = 0; i < info_count; i++) { | ||
| 41 | GetInfo(i).GetInParams().final_mix_distance = AudioCommon::NO_FINAL_MIX; | ||
| 42 | } | ||
| 43 | |||
| 44 | for (std::size_t i = 0; i < info_count; i++) { | ||
| 45 | auto& info = GetInfo(i); | ||
| 46 | auto& in_params = info.GetInParams(); | ||
| 47 | // Populate our sorted info | ||
| 48 | sorted_info[i] = &info; | ||
| 49 | |||
| 50 | if (!in_params.in_use) { | ||
| 51 | continue; | ||
| 52 | } | ||
| 53 | |||
| 54 | auto mix_id = in_params.mix_id; | ||
| 55 | // Needs to be referenced out of scope | ||
| 56 | s32 distance_to_final_mix{AudioCommon::FINAL_MIX}; | ||
| 57 | for (; distance_to_final_mix < static_cast<s32>(info_count); distance_to_final_mix++) { | ||
| 58 | if (mix_id == AudioCommon::FINAL_MIX) { | ||
| 59 | // If we're at the final mix, we're done | ||
| 60 | break; | ||
| 61 | } else if (mix_id == AudioCommon::NO_MIX) { | ||
| 62 | // If we have no more mix ids, we're done | ||
| 63 | distance_to_final_mix = AudioCommon::NO_FINAL_MIX; | ||
| 64 | break; | ||
| 65 | } else { | ||
| 66 | const auto& dest_mix = GetInfo(mix_id); | ||
| 67 | const auto dest_mix_distance = dest_mix.GetInParams().final_mix_distance; | ||
| 68 | |||
| 69 | if (dest_mix_distance == AudioCommon::NO_FINAL_MIX) { | ||
| 70 | // If our current mix isn't pointing to a final mix, follow through | ||
| 71 | mix_id = dest_mix.GetInParams().dest_mix_id; | ||
| 72 | } else { | ||
| 73 | // Our current mix + 1 = final distance | ||
| 74 | distance_to_final_mix = dest_mix_distance + 1; | ||
| 75 | break; | ||
| 76 | } | ||
| 77 | } | ||
| 78 | } | ||
| 79 | |||
| 80 | // If we're out of range for our distance, mark it as no final mix | ||
| 81 | if (distance_to_final_mix >= static_cast<s32>(info_count)) { | ||
| 82 | distance_to_final_mix = AudioCommon::NO_FINAL_MIX; | ||
| 83 | } | ||
| 84 | |||
| 85 | in_params.final_mix_distance = distance_to_final_mix; | ||
| 86 | } | ||
| 87 | } | ||
| 88 | |||
| 89 | void MixContext::CalcMixBufferOffset() { | ||
| 90 | s32 offset{}; | ||
| 91 | for (std::size_t i = 0; i < info_count; i++) { | ||
| 92 | auto& info = GetSortedInfo(i); | ||
| 93 | auto& in_params = info.GetInParams(); | ||
| 94 | if (in_params.in_use) { | ||
| 95 | // Only update if in use | ||
| 96 | in_params.buffer_offset = offset; | ||
| 97 | offset += in_params.buffer_count; | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
| 101 | |||
| 102 | void MixContext::SortInfo() { | ||
| 103 | // Get the distance to the final mix | ||
| 104 | UpdateDistancesFromFinalMix(); | ||
| 105 | |||
| 106 | // Sort based on the distance to the final mix | ||
| 107 | std::sort(sorted_info.begin(), sorted_info.end(), | ||
| 108 | [](const ServerMixInfo* lhs, const ServerMixInfo* rhs) { | ||
| 109 | return lhs->GetInParams().final_mix_distance > | ||
| 110 | rhs->GetInParams().final_mix_distance; | ||
| 111 | }); | ||
| 112 | |||
| 113 | // Calculate the mix buffer offset | ||
| 114 | CalcMixBufferOffset(); | ||
| 115 | } | ||
| 116 | |||
| 117 | bool MixContext::TsortInfo(SplitterContext& splitter_context) { | ||
| 118 | // If we're not using mixes, just calculate the mix buffer offset | ||
| 119 | if (!splitter_context.UsingSplitter()) { | ||
| 120 | CalcMixBufferOffset(); | ||
| 121 | return true; | ||
| 122 | } | ||
| 123 | // Sort our node states | ||
| 124 | if (!node_states.Tsort(edge_matrix)) { | ||
| 125 | return false; | ||
| 126 | } | ||
| 127 | |||
| 128 | // Get our sorted list | ||
| 129 | const auto sorted_list = node_states.GetIndexList(); | ||
| 130 | std::size_t info_id{}; | ||
| 131 | for (auto itr = sorted_list.rbegin(); itr != sorted_list.rend(); ++itr) { | ||
| 132 | // Set our sorted info | ||
| 133 | sorted_info[info_id++] = &GetInfo(*itr); | ||
| 134 | } | ||
| 135 | |||
| 136 | // Calculate the mix buffer offset | ||
| 137 | CalcMixBufferOffset(); | ||
| 138 | return true; | ||
| 139 | } | ||
| 140 | |||
| 141 | std::size_t MixContext::GetCount() const { | ||
| 142 | return info_count; | ||
| 143 | } | ||
| 144 | |||
| 145 | ServerMixInfo& MixContext::GetInfo(std::size_t i) { | ||
| 146 | ASSERT(i < info_count); | ||
| 147 | return infos.at(i); | ||
| 148 | } | ||
| 149 | |||
| 150 | const ServerMixInfo& MixContext::GetInfo(std::size_t i) const { | ||
| 151 | ASSERT(i < info_count); | ||
| 152 | return infos.at(i); | ||
| 153 | } | ||
| 154 | |||
| 155 | ServerMixInfo& MixContext::GetSortedInfo(std::size_t i) { | ||
| 156 | ASSERT(i < info_count); | ||
| 157 | return *sorted_info.at(i); | ||
| 158 | } | ||
| 159 | |||
| 160 | const ServerMixInfo& MixContext::GetSortedInfo(std::size_t i) const { | ||
| 161 | ASSERT(i < info_count); | ||
| 162 | return *sorted_info.at(i); | ||
| 163 | } | ||
| 164 | |||
| 165 | ServerMixInfo& MixContext::GetFinalMixInfo() { | ||
| 166 | return infos.at(AudioCommon::FINAL_MIX); | ||
| 167 | } | ||
| 168 | |||
| 169 | const ServerMixInfo& MixContext::GetFinalMixInfo() const { | ||
| 170 | return infos.at(AudioCommon::FINAL_MIX); | ||
| 171 | } | ||
| 172 | |||
| 173 | EdgeMatrix& MixContext::GetEdgeMatrix() { | ||
| 174 | return edge_matrix; | ||
| 175 | } | ||
| 176 | |||
| 177 | const EdgeMatrix& MixContext::GetEdgeMatrix() const { | ||
| 178 | return edge_matrix; | ||
| 179 | } | ||
| 180 | |||
| 181 | ServerMixInfo::ServerMixInfo() { | ||
| 182 | Cleanup(); | ||
| 183 | } | ||
| 184 | ServerMixInfo::~ServerMixInfo() = default; | ||
| 185 | |||
| 186 | const ServerMixInfo::InParams& ServerMixInfo::GetInParams() const { | ||
| 187 | return in_params; | ||
| 188 | } | ||
| 189 | |||
| 190 | ServerMixInfo::InParams& ServerMixInfo::GetInParams() { | ||
| 191 | return in_params; | ||
| 192 | } | ||
| 193 | |||
| 194 | bool ServerMixInfo::Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, | ||
| 195 | BehaviorInfo& behavior_info, SplitterContext& splitter_context, | ||
| 196 | EffectContext& effect_context) { | ||
| 197 | in_params.volume = mix_in.volume; | ||
| 198 | in_params.sample_rate = mix_in.sample_rate; | ||
| 199 | in_params.buffer_count = mix_in.buffer_count; | ||
| 200 | in_params.in_use = mix_in.in_use; | ||
| 201 | in_params.mix_id = mix_in.mix_id; | ||
| 202 | in_params.node_id = mix_in.node_id; | ||
| 203 | for (std::size_t i = 0; i < mix_in.mix_volume.size(); i++) { | ||
| 204 | std::copy(mix_in.mix_volume[i].begin(), mix_in.mix_volume[i].end(), | ||
| 205 | in_params.mix_volume[i].begin()); | ||
| 206 | } | ||
| 207 | |||
| 208 | bool require_sort = false; | ||
| 209 | |||
| 210 | if (behavior_info.IsSplitterSupported()) { | ||
| 211 | require_sort = UpdateConnection(edge_matrix, mix_in, splitter_context); | ||
| 212 | } else { | ||
| 213 | in_params.dest_mix_id = mix_in.dest_mix_id; | ||
| 214 | in_params.splitter_id = AudioCommon::NO_SPLITTER; | ||
| 215 | } | ||
| 216 | |||
| 217 | ResetEffectProcessingOrder(); | ||
| 218 | const auto effect_count = effect_context.GetCount(); | ||
| 219 | for (std::size_t i = 0; i < effect_count; i++) { | ||
| 220 | auto* effect_info = effect_context.GetInfo(i); | ||
| 221 | if (effect_info->GetMixID() == in_params.mix_id) { | ||
| 222 | effect_processing_order[effect_info->GetProcessingOrder()] = static_cast<s32>(i); | ||
| 223 | } | ||
| 224 | } | ||
| 225 | |||
| 226 | // TODO(ogniK): Update effect processing order | ||
| 227 | return require_sort; | ||
| 228 | } | ||
| 229 | |||
| 230 | bool ServerMixInfo::HasAnyConnection() const { | ||
| 231 | return in_params.splitter_id != AudioCommon::NO_SPLITTER || | ||
| 232 | in_params.mix_id != AudioCommon::NO_MIX; | ||
| 233 | } | ||
| 234 | |||
| 235 | void ServerMixInfo::Cleanup() { | ||
| 236 | in_params.volume = 0.0f; | ||
| 237 | in_params.sample_rate = 0; | ||
| 238 | in_params.buffer_count = 0; | ||
| 239 | in_params.in_use = false; | ||
| 240 | in_params.mix_id = AudioCommon::NO_MIX; | ||
| 241 | in_params.node_id = 0; | ||
| 242 | in_params.buffer_offset = 0; | ||
| 243 | in_params.dest_mix_id = AudioCommon::NO_MIX; | ||
| 244 | in_params.splitter_id = AudioCommon::NO_SPLITTER; | ||
| 245 | std::memset(in_params.mix_volume.data(), 0, sizeof(float) * in_params.mix_volume.size()); | ||
| 246 | } | ||
| 247 | |||
| 248 | void ServerMixInfo::SetEffectCount(std::size_t count) { | ||
| 249 | effect_processing_order.resize(count); | ||
| 250 | ResetEffectProcessingOrder(); | ||
| 251 | } | ||
| 252 | |||
| 253 | void ServerMixInfo::ResetEffectProcessingOrder() { | ||
| 254 | for (auto& order : effect_processing_order) { | ||
| 255 | order = AudioCommon::NO_EFFECT_ORDER; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | s32 ServerMixInfo::GetEffectOrder(std::size_t i) const { | ||
| 260 | return effect_processing_order.at(i); | ||
| 261 | } | ||
| 262 | |||
| 263 | bool ServerMixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, | ||
| 264 | SplitterContext& splitter_context) { | ||
| 265 | // Mixes are identical | ||
| 266 | if (in_params.dest_mix_id == mix_in.dest_mix_id && | ||
| 267 | in_params.splitter_id == mix_in.splitter_id && | ||
| 268 | ((in_params.splitter_id == AudioCommon::NO_SPLITTER) || | ||
| 269 | !splitter_context.GetInfo(in_params.splitter_id).HasNewConnection())) { | ||
| 270 | return false; | ||
| 271 | } | ||
| 272 | // Remove current edges for mix id | ||
| 273 | edge_matrix.RemoveEdges(in_params.mix_id); | ||
| 274 | if (mix_in.dest_mix_id != AudioCommon::NO_MIX) { | ||
| 275 | // If we have a valid destination mix id, set our edge matrix | ||
| 276 | edge_matrix.Connect(in_params.mix_id, mix_in.dest_mix_id); | ||
| 277 | } else if (mix_in.splitter_id != AudioCommon::NO_SPLITTER) { | ||
| 278 | // Recurse our splitter linked and set our edges | ||
| 279 | auto& splitter_info = splitter_context.GetInfo(mix_in.splitter_id); | ||
| 280 | const auto length = splitter_info.GetLength(); | ||
| 281 | for (s32 i = 0; i < length; i++) { | ||
| 282 | const auto* splitter_destination = | ||
| 283 | splitter_context.GetDestinationData(mix_in.splitter_id, i); | ||
| 284 | if (splitter_destination == nullptr) { | ||
| 285 | continue; | ||
| 286 | } | ||
| 287 | if (splitter_destination->ValidMixId()) { | ||
| 288 | edge_matrix.Connect(in_params.mix_id, splitter_destination->GetMixId()); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | } | ||
| 292 | in_params.dest_mix_id = mix_in.dest_mix_id; | ||
| 293 | in_params.splitter_id = mix_in.splitter_id; | ||
| 294 | return true; | ||
| 295 | } | ||
| 296 | |||
| 297 | } // namespace AudioCore | ||