diff options
| author | 2020-11-17 14:14:29 +1100 | |
|---|---|---|
| committer | 2020-11-17 14:14:29 +1100 | |
| commit | 9a4beac95a0f88ec312a28d06da8270aa58736e3 (patch) | |
| tree | f3cbfbea9881288a32c52181ad16201f2958946a /src/audio_core/audio_renderer.cpp | |
| parent | Merge pull request #4895 from Morph1984/cave-story-plus-applet-fix (diff) | |
| download | yuzu-9a4beac95a0f88ec312a28d06da8270aa58736e3.tar.gz yuzu-9a4beac95a0f88ec312a28d06da8270aa58736e3.tar.xz yuzu-9a4beac95a0f88ec312a28d06da8270aa58736e3.zip | |
audren: Make use of nodiscard, rework downmixing, release all buffers
Preliminary work for upmixing & general cleanup. Fixes basic issues in games such as Shovel Knight and slightly improves the LEGO games. Upmixing stitll needs to be implemented.
Audio levels in a few games will be fixed as we now use the downmix coefficients when possible instead of supplying our own
Diffstat (limited to 'src/audio_core/audio_renderer.cpp')
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 110 |
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 | ||
| 18 | namespace { | ||
| 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 | |||
| 17 | namespace AudioCore { | 71 | namespace AudioCore { |
| 18 | AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | 72 | AudioRenderer::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 | ||
| 65 | static constexpr s16 ClampToS16(s32 value) { | ||
| 66 | return static_cast<s16>(std::clamp(value, -32768, 32767)); | ||
| 67 | } | ||
| 68 | |||
| 69 | ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params, | 119 | ResultCode 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 | ||
| 261 | void AudioRenderer::ReleaseAndQueueBuffers() { | 321 | void 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 | } |