summaryrefslogtreecommitdiffstats
path: root/src/audio_core/renderer/command/effect/compressor.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/audio_core/renderer/command/effect/compressor.cpp156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/audio_core/renderer/command/effect/compressor.cpp b/src/audio_core/renderer/command/effect/compressor.cpp
new file mode 100644
index 000000000..2ebc140f1
--- /dev/null
+++ b/src/audio_core/renderer/command/effect/compressor.cpp
@@ -0,0 +1,156 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <cmath>
+#include <span>
+#include <vector>
+
+#include "audio_core/renderer/adsp/command_list_processor.h"
+#include "audio_core/renderer/command/effect/compressor.h"
+#include "audio_core/renderer/effect/compressor.h"
+
+namespace AudioCore::AudioRenderer {
+
+static void SetCompressorEffectParameter(CompressorInfo::ParameterVersion2& params,
+ CompressorInfo::State& state) {
+ const auto ratio{1.0f / params.compressor_ratio};
+ auto makeup_gain{0.0f};
+ if (params.makeup_gain_enabled) {
+ makeup_gain = (params.threshold * 0.5f) * (ratio - 1.0f) - 3.0f;
+ }
+ state.makeup_gain = makeup_gain;
+ state.unk_18 = params.unk_28;
+
+ const auto a{(params.out_gain + makeup_gain) / 20.0f * 3.3219f};
+ const auto b{(a - std::trunc(a)) * 0.69315f};
+ const auto c{std::pow(2.0f, b)};
+
+ state.unk_0C = (1.0f - ratio) / 6.0f;
+ state.unk_14 = params.threshold + 1.5f;
+ state.unk_10 = params.threshold - 1.5f;
+ state.unk_20 = c;
+}
+
+static void InitializeCompressorEffect(CompressorInfo::ParameterVersion2& params,
+ CompressorInfo::State& state) {
+ std::memset(&state, 0, sizeof(CompressorInfo::State));
+
+ state.unk_00 = 0;
+ state.unk_04 = 1.0f;
+ state.unk_08 = 1.0f;
+
+ SetCompressorEffectParameter(params, state);
+}
+
+static void ApplyCompressorEffect(CompressorInfo::ParameterVersion2& params,
+ CompressorInfo::State& state, bool enabled,
+ std::vector<std::span<const s32>> input_buffers,
+ std::vector<std::span<s32>> output_buffers, u32 sample_count) {
+ if (enabled) {
+ auto state_00{state.unk_00};
+ auto state_04{state.unk_04};
+ auto state_08{state.unk_08};
+ auto state_18{state.unk_18};
+
+ for (u32 i = 0; i < sample_count; i++) {
+ auto a{0.0f};
+ for (s16 channel = 0; channel < params.channel_count; channel++) {
+ const auto input_sample{Common::FixedPoint<49, 15>(input_buffers[channel][i])};
+ a += (input_sample * input_sample).to_float();
+ }
+
+ state_00 += params.unk_24 * ((a / params.channel_count) - state.unk_00);
+
+ auto b{-100.0f};
+ auto c{0.0f};
+ if (state_00 >= 1.0e-10) {
+ b = std::log10(state_00) * 10.0f;
+ c = 1.0f;
+ }
+
+ if (b >= state.unk_10) {
+ const auto d{b >= state.unk_14
+ ? ((1.0f / params.compressor_ratio) - 1.0f) *
+ (b - params.threshold)
+ : (b - state.unk_10) * (b - state.unk_10) * -state.unk_0C};
+ const auto e{d / 20.0f * 3.3219f};
+ const auto f{(e - std::trunc(e)) * 0.69315f};
+ c = std::pow(2.0f, f);
+ }
+
+ state_18 = params.unk_28;
+ auto tmp{c};
+ if ((state_04 - c) <= 0.08f) {
+ state_18 = params.unk_2C;
+ if (((state_04 - c) >= -0.08f) && (std::abs(state_08 - c) >= 0.001f)) {
+ tmp = state_04;
+ }
+ }
+
+ state_04 = tmp;
+ state_08 += (c - state_08) * state_18;
+
+ for (s16 channel = 0; channel < params.channel_count; channel++) {
+ output_buffers[channel][i] = static_cast<s32>(
+ static_cast<f32>(input_buffers[channel][i]) * state_08 * state.unk_20);
+ }
+ }
+
+ state.unk_00 = state_00;
+ state.unk_04 = state_04;
+ state.unk_08 = state_08;
+ state.unk_18 = state_18;
+ } else {
+ for (s16 channel = 0; channel < params.channel_count; channel++) {
+ if (params.inputs[channel] != params.outputs[channel]) {
+ std::memcpy((char*)output_buffers[channel].data(),
+ (char*)input_buffers[channel].data(),
+ output_buffers[channel].size_bytes());
+ }
+ }
+ }
+}
+
+void CompressorCommand::Dump([[maybe_unused]] const ADSP::CommandListProcessor& processor,
+ std::string& string) {
+ string += fmt::format("CompressorCommand\n\tenabled {} \n\tinputs: ", effect_enabled);
+ for (s16 i = 0; i < parameter.channel_count; i++) {
+ string += fmt::format("{:02X}, ", inputs[i]);
+ }
+ string += "\n\toutputs: ";
+ for (s16 i = 0; i < parameter.channel_count; i++) {
+ string += fmt::format("{:02X}, ", outputs[i]);
+ }
+ string += "\n";
+}
+
+void CompressorCommand::Process(const ADSP::CommandListProcessor& processor) {
+ std::vector<std::span<const s32>> input_buffers(parameter.channel_count);
+ std::vector<std::span<s32>> output_buffers(parameter.channel_count);
+
+ for (s16 i = 0; i < parameter.channel_count; i++) {
+ input_buffers[i] = processor.mix_buffers.subspan(inputs[i] * processor.sample_count,
+ processor.sample_count);
+ output_buffers[i] = processor.mix_buffers.subspan(outputs[i] * processor.sample_count,
+ processor.sample_count);
+ }
+
+ auto state_{reinterpret_cast<CompressorInfo::State*>(state)};
+
+ if (effect_enabled) {
+ if (parameter.state == CompressorInfo::ParameterState::Updating) {
+ SetCompressorEffectParameter(parameter, *state_);
+ } else if (parameter.state == CompressorInfo::ParameterState::Initialized) {
+ InitializeCompressorEffect(parameter, *state_);
+ }
+ }
+
+ ApplyCompressorEffect(parameter, *state_, effect_enabled, input_buffers, output_buffers,
+ processor.sample_count);
+}
+
+bool CompressorCommand::Verify(const ADSP::CommandListProcessor& processor) {
+ return true;
+}
+
+} // namespace AudioCore::AudioRenderer