diff options
Diffstat (limited to 'src/audio_core/audio_renderer.cpp')
-rw-r--r-- | src/audio_core/audio_renderer.cpp | 131 |
1 files changed, 92 insertions, 39 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp index 56dc892b1..d2ce8c814 100644 --- a/src/audio_core/audio_renderer.cpp +++ b/src/audio_core/audio_renderer.cpp @@ -2,43 +2,90 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <limits> #include <vector> -#include "audio_core/algorithm/interpolate.h" + #include "audio_core/audio_out.h" #include "audio_core/audio_renderer.h" -#include "audio_core/codec.h" #include "audio_core/common.h" #include "audio_core/info_updater.h" #include "audio_core/voice_context.h" -#include "common/assert.h" #include "common/logging/log.h" -#include "core/core.h" -#include "core/hle/kernel/writable_event.h" #include "core/memory.h" #include "core/settings.h" +namespace { +[[nodiscard]] static constexpr s16 ClampToS16(s32 value) { + return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()}, + s32{std::numeric_limits<s16>::max()})); +} + +[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) { + // Mix 50% from left and 50% from right channel + constexpr float l_mix_amount = 50.0f / 100.0f; + constexpr float r_mix_amount = 50.0f / 100.0f; + return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) + + (static_cast<float>(r_channel) * r_mix_amount))); +} + +[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel, + s16 fc_channel, + [[maybe_unused]] s16 lf_channel, + s16 bl_channel, s16 br_channel) { + // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels + // are mixed to be 36.94% + + constexpr float front_mix_amount = 36.94f / 100.0f; + constexpr float center_mix_amount = 26.12f / 100.0f; + constexpr float back_mix_amount = 36.94f / 100.0f; + + // Mix 50% from left and 50% from right channel + const auto left = front_mix_amount * static_cast<float>(fl_channel) + + center_mix_amount * static_cast<float>(fc_channel) + + back_mix_amount * static_cast<float>(bl_channel); + + const auto right = front_mix_amount * static_cast<float>(fr_channel) + + center_mix_amount * static_cast<float>(fc_channel) + + back_mix_amount * static_cast<float>(br_channel); + + return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; +} + +[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients( + s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel, + const std::array<float_le, 4>& coeff) { + const auto left = + static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + + static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0]; + + const auto right = + static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + + static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0]; + + return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; +} + +} // namespace + namespace AudioCore { AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, AudioCommon::AudioRendererParameter params, - std::shared_ptr<Kernel::WritableEvent> buffer_event, + Stream::ReleaseCallback&& release_callback, std::size_t instance_number) - : worker_params{params}, buffer_event{buffer_event}, - memory_pool_info(params.effect_count + params.voice_count * 4), + : worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4), voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), sink_context(params.sink_count), splitter_context(), voices(params.voice_count), memory{memory_}, command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context, - memory), - temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) { + memory) { behavior_info.SetUserRevision(params.revision); splitter_context.Initialize(behavior_info, params.splitter_count, params.num_splitter_send_channels); mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count); audio_out = std::make_unique<AudioCore::AudioOut>(); - stream = - audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, - fmt::format("AudioRenderer-Instance{}", instance_number), - [=]() { buffer_event->Signal(); }); + stream = audio_out->OpenStream( + core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, + fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback)); audio_out->StartStream(stream); QueueMixedBuffer(0); @@ -65,10 +112,6 @@ Stream::State AudioRenderer::GetStreamState() const { return stream->GetState(); } -static constexpr s16 ClampToS16(s32 value) { - return static_cast<s16>(std::clamp(value, -32768, 32767)); -} - ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, std::vector<u8>& output_params) { @@ -107,8 +150,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param } } - auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, - splitter_context, effect_context); + const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, + splitter_context, effect_context); if (mix_result.IsError()) { LOG_ERROR(Audio, "Failed to update mix parameters"); @@ -197,20 +240,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { for (std::size_t i = 0; i < BUFFER_SIZE; i++) { if (channel_count == 1) { const auto sample = ClampToS16(mix_buffers[0][i]); - buffer[i * stream_channel_count + 0] = sample; - if (stream_channel_count > 1) { - buffer[i * stream_channel_count + 1] = sample; + + // Place sample in all channels + for (u32 channel = 0; channel < stream_channel_count; channel++) { + buffer[i * stream_channel_count + channel] = sample; } + if (stream_channel_count == 6) { - buffer[i * stream_channel_count + 2] = sample; - buffer[i * stream_channel_count + 4] = sample; - buffer[i * stream_channel_count + 5] = sample; + // Output stream has a LF channel, mute it! + buffer[i * stream_channel_count + 3] = 0; } + } else if (channel_count == 2) { const auto l_sample = ClampToS16(mix_buffers[0][i]); const auto r_sample = ClampToS16(mix_buffers[1][i]); if (stream_channel_count == 1) { - buffer[i * stream_channel_count + 0] = l_sample; + buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample); } else if (stream_channel_count == 2) { buffer[i * stream_channel_count + 0] = l_sample; buffer[i * stream_channel_count + 1] = r_sample; @@ -218,8 +263,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { buffer[i * stream_channel_count + 0] = l_sample; buffer[i * stream_channel_count + 1] = r_sample; - buffer[i * stream_channel_count + 2] = - ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); + // Combine both left and right channels to the center channel + buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample); buffer[i * stream_channel_count + 4] = l_sample; buffer[i * stream_channel_count + 5] = r_sample; @@ -234,17 +279,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { const auto br_sample = ClampToS16(mix_buffers[5][i]); if (stream_channel_count == 1) { - buffer[i * stream_channel_count + 0] = fc_sample; + // Games seem to ignore the center channel half the time, we use the front left + // and right channel for mixing as that's where majority of the audio goes + buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample); } else if (stream_channel_count == 2) { - buffer[i * stream_channel_count + 0] = - static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + - 0.2612f * static_cast<float>(fc_sample) + - 0.3694f * static_cast<float>(bl_sample)); - buffer[i * stream_channel_count + 1] = - static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + - 0.2612f * static_cast<float>(fc_sample) + - 0.3694f * static_cast<float>(br_sample)); + // Mix all channels into 2 channels + if (sink_context.HasDownMixingCoefficients()) { + const auto [left, right] = Mix6To2WithCoefficients( + fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample, + sink_context.GetDownmixCoefficients()); + buffer[i * stream_channel_count + 0] = left; + buffer[i * stream_channel_count + 1] = right; + } else { + const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample, + lf_sample, bl_sample, br_sample); + buffer[i * stream_channel_count + 0] = left; + buffer[i * stream_channel_count + 1] = right; + } } else if (stream_channel_count == 6) { + // Pass through buffer[i * stream_channel_count + 0] = fl_sample; buffer[i * stream_channel_count + 1] = fr_sample; buffer[i * stream_channel_count + 2] = fc_sample; @@ -262,7 +315,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) { } void AudioRenderer::ReleaseAndQueueBuffers() { - const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; + const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)}; for (const auto& tag : released_buffers) { QueueMixedBuffer(tag); } |