summaryrefslogtreecommitdiffstats
path: root/src/audio_core/audio_renderer.h
blob: abed224bb4c1f54f97d0a1027d2ba3f5396da3ab (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
// Copyright 2018 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <array>
#include <memory>
#include <vector>

#include "audio_core/stream.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
#include "core/hle/kernel/object.h"

namespace Core::Timing {
class CoreTiming;
}

namespace Kernel {
class WritableEvent;
}

namespace AudioCore {

class AudioOut;

enum class PlayState : u8 {
    Started = 0,
    Stopped = 1,
    Paused = 2,
};

enum class Effect : u8 {
    None = 0,
    Aux = 2,
};

enum class EffectStatus : u8 {
    None = 0,
    New = 1,
};

struct AudioRendererParameter {
    u32_le sample_rate;
    u32_le sample_count;
    u32_le mix_buffer_count;
    u32_le submix_count;
    u32_le voice_count;
    u32_le sink_count;
    u32_le effect_count;
    u32_le performance_frame_count;
    u8 is_voice_drop_enabled;
    u8 unknown_21;
    u8 unknown_22;
    u8 execution_mode;
    u32_le splitter_count;
    u32_le num_splitter_send_channels;
    u32_le unknown_30;
    u32_le revision;
};
static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");

enum class MemoryPoolStates : u32 { // Should be LE
    Invalid = 0x0,
    Unknown = 0x1,
    RequestDetach = 0x2,
    Detached = 0x3,
    RequestAttach = 0x4,
    Attached = 0x5,
    Released = 0x6,
};

struct MemoryPoolEntry {
    MemoryPoolStates state;
    u32_le unknown_4;
    u32_le unknown_8;
    u32_le unknown_c;
};
static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");

struct MemoryPoolInfo {
    u64_le pool_address;
    u64_le pool_size;
    MemoryPoolStates pool_state;
    INSERT_PADDING_WORDS(3); // Unknown
};
static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
struct BiquadFilter {
    u8 enable;
    INSERT_PADDING_BYTES(1);
    std::array<s16_le, 3> numerator;
    std::array<s16_le, 2> denominator;
};
static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");

struct WaveBuffer {
    u64_le buffer_addr;
    u64_le buffer_sz;
    s32_le start_sample_offset;
    s32_le end_sample_offset;
    u8 is_looping;
    u8 end_of_stream;
    u8 sent_to_server;
    INSERT_PADDING_BYTES(5);
    u64 context_addr;
    u64 context_sz;
    INSERT_PADDING_BYTES(8);
};
static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");

struct VoiceInfo {
    u32_le id;
    u32_le node_id;
    u8 is_new;
    u8 is_in_use;
    PlayState play_state;
    u8 sample_format;
    u32_le sample_rate;
    u32_le priority;
    u32_le sorting_order;
    u32_le channel_count;
    float_le pitch;
    float_le volume;
    std::array<BiquadFilter, 2> biquad_filter;
    u32_le wave_buffer_count;
    u32_le wave_buffer_head;
    INSERT_PADDING_WORDS(1);
    u64_le additional_params_addr;
    u64_le additional_params_sz;
    u32_le mix_id;
    u32_le splitter_info_id;
    std::array<WaveBuffer, 4> wave_buffer;
    std::array<u32_le, 6> voice_channel_resource_ids;
    INSERT_PADDING_BYTES(24);
};
static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");

struct VoiceOutStatus {
    u64_le played_sample_count;
    u32_le wave_buffer_consumed;
    u32_le voice_drops_count;
};
static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");

struct AuxInfo {
    std::array<u8, 24> input_mix_buffers;
    std::array<u8, 24> output_mix_buffers;
    u32_le mix_buffer_count;
    u32_le sample_rate; // Stored in the aux buffer currently
    u32_le sample_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 EffectInStatus {
    Effect type;
    u8 is_new;
    u8 is_enabled;
    INSERT_PADDING_BYTES(1);
    u32_le mix_id;
    u64_le buffer_base;
    u64_le buffer_sz;
    s32_le priority;
    INSERT_PADDING_BYTES(4);
    union {
        std::array<u8, 0xa0> raw;
        AuxInfo aux_info;
    };
};
static_assert(sizeof(EffectInStatus) == 0xc0, "EffectInStatus is an invalid size");

struct EffectOutStatus {
    EffectStatus state;
    INSERT_PADDING_BYTES(0xf);
};
static_assert(sizeof(EffectOutStatus) == 0x10, "EffectOutStatus is an invalid size");

struct UpdateDataHeader {
    UpdateDataHeader() {}

    explicit UpdateDataHeader(const AudioRendererParameter& config) {
        revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
        behavior_size = 0xb0;
        memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
        voices_size = config.voice_count * 0x10;
        voice_resource_size = 0x0;
        effects_size = config.effect_count * 0x10;
        mixes_size = 0x0;
        sinks_size = config.sink_count * 0x20;
        performance_manager_size = 0x10;
        frame_count = 0;
        total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size +
                     effects_size + sinks_size + performance_manager_size;
    }

    u32_le revision{};
    u32_le behavior_size{};
    u32_le memory_pools_size{};
    u32_le voices_size{};
    u32_le voice_resource_size{};
    u32_le effects_size{};
    u32_le mixes_size{};
    u32_le sinks_size{};
    u32_le performance_manager_size{};
    INSERT_PADDING_WORDS(1);
    u32_le frame_count{};
    INSERT_PADDING_WORDS(4);
    u32_le total_size{};
};
static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");

class AudioRenderer {
public:
    AudioRenderer(Core::Timing::CoreTiming& core_timing, AudioRendererParameter params,
                  std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
    ~AudioRenderer();

    std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
    void QueueMixedBuffer(Buffer::Tag tag);
    void ReleaseAndQueueBuffers();
    u32 GetSampleRate() const;
    u32 GetSampleCount() const;
    u32 GetMixBufferCount() const;
    Stream::State GetStreamState() const;

private:
    class EffectState;
    class VoiceState;

    AudioRendererParameter worker_params;
    std::shared_ptr<Kernel::WritableEvent> buffer_event;
    std::vector<VoiceState> voices;
    std::vector<EffectState> effects;
    std::unique_ptr<AudioOut> audio_out;
    AudioCore::StreamPtr stream;
};

} // namespace AudioCore