summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------externals/vcpkg0
-rw-r--r--src/audio_core/renderer/audio_renderer.h15
-rw-r--r--src/audio_core/renderer/compressor.h39
-rw-r--r--src/audio_core/renderer/effect/compressor.cpp46
-rw-r--r--src/audio_core/renderer/effect/compressor.h49
-rw-r--r--src/audio_core/renderer/splitter.h26
6 files changed, 175 insertions, 0 deletions
diff --git a/externals/vcpkg b/externals/vcpkg
-Subproject 2ded45cc7a35667ad8d96e5e50b4a24afacafb3
+Subproject 561cf50a731761f9890fb720f830cb3501b8472
diff --git a/src/audio_core/renderer/audio_renderer.h b/src/audio_core/renderer/audio_renderer.h
index f16adeda7..5b0875c81 100644
--- a/src/audio_core/renderer/audio_renderer.h
+++ b/src/audio_core/renderer/audio_renderer.h
@@ -1,4 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@@ -23,6 +24,11 @@ struct AudioRendererParameterInternal;
namespace Renderer {
class Manager;
+enum class AudioRendererRevision {
+ Rev12 = 12 << 24,
+ Rev13 = 13 << 24,
+};
+
/**
* Audio Renderer, wraps the main audio system and is mainly responsible for handling service calls.
*/
@@ -82,6 +88,14 @@ public:
Result RequestUpdate(std::span<const u8> input, std::span<u8> performance,
std::span<u8> output);
+ bool IsCompressorStatisticsSupported() const {
+ return revision >= static_cast<u32>(AudioRendererRevision::Rev13);
+ }
+
+ bool IsSplitterPrevVolumeResetSupported() const {
+ return revision >= static_cast<u32>(AudioRendererRevision::Rev13);
+ }
+
private:
/// System core
Core::System& core;
@@ -93,6 +107,7 @@ private:
bool system_registered{};
/// Audio render system, main driver of audio rendering
System system;
+ u32 revision;
};
} // namespace Renderer
diff --git a/src/audio_core/renderer/compressor.h b/src/audio_core/renderer/compressor.h
new file mode 100644
index 000000000..97f43dfae
--- /dev/null
+++ b/src/audio_core/renderer/compressor.h
@@ -0,0 +1,39 @@
+// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <array>
+#include "common/common_types.h"
+
+namespace AudioCore::Renderer {
+
+struct CompressorStatistics {
+ float maximum_mean{};
+ float minimum_gain{1.0f};
+ std::array<float, 6> last_samples{}; // 6 channels max
+
+ void Reset(u16 channel_count) {
+ maximum_mean = 0.0f;
+ minimum_gain = 1.0f;
+ std::fill_n(last_samples.begin(), channel_count, 0.0f);
+ }
+};
+
+struct CompressorParameter {
+ u32 channel_count{};
+ float input_gain{};
+ float release_coefficient{};
+ float attack_coefficient{};
+ float ratio{};
+ float threshold{};
+ bool makeup_gain_enabled{};
+ bool statistics_enabled{};
+ bool statistics_reset{};
+
+ bool IsChannelCountValid() const {
+ return channel_count > 0 && channel_count <= 6;
+ }
+};
+
+} // namespace AudioCore::Renderer
diff --git a/src/audio_core/renderer/effect/compressor.cpp b/src/audio_core/renderer/effect/compressor.cpp
index fea0aefcf..3b32670f7 100644
--- a/src/audio_core/renderer/effect/compressor.cpp
+++ b/src/audio_core/renderer/effect/compressor.cpp
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include <cmath>
#include "audio_core/renderer/effect/compressor.h"
namespace AudioCore::Renderer {
@@ -37,4 +39,48 @@ CpuAddr CompressorInfo::GetWorkbuffer(s32 index) {
return GetSingleBuffer(index);
}
+CompressorEffect::CompressorEffect(std::size_t sample_count_) : sample_count{sample_count_} {}
+
+void CompressorEffect::Process(std::span<f32> output_buffer, std::span<const f32> input_buffer) {
+ if (!IsEnabled() || !parameter.IsChannelCountValid()) {
+ std::copy(input_buffer.begin(), input_buffer.end(), output_buffer.begin());
+ return;
+ }
+
+ if (!result_state.empty() && parameter.statistics_reset) {
+ statistics.Reset(static_cast<u16>(parameter.channel_count));
+ }
+
+ // Process audio with compressor effect
+ for (u32 sample_index = 0; sample_index < sample_count; sample_index++) {
+ float mean = 0.0f;
+ for (u32 channel = 0; channel < parameter.channel_count; channel++) {
+ const auto sample = input_buffer[sample_index * parameter.channel_count + channel];
+ mean += sample * sample;
+ }
+ mean /= static_cast<float>(parameter.channel_count);
+
+ // Calculate compression gain
+ float compression_gain = 1.0f;
+ if (mean > parameter.threshold) {
+ compression_gain = parameter.threshold / mean;
+ compression_gain = std::pow(compression_gain, 1.0f - (1.0f / parameter.ratio));
+ }
+
+ // Apply compression
+ for (u32 channel = 0; channel < parameter.channel_count; channel++) {
+ const auto in_sample = input_buffer[sample_index * parameter.channel_count + channel];
+ const auto out_sample = in_sample * compression_gain * parameter.input_gain;
+ output_buffer[sample_index * parameter.channel_count + channel] = out_sample;
+
+ // Update statistics if enabled
+ if (parameter.statistics_enabled) {
+ statistics.maximum_mean = std::max(statistics.maximum_mean, mean);
+ statistics.minimum_gain = std::min(statistics.minimum_gain, compression_gain);
+ statistics.last_samples[channel] = std::abs(in_sample) * (1.0f / 32768.0f);
+ }
+ }
+ }
+}
+
} // namespace AudioCore::Renderer
diff --git a/src/audio_core/renderer/effect/compressor.h b/src/audio_core/renderer/effect/compressor.h
index cda55c284..7074c8484 100644
--- a/src/audio_core/renderer/effect/compressor.h
+++ b/src/audio_core/renderer/effect/compressor.h
@@ -1,9 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
+#include <span>
#include "audio_core/common/common.h"
#include "audio_core/renderer/effect/effect_info_base.h"
@@ -12,6 +14,53 @@
namespace AudioCore::Renderer {
+struct CompressorStatistics {
+ float maximum_mean{};
+ float minimum_gain{1.0f};
+ std::array<float, 6> last_samples{}; // 6 channels max
+
+ void Reset(u16 channel_count) {
+ maximum_mean = 0.0f;
+ minimum_gain = 1.0f;
+ std::fill_n(last_samples.begin(), channel_count, 0.0f);
+ }
+};
+
+struct CompressorParameter {
+ u32 channel_count{};
+ float input_gain{};
+ float release_coefficient{};
+ float attack_coefficient{};
+ float ratio{};
+ float threshold{};
+ bool makeup_gain_enabled{};
+ bool statistics_enabled{};
+ bool statistics_reset{};
+
+ bool IsChannelCountValid() const {
+ return channel_count > 0 && channel_count <= 6;
+ }
+};
+
+class CompressorEffect : public EffectInfoBase {
+public:
+ explicit CompressorEffect(std::size_t sample_count_);
+ ~CompressorEffect() override = default;
+
+ void Process(std::span<f32> output_buffer, std::span<const f32> input_buffer);
+
+ bool IsEnabled() const {
+ return effect_enabled;
+ }
+
+private:
+ CompressorParameter parameter;
+ CompressorStatistics statistics;
+ std::size_t sample_count;
+ bool effect_enabled{false};
+ std::span<u8> result_state;
+};
+
class CompressorInfo : public EffectInfoBase {
public:
struct ParameterVersion1 {
diff --git a/src/audio_core/renderer/splitter.h b/src/audio_core/renderer/splitter.h
new file mode 100644
index 000000000..373656d44
--- /dev/null
+++ b/src/audio_core/renderer/splitter.h
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+namespace AudioCore::Renderer {
+
+class SplitterDestination {
+public:
+ void Update(const SplitterDestinationParameter& parameter, bool is_prev_volume_reset_supported) {
+ if (is_prev_volume_reset_supported ? parameter.reset_prev_volume
+ : (!is_used && parameter.is_used)) {
+ // Reset previous mix volumes
+ prev_mix_volumes = parameter.mix_volumes;
+ mix_volumes = parameter.mix_volumes;
+ }
+ is_used = parameter.is_used;
+ }
+
+private:
+ bool is_used{};
+ std::array<float, MaxMixBuffers> mix_volumes{};
+ std::array<float, MaxMixBuffers> prev_mix_volumes{};
+};
+
+} // namespace AudioCore::Renderer