diff options
Diffstat (limited to 'src/audio_core/audio_renderer.cpp')
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 96 |
1 files changed, 85 insertions, 11 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index d18ef6940..f54ce48c5 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp | |||
| @@ -37,9 +37,11 @@ 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 | std::array<VoiceResourceInformation*, 6> voice_resources); | ||
| 41 | void UpdateState(); | 42 | void UpdateState(); |
| 42 | void RefreshBuffer(Core::Memory::Memory& memory); | 43 | void RefreshBuffer(Core::Memory::Memory& memory, |
| 44 | std::array<VoiceResourceInformation*, 6> voice_resources); | ||
| 43 | 45 | ||
| 44 | private: | 46 | private: |
| 45 | bool is_in_use{}; | 47 | bool is_in_use{}; |
| @@ -79,7 +81,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory | |||
| 79 | std::shared_ptr<Kernel::WritableEvent> buffer_event, | 81 | std::shared_ptr<Kernel::WritableEvent> buffer_event, |
| 80 | std::size_t instance_number) | 82 | std::size_t instance_number) |
| 81 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), | 83 | : worker_params{params}, buffer_event{buffer_event}, voices(params.voice_count), |
| 82 | effects(params.effect_count), memory{memory_} { | 84 | voice_resources(params.voice_count), effects(params.effect_count), memory{memory_} { |
| 83 | behavior_info.SetUserRevision(params.revision); | 85 | behavior_info.SetUserRevision(params.revision); |
| 84 | audio_out = std::make_unique<AudioCore::AudioOut>(); | 86 | audio_out = std::make_unique<AudioCore::AudioOut>(); |
| 85 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, | 87 | stream = audio_out->OpenStream(core_timing, STREAM_SAMPLE_RATE, STREAM_NUM_CHANNELS, |
| @@ -127,6 +129,12 @@ ResultVal<std::vector<u8>> AudioRenderer::UpdateAudioRenderer(const std::vector< | |||
| 127 | input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, | 129 | input_params.data() + sizeof(UpdateDataHeader) + config.behavior_size, |
| 128 | memory_pool_count * sizeof(MemoryPoolInfo)); | 130 | memory_pool_count * sizeof(MemoryPoolInfo)); |
| 129 | 131 | ||
| 132 | // Copy voice resources | ||
| 133 | const std::size_t voice_resource_offset{sizeof(UpdateDataHeader) + config.behavior_size + | ||
| 134 | config.memory_pools_size}; | ||
| 135 | std::memcpy(voice_resources.data(), input_params.data() + voice_resource_offset, | ||
| 136 | sizeof(VoiceResourceInformation) * voice_resources.size()); | ||
| 137 | |||
| 130 | // Copy VoiceInfo structs | 138 | // Copy VoiceInfo structs |
| 131 | std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + | 139 | std::size_t voice_offset{sizeof(UpdateDataHeader) + config.behavior_size + |
| 132 | config.memory_pools_size + config.voice_resource_size}; | 140 | config.memory_pools_size + config.voice_resource_size}; |
| @@ -220,14 +228,15 @@ void AudioRenderer::VoiceState::SetWaveIndex(std::size_t index) { | |||
| 220 | is_refresh_pending = true; | 228 | is_refresh_pending = true; |
| 221 | } | 229 | } |
| 222 | 230 | ||
| 223 | std::vector<s16> AudioRenderer::VoiceState::DequeueSamples(std::size_t sample_count, | 231 | std::vector<s16> AudioRenderer::VoiceState::DequeueSamples( |
| 224 | Core::Memory::Memory& memory) { | 232 | std::size_t sample_count, Core::Memory::Memory& memory, |
| 233 | std::array<VoiceResourceInformation*, 6> voice_resources) { | ||
| 225 | if (!IsPlaying()) { | 234 | if (!IsPlaying()) { |
| 226 | return {}; | 235 | return {}; |
| 227 | } | 236 | } |
| 228 | 237 | ||
| 229 | if (is_refresh_pending) { | 238 | if (is_refresh_pending) { |
| 230 | RefreshBuffer(memory); | 239 | RefreshBuffer(memory, voice_resources); |
| 231 | } | 240 | } |
| 232 | 241 | ||
| 233 | const std::size_t max_size{samples.size() - offset}; | 242 | const std::size_t max_size{samples.size() - offset}; |
| @@ -271,7 +280,8 @@ void AudioRenderer::VoiceState::UpdateState() { | |||
| 271 | is_in_use = info.is_in_use; | 280 | is_in_use = info.is_in_use; |
| 272 | } | 281 | } |
| 273 | 282 | ||
| 274 | void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { | 283 | void AudioRenderer::VoiceState::RefreshBuffer( |
| 284 | Core::Memory::Memory& memory, std::array<VoiceResourceInformation*, 6> voice_resources) { | ||
| 275 | const auto wave_buffer_address = info.wave_buffer[wave_index].buffer_addr; | 285 | 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; | 286 | const auto wave_buffer_size = info.wave_buffer[wave_index].buffer_sz; |
| 277 | std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); | 287 | std::vector<s16> new_samples(wave_buffer_size / sizeof(s16)); |
| @@ -296,17 +306,75 @@ void AudioRenderer::VoiceState::RefreshBuffer(Core::Memory::Memory& memory) { | |||
| 296 | } | 306 | } |
| 297 | 307 | ||
| 298 | switch (info.channel_count) { | 308 | switch (info.channel_count) { |
| 299 | case 1: | 309 | case 1: { |
| 300 | // 1 channel is upsampled to 2 channel | 310 | // 1 channel is upsampled to 2 channel |
| 301 | samples.resize(new_samples.size() * 2); | 311 | samples.resize(new_samples.size() * 2); |
| 312 | |||
| 302 | for (std::size_t index = 0; index < new_samples.size(); ++index) { | 313 | for (std::size_t index = 0; index < new_samples.size(); ++index) { |
| 303 | samples[index * 2] = new_samples[index]; | 314 | auto sample = static_cast<float>(new_samples[index]); |
| 304 | samples[index * 2 + 1] = new_samples[index]; | 315 | if (voice_resources[0]->in_use) { |
| 316 | sample *= voice_resources[0]->mix_volumes[0]; | ||
| 317 | } | ||
| 318 | |||
| 319 | samples[index * 2] = static_cast<s16>(sample); | ||
| 320 | samples[index * 2 + 1] = static_cast<s16>(sample); | ||
| 305 | } | 321 | } |
| 306 | break; | 322 | break; |
| 323 | } | ||
| 307 | case 2: { | 324 | case 2: { |
| 308 | // 2 channel is played as is | 325 | // 2 channel is played as is |
| 309 | samples = std::move(new_samples); | 326 | samples = std::move(new_samples); |
| 327 | const std::size_t sample_count = (samples.size() / 2); | ||
| 328 | for (std::size_t index = 0; index < sample_count; ++index) { | ||
| 329 | const std::size_t index_l = index * 2; | ||
| 330 | const std::size_t index_r = index * 2 + 1; | ||
| 331 | |||
| 332 | auto sample_l = static_cast<float>(samples[index_l]); | ||
| 333 | auto sample_r = static_cast<float>(samples[index_r]); | ||
| 334 | |||
| 335 | if (voice_resources[0]->in_use) { | ||
| 336 | sample_l *= voice_resources[0]->mix_volumes[0]; | ||
| 337 | } | ||
| 338 | |||
| 339 | if (voice_resources[1]->in_use) { | ||
| 340 | sample_l *= voice_resources[1]->mix_volumes[1]; | ||
| 341 | } | ||
| 342 | |||
| 343 | samples[index_l] = static_cast<s16>(sample_l); | ||
| 344 | samples[index_r] = static_cast<s16>(sample_r); | ||
| 345 | } | ||
| 346 | break; | ||
| 347 | } | ||
| 348 | case 6: { | ||
| 349 | samples.resize((new_samples.size() / 6) * 2); | ||
| 350 | const std::size_t sample_count = samples.size() / 2; | ||
| 351 | |||
| 352 | for (std::size_t index = 0; index < sample_count; ++index) { | ||
| 353 | auto FL = static_cast<float>(new_samples[index * 6]); | ||
| 354 | auto FR = static_cast<float>(new_samples[index * 6 + 1]); | ||
| 355 | auto FC = static_cast<float>(new_samples[index * 6 + 2]); | ||
| 356 | auto BL = static_cast<float>(new_samples[index * 6 + 4]); | ||
| 357 | auto BR = static_cast<float>(new_samples[index * 6 + 5]); | ||
| 358 | |||
| 359 | if (voice_resources[0]->in_use) { | ||
| 360 | FL *= voice_resources[0]->mix_volumes[0]; | ||
| 361 | } | ||
| 362 | if (voice_resources[1]->in_use) { | ||
| 363 | FR *= voice_resources[1]->mix_volumes[1]; | ||
| 364 | } | ||
| 365 | if (voice_resources[2]->in_use) { | ||
| 366 | FC *= voice_resources[2]->mix_volumes[2]; | ||
| 367 | } | ||
| 368 | if (voice_resources[4]->in_use) { | ||
| 369 | BL *= voice_resources[4]->mix_volumes[4]; | ||
| 370 | } | ||
| 371 | if (voice_resources[5]->in_use) { | ||
| 372 | BR *= voice_resources[5]->mix_volumes[5]; | ||
| 373 | } | ||
| 374 | |||
| 375 | samples[index * 2] = static_cast<s16>(0.3694f * FL + 0.2612f * FC + 0.3694f * BL); | ||
| 376 | samples[index * 2 + 1] = static_cast<s16>(0.3694f * FR + 0.2612f * FC + 0.3694f * BR); | ||
| 377 | } | ||
| 310 | break; | 378 | break; |
| 311 | } | 379 | } |
| 312 | default: | 380 | default: |
| @@ -352,11 +420,17 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { | |||
| 352 | if (!voice.IsPlaying()) { | 420 | if (!voice.IsPlaying()) { |
| 353 | continue; | 421 | continue; |
| 354 | } | 422 | } |
| 423 | std::array<VoiceResourceInformation*, 6> resources{}; | ||
| 424 | for (u32 channel = 0; channel < voice.GetInfo().channel_count; channel++) { | ||
| 425 | const auto channel_resource_id = voice.GetInfo().voice_channel_resource_ids[channel]; | ||
| 426 | resources[channel] = &voice_resources[channel_resource_id]; | ||
| 427 | } | ||
| 355 | 428 | ||
| 356 | std::size_t offset{}; | 429 | std::size_t offset{}; |
| 357 | s64 samples_remaining{BUFFER_SIZE}; | 430 | s64 samples_remaining{BUFFER_SIZE}; |
| 358 | while (samples_remaining > 0) { | 431 | while (samples_remaining > 0) { |
| 359 | const std::vector<s16> samples{voice.DequeueSamples(samples_remaining, memory)}; | 432 | const std::vector<s16> samples{ |
| 433 | voice.DequeueSamples(samples_remaining, memory, resources)}; | ||
| 360 | 434 | ||
| 361 | if (samples.empty()) { | 435 | if (samples.empty()) { |
| 362 | break; | 436 | break; |