summaryrefslogtreecommitdiff
path: root/src/audio_core/audio_renderer.cpp
diff options
context:
space:
mode:
authorGravatar David Marcec2020-07-12 21:59:14 +1000
committerGravatar David Marcec2020-07-25 12:39:34 +1000
commit380658c21d39cf05ac765a9284da246388cca2a4 (patch)
tree1416cd7e9aee96ec40675078d16a8240d410d04b /src/audio_core/audio_renderer.cpp
parentMerge pull request #4377 from Morph1984/dark-themes (diff)
downloadyuzu-380658c21d39cf05ac765a9284da246388cca2a4.tar.gz
yuzu-380658c21d39cf05ac765a9284da246388cca2a4.tar.xz
yuzu-380658c21d39cf05ac765a9284da246388cca2a4.zip
audio_core: Apollo Part 1, AudioRenderer refactor
Diffstat (limited to 'src/audio_core/audio_renderer.cpp')
-rw-r--r--src/audio_core/audio_renderer.cpp541
1 files changed, 169 insertions, 372 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index d64452617..fbd87d5bf 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,90 +2,42 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector>
5#include "audio_core/algorithm/interpolate.h" 6#include "audio_core/algorithm/interpolate.h"
6#include "audio_core/audio_out.h" 7#include "audio_core/audio_out.h"
7#include "audio_core/audio_renderer.h" 8#include "audio_core/audio_renderer.h"
8#include "audio_core/codec.h" 9#include "audio_core/codec.h"
9#include "audio_core/common.h" 10#include "audio_core/common.h"
11#include "audio_core/info_updater.h"
12#include "audio_core/voice_context.h"
10#include "common/assert.h" 13#include "common/assert.h"
11#include "common/logging/log.h" 14#include "common/logging/log.h"
12#include "core/core.h" 15#include "core/core.h"
13#include "core/hle/kernel/writable_event.h" 16#include "core/hle/kernel/writable_event.h"
14#include "core/memory.h" 17#include "core/memory.h"
18#include "core/settings.h"
15 19
16namespace AudioCore { 20namespace AudioCore {
17
18constexpr u32 STREAM_SAMPLE_RATE{48000};
19constexpr u32 STREAM_NUM_CHANNELS{2};
20using VoiceChannelHolder = std::array<VoiceResourceInformation*, 6>;
21class AudioRenderer::VoiceState {
22public:
23 bool IsPlaying() const {
24 return is_in_use && info.play_state == PlayState::Started;
25 }
26
27 const VoiceOutStatus& GetOutStatus() const {
28 return out_status;
29 }
30
31 const VoiceInfo& GetInfo() const {
32 return info;
33 }
34
35 VoiceInfo& GetInfo() {
36 return info;
37 }
38
39 void SetWaveIndex(std::size_t index);
40 std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory,
41 const VoiceChannelHolder& voice_resources);
42 void UpdateState();
43 void RefreshBuffer(Core::Memory::Memory& memory, const VoiceChannelHolder& voice_resources);
44
45private:
46 bool is_in_use{};
47 bool is_refresh_pending{};
48 std::size_t wave_index{};
49 std::size_t offset{};
50 Codec::ADPCMState adpcm_state{};
51 InterpolationState interp_state{};
52 std::vector<s16> samples;
53 VoiceOutStatus out_status{};
54 VoiceInfo info{};
55};
56
57class AudioRenderer::EffectState {
58public:
59 const EffectOutStatus& GetOutStatus() const {
60 return out_status;
61 }
62
63 const EffectInStatus& GetInfo() const {
64 return info;
65 }
66
67 EffectInStatus& GetInfo() {
68 return info;
69 }
70
71 void UpdateState(Core::Memory::Memory& memory);
72
73private:
74 EffectOutStatus out_status{};
75 EffectInStatus info{};
76};
77
78AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 21AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
79 AudioRendererParameter params, 22 AudioCommon::AudioRendererParameter params,
80 std::shared_ptr<Kernel::WritableEvent> buffer_event, 23 std::shared_ptr<Kernel::WritableEvent> buffer_event,
81 std::size_t instance_number) 24 std::size_t instance_number)
82 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 25 : worker_params{params}, buffer_event{buffer_event},
83 voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} { 26 memory_pool_info(params.effect_count + params.voice_count * 4),
27 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
28 sink_context(params.sink_count), splitter_context(),
29 voices(params.voice_count), memory{memory_},
30 command_generator(worker_params, voice_context, mix_context, splitter_context, memory),
31 temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) {
84 behavior_info.SetUserRevision(params.revision); 32 behavior_info.SetUserRevision(params.revision);
33 splitter_context.Initialize(behavior_info, params.splitter_count,
34 params.num_splitter_send_channels);
35 mix_context.Initialize(behavior_info, params.submix_count + 1);
85 audio_out = std::make_unique<AudioCore::AudioOut>(); 36 audio_out = std::make_unique<AudioCore::AudioOut>();
86 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, 37 stream =
87 fmt::format("AudioRenderer-Instance{}", instance_number), 38 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
88 [=]() { buffer_event->Signal(); }); 39 fmt::format("AudioRenderer-Instance{}", instance_number),
40 [=]() { buffer_event->Signal(); });
89 audio_out->StartStream(stream); 41 audio_out->StartStream(stream);
90 42
91 QueueMixedBuffer(0); 43 QueueMixedBuffer(0);
@@ -111,355 +63,200 @@ Stream::State AudioRenderer::GetStreamState() const {
111 return stream->GetState(); 63 return stream->GetState();
112} 64}
113 65
114ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params) { 66static constexpr s16 ClampToS16(s32 value) {
115 // Copy UpdateDataHeader struct 67 return static_cast<s16>(std::clamp(value, -32768, 32767));
116 UpdateDataHeader config{}; 68}
117 std::memcpy(&config, input_params.data(), sizeof(UpdateDataHeader));
118 u32 memory_pool_count = worker_params.effect_count + (worker_params.voice_count * 4);
119
120 if (!behavior_info.UpdateInput(input_params, sizeof(UpdateDataHeader))) {
121 LOG_ERROR(Audio, "Failed to update behavior info input parameters");
122 return Audren::ERR_INVALID_PARAMETERS;
123 }
124
125 // Copy MemoryPoolInfo structs
126 std::vector<MemoryPoolInfo> mem_pool_info(memory_pool_count);
127 std::memcpy(mem_pool_info.data(),
128 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
129 memory_pool_count * sizeof(MemoryPoolInfo));
130
131 // Copy voice resources
132 const std::size_t voice_resource_offset{sizeof(UpdateDataHeader) + config.behavior_size +
133 config.memory_pools_size};
134 std::memcpy(voice_resources.data(), input_params.data() + voice_resource_offset,
135 sizeof(VoiceResourceInformation) * voice_resources.size());
136
137 // Copy VoiceInfo structs
138 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
139 config.memory_pools_size + config.voice_resource_size};
140 for (auto& voice : voices) {
141 std::memcpy(&voice.GetInfo(), input_params.data() + voice_offset, sizeof(VoiceInfo));
142 voice_offset += sizeof(VoiceInfo);
143 }
144
145 std::size_t effect_offset{sizeof(UpdateDataHeader) + config.behavior_size +
146 config.memory_pools_size + config.voice_resource_size +
147 config.voices_size};
148 for (auto& effect : effects) {
149 std::memcpy(&effect.GetInfo(), input_params.data() + effect_offset, sizeof(EffectInStatus));
150 effect_offset += sizeof(EffectInStatus);
151 }
152
153 // Update memory pool state
154 std::vector<MemoryPoolEntry> memory_pool(memory_pool_count);
155 for (std::size_t index = 0; index < memory_pool.size(); ++index) {
156 if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestAttach) {
157 memory_pool[index].state = MemoryPoolStates::Attached;
158 } else if (mem_pool_info[index].pool_state == MemoryPoolStates::RequestDetach) {
159 memory_pool[index].state = MemoryPoolStates::Detached;
160 }
161 }
162
163 // Update voices
164 for (auto& voice : voices) {
165 voice.UpdateState();
166 if (!voice.GetInfo().is_in_use) {
167 continue;
168 }
169 if (voice.GetInfo().is_new) {
170 voice.SetWaveIndex(voice.GetInfo().wave_buffer_head);
171 }
172 }
173
174 for (auto& effect : effects) {
175 effect.UpdateState(memory);
176 }
177
178 // Release previous buffers and queue next ones for playback
179 ReleaseAndQueueBuffers();
180
181 // Copy output header
182 UpdateDataHeader response_data{worker_params};
183 if (behavior_info.IsElapsedFrameCountSupported()) {
184 response_data.render_info = sizeof(RendererInfo);
185 response_data.total_size += sizeof(RendererInfo);
186 }
187
188 std::vector<u8> output_params(response_data.total_size);
189 std::memcpy(output_params.data(), &response_data, sizeof(UpdateDataHeader));
190
191 // Copy output memory pool entries
192 std::memcpy(output_params.data() + sizeof(UpdateDataHeader), memory_pool.data(),
193 response_data.memory_pools_size);
194
195 // Copy output voice status
196 std::size_t voice_out_status_offset{sizeof(UpdateDataHeader) + response_data.memory_pools_size};
197 for (const auto& voice : voices) {
198 std::memcpy(output_params.data() + voice_out_status_offset, &voice.GetOutStatus(),
199 sizeof(VoiceOutStatus));
200 voice_out_status_offset += sizeof(VoiceOutStatus);
201 }
202 69
203 std::size_t effect_out_status_offset{ 70ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
204 sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size + 71 std::vector<u8>& output_params) {
205 response_data.voice_resource_size};
206 for (const auto& effect : effects) {
207 std::memcpy(output_params.data() + effect_out_status_offset, &effect.GetOutStatus(),
208 sizeof(EffectOutStatus));
209 effect_out_status_offset += sizeof(EffectOutStatus);
210 }
211 72
212 // Update behavior info output 73 InfoUpdater info_updater{input_params, output_params, behavior_info};
213 const std::size_t behavior_out_status_offset{
214 sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size +
215 response_data.effects_size + response_data.sinks_size +
216 response_data.performance_manager_size};
217 74
218 if (!behavior_info.UpdateOutput(output_params, behavior_out_status_offset)) { 75 if (!info_updater.UpdateBehaviorInfo(behavior_info)) {
219 LOG_ERROR(Audio, "Failed to update behavior info output parameters"); 76 LOG_ERROR(Audio, "Failed to update behavior info input parameters");
220 return Audren::ERR_INVALID_PARAMETERS; 77 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
221 } 78 }
222 79
223 if (behavior_info.IsElapsedFrameCountSupported()) { 80 if (!info_updater.UpdateMemoryPools(memory_pool_info)) {
224 const std::size_t renderer_info_offset{ 81 LOG_ERROR(Audio, "Failed to update memory pool parameters");
225 sizeof(UpdateDataHeader) + response_data.memory_pools_size + response_data.voices_size + 82 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
226 response_data.effects_size + response_data.sinks_size +
227 response_data.performance_manager_size + response_data.behavior_size};
228 RendererInfo renderer_info{};
229 renderer_info.elasped_frame_count = elapsed_frame_count;
230 std::memcpy(output_params.data() + renderer_info_offset, &renderer_info,
231 sizeof(RendererInfo));
232 } 83 }
233 84
234 return MakeResult(output_params); 85 if (!info_updater.UpdateVoiceChannelResources(voice_context)) {
235} 86 LOG_ERROR(Audio, "Failed to update voice channel resource parameters");
236 87 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
237void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
238 wave_index = index & 3;
239 is_refresh_pending = true;
240}
241
242std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(
243 std::size_t sample_count, Core::Memory::Memory& memory,
244 const VoiceChannelHolder& voice_resources) {
245 if (!IsPlaying()) {
246 return {};
247 } 88 }
248 89
249 if (is_refresh_pending) { 90 if (!info_updater.UpdateVoices(voice_context, memory_pool_info, 0)) {
250 RefreshBuffer(memory, voice_resources); 91 LOG_ERROR(Audio, "Failed to update voice parameters");
92 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
251 } 93 }
252 94
253 const std::size_t max_size{samples.size() - offset}; 95 // TODO(ogniK): Deal with stopped audio renderer but updates still taking place
254 const std::size_t dequeue_offset{offset}; 96 if (!info_updater.UpdateEffects(effect_context, true)) {
255 std::size_t size{sample_count * STREAM_NUM_CHANNELS}; 97 LOG_ERROR(Audio, "Failed to update effect parameters");
256 if (size > max_size) { 98 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
257 size = max_size;
258 } 99 }
259 100
260 out_status.played_sample_count += size / STREAM_NUM_CHANNELS; 101 if (behavior_info.IsSplitterSupported()) {
261 offset += size; 102 if (!info_updater.UpdateSplitterInfo(splitter_context)) {
262 103 LOG_ERROR(Audio, "Failed to update splitter parameters");
263 const auto& wave_buffer{info.wave_buffer[wave_index]}; 104 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
264 if (offset == samples.size()) {
265 offset = 0;
266
267 if (!wave_buffer.is_looping && wave_buffer.buffer_sz) {
268 SetWaveIndex(wave_index + 1);
269 }
270
271 if (wave_buffer.buffer_sz) {
272 out_status.wave_buffer_consumed++;
273 }
274
275 if (wave_buffer.end_of_stream || wave_buffer.buffer_sz == 0) {
276 info.play_state = PlayState::Paused;
277 } 105 }
278 } 106 }
279 107
280 return {samples.begin() + dequeue_offset, samples.begin() + dequeue_offset + size}; 108 auto mix_result =
281} 109 info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, splitter_context);
282 110
283void AudioRenderer::VoiceState::UpdateState() { 111 if (mix_result.IsError()) {
284 if (is_in_use && !info.is_in_use) { 112 LOG_ERROR(Audio, "Failed to update mix parameters");
285 // No longer in use, reset state 113 return mix_result;
286 is_refresh_pending = true;
287 wave_index = 0;
288 offset = 0;
289 out_status = {};
290 } 114 }
291 is_in_use = info.is_in_use;
292}
293 115
294void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory, 116 // TODO(ogniK): Sinks
295 const VoiceChannelHolder& voice_resources) { 117 if (!info_updater.UpdateSinks(sink_context)) {
296 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; 118 LOG_ERROR(Audio, "Failed to update sink parameters");
297 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; 119 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
298 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
299 memory.ReadBlock(wave_buffer_address, new_samples.data(), wave_buffer_size);
300
301 switch (static_cast<Codec::PcmFormat>(info.sample_format)) {
302 case Codec::PcmFormat::Int16: {
303 // PCM16 is played as-is
304 break;
305 }
306 case Codec::PcmFormat::Adpcm: {
307 // Decode ADPCM to PCM16
308 Codec::ADPCM_Coeff coeffs;
309 memory.ReadBlock(info.additional_params_addr, coeffs.data(), sizeof(Codec::ADPCM_Coeff));
310 new_samples = Codec::DecodeADPCM(reinterpret_cast<u8*>(new_samples.data()),
311 new_samples.size() * sizeof(s16), coeffs, adpcm_state);
312 break;
313 } 120 }
314 default:
315 UNIMPLEMENTED_MSG("Unimplemented sample_format={}", info.sample_format);
316 break;
317 }
318
319 switch (info.channel_count) {
320 case 1: {
321 // 1 channel is upsampled to 2 channel
322 samples.resize(new_samples.size() * 2);
323 121
324 for (std::size_t index = 0; index < new_samples.size(); ++index) { 122 // TODO(ogniK): Performance buffer
325 auto sample = static_cast<float>(new_samples[index]); 123 if (!info_updater.UpdatePerformanceBuffer()) {
326 if (voice_resources[0]->in_use) { 124 LOG_ERROR(Audio, "Failed to update performance buffer parameters");
327 sample *= voice_resources[0]->mix_volumes[0]; 125 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
328 }
329
330 samples[index * 2] = static_cast<s16>(sample * info.volume);
331 samples[index * 2 + 1] = static_cast<s16>(sample * info.volume);
332 }
333 break;
334 } 126 }
335 case 2: {
336 // 2 channel is played as is
337 samples = std::move(new_samples);
338 const std::size_t sample_count = (samples.size() / 2);
339 for (std::size_t index = 0; index < sample_count; ++index) {
340 const std::size_t index_l = index * 2;
341 const std::size_t index_r = index * 2 + 1;
342
343 auto sample_l = static_cast<float>(samples[index_l]);
344 auto sample_r = static_cast<float>(samples[index_r]);
345
346 if (voice_resources[0]->in_use) {
347 sample_l *= voice_resources[0]->mix_volumes[0];
348 }
349
350 if (voice_resources[1]->in_use) {
351 sample_r *= voice_resources[1]->mix_volumes[1];
352 }
353 127
354 samples[index_l] = static_cast<s16>(sample_l * info.volume); 128 if (!info_updater.UpdateErrorInfo(behavior_info)) {
355 samples[index_r] = static_cast<s16>(sample_r * info.volume); 129 LOG_ERROR(Audio, "Failed to update error info");
356 } 130 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
357 break;
358 } 131 }
359 case 6: {
360 samples.resize((new_samples.size() / 6) * 2);
361 const std::size_t sample_count = samples.size() / 2;
362
363 for (std::size_t index = 0; index < sample_count; ++index) {
364 auto FL = static_cast<float>(new_samples[index * 6]);
365 auto FR = static_cast<float>(new_samples[index * 6 + 1]);
366 auto FC = static_cast<float>(new_samples[index * 6 + 2]);
367 auto BL = static_cast<float>(new_samples[index * 6 + 4]);
368 auto BR = static_cast<float>(new_samples[index * 6 + 5]);
369
370 if (voice_resources[0]->in_use) {
371 FL *= voice_resources[0]->mix_volumes[0];
372 }
373 if (voice_resources[1]->in_use) {
374 FR *= voice_resources[1]->mix_volumes[1];
375 }
376 if (voice_resources[2]->in_use) {
377 FC *= voice_resources[2]->mix_volumes[2];
378 }
379 if (voice_resources[4]->in_use) {
380 BL *= voice_resources[4]->mix_volumes[4];
381 }
382 if (voice_resources[5]->in_use) {
383 BR *= voice_resources[5]->mix_volumes[5];
384 }
385 132
386 samples[index * 2] = 133 if (behavior_info.IsElapsedFrameCountSupported()) {
387 static_cast<s16>((0.3694f * FL + 0.2612f * FC + 0.3694f * BL) * info.volume); 134 if (!info_updater.UpdateRendererInfo(elapsed_frame_count)) {
388 samples[index * 2 + 1] = 135 LOG_ERROR(Audio, "Failed to update renderer info");
389 static_cast<s16>((0.3694f * FR + 0.2612f * FC + 0.3694f * BR) * info.volume); 136 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
390 } 137 }
391 break;
392 }
393 default:
394 UNIMPLEMENTED_MSG("Unimplemented channel_count={}", info.channel_count);
395 break;
396 } 138 }
139 // TODO(ogniK): Statistics
397 140
398 // Only interpolate when necessary, expensive. 141 if (!info_updater.WriteOutputHeader()) {
399 if (GetInfo().sample_rate != STREAM_SAMPLE_RATE) { 142 LOG_ERROR(Audio, "Failed to write output header");
400 samples = Interpolate(interp_state, std::move(samples), GetInfo().sample_rate, 143 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
401 STREAM_SAMPLE_RATE);
402 } 144 }
403 145
404 is_refresh_pending = false; 146 // TODO(ogniK): Check when all sections are implemented
405}
406 147
407void AudioRenderer::EffectState::UpdateState(Core::Memory::Memory& memory) { 148 if (!info_updater.CheckConsumedSize()) {
408 if (info.is_new) { 149 LOG_ERROR(Audio, "Audio buffers were not consumed!");
409 out_status.state = EffectStatus::New; 150 return AudioCommon::Audren::ERR_INVALID_PARAMETERS;
410 } else {
411 if (info.type == Effect::Aux) {
412 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_info) == 0,
413 "Aux buffers tried to update");
414 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_info) == 0,
415 "Aux buffers tried to update");
416 ASSERT_MSG(memory.Read32(info.aux_info.return_buffer_base) == 0,
417 "Aux buffers tried to update");
418 ASSERT_MSG(memory.Read32(info.aux_info.send_buffer_base) == 0,
419 "Aux buffers tried to update");
420 }
421 } 151 }
422}
423 152
424static constexpr s16 ClampToS16(s32 value) { 153 ReleaseAndQueueBuffers();
425 return static_cast<s16>(std::clamp(value, -32768, 32767)); 154
155 return RESULT_SUCCESS;
426} 156}
427 157
428void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { 158void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
429 constexpr std::size_t BUFFER_SIZE{512}; 159 command_generator.PreCommand();
160 // Clear mix buffers before our next operation
161 command_generator.ClearMixBuffers();
162
163 // If the splitter is not in use, sort our mixes
164 if (!splitter_context.UsingSplitter()) {
165 mix_context.SortInfo();
166 }
167 // Sort our voices
168 voice_context.SortInfo();
169
170 // Handle samples
171 command_generator.GenerateVoiceCommands();
172 command_generator.GenerateSubMixCommands();
173 command_generator.GenerateFinalMixCommands();
174
175 command_generator.PostCommand();
176 // Base sample size
177 std::size_t BUFFER_SIZE{worker_params.sample_count};
178 // Samples
430 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels()); 179 std::vector<s16> buffer(BUFFER_SIZE * stream->GetNumChannels());
431 180 // Make sure to clear our samples
432 for (auto& voice : voices) { 181 std::memset(buffer.data(), 0, buffer.size() * sizeof(s16));
433 if (!voice.IsPlaying()) { 182
434 continue; 183 if (sink_context.InUse()) {
435 } 184 const auto stream_channel_count = stream->GetNumChannels();
436 VoiceChannelHolder resources{}; 185 const auto buffer_offsets = sink_context.OutputBuffers();
437 for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) { 186 const auto channel_count = buffer_offsets.size();
438 const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel]; 187 const auto& final_mix = mix_context.GetFinalMixInfo();
439 resources[channel] = &voice_resources[channel_resource_id]; 188 const auto& in_params = final_mix.GetInParams();
189 std::vector<s32*> mix_buffers(channel_count);
190 for (std::size_t i = 0; i < channel_count; i++) {
191 mix_buffers[i] =
192 command_generator.GetMixBuffer(in_params.buffer_offset + buffer_offsets[i]);
440 } 193 }
441 194
442 std::size_t offset{}; 195 for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
443 s64 samples_remaining{BUFFER_SIZE}; 196 if (channel_count == 1) {
444 while (samples_remaining > 0) { 197 const auto sample = ClampToS16(mix_buffers[0][i]);
445 const std::vector<s16> samples{ 198 buffer[i * stream_channel_count + 0] = sample;
446 voice.DequeueSamples(samples_remaining, memory, resources)}; 199 if (stream_channel_count > 1) {
447 200 buffer[i * stream_channel_count + 1] = sample;
448 if (samples.empty()) { 201 }
449 break; 202 if (stream_channel_count == 6) {
450 } 203 buffer[i * stream_channel_count + 2] = sample;
451 204 buffer[i * stream_channel_count + 4] = sample;
452 samples_remaining -= samples.size() / stream->GetNumChannels(); 205 buffer[i * stream_channel_count + 5] = sample;
453 206 }
454 for (const auto& sample : samples) { 207 } else if (channel_count == 2) {
455 const s32 buffer_sample{buffer[offset]}; 208 const auto l_sample = ClampToS16(mix_buffers[0][i]);
456 buffer[offset++] = 209 const auto r_sample = ClampToS16(mix_buffers[1][i]);
457 ClampToS16(buffer_sample + static_cast<s32>(sample * voice.GetInfo().volume)); 210 if (stream_channel_count == 0) {
211 buffer[i * stream_channel_count + 0] = l_sample;
212 } else if (stream_channel_count == 2) {
213 buffer[i * stream_channel_count + 0] = l_sample;
214 buffer[i * stream_channel_count + 1] = r_sample;
215 } else if (stream_channel_count == 6) {
216 buffer[i * stream_channel_count + 0] = l_sample;
217 buffer[i * stream_channel_count + 1] = r_sample;
218
219 buffer[i * stream_channel_count + 2] =
220 ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2);
221
222 buffer[i * stream_channel_count + 4] = l_sample;
223 buffer[i * stream_channel_count + 5] = r_sample;
224 }
225
226 } else if (channel_count == 6) {
227 const auto fl_sample = ClampToS16(mix_buffers[0][i]);
228 const auto fr_sample = ClampToS16(mix_buffers[1][i]);
229 const auto fc_sample = ClampToS16(mix_buffers[2][i]);
230 const auto lf_sample = ClampToS16(mix_buffers[3][i]);
231 const auto bl_sample = ClampToS16(mix_buffers[4][i]);
232 const auto br_sample = ClampToS16(mix_buffers[5][i]);
233
234 if (stream_channel_count == 1) {
235 buffer[i * stream_channel_count + 0] = fc_sample;
236 } else if (stream_channel_count == 2) {
237 buffer[i * stream_channel_count + 0] =
238 static_cast<s16>(0.3694f * static_cast<float>(fl_sample) +
239 0.2612f * static_cast<float>(fc_sample) +
240 0.3694f * static_cast<float>(bl_sample));
241 buffer[i * stream_channel_count + 1] =
242 static_cast<s16>(0.3694f * static_cast<float>(fr_sample) +
243 0.2612f * static_cast<float>(fc_sample) +
244 0.3694f * static_cast<float>(br_sample));
245 } else if (stream_channel_count == 6) {
246 buffer[i * stream_channel_count + 0] = fl_sample;
247 buffer[i * stream_channel_count + 1] = fr_sample;
248 buffer[i * stream_channel_count + 2] = fc_sample;
249 buffer[i * stream_channel_count + 3] = lf_sample;
250 buffer[i * stream_channel_count + 4] = bl_sample;
251 buffer[i * stream_channel_count + 5] = br_sample;
252 }
458 } 253 }
459 } 254 }
460 } 255 }
256
461 audio_out->QueueBuffer(stream, tag, std::move(buffer)); 257 audio_out->QueueBuffer(stream, tag, std::move(buffer));
462 elapsed_frame_count++; 258 elapsed_frame_count++;
259 voice_context.UpdateStateByDspShared();
463} 260}
464 261
465void AudioRenderer::ReleaseAndQueueBuffers() { 262void AudioRenderer::ReleaseAndQueueBuffers() {