summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2020-05-13 22:46:41 -0400
committerGravatar GitHub2020-05-13 22:46:41 -0400
commit0e2ded049d6d5a39d18cf904e54c053355482e31 (patch)
tree0cc136ecc5d107308fb47907feb235af51394f68 /src
parentMerge pull request #3909 from bunnei/timezone (diff)
parentfix logic error & scale sample volume based on voice volume (diff)
downloadyuzu-0e2ded049d6d5a39d18cf904e54c053355482e31.tar.gz
yuzu-0e2ded049d6d5a39d18cf904e54c053355482e31.tar.xz
yuzu-0e2ded049d6d5a39d18cf904e54c053355482e31.zip
Merge pull request #3757 from ogniK5377/better-voice-mixing
audio_renderer: Better voice mixing and 6 channel downmixing
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp99
-rw-r--r--src/audio_core/audio_renderer.h10
-rw-r--r--src/audio_core/common.h1
3 files changed, 98 insertions, 12 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index d18ef6940..50846a854 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -17,7 +17,7 @@ namespace AudioCore {
17 17
18constexpr u32 STREAM_SAMPLE_RATE{48000}; 18constexpr u32 STREAM_SAMPLE_RATE{48000};
19constexpr u32 STREAM_NUM_CHANNELS{2}; 19constexpr u32 STREAM_NUM_CHANNELS{2};
20 20using VoiceChannelHolder = std::array<VoiceResourceInformation*, 6>;
21class AudioRenderer::VoiceState { 21class AudioRenderer::VoiceState {
22public: 22public:
23 bool IsPlaying() const { 23 bool IsPlaying() const {
@@ -37,9 +37,10 @@ public:
37 } 37 }
38 38
39 void SetWaveIndex(std::size_t index); 39 void SetWaveIndex(std::size_t index);
40 std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory); 40 std::vector<s16> DequeueSamples(std::size_t sample_count, Core::Memory::Memory& memory,
41 const VoiceChannelHolder& voice_resources);
41 void UpdateState(); 42 void UpdateState();
42 void RefreshBuffer(Core::Memory::Memory& memory); 43 void RefreshBuffer(Core::Memory::Memory& memory, const VoiceChannelHolder& voice_resources);
43 44
44private: 45private:
45 bool is_in_use{}; 46 bool is_in_use{};
@@ -79,7 +80,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
79 std::shared_ptr<Kernel::WritableEvent> buffer_event, 80 std::shared_ptr<Kernel::WritableEvent> buffer_event,
80 std::size_t instance_number) 81 std::size_t instance_number)
81 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), 82 : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count),
82 effects(params.effect_count), memory{memory_} { 83 voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} {
83 behavior_info.SetUserRevision(params.revision); 84 behavior_info.SetUserRevision(params.revision);
84 audio_out = std::make_unique<AudioCore::AudioOut>(); 85 audio_out = std::make_unique<AudioCore::AudioOut>();
85 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, 86 stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS,
@@ -127,6 +128,12 @@ ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector<
127 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, 128 input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size,
128 memory_pool_count * sizeof(MemoryPoolInfo)); 129 memory_pool_count * sizeof(MemoryPoolInfo));
129 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
130 // Copy VoiceInfo structs 137 // Copy VoiceInfo structs
131 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + 138 std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size +
132 config.memory_pools_size + config.voice_resource_size}; 139 config.memory_pools_size + config.voice_resource_size};
@@ -220,14 +227,15 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) {
220 is_refresh_pending = true; 227 is_refresh_pending = true;
221} 228}
222 229
223std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count, 230std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(
224 Core::Memory::Memory& memory) { 231 std::size_t sample_count, Core::Memory::Memory& memory,
232 const VoiceChannelHolder& voice_resources) {
225 if (!IsPlaying()) { 233 if (!IsPlaying()) {
226 return {}; 234 return {};
227 } 235 }
228 236
229 if (is_refresh_pending) { 237 if (is_refresh_pending) {
230 RefreshBuffer(memory); 238 RefreshBuffer(memory, voice_resources);
231 } 239 }
232 240
233 const std::size_t max_size{samples.size() - offset}; 241 const std::size_t max_size{samples.size() - offset};
@@ -271,7 +279,8 @@ void AudioRenderer::VoiceState::UpdateState() {
271 is_in_use = info.is_in_use; 279 is_in_use = info.is_in_use;
272} 280}
273 281
274void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { 282void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory,
283 const VoiceChannelHolder& voice_resources) {
275 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; 284 const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr;
276 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; 285 const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz;
277 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); 286 std::vector<s16> new_samples(wave_buffer_size / sizeof(s16));
@@ -296,17 +305,77 @@ void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) {
296 } 305 }
297 306
298 switch (info.channel_count) { 307 switch (info.channel_count) {
299 case 1: 308 case 1: {
300 // 1 channel is upsampled to 2 channel 309 // 1 channel is upsampled to 2 channel
301 samples.resize(new_samples.size() * 2); 310 samples.resize(new_samples.size() * 2);
311
302 for (std::size_t index = 0; index < new_samples.size(); ++index) { 312 for (std::size_t index = 0; index < new_samples.size(); ++index) {
303 samples[index * 2] = new_samples[index]; 313 auto sample = static_cast<float>(new_samples[index]);
304 samples[index * 2 + 1] = new_samples[index]; 314 if (voice_resources[0]->in_use) {
315 sample *= voice_resources[0]->mix_volumes[0];
316 }
317
318 samples[index * 2] = static_cast<s16>(sample * info.volume);
319 samples[index * 2 + 1] = static_cast<s16>(sample * info.volume);
305 } 320 }
306 break; 321 break;
322 }
307 case 2: { 323 case 2: {
308 // 2 channel is played as is 324 // 2 channel is played as is
309 samples = std::move(new_samples); 325 samples = std::move(new_samples);
326 const std::size_t sample_count = (samples.size() / 2);
327 for (std::size_t index = 0; index < sample_count; ++index) {
328 const std::size_t index_l = index * 2;
329 const std::size_t index_r = index * 2 + 1;
330
331 auto sample_l = static_cast<float>(samples[index_l]);
332 auto sample_r = static_cast<float>(samples[index_r]);
333
334 if (voice_resources[0]->in_use) {
335 sample_l *= voice_resources[0]->mix_volumes[0];
336 }
337
338 if (voice_resources[1]->in_use) {
339 sample_r *= voice_resources[1]->mix_volumes[1];
340 }
341
342 samples[index_l] = static_cast<s16>(sample_l * info.volume);
343 samples[index_r] = static_cast<s16>(sample_r * info.volume);
344 }
345 break;
346 }
347 case 6: {
348 samples.resize((new_samples.size() / 6) * 2);
349 const std::size_t sample_count = samples.size() / 2;
350
351 for (std::size_t index = 0; index < sample_count; ++index) {
352 auto FL = static_cast<float>(new_samples[index * 6]);
353 auto FR = static_cast<float>(new_samples[index * 6 + 1]);
354 auto FC = static_cast<float>(new_samples[index * 6 + 2]);
355 auto BL = static_cast<float>(new_samples[index * 6 + 4]);
356 auto BR = static_cast<float>(new_samples[index * 6 + 5]);
357
358 if (voice_resources[0]->in_use) {
359 FL *= voice_resources[0]->mix_volumes[0];
360 }
361 if (voice_resources[1]->in_use) {
362 FR *= voice_resources[1]->mix_volumes[1];
363 }
364 if (voice_resources[2]->in_use) {
365 FC *= voice_resources[2]->mix_volumes[2];
366 }
367 if (voice_resources[4]->in_use) {
368 BL *= voice_resources[4]->mix_volumes[4];
369 }
370 if (voice_resources[5]->in_use) {
371 BR *= voice_resources[5]->mix_volumes[5];
372 }
373
374 samples[index * 2] =
375 static_cast<s16>((0.3694f * FL + 0.2612f * FC + 0.3694f * BL) * info.volume);
376 samples[index * 2 + 1] =
377 static_cast<s16>((0.3694f * FR + 0.2612f * FC + 0.3694f * BR) * info.volume);
378 }
310 break; 379 break;
311 } 380 }
312 default: 381 default:
@@ -352,11 +421,17 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
352 if (!voice.IsPlaying()) { 421 if (!voice.IsPlaying()) {
353 continue; 422 continue;
354 } 423 }
424 VoiceChannelHolder resources{};
425 for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) {
426 const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel];
427 resources[channel] = &voice_resources[channel_resource_id];
428 }
355 429
356 std::size_t offset{}; 430 std::size_t offset{};
357 s64 samples_remaining{BUFFER_SIZE}; 431 s64 samples_remaining{BUFFER_SIZE};
358 while (samples_remaining > 0) { 432 while (samples_remaining > 0) {
359 const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)}; 433 const std::vector<s16> samples{
434 voice.DequeueSamples(samples_remaining, memory, resources)};
360 435
361 if (samples.empty()) { 436 if (samples.empty()) {
362 break; 437 break;
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index b42770fae..1f9114c07 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -9,6 +9,7 @@
9#include <vector> 9#include <vector>
10 10
11#include "audio_core/behavior_info.h" 11#include "audio_core/behavior_info.h"
12#include "audio_core/common.h"
12#include "audio_core/stream.h" 13#include "audio_core/stream.h"
13#include "common/common_funcs.h" 14#include "common/common_funcs.h"
14#include "common/common_types.h" 15#include "common/common_types.h"
@@ -116,6 +117,14 @@ struct WaveBuffer {
116}; 117};
117static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size"); 118static_assert(sizeof(WaveBuffer) == 0x38, "WaveBuffer has wrong size");
118 119
120struct VoiceResourceInformation {
121 s32_le id{};
122 std::array<float_le, MAX_MIX_BUFFERS> mix_volumes{};
123 bool in_use{};
124 INSERT_PADDING_BYTES(11);
125};
126static_assert(sizeof(VoiceResourceInformation) == 0x70, "VoiceResourceInformation has wrong size");
127
119struct VoiceInfo { 128struct VoiceInfo {
120 u32_le id; 129 u32_le id;
121 u32_le node_id; 130 u32_le node_id;
@@ -244,6 +253,7 @@ private:
244 AudioRendererParameter worker_params; 253 AudioRendererParameter worker_params;
245 std::shared_ptr<Kernel::WritableEvent> buffer_event; 254 std::shared_ptr<Kernel::WritableEvent> buffer_event;
246 std::vector<VoiceState> voices; 255 std::vector<VoiceState> voices;
256 std::vector<VoiceResourceInformation> voice_resources;
247 std::vector<EffectState> effects; 257 std::vector<EffectState> effects;
248 std::unique_ptr<AudioOut> audio_out; 258 std::unique_ptr<AudioOut> audio_out;
249 StreamPtr stream; 259 StreamPtr stream;
diff --git a/src/audio_core/common.h b/src/audio_core/common.h
index 98478b66b..7bb145c53 100644
--- a/src/audio_core/common.h
+++ b/src/audio_core/common.h
@@ -14,6 +14,7 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
14} 14}
15 15
16constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8'); 16constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
17constexpr std::size_t MAX_MIX_BUFFERS = 24;
17 18
18static constexpr u32 VersionFromRevision(u32_le rev) { 19static constexpr u32 VersionFromRevision(u32_le rev) {
19 // "REV7" -> 7 20 // "REV7" -> 7