summaryrefslogtreecommitdiffstats
path: root/src/audio_core/effect_context.h
blob: cb47df4729b99fa43b8ce410f5d5f034c93cb9d9 (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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>
#include <memory>
#include <vector>
#include "audio_core/common.h"
#include "audio_core/delay_line.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"

namespace AudioCore {
enum class EffectType : u8 {
    Invalid = 0,
    BufferMixer = 1,
    Aux = 2,
    Delay = 3,
    Reverb = 4,
    I3dl2Reverb = 5,
    BiquadFilter = 6,
};

enum class UsageStatus : u8 {
    Invalid = 0,
    New = 1,
    Initialized = 2,
    Used = 3,
    Removed = 4,
};

enum class UsageState {
    Invalid = 0,
    Initialized = 1,
    Running = 2,
    Stopped = 3,
};

enum class ParameterStatus : u8 {
    Initialized = 0,
    Updating = 1,
    Updated = 2,
};

struct BufferMixerParams {
    std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input{};
    std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output{};
    std::array<float_le, AudioCommon::MAX_MIX_BUFFERS> volume{};
    s32_le count{};
};
static_assert(sizeof(BufferMixerParams) == 0x94, "BufferMixerParams is an invalid size");

struct AuxInfoDSP {
    u32_le read_offset{};
    u32_le write_offset{};
    u32_le remaining{};
    INSERT_PADDING_WORDS(13);
};
static_assert(sizeof(AuxInfoDSP) == 0x40, "AuxInfoDSP is an invalid size");

struct AuxInfo {
    std::array<s8, AudioCommon::MAX_MIX_BUFFERS> input_mix_buffers{};
    std::array<s8, AudioCommon::MAX_MIX_BUFFERS> output_mix_buffers{};
    u32_le count{};
    s32_le sample_rate{};
    s32_le sample_count{};
    s32_le mix_buffer_count{};
    u64_le send_buffer_info{};
    u64_le send_buffer_base{};

    u64_le return_buffer_info{};
    u64_le return_buffer_base{};
};
static_assert(sizeof(AuxInfo) == 0x60, "AuxInfo is an invalid size");

struct I3dl2ReverbParams {
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
    u16_le max_channels{};
    u16_le channel_count{};
    INSERT_PADDING_BYTES(1);
    u32_le sample_rate{};
    f32 room_hf{};
    f32 hf_reference{};
    f32 decay_time{};
    f32 hf_decay_ratio{};
    f32 room{};
    f32 reflection{};
    f32 reverb{};
    f32 diffusion{};
    f32 reflection_delay{};
    f32 reverb_delay{};
    f32 density{};
    f32 dry_gain{};
    ParameterStatus status{};
    INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(I3dl2ReverbParams) == 0x4c, "I3dl2ReverbParams is an invalid size");

struct BiquadFilterParams {
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
    std::array<s16_le, 3> numerator;
    std::array<s16_le, 2> denominator;
    s8 channel_count{};
    ParameterStatus status{};
};
static_assert(sizeof(BiquadFilterParams) == 0x18, "BiquadFilterParams is an invalid size");

struct DelayParams {
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
    u16_le max_channels{};
    u16_le channels{};
    s32_le max_delay{};
    s32_le delay{};
    s32_le sample_rate{};
    s32_le gain{};
    s32_le feedback_gain{};
    s32_le out_gain{};
    s32_le dry_gain{};
    s32_le channel_spread{};
    s32_le low_pass{};
    ParameterStatus status{};
    INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(DelayParams) == 0x38, "DelayParams is an invalid size");

struct ReverbParams {
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> input{};
    std::array<s8, AudioCommon::MAX_CHANNEL_COUNT> output{};
    u16_le max_channels{};
    u16_le channels{};
    s32_le sample_rate{};
    s32_le mode0{};
    s32_le mode0_gain{};
    s32_le pre_delay{};
    s32_le mode1{};
    s32_le mode1_gain{};
    s32_le decay{};
    s32_le hf_decay_ratio{};
    s32_le coloration{};
    s32_le reverb_gain{};
    s32_le out_gain{};
    s32_le dry_gain{};
    ParameterStatus status{};
    INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(ReverbParams) == 0x44, "ReverbParams is an invalid size");

class EffectInfo {
public:
    struct InParams {
        EffectType type{};
        u8 is_new{};
        u8 is_enabled{};
        INSERT_PADDING_BYTES(1);
        s32_le mix_id{};
        u64_le buffer_address{};
        u64_le buffer_size{};
        s32_le processing_order{};
        INSERT_PADDING_BYTES(4);
        union {
            std::array<u8, 0xa0> raw;
        };
    };
    static_assert(sizeof(InParams) == 0xc0, "InParams is an invalid size");

    struct OutParams {
        UsageStatus status{};
        INSERT_PADDING_BYTES(15);
    };
    static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size");
};

struct AuxAddress {
    VAddr send_dsp_info{};
    VAddr send_buffer_base{};
    VAddr return_dsp_info{};
    VAddr return_buffer_base{};
};

class EffectBase {
public:
    explicit EffectBase(EffectType effect_type_);
    virtual ~EffectBase();

    virtual void Update(EffectInfo::InParams& in_params) = 0;
    virtual void UpdateForCommandGeneration() = 0;
    [[nodiscard]] UsageState GetUsage() const;
    [[nodiscard]] EffectType GetType() const;
    [[nodiscard]] bool IsEnabled() const;
    [[nodiscard]] s32 GetMixID() const;
    [[nodiscard]] s32 GetProcessingOrder() const;
    [[nodiscard]] std::vector<u8>& GetWorkBuffer();
    [[nodiscard]] const std::vector<u8>& GetWorkBuffer() const;

protected:
    UsageState usage{UsageState::Invalid};
    EffectType effect_type{};
    s32 mix_id{};
    s32 processing_order{};
    bool enabled = false;
    std::vector<u8> work_buffer{};
};

template <typename T>
class EffectGeneric : public EffectBase {
public:
    explicit EffectGeneric(EffectType effect_type_) : EffectBase(effect_type_) {}

    T& GetParams() {
        return internal_params;
    }

    const T& GetParams() const {
        return internal_params;
    }

private:
    T internal_params{};
};

class EffectStubbed : public EffectBase {
public:
    explicit EffectStubbed();
    ~EffectStubbed() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;
};

struct I3dl2ReverbState {
    f32 lowpass_0{};
    f32 lowpass_1{};
    f32 lowpass_2{};

    DelayLineBase early_delay_line{};
    std::array<u32, AudioCommon::I3DL2REVERB_TAPS> early_tap_steps{};
    f32 early_gain{};
    f32 late_gain{};

    u32 early_to_late_taps{};
    std::array<DelayLineBase, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> fdn_delay_line{};
    std::array<DelayLineAllPass, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> decay_delay_line0{};
    std::array<DelayLineAllPass, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> decay_delay_line1{};
    f32 last_reverb_echo{};
    DelayLineBase center_delay_line{};
    std::array<std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT>, 3> lpf_coefficients{};
    std::array<f32, AudioCommon::I3DL2REVERB_DELAY_LINE_COUNT> shelf_filter{};
    f32 dry_gain{};
};

class EffectI3dl2Reverb : public EffectGeneric<I3dl2ReverbParams> {
public:
    explicit EffectI3dl2Reverb();
    ~EffectI3dl2Reverb() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;

    I3dl2ReverbState& GetState();
    const I3dl2ReverbState& GetState() const;

private:
    bool skipped = false;
    I3dl2ReverbState state{};
};

class EffectBiquadFilter : public EffectGeneric<BiquadFilterParams> {
public:
    explicit EffectBiquadFilter();
    ~EffectBiquadFilter() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;
};

class EffectAuxInfo : public EffectGeneric<AuxInfo> {
public:
    explicit EffectAuxInfo();
    ~EffectAuxInfo() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;
    [[nodiscard]] VAddr GetSendInfo() const;
    [[nodiscard]] VAddr GetSendBuffer() const;
    [[nodiscard]] VAddr GetRecvInfo() const;
    [[nodiscard]] VAddr GetRecvBuffer() const;

private:
    VAddr send_info{};
    VAddr send_buffer{};
    VAddr recv_info{};
    VAddr recv_buffer{};
    bool skipped = false;
    AuxAddress addresses{};
};

class EffectDelay : public EffectGeneric<DelayParams> {
public:
    explicit EffectDelay();
    ~EffectDelay() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;

private:
    bool skipped = false;
};

class EffectBufferMixer : public EffectGeneric<BufferMixerParams> {
public:
    explicit EffectBufferMixer();
    ~EffectBufferMixer() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;
};

class EffectReverb : public EffectGeneric<ReverbParams> {
public:
    explicit EffectReverb();
    ~EffectReverb() override;

    void Update(EffectInfo::InParams& in_params) override;
    void UpdateForCommandGeneration() override;

private:
    bool skipped = false;
};

class EffectContext {
public:
    explicit EffectContext(std::size_t effect_count_);
    ~EffectContext();

    [[nodiscard]] std::size_t GetCount() const;
    [[nodiscard]] EffectBase* GetInfo(std::size_t i);
    [[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect);
    [[nodiscard]] const EffectBase* GetInfo(std::size_t i) const;

private:
    std::size_t effect_count{};
    std::vector<std::unique_ptr<EffectBase>> effects;
};
} // namespace AudioCore