yuzu/src/audio_core/renderer/mix/mix_info.cpp

121 lines
4.3 KiB
C++

// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "audio_core/renderer/behavior/behavior_info.h"
#include "audio_core/renderer/effect/effect_context.h"
#include "audio_core/renderer/mix/mix_info.h"
#include "audio_core/renderer/nodes/edge_matrix.h"
#include "audio_core/renderer/splitter/splitter_context.h"
namespace AudioCore::Renderer {
MixInfo::MixInfo(std::span<s32> effect_order_buffer_, s32 effect_count_, BehaviorInfo& behavior)
: effect_order_buffer{effect_order_buffer_}, effect_count{effect_count_},
long_size_pre_delay_supported{behavior.IsLongSizePreDelaySupported()} {
ClearEffectProcessingOrder();
}
void MixInfo::Cleanup() {
mix_id = UnusedMixId;
dst_mix_id = UnusedMixId;
dst_splitter_id = UnusedSplitterId;
}
void MixInfo::ClearEffectProcessingOrder() {
for (s32 i = 0; i < effect_count; i++) {
effect_order_buffer[i] = -1;
}
}
bool MixInfo::Update(EdgeMatrix& edge_matrix, const InParameter& in_params,
EffectContext& effect_context, SplitterContext& splitter_context,
const BehaviorInfo& behavior) {
volume = in_params.volume;
sample_rate = in_params.sample_rate;
buffer_count = static_cast<s16>(in_params.buffer_count);
in_use = in_params.in_use;
mix_id = in_params.mix_id;
node_id = in_params.node_id;
mix_volumes = in_params.mix_volumes;
bool sort_required{false};
if (behavior.IsSplitterSupported()) {
sort_required = UpdateConnection(edge_matrix, in_params, splitter_context);
} else {
if (dst_mix_id != in_params.dest_mix_id) {
dst_mix_id = in_params.dest_mix_id;
sort_required = true;
}
dst_splitter_id = UnusedSplitterId;
}
ClearEffectProcessingOrder();
// Check all effects, and set their order if they belong to this mix.
const auto count{effect_context.GetCount()};
for (u32 i = 0; i < count; i++) {
const auto& info{effect_context.GetInfo(i)};
if (mix_id == info.GetMixId()) {
const auto processing_order{info.GetProcessingOrder()};
if (processing_order > effect_count) {
break;
}
effect_order_buffer[processing_order] = i;
}
}
return sort_required;
}
bool MixInfo::UpdateConnection(EdgeMatrix& edge_matrix, const InParameter& in_params,
SplitterContext& splitter_context) {
auto has_new_connection{false};
if (dst_splitter_id != UnusedSplitterId) {
auto& splitter_info{splitter_context.GetInfo(dst_splitter_id)};
has_new_connection = splitter_info.HasNewConnection();
}
// Check if this mix matches the input parameters.
// If everything is the same, don't bother updating.
if (dst_mix_id == in_params.dest_mix_id && dst_splitter_id == in_params.dest_splitter_id &&
!has_new_connection) {
return false;
}
// Reset the mix in the graph, as we're about to update it.
edge_matrix.RemoveEdges(mix_id);
if (in_params.dest_mix_id == UnusedMixId) {
if (in_params.dest_splitter_id != UnusedSplitterId) {
// If the splitter is used, connect this mix to each active destination.
auto& splitter_info{splitter_context.GetInfo(in_params.dest_splitter_id)};
auto const destination_count{splitter_info.GetDestinationCount()};
for (u32 i = 0; i < destination_count; i++) {
auto destination{
splitter_context.GetDestinationData(in_params.dest_splitter_id, i)};
if (destination) {
const auto destination_id{destination->GetMixId()};
if (destination_id != UnusedMixId) {
edge_matrix.Connect(mix_id, destination_id);
}
}
}
}
} else {
// If the splitter is not used, only connect this mix to its destination.
edge_matrix.Connect(mix_id, in_params.dest_mix_id);
}
dst_mix_id = in_params.dest_mix_id;
dst_splitter_id = in_params.dest_splitter_id;
return true;
}
bool MixInfo::HasAnyConnection() const {
return dst_mix_id != UnusedMixId || dst_splitter_id != UnusedSplitterId;
}
} // namespace AudioCore::Renderer