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.cpp110
1 files changed, 85 insertions, 25 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index a7e851bb8..03a133640 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -2,6 +2,7 @@
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 7
7#include "audio_core/audio_out.h" 8#include "audio_core/audio_out.h"
@@ -14,6 +15,59 @@
14#include "core/memory.h" 15#include "core/memory.h"
15#include "core/settings.h" 16#include "core/settings.h"
16 17
18namespace {
19[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
20 return static_cast<s16>(std::clamp(value, static_cast<s32>(std::numeric_limits<s16>::min()),
21 static_cast<s32>(std::numeric_limits<s16>::max())));
22}
23
24[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) {
25 // Mix 50% from left and 50% from right channel
26 constexpr float l_mix_amount = 50.0f / 100.0f;
27 constexpr float r_mix_amount = 50.0f / 100.0f;
28 return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) +
29 (static_cast<float>(r_channel) * r_mix_amount)));
30}
31
32[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel,
33 s16 fc_channel,
34 [[maybe_unused]] s16 lf_channel,
35 s16 bl_channel, s16 br_channel) {
36 // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
37 // are mixed to be 36.94%
38
39 constexpr float front_mix_amount = 36.94f / 100.0f;
40 constexpr float center_mix_amount = 26.12f / 100.0f;
41 constexpr float back_mix_amount = 36.94f / 100.0f;
42
43 // Mix 50% from left and 50% from right channel
44 const auto left = front_mix_amount * static_cast<float>(fl_channel) +
45 center_mix_amount * static_cast<float>(fc_channel) +
46 back_mix_amount * static_cast<float>(bl_channel);
47
48 const auto right = front_mix_amount * static_cast<float>(fr_channel) +
49 center_mix_amount * static_cast<float>(fc_channel) +
50 back_mix_amount * static_cast<float>(br_channel);
51
52 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
53}
54
55[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients(
56 s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel,
57 const std::array<float_le, 4>& coeff) {
58 const auto left =
59 static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
60 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0];
61
62 const auto right =
63 static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
64 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0];
65
66 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
67}
68
69} // namespace
70
17namespace AudioCore { 71namespace AudioCore {
18AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, 72AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
19 AudioCommon::AudioRendererParameter params, 73 AudioCommon::AudioRendererParameter params,
@@ -62,10 +116,6 @@ Stream::State AudioRenderer::GetStreamState() const {
62 return stream->GetState(); 116 return stream->GetState();
63} 117}
64 118
65static constexpr s16 ClampToS16(s32 value) {
66 return static_cast<s16>(std::clamp(value, -32768, 32767));
67}
68
69ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, 119ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
70 std::vector<u8>& output_params) { 120 std::vector<u8>& output_params) {
71 121
@@ -104,8 +154,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
104 } 154 }
105 } 155 }
106 156
107 auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count, 157 const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
108 splitter_context, effect_context); 158 splitter_context, effect_context);
109 159
110 if (mix_result.IsError()) { 160 if (mix_result.IsError()) {
111 LOG_ERROR(Audio, "Failed to update mix parameters"); 161 LOG_ERROR(Audio, "Failed to update mix parameters");
@@ -194,20 +244,22 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
194 for (std::size_t i = 0; i < BUFFER_SIZE; i++) { 244 for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
195 if (channel_count == 1) { 245 if (channel_count == 1) {
196 const auto sample = ClampToS16(mix_buffers[0][i]); 246 const auto sample = ClampToS16(mix_buffers[0][i]);
197 buffer[i * stream_channel_count + 0] = sample; 247
198 if (stream_channel_count > 1) { 248 // Place sample in all channels
199 buffer[i * stream_channel_count + 1] = sample; 249 for (u32 channel = 0; channel < stream_channel_count; channel++) {
250 buffer[i * stream_channel_count + channel] = sample;
200 } 251 }
252
201 if (stream_channel_count == 6) { 253 if (stream_channel_count == 6) {
202 buffer[i * stream_channel_count + 2] = sample; 254 // Output stream has a LF channel, mute it!
203 buffer[i * stream_channel_count + 4] = sample; 255 buffer[i * stream_channel_count + 3] = 0;
204 buffer[i * stream_channel_count + 5] = sample;
205 } 256 }
257
206 } else if (channel_count == 2) { 258 } else if (channel_count == 2) {
207 const auto l_sample = ClampToS16(mix_buffers[0][i]); 259 const auto l_sample = ClampToS16(mix_buffers[0][i]);
208 const auto r_sample = ClampToS16(mix_buffers[1][i]); 260 const auto r_sample = ClampToS16(mix_buffers[1][i]);
209 if (stream_channel_count == 1) { 261 if (stream_channel_count == 1) {
210 buffer[i * stream_channel_count + 0] = l_sample; 262 buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample);
211 } else if (stream_channel_count == 2) { 263 } else if (stream_channel_count == 2) {
212 buffer[i * stream_channel_count + 0] = l_sample; 264 buffer[i * stream_channel_count + 0] = l_sample;
213 buffer[i * stream_channel_count + 1] = r_sample; 265 buffer[i * stream_channel_count + 1] = r_sample;
@@ -215,8 +267,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
215 buffer[i * stream_channel_count + 0] = l_sample; 267 buffer[i * stream_channel_count + 0] = l_sample;
216 buffer[i * stream_channel_count + 1] = r_sample; 268 buffer[i * stream_channel_count + 1] = r_sample;
217 269
218 buffer[i * stream_channel_count + 2] = 270 // Combine both left and right channels to the center channel
219 ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2); 271 buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample);
220 272
221 buffer[i * stream_channel_count + 4] = l_sample; 273 buffer[i * stream_channel_count + 4] = l_sample;
222 buffer[i * stream_channel_count + 5] = r_sample; 274 buffer[i * stream_channel_count + 5] = r_sample;
@@ -231,17 +283,25 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
231 const auto br_sample = ClampToS16(mix_buffers[5][i]); 283 const auto br_sample = ClampToS16(mix_buffers[5][i]);
232 284
233 if (stream_channel_count == 1) { 285 if (stream_channel_count == 1) {
234 buffer[i * stream_channel_count + 0] = fc_sample; 286 // Games seem to ignore the center channel half the time, we use the front left
287 // and right channel for mixing as that's where majority of the audio goes
288 buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
235 } else if (stream_channel_count == 2) { 289 } else if (stream_channel_count == 2) {
236 buffer[i * stream_channel_count + 0] = 290 // Mix all channels into 2 channels
237 static_cast<s16>(0.3694f * static_cast<float>(fl_sample) + 291 if (sink_context.HasDownMixingCoefficients()) {
238 0.2612f * static_cast<float>(fc_sample) + 292 const auto [left, right] = Mix6To2WithCoefficients(
239 0.3694f * static_cast<float>(bl_sample)); 293 fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
240 buffer[i * stream_channel_count + 1] = 294 sink_context.GetDownmixCoefficients());
241 static_cast<s16>(0.3694f * static_cast<float>(fr_sample) + 295 buffer[i * stream_channel_count + 0] = left;
242 0.2612f * static_cast<float>(fc_sample) + 296 buffer[i * stream_channel_count + 1] = right;
243 0.3694f * static_cast<float>(br_sample)); 297 } else {
298 const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
299 lf_sample, bl_sample, br_sample);
300 buffer[i * stream_channel_count + 0] = left;
301 buffer[i * stream_channel_count + 1] = right;
302 }
244 } else if (stream_channel_count == 6) { 303 } else if (stream_channel_count == 6) {
304 // Pass through
245 buffer[i * stream_channel_count + 0] = fl_sample; 305 buffer[i * stream_channel_count + 0] = fl_sample;
246 buffer[i * stream_channel_count + 1] = fr_sample; 306 buffer[i * stream_channel_count + 1] = fr_sample;
247 buffer[i * stream_channel_count + 2] = fc_sample; 307 buffer[i * stream_channel_count + 2] = fc_sample;
@@ -259,7 +319,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
259} 319}
260 320
261void AudioRenderer::ReleaseAndQueueBuffers() { 321void AudioRenderer::ReleaseAndQueueBuffers() {
262 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)}; 322 const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
263 for (const auto& tag : released_buffers) { 323 for (const auto& tag : released_buffers) {
264 QueueMixedBuffer(tag); 324 QueueMixedBuffer(tag);
265 } 325 }