summaryrefslogtreecommitdiff
path: root/src/audio_core/renderer/effect/compressor.h
blob: 7074c848463845989310e9df8a4c9d6c98b6c1b3 (plain)
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-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"
#include "common/common_types.h"
#include "common/fixed_point.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;
    }
};

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 {
        /* 0x00 */ std::array<s8, MaxChannels> inputs;
        /* 0x06 */ std::array<s8, MaxChannels> outputs;
        /* 0x0C */ s16 channel_count_max;
        /* 0x0E */ s16 channel_count;
        /* 0x10 */ s32 sample_rate;
        /* 0x14 */ f32 threshold;
        /* 0x18 */ f32 compressor_ratio;
        /* 0x1C */ s32 attack_time;
        /* 0x20 */ s32 release_time;
        /* 0x24 */ f32 unk_24;
        /* 0x28 */ f32 unk_28;
        /* 0x2C */ f32 unk_2C;
        /* 0x30 */ f32 out_gain;
        /* 0x34 */ ParameterState state;
        /* 0x35 */ bool makeup_gain_enabled;
    };
    static_assert(sizeof(ParameterVersion1) <= sizeof(EffectInfoBase::InParameterVersion1),
                  "CompressorInfo::ParameterVersion1 has the wrong size!");

    struct ParameterVersion2 {
        /* 0x00 */ std::array<s8, MaxChannels> inputs;
        /* 0x06 */ std::array<s8, MaxChannels> outputs;
        /* 0x0C */ s16 channel_count_max;
        /* 0x0E */ s16 channel_count;
        /* 0x10 */ s32 sample_rate;
        /* 0x14 */ f32 threshold;
        /* 0x18 */ f32 compressor_ratio;
        /* 0x1C */ s32 attack_time;
        /* 0x20 */ s32 release_time;
        /* 0x24 */ f32 unk_24;
        /* 0x28 */ f32 unk_28;
        /* 0x2C */ f32 unk_2C;
        /* 0x30 */ f32 out_gain;
        /* 0x34 */ ParameterState state;
        /* 0x35 */ bool makeup_gain_enabled;
    };
    static_assert(sizeof(ParameterVersion2) <= sizeof(EffectInfoBase::InParameterVersion2),
                  "CompressorInfo::ParameterVersion2 has the wrong size!");

    struct State {
        f32 unk_00;
        f32 unk_04;
        f32 unk_08;
        f32 unk_0C;
        f32 unk_10;
        f32 unk_14;
        f32 unk_18;
        f32 makeup_gain;
        f32 unk_20;
        char unk_24[0x1C];
    };
    static_assert(sizeof(State) <= sizeof(EffectInfoBase::State),
                  "CompressorInfo::State has the wrong size!");

    /**
     * Update the info with new parameters, version 1.
     *
     * @param error_info  - Used to write call result code.
     * @param in_params   - New parameters to update the info with.
     * @param pool_mapper - Pool for mapping buffers.
     */
    void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion1& in_params,
                const PoolMapper& pool_mapper) override;

    /**
     * Update the info with new parameters, version 2.
     *
     * @param error_info  - Used to write call result code.
     * @param in_params   - New parameters to update the info with.
     * @param pool_mapper - Pool for mapping buffers.
     */
    void Update(BehaviorInfo::ErrorInfo& error_info, const InParameterVersion2& in_params,
                const PoolMapper& pool_mapper) override;

    /**
     * Update the info after command generation. Usually only changes its state.
     */
    void UpdateForCommandGeneration() override;

    /**
     * Get a workbuffer assigned to this effect with the given index.
     *
     * @param index - Workbuffer index.
     * @return Address of the buffer.
     */
    CpuAddr GetWorkbuffer(s32 index) override;
};

} // namespace AudioCore::Renderer