summaryrefslogtreecommitdiff
path: root/src/audio_core/audio_renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/audio_core/audio_renderer.cpp')
-rw-r--r--src/audio_core/audio_renderer.cpp131
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 @@
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 <limits>
5#include <vector> 6#include <vector>
6#include "audio_core/algorithm/interpolate.h" 7
7#include "audio_core/audio_out.h" 8#include "audio_core/audio_out.h"
8#include "audio_core/audio_renderer.h" 9#include "audio_core/audio_renderer.h"
9#include "audio_core/codec.h"
10#include "audio_core/common.h" 10#include "audio_core/common.h"
11#include "audio_core/info_updater.h" 11#include "audio_core/info_updater.h"
12#include "audio_core/voice_context.h" 12#include "audio_core/voice_context.h"
13#include "common/assert.h"
14#include "common/logging/log.h" 13#include "common/logging/log.h"
15#include "core/core.h"
16#include "core/hle/kernel/writable_event.h"
17#include "core/memory.h" 14#include "core/memory.h"
18#include "core/settings.h" 15#include "core/settings.h"
19 16
17namespace {
18[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
19 return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()},
20 s32{std::numeric_limits<s16>::max()}));
21}
22
23[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) {
24 // Mix 50% from left and 50% from right channel
25 constexpr float l_mix_amount = 50.0f / 100.0f;
26 constexpr float r_mix_amount = 50.0f / 100.0f;
27 return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) +
28 (static_cast<float>(r_channel) * r_mix_amount)));
29}
30
31[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel,
32 s16 fc_channel,
33 [[maybe_unused]] s16 lf_channel,
34 s16 bl_channel, s16 br_channel) {
35 // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
36 // are mixed to be 36.94%
37
38 constexpr float front_mix_amount = 36.94f / 100.0f;
39 constexpr float center_mix_amount = 26.12f / 100.0f;
40 constexpr float back_mix_amount = 36.94f / 100.0f;
41
42 // Mix 50% from left and 50% from right channel
43 const auto left = front_mix_amount * static_cast<float>(fl_channel) +
44 center_mix_amount * static_cast<float>(fc_channel) +
45 back_mix_amount * static_cast<float>(bl_channel);
46
47 const auto right = front_mix_amount * static_cast<float>(fr_channel) +
48 center_mix_amount * static_cast<float>(fc_channel) +
49 back_mix_amount * static_cast<float>(br_channel);
50
51 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
52}
53
54[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients(
55 s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel,
56 const std::array<float_le, 4>& coeff) {
57 const auto left =
58 static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
59 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0];
60
61 const auto right =
62 static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
63 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0];
64
65 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
66}
67
68} // namespace
69
20namespace AudioCore { 70namespace AudioCore {
21AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 71AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
22 AudioCommon::AudioRendererParameter params, 72 AudioCommon::AudioRendererParameter params,
23 std::shared_ptr<Kernel::WritableEvent> buffer_event, 73 Stream::ReleaseCallback&& release_callback,
24 std::size_t instance_number) 74 std::size_t instance_number)
25 : worker_params{params}, buffer_event{buffer_event}, 75 : worker_params{params}, memory_pool_info(params.effect_count + params.voice_count * 4),
26 memory_pool_info(params.effect_count + params.voice_count * 4),
27 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(), 76 voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
28 sink_context(params.sink_count), splitter_context(), 77 sink_context(params.sink_count), splitter_context(),
29 voices(params.voice_count), memory{memory_}, 78 voices(params.voice_count), memory{memory_},
30 command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context, 79 command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
31 memory), 80 memory) {
32 temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) {
33 behavior_info.SetUserRevision(params.revision); 81 behavior_info.SetUserRevision(params.revision);
34 splitter_context.Initialize(behavior_info, params.splitter_count, 82 splitter_context.Initialize(behavior_info, params.splitter_count,
35 params.num_splitter_send_channels); 83 params.num_splitter_send_channels);
36 mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count); 84 mix_context.Initialize(behavior_info, params.submix_count + 1, params.effect_count);
37 audio_out = std::make_unique<AudioCore::AudioOut>(); 85 audio_out = std::make_unique<AudioCore::AudioOut>();
38 stream = 86 stream = audio_out->OpenStream(
39 audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS, 87 core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
40 fmt::format("AudioRenderer-Instance{}", instance_number), 88 fmt::format("AudioRenderer-Instance{}", instance_number), std::move(release_callback));
41 [=]() { buffer_event->Signal(); });
42 audio_out->StartStream(stream); 89 audio_out->StartStream(stream);
43 90
44 QueueMixedBuffer(0); 91 QueueMixedBuffer(0);
@@ -65,10 +112,6 @@ Stream::State AudioRenderer::GetStreamState() const {
65 return stream->GetState(); 112 return stream->GetState();
66} 113}
67 114
68static constexpr s16 ClampToS16(s32 value) {
69 return static_cast<s16>(std::clamp(value, -32768, 32767));
70}
71
72ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, 115ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
73 std::vector<u8>& output_params) { 116 std::vector<u8>& output_params) {
74 117
@@ -107,8 +150,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
107 } 150 }
108 } 151 }
109 152
110 auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, 153 const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
111 splitter_context, effect_context); 154 splitter_context, effect_context);
112 155
113 if (mix_result.IsError()) { 156 if (mix_result.IsError()) {
114 LOG_ERROR(Audio, "Failed to update mix parameters"); 157 LOG_ERROR(Audio, "Failed to update mix parameters");
@@ -197,20 +240,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
197 for (std::size_t i = 0; i < BUFFER_SIZE; i++) { 240 for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
198 if (channel_count == 1) { 241 if (channel_count == 1) {
199 const auto sample = ClampToS16(mix_buffers[0][i]); 242 const auto sample = ClampToS16(mix_buffers[0][i]);
200 buffer[i * stream_channel_count + 0] = sample; 243
201 if (stream_channel_count > 1) { 244 // Place sample in all channels
202 buffer[i * stream_channel_count + 1] = sample; 245 for (u32 channel = 0; channel < stream_channel_count; channel++) {
246 buffer[i * stream_channel_count + channel] = sample;
203 } 247 }
248
204 if (stream_channel_count == 6) { 249 if (stream_channel_count == 6) {
205 buffer[i * stream_channel_count + 2] = sample; 250 // Output stream has a LF channel, mute it!
206 buffer[i * stream_channel_count + 4] = sample; 251 buffer[i * stream_channel_count + 3] = 0;
207 buffer[i * stream_channel_count + 5] = sample;
208 } 252 }
253
209 } else if (channel_count == 2) { 254 } else if (channel_count == 2) {
210 const auto l_sample = ClampToS16(mix_buffers[0][i]); 255 const auto l_sample = ClampToS16(mix_buffers[0][i]);
211 const auto r_sample = ClampToS16(mix_buffers[1][i]); 256 const auto r_sample = ClampToS16(mix_buffers[1][i]);
212 if (stream_channel_count == 1) { 257 if (stream_channel_count == 1) {
213 buffer[i * stream_channel_count + 0] = l_sample; 258 buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample);
214 } else if (stream_channel_count == 2) { 259 } else if (stream_channel_count == 2) {
215 buffer[i * stream_channel_count + 0] = l_sample; 260 buffer[i * stream_channel_count + 0] = l_sample;
216 buffer[i * stream_channel_count + 1] = r_sample; 261 buffer[i * stream_channel_count + 1] = r_sample;
@@ -218,8 +263,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
218 buffer[i * stream_channel_count + 0] = l_sample; 263 buffer[i * stream_channel_count + 0] = l_sample;
219 buffer[i * stream_channel_count + 1] = r_sample; 264 buffer[i * stream_channel_count + 1] = r_sample;
220 265
221 buffer[i * stream_channel_count + 2] = 266 // Combine both left and right channels to the center channel
222 ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); 267 buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample);
223 268
224 buffer[i * stream_channel_count + 4] = l_sample; 269 buffer[i * stream_channel_count + 4] = l_sample;
225 buffer[i * stream_channel_count + 5] = r_sample; 270 buffer[i * stream_channel_count + 5] = r_sample;
@@ -234,17 +279,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
234 const auto br_sample = ClampToS16(mix_buffers[5][i]); 279 const auto br_sample = ClampToS16(mix_buffers[5][i]);
235 280
236 if (stream_channel_count == 1) { 281 if (stream_channel_count == 1) {
237 buffer[i * stream_channel_count + 0] = fc_sample; 282 // Games seem to ignore the center channel half the time, we use the front left
283 // and right channel for mixing as that's where majority of the audio goes
284 buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
238 } else if (stream_channel_count == 2) { 285 } else if (stream_channel_count == 2) {
239 buffer[i * stream_channel_count + 0] = 286 // Mix all channels into 2 channels
240 static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + 287 if (sink_context.HasDownMixingCoefficients()) {
241 0.2612f * static_cast<float>(fc_sample) + 288 const auto [left, right] = Mix6To2WithCoefficients(
242 0.3694f * static_cast<float>(bl_sample)); 289 fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
243 buffer[i * stream_channel_count + 1] = 290 sink_context.GetDownmixCoefficients());
244 static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + 291 buffer[i * stream_channel_count + 0] = left;
245 0.2612f * static_cast<float>(fc_sample) + 292 buffer[i * stream_channel_count + 1] = right;
246 0.3694f * static_cast<float>(br_sample)); 293 } else {
294 const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
295 lf_sample, bl_sample, br_sample);
296 buffer[i * stream_channel_count + 0] = left;
297 buffer[i * stream_channel_count + 1] = right;
298 }
247 } else if (stream_channel_count == 6) { 299 } else if (stream_channel_count == 6) {
300 // Pass through
248 buffer[i * stream_channel_count + 0] = fl_sample; 301 buffer[i * stream_channel_count + 0] = fl_sample;
249 buffer[i * stream_channel_count + 1] = fr_sample; 302 buffer[i * stream_channel_count + 1] = fr_sample;
250 buffer[i * stream_channel_count + 2] = fc_sample; 303 buffer[i * stream_channel_count + 2] = fc_sample;
@@ -262,7 +315,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
262} 315}
263 316
264void AudioRenderer::ReleaseAndQueueBuffers() { 317void AudioRenderer::ReleaseAndQueueBuffers() {
265 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; 318 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
266 for (const auto& tag : released_buffers) { 319 for (const auto& tag : released_buffers) {
267 QueueMixedBuffer(tag); 320 QueueMixedBuffer(tag);
268 } 321 }