summaryrefslogtreecommitdiffstats
path: root/src/audio_core/renderer/command/effect/compressor.cpp
blob: 7ff707f4e0299f9a839e26b718e0962ddc596f6c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <cmath>
#include <span>
#include <vector>

#include "audio_core/adsp/apps/audio_renderer/command_list_processor.h"
#include "audio_core/renderer/command/effect/compressor.h"
#include "audio_core/renderer/effect/compressor.h"

namespace AudioCore::Renderer {

static void SetCompressorEffectParameter(const 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(const CompressorInfo::ParameterVersion2& params,
                                       CompressorInfo::State& state) {
    state = {};

    state.unk_00 = 0;
    state.unk_04 = 1.0f;
    state.unk_08 = 1.0f;

    SetCompressorEffectParameter(params, state);
}

static void ApplyCompressorEffect(const CompressorInfo::ParameterVersion2& params,
                                  CompressorInfo::State& state, bool enabled,
                                  std::span<std::span<const s32>> input_buffers,
                                  std::span<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(output_buffers[channel].data(), input_buffers[channel].data(),
                            output_buffers[channel].size_bytes());
            }
        }
    }
}

void CompressorCommand::Dump([[maybe_unused]] const AudioRenderer::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 AudioRenderer::CommandListProcessor& processor) {
    std::array<std::span<const s32>, MaxChannels> input_buffers{};
    std::array<std::span<s32>, MaxChannels> output_buffers{};

    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 AudioRenderer::CommandListProcessor& processor) {
    return true;
}

} // namespace AudioCore::Renderer