summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2018-08-04 17:45:14 -0400
committerGravatar bunnei2018-08-04 21:54:30 -0400
commitb46df98e935552ea48ed86360e8c8b34b294982d (patch)
tree95a17bc97a704c5e3dfb41d11c3579b88141dbe2 /src
parentaudio_core: Use s16 where possible for audio samples. (diff)
downloadyuzu-b46df98e935552ea48ed86360e8c8b34b294982d.tar.gz
yuzu-b46df98e935552ea48ed86360e8c8b34b294982d.tar.xz
yuzu-b46df98e935552ea48ed86360e8c8b34b294982d.zip
audio_core: Implement audren_u audio playback.
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/CMakeLists.txt2
-rw-r--r--src/audio_core/audio_renderer.cpp234
-rw-r--r--src/audio_core/audio_renderer.h206
-rw-r--r--src/core/hle/service/audio/audren_u.cpp208
-rw-r--r--src/core/hle/service/audio/audren_u.h19
5 files changed, 451 insertions, 218 deletions
diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt
index 05a61b5cd..827ab0ac7 100644
--- a/src/audio_core/CMakeLists.txt
+++ b/src/audio_core/CMakeLists.txt
@@ -1,6 +1,8 @@
1add_library(audio_core STATIC 1add_library(audio_core STATIC
2 audio_out.cpp 2 audio_out.cpp
3 audio_out.h 3 audio_out.h
4 audio_renderer.cpp
5 audio_renderer.h
4 buffer.h 6 buffer.h
5 cubeb_sink.cpp 7 cubeb_sink.cpp
6 cubeb_sink.h 8 cubeb_sink.h
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
new file mode 100644
index 000000000..282f345c5
--- /dev/null
+++ b/src/audio_core/audio_renderer.cpp
@@ -0,0 +1,234 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "audio_core/audio_renderer.h"
6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/memory.h"
9
10namespace AudioCore {
11
12constexpr u32 STREAM_SAMPLE_RATE{48000};
13constexpr u32 STREAM_NUM_CHANNELS{2};
14
15AudioRenderer::AudioRenderer(AudioRendererParameter params,
16 Kernel::SharedPtr<Kernel::Event> buffer_event)
17 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count) {
18
19 audio_core = std::make_unique<AudioCore::AudioOut>();
20 stream = audio_core->OpenStream(STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, "AudioRenderer",
21 [=]() { buffer_event->Signal(); });
22 audio_core->StartStream(stream);
23
24 QueueMixedBuffer(0);
25 QueueMixedBuffer(1);
26 QueueMixedBuffer(2);
27}
28
29std::vector<u8> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) {
30 // Copy UpdateDataHeader struct
31 UpdateDataHeader config{};
32 std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
33 u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
34
35 // Copy MemoryPoolInfo structs
36 std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
37 std::memcpy(mem_pool_info.data(),
38 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
39 memory_pool_count * sizeof(MemoryPoolInfo));
40
41 // Copy VoiceInfo structs
42 size_t offset{sizeof(UpdateDataHeader) + config.behavior_size + config.memory_pools_size +
43 config.voice_resource_size};
44 for (auto& voice : voices) {
45 std::memcpy(&voice.Info(), input_params.data() + offset, sizeof(VoiceInfo));
46 offset += sizeof(VoiceInfo);
47 }
48
49 // Update voices
50 for (auto& voice : voices) {
51 voice.UpdateState();
52 if (!voice.GetInfo().is_in_use) {
53 continue;
54 }
55 if (voice.GetInfo().is_new) {
56 voice.SetWaveIndex(voice.GetInfo().wave_buffer_head);
57 }
58 }
59
60 // Update memory pool state
61 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
62 for (size_t index = 0; index < memory_pool.size(); ++index) {
63 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
64 memory_pool[index].state = MemoryPoolStates::Attached;
65 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
66 memory_pool[index].state = MemoryPoolStates::Detached;
67 }
68 }
69
70 // Release previous buffers and queue next ones for playback
71 ReleaseAndQueueBuffers();
72
73 // Copy output header
74 UpdateDataHeader response_data{worker_params};
75 std::vector<u8> output_params(response_data.total_size);
76 std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader));
77
78 // Copy output memory pool entries
79 std::memcpy(output_params.data() + sizeof(UpdateDataHeader), memory_pool.data(),
80 response_data.memory_pools_size);
81
82 // Copy output voice status
83 size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
84 for (const auto& voice : voices) {
85 std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
86 sizeof(VoiceOutStatus));
87 voice_out_status_offset += sizeof(VoiceOutStatus);
88 }
89
90 return output_params;
91}
92
93void AudioRenderer::VoiceState::SetWaveIndex(size_t index) {
94 wave_index = index & 3;
95 is_refresh_pending = true;
96}
97
98std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(size_t sample_count) {
99 if (!IsPlaying()) {
100 return {};
101 }
102
103 if (is_refresh_pending) {
104 RefreshBuffer();
105 }
106
107 const size_t max_size{samples.size() - offset};
108 const size_t dequeue_offset{offset};
109 size_t size{sample_count * STREAM_NUM_CHANNELS};
110 if (size > max_size) {
111 size = max_size;
112 }
113
114 out_status.played_sample_count += size / STREAM_NUM_CHANNELS;
115 offset += size;
116
117 const auto& wave_buffer{info.wave_buffer[wave_index]};
118 if (offset == samples.size()) {
119 offset = 0;
120
121 if (!wave_buffer.is_looping) {
122 SetWaveIndex(wave_index + 1);
123 }
124
125 out_status.wave_buffer_consumed++;
126
127 if (wave_buffer.end_of_stream) {
128 info.play_state = PlayState::Paused;
129 }
130 }
131
132 return {samples.begin() + dequeue_offset, samples.begin() + dequeue_offset + size};
133}
134
135void AudioRenderer::VoiceState::UpdateState() {
136 if (is_in_use && !info.is_in_use) {
137 // No longer in use, reset state
138 is_refresh_pending = true;
139 wave_index = 0;
140 offset = 0;
141 out_status = {};
142 }
143 is_in_use = info.is_in_use;
144}
145
146void AudioRenderer::VoiceState::RefreshBuffer() {
147 std::vector<s16> new_samples(info.wave_buffer[wave_index].buffer_sz / sizeof(s16));
148 Memory::ReadBlock(info.wave_buffer[wave_index].buffer_addr, new_samples.data(),
149 info.wave_buffer[wave_index].buffer_sz);
150
151 switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
152 case Codec::PcmFormat::Int16: {
153 // PCM16 is played as-is
154 break;
155 }
156 case Codec::PcmFormat::Adpcm: {
157 // Decode ADPCM to PCM16
158 Codec::ADPCM_Coeff coeffs;
159 Memory::ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
160 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
161 new_samples.size() * sizeof(s16), coeffs, adpcm_state);
162 break;
163 }
164 default:
165 LOG_CRITICAL(Audio, "Unimplemented sample_format={}", info.sample_format);
166 UNREACHABLE();
167 break;
168 }
169
170 switch (info.channel_count) {
171 case 1:
172 // 1 channel is upsampled to 2 channel
173 samples.resize(new_samples.size() * 2);
174 for (size_t index = 0; index < new_samples.size(); ++index) {
175 samples[index * 2] = new_samples[index];
176 samples[index * 2 + 1] = new_samples[index];
177 }
178 break;
179 case 2: {
180 // 2 channel is played as is
181 samples = std::move(new_samples);
182 break;
183 }
184 default:
185 LOG_CRITICAL(Audio, "Unimplemented channel_count={}", info.channel_count);
186 UNREACHABLE();
187 break;
188 }
189
190 is_refresh_pending = false;
191}
192
193static constexpr s16 ClampToS16(s32 value) {
194 return static_cast<s16>(std::clamp(value, -32768, 32767));
195}
196
197void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
198 constexpr size_t BUFFER_SIZE{512};
199 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
200
201 for (auto& voice : voices) {
202 if (!voice.IsPlaying()) {
203 continue;
204 }
205
206 size_t offset{};
207 s64 samples_remaining{BUFFER_SIZE};
208 while (samples_remaining > 0) {
209 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining)};
210
211 if (samples.empty()) {
212 break;
213 }
214
215 samples_remaining -= samples.size();
216
217 for (const auto& sample : samples) {
218 const s32 buffer_sample{buffer[offset]};
219 buffer[offset++] =
220 ClampToS16(buffer_sample + static_cast<s32>(sample * voice.GetInfo().volume));
221 }
222 }
223 }
224 audio_core->QueueBuffer(stream, tag, std::move(buffer));
225}
226
227void AudioRenderer::ReleaseAndQueueBuffers() {
228 const auto released_buffers{audio_core->GetTagsAndReleaseBuffers(stream, 2)};
229 for (const auto& tag : released_buffers) {
230 QueueMixedBuffer(tag);
231 }
232}
233
234} // namespace AudioCore
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
new file mode 100644
index 000000000..6950a4681
--- /dev/null
+++ b/src/audio_core/audio_renderer.h
@@ -0,0 +1,206 @@
1// Copyright 2018 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <memory>
9#include <vector>
10
11#include "audio_core/audio_out.h"
12#include "audio_core/codec.h"
13#include "audio_core/stream.h"
14#include "common/common_types.h"
15#include "common/swap.h"
16#include "core/hle/kernel/event.h"
17
18namespace AudioCore {
19
20enum class PlayState : u8 {
21 Started = 0,
22 Stopped = 1,
23 Paused = 2,
24};
25
26struct AudioRendererParameter {
27 u32_le sample_rate;
28 u32_le sample_count;
29 u32_le unknown_8;
30 u32_le unknown_c;
31 u32_le voice_count;
32 u32_le sink_count;
33 u32_le effect_count;
34 u32_le unknown_1c;
35 u8 unknown_20;
36 INSERT_PADDING_BYTES(3);
37 u32_le splitter_count;
38 u32_le unknown_2c;
39 INSERT_PADDING_WORDS(1);
40 u32_le revision;
41};
42static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
43
44enum class MemoryPoolStates : u32 { // Should be LE
45 Invalid = 0x0,
46 Unknown = 0x1,
47 RequestDetach = 0x2,
48 Detached = 0x3,
49 RequestAttach = 0x4,
50 Attached = 0x5,
51 Released = 0x6,
52};
53
54struct MemoryPoolEntry {
55 MemoryPoolStates state;
56 u32_le unknown_4;
57 u32_le unknown_8;
58 u32_le unknown_c;
59};
60static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
61
62struct MemoryPoolInfo {
63 u64_le pool_address;
64 u64_le pool_size;
65 MemoryPoolStates pool_state;
66 INSERT_PADDING_WORDS(3); // Unknown
67};
68static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
69struct BiquadFilter {
70 u8 enable;
71 INSERT_PADDING_BYTES(1);
72 std::array<s16_le, 3> numerator;
73 std::array<s16_le, 2> denominator;
74};
75static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
76
77struct WaveBuffer {
78 u64_le buffer_addr;
79 u64_le buffer_sz;
80 s32_le start_sample_offset;
81 s32_le end_sample_offset;
82 u8 is_looping;
83 u8 end_of_stream;
84 u8 sent_to_server;
85 INSERT_PADDING_BYTES(5);
86 u64 context_addr;
87 u64 context_sz;
88 INSERT_PADDING_BYTES(8);
89};
90static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
91
92struct VoiceInfo {
93 u32_le id;
94 u32_le node_id;
95 u8 is_new;
96 u8 is_in_use;
97 PlayState play_state;
98 u8 sample_format;
99 u32_le sample_rate;
100 u32_le priority;
101 u32_le sorting_order;
102 u32_le channel_count;
103 float_le pitch;
104 float_le volume;
105 std::array<BiquadFilter, 2> biquad_filter;
106 u32_le wave_buffer_count;
107 u32_le wave_buffer_head;
108 INSERT_PADDING_WORDS(1);
109 u64_le additional_params_addr;
110 u64_le additional_params_sz;
111 u32_le mix_id;
112 u32_le splitter_info_id;
113 std::array<WaveBuffer, 4> wave_buffer;
114 std::array<u32_le, 6> voice_channel_resource_ids;
115 INSERT_PADDING_BYTES(24);
116};
117static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
118
119struct VoiceOutStatus {
120 u64_le played_sample_count;
121 u32_le wave_buffer_consumed;
122 u32_le voice_drops_count;
123};
124static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
125
126struct UpdateDataHeader {
127 UpdateDataHeader() {}
128
129 explicit UpdateDataHeader(const AudioRendererParameter& config) {
130 revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
131 behavior_size = 0xb0;
132 memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
133 voices_size = config.voice_count * 0x10;
134 voice_resource_size = 0x0;
135 effects_size = config.effect_count * 0x10;
136 mixes_size = 0x0;
137 sinks_size = config.sink_count * 0x20;
138 performance_manager_size = 0x10;
139 total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size + voices_size +
140 effects_size + sinks_size + performance_manager_size;
141 }
142
143 u32_le revision;
144 u32_le behavior_size;
145 u32_le memory_pools_size;
146 u32_le voices_size;
147 u32_le voice_resource_size;
148 u32_le effects_size;
149 u32_le mixes_size;
150 u32_le sinks_size;
151 u32_le performance_manager_size;
152 INSERT_PADDING_WORDS(6);
153 u32_le total_size;
154};
155static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
156
157class AudioRenderer {
158public:
159 AudioRenderer(AudioRendererParameter params, Kernel::SharedPtr<Kernel::Event> buffer_event);
160 std::vector<u8> UpdateAudioRenderer(const std::vector<u8>& input_params);
161 void QueueMixedBuffer(Buffer::Tag tag);
162 void ReleaseAndQueueBuffers();
163
164private:
165 class VoiceState {
166 public:
167 bool IsPlaying() const {
168 return is_in_use && info.play_state == PlayState::Started;
169 }
170
171 const VoiceOutStatus& GetOutStatus() const {
172 return out_status;
173 }
174
175 const VoiceInfo& GetInfo() const {
176 return info;
177 }
178
179 VoiceInfo& Info() {
180 return info;
181 }
182
183 void SetWaveIndex(size_t index);
184 std::vector<s16> DequeueSamples(size_t sample_count);
185 void UpdateState();
186 void RefreshBuffer();
187
188 private:
189 bool is_in_use{};
190 bool is_refresh_pending{};
191 size_t wave_index{};
192 size_t offset{};
193 Codec::ADPCMState adpcm_state{};
194 std::vector<s16> samples;
195 VoiceOutStatus out_status{};
196 VoiceInfo info{};
197 };
198
199 AudioRendererParameter worker_params;
200 Kernel::SharedPtr<Kernel::Event> buffer_event;
201 std::vector<VoiceState> voices;
202 std::unique_ptr<AudioCore::AudioOut> audio_core;
203 AudioCore::StreamPtr stream;
204};
205
206} // namespace AudioCore
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index 6aed9e2fa..f99304de5 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -15,13 +15,10 @@
15 15
16namespace Service::Audio { 16namespace Service::Audio {
17 17
18/// TODO(bunnei): Find a proper value for the audio_ticks
19constexpr u64 audio_ticks{static_cast<u64>(CoreTiming::BASE_CLOCK_RATE / 200)};
20
21class IAudioRenderer final : public ServiceFramework<IAudioRenderer> { 18class IAudioRenderer final : public ServiceFramework<IAudioRenderer> {
22public: 19public:
23 explicit IAudioRenderer(AudioRendererParameter audren_params) 20 explicit IAudioRenderer(AudioCore::AudioRendererParameter audren_params)
24 : ServiceFramework("IAudioRenderer"), worker_params(audren_params) { 21 : ServiceFramework("IAudioRenderer") {
25 static const FunctionInfo functions[] = { 22 static const FunctionInfo functions[] = {
26 {0, nullptr, "GetAudioRendererSampleRate"}, 23 {0, nullptr, "GetAudioRendererSampleRate"},
27 {1, nullptr, "GetAudioRendererSampleCount"}, 24 {1, nullptr, "GetAudioRendererSampleCount"},
@@ -39,21 +36,8 @@ public:
39 RegisterHandlers(functions); 36 RegisterHandlers(functions);
40 37
41 system_event = 38 system_event =
42 Kernel::Event::Create(Kernel::ResetType::OneShot, "IAudioRenderer:SystemEvent"); 39 Kernel::Event::Create(Kernel::ResetType::Sticky, "IAudioRenderer:SystemEvent");
43 40 renderer = std::make_unique<AudioCore::AudioRenderer>(audren_params, system_event);
44 // Register event callback to update the Audio Buffer
45 audio_event = CoreTiming::RegisterEvent(
46 "IAudioRenderer::UpdateAudioCallback", [this](u64 userdata, int cycles_late) {
47 UpdateAudioCallback();
48 CoreTiming::ScheduleEvent(audio_ticks - cycles_late, audio_event);
49 });
50
51 // Start the audio event
52 CoreTiming::ScheduleEvent(audio_ticks, audio_event);
53 voice_status_list.resize(worker_params.voice_count);
54 }
55 ~IAudioRenderer() {
56 CoreTiming::UnscheduleEvent(audio_event, 0);
57 } 41 }
58 42
59private: 43private:
@@ -62,60 +46,9 @@ private:
62 } 46 }
63 47
64 void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) { 48 void RequestUpdateAudioRenderer(Kernel::HLERequestContext& ctx) {
65 UpdateDataHeader config{}; 49 ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer()));
66 auto buf = ctx.ReadBuffer();
67 std::memcpy(&config, buf.data(), sizeof(UpdateDataHeader));
68 u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
69
70 std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
71 std::memcpy(mem_pool_info.data(),
72 buf.data() + sizeof(UpdateDataHeader) + config.behavior_size,
73 memory_pool_count * sizeof(MemoryPoolInfo));
74
75 std::vector<VoiceInfo> voice_info(worker_params.voice_count);
76 std::memcpy(voice_info.data(),
77 buf.data() + sizeof(UpdateDataHeader) + config.behavior_size +
78 config.memory_pools_size + config.voice_resource_size,
79 worker_params.voice_count * sizeof(VoiceInfo));
80
81 UpdateDataHeader response_data{worker_params};
82
83 ASSERT(ctx.GetWriteBufferSize() == response_data.total_size);
84
85 std::vector<u8> output(response_data.total_size);
86 std::memcpy(output.data(), &response_data, sizeof(UpdateDataHeader));
87 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
88 for (unsigned i = 0; i < memory_pool.size(); i++) {
89 if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestAttach)
90 memory_pool[i].state = MemoryPoolStates::Attached;
91 else if (mem_pool_info[i].pool_state == MemoryPoolStates::RequestDetach)
92 memory_pool[i].state = MemoryPoolStates::Detached;
93 }
94 std::memcpy(output.data() + sizeof(UpdateDataHeader), memory_pool.data(),
95 response_data.memory_pools_size);
96
97 for (unsigned i = 0; i < voice_info.size(); i++) {
98 if (voice_info[i].is_new) {
99 voice_status_list[i].played_sample_count = 0;
100 voice_status_list[i].wave_buffer_consumed = 0;
101 } else if (voice_info[i].play_state == (u8)PlayStates::Started) {
102 for (u32 buff_idx = 0; buff_idx < voice_info[i].wave_buffer_count; buff_idx++) {
103 voice_status_list[i].played_sample_count +=
104 (voice_info[i].wave_buffer[buff_idx].end_sample_offset -
105 voice_info[i].wave_buffer[buff_idx].start_sample_offset) /
106 2;
107 voice_status_list[i].wave_buffer_consumed++;
108 }
109 }
110 }
111 std::memcpy(output.data() + sizeof(UpdateDataHeader) + response_data.memory_pools_size,
112 voice_status_list.data(), response_data.voices_size);
113
114 ctx.WriteBuffer(output);
115
116 IPC::ResponseBuilder rb{ctx, 2}; 50 IPC::ResponseBuilder rb{ctx, 2};
117 rb.Push(RESULT_SUCCESS); 51 rb.Push(RESULT_SUCCESS);
118
119 LOG_WARNING(Service_Audio, "(STUBBED) called"); 52 LOG_WARNING(Service_Audio, "(STUBBED) called");
120 } 53 }
121 54
@@ -136,8 +69,6 @@ private:
136 } 69 }
137 70
138 void QuerySystemEvent(Kernel::HLERequestContext& ctx) { 71 void QuerySystemEvent(Kernel::HLERequestContext& ctx) {
139 // system_event->Signal();
140
141 IPC::ResponseBuilder rb{ctx, 2, 1}; 72 IPC::ResponseBuilder rb{ctx, 2, 1};
142 rb.Push(RESULT_SUCCESS); 73 rb.Push(RESULT_SUCCESS);
143 rb.PushCopyObjects(system_event); 74 rb.PushCopyObjects(system_event);
@@ -145,131 +76,8 @@ private:
145 LOG_WARNING(Service_Audio, "(STUBBED) called"); 76 LOG_WARNING(Service_Audio, "(STUBBED) called");
146 } 77 }
147 78
148 enum class MemoryPoolStates : u32 { // Should be LE
149 Invalid = 0x0,
150 Unknown = 0x1,
151 RequestDetach = 0x2,
152 Detached = 0x3,
153 RequestAttach = 0x4,
154 Attached = 0x5,
155 Released = 0x6,
156 };
157
158 enum class PlayStates : u8 {
159 Started = 0,
160 Stopped = 1,
161 };
162
163 struct MemoryPoolEntry {
164 MemoryPoolStates state;
165 u32_le unknown_4;
166 u32_le unknown_8;
167 u32_le unknown_c;
168 };
169 static_assert(sizeof(MemoryPoolEntry) == 0x10, "MemoryPoolEntry has wrong size");
170
171 struct MemoryPoolInfo {
172 u64_le pool_address;
173 u64_le pool_size;
174 MemoryPoolStates pool_state;
175 INSERT_PADDING_WORDS(3); // Unknown
176 };
177 static_assert(sizeof(MemoryPoolInfo) == 0x20, "MemoryPoolInfo has wrong size");
178
179 struct UpdateDataHeader {
180 UpdateDataHeader() {}
181
182 explicit UpdateDataHeader(const AudioRendererParameter& config) {
183 revision = Common::MakeMagic('R', 'E', 'V', '4'); // 5.1.0 Revision
184 behavior_size = 0xb0;
185 memory_pools_size = (config.effect_count + (config.voice_count * 4)) * 0x10;
186 voices_size = config.voice_count * 0x10;
187 voice_resource_size = 0x0;
188 effects_size = config.effect_count * 0x10;
189 mixes_size = 0x0;
190 sinks_size = config.sink_count * 0x20;
191 performance_manager_size = 0x10;
192 total_size = sizeof(UpdateDataHeader) + behavior_size + memory_pools_size +
193 voices_size + effects_size + sinks_size + performance_manager_size;
194 }
195
196 u32_le revision;
197 u32_le behavior_size;
198 u32_le memory_pools_size;
199 u32_le voices_size;
200 u32_le voice_resource_size;
201 u32_le effects_size;
202 u32_le mixes_size;
203 u32_le sinks_size;
204 u32_le performance_manager_size;
205 INSERT_PADDING_WORDS(6);
206 u32_le total_size;
207 };
208 static_assert(sizeof(UpdateDataHeader) == 0x40, "UpdateDataHeader has wrong size");
209
210 struct BiquadFilter {
211 u8 enable;
212 INSERT_PADDING_BYTES(1);
213 s16_le numerator[3];
214 s16_le denominator[2];
215 };
216 static_assert(sizeof(BiquadFilter) == 0xc, "BiquadFilter has wrong size");
217
218 struct WaveBuffer {
219 u64_le buffer_addr;
220 u64_le buffer_sz;
221 s32_le start_sample_offset;
222 s32_le end_sample_offset;
223 u8 loop;
224 u8 end_of_stream;
225 u8 sent_to_server;
226 INSERT_PADDING_BYTES(5);
227 u64 context_addr;
228 u64 context_sz;
229 INSERT_PADDING_BYTES(8);
230 };
231 static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
232
233 struct VoiceInfo {
234 u32_le id;
235 u32_le node_id;
236 u8 is_new;
237 u8 is_in_use;
238 u8 play_state;
239 u8 sample_format;
240 u32_le sample_rate;
241 u32_le priority;
242 u32_le sorting_order;
243 u32_le channel_count;
244 float_le pitch;
245 float_le volume;
246 BiquadFilter biquad_filter[2];
247 u32_le wave_buffer_count;
248 u16_le wave_buffer_head;
249 INSERT_PADDING_BYTES(6);
250 u64_le additional_params_addr;
251 u64_le additional_params_sz;
252 u32_le mix_id;
253 u32_le splitter_info_id;
254 WaveBuffer wave_buffer[4];
255 u32_le voice_channel_resource_ids[6];
256 INSERT_PADDING_BYTES(24);
257 };
258 static_assert(sizeof(VoiceInfo) == 0x170, "VoiceInfo is wrong size");
259
260 struct VoiceOutStatus {
261 u64_le played_sample_count;
262 u32_le wave_buffer_consumed;
263 INSERT_PADDING_WORDS(1);
264 };
265 static_assert(sizeof(VoiceOutStatus) == 0x10, "VoiceOutStatus has wrong size");
266
267 /// This is used to trigger the audio event callback.
268 CoreTiming::EventType* audio_event;
269
270 Kernel::SharedPtr<Kernel::Event> system_event; 79 Kernel::SharedPtr<Kernel::Event> system_event;
271 AudioRendererParameter worker_params; 80 std::unique_ptr<AudioCore::AudioRenderer> renderer;
272 std::vector<VoiceOutStatus> voice_status_list;
273}; 81};
274 82
275class IAudioDevice final : public ServiceFramework<IAudioDevice> { 83class IAudioDevice final : public ServiceFramework<IAudioDevice> {
@@ -368,7 +176,7 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") {
368 176
369void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 177void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
370 IPC::RequestParser rp{ctx}; 178 IPC::RequestParser rp{ctx};
371 auto params = rp.PopRaw<AudioRendererParameter>(); 179 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
372 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 180 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
373 181
374 rb.Push(RESULT_SUCCESS); 182 rb.Push(RESULT_SUCCESS);
@@ -379,7 +187,7 @@ void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) {
379 187
380void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 188void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) {
381 IPC::RequestParser rp{ctx}; 189 IPC::RequestParser rp{ctx};
382 auto params = rp.PopRaw<AudioRendererParameter>(); 190 auto params = rp.PopRaw<AudioCore::AudioRendererParameter>();
383 191
384 u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40); 192 u64 buffer_sz = Common::AlignUp(4 * params.unknown_8, 0x40);
385 buffer_sz += params.unknown_c * 1024; 193 buffer_sz += params.unknown_c * 1024;
diff --git a/src/core/hle/service/audio/audren_u.h b/src/core/hle/service/audio/audren_u.h
index b9b81db4f..14907f8ae 100644
--- a/src/core/hle/service/audio/audren_u.h
+++ b/src/core/hle/service/audio/audren_u.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "audio_core/audio_renderer.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Kernel { 10namespace Kernel {
@@ -12,24 +13,6 @@ class HLERequestContext;
12 13
13namespace Service::Audio { 14namespace Service::Audio {
14 15
15struct AudioRendererParameter {
16 u32_le sample_rate;
17 u32_le sample_count;
18 u32_le unknown_8;
19 u32_le unknown_c;
20 u32_le voice_count;
21 u32_le sink_count;
22 u32_le effect_count;
23 u32_le unknown_1c;
24 u8 unknown_20;
25 INSERT_PADDING_BYTES(3);
26 u32_le splitter_count;
27 u32_le unknown_2c;
28 INSERT_PADDING_WORDS(1);
29 u32_le revision;
30};
31static_assert(sizeof(AudioRendererParameter) == 52, "AudioRendererParameter is an invalid size");
32
33class AudRenU final : public ServiceFramework<AudRenU> { 16class AudRenU final : public ServiceFramework<AudRenU> {
34public: 17public:
35 explicit AudRenU(); 18 explicit AudRenU();