summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/audio_core/audio_renderer.cpp30
-rw-r--r--src/audio_core/command_generator.cpp86
-rw-r--r--src/audio_core/command_generator.h23
-rw-r--r--src/audio_core/sink_context.cpp15
-rw-r--r--src/audio_core/sink_context.h2
5 files changed, 81 insertions, 75 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index ccd5ca6cc..7dba739b4 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -29,10 +29,9 @@ namespace {
29 (static_cast<float>(r_channel) * r_mix_amount))); 29 (static_cast<float>(r_channel) * r_mix_amount)));
30} 30}
31 31
32[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel, 32[[maybe_unused, nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(
33 s16 fc_channel, 33 s16 fl_channel, s16 fr_channel, s16 fc_channel, [[maybe_unused]] s16 lf_channel, s16 bl_channel,
34 [[maybe_unused]] s16 lf_channel, 34 s16 br_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 35 // Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
37 // are mixed to be 36.94% 36 // are mixed to be 36.94%
38 37
@@ -57,11 +56,11 @@ namespace {
57 const std::array<float_le, 4>& coeff) { 56 const std::array<float_le, 4>& coeff) {
58 const auto left = 57 const auto left =
59 static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + 58 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]; 59 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[3];
61 60
62 const auto right = 61 const auto right =
63 static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] + 62 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]; 63 static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[3];
65 64
66 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))}; 65 return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
67} 66}
@@ -241,7 +240,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
241 const auto channel_count = buffer_offsets.size(); 240 const auto channel_count = buffer_offsets.size();
242 const auto& final_mix = mix_context.GetFinalMixInfo(); 241 const auto& final_mix = mix_context.GetFinalMixInfo();
243 const auto& in_params = final_mix.GetInParams(); 242 const auto& in_params = final_mix.GetInParams();
244 std::vector<s32*> mix_buffers(channel_count); 243 std::vector<std::span<s32>> mix_buffers(channel_count);
245 for (std::size_t i = 0; i < channel_count; i++) { 244 for (std::size_t i = 0; i < channel_count; i++) {
246 mix_buffers[i] = 245 mix_buffers[i] =
247 command_generator.GetMixBuffer(in_params.buffer_offset + buffer_offsets[i]); 246 command_generator.GetMixBuffer(in_params.buffer_offset + buffer_offsets[i]);
@@ -294,18 +293,11 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
294 buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample); 293 buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
295 } else if (stream_channel_count == 2) { 294 } else if (stream_channel_count == 2) {
296 // Mix all channels into 2 channels 295 // Mix all channels into 2 channels
297 if (sink_context.HasDownMixingCoefficients()) { 296 const auto [left, right] = Mix6To2WithCoefficients(
298 const auto [left, right] = Mix6To2WithCoefficients( 297 fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
299 fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample, 298 sink_context.GetDownmixCoefficients());
300 sink_context.GetDownmixCoefficients()); 299 buffer[i * stream_channel_count + 0] = left;
301 buffer[i * stream_channel_count + 0] = left; 300 buffer[i * stream_channel_count + 1] = right;
302 buffer[i * stream_channel_count + 1] = right;
303 } else {
304 const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
305 lf_sample, bl_sample, br_sample);
306 buffer[i * stream_channel_count + 0] = left;
307 buffer[i * stream_channel_count + 1] = right;
308 }
309 } else if (stream_channel_count == 6) { 301 } else if (stream_channel_count == 6) {
310 // Pass through 302 // Pass through
311 buffer[i * stream_channel_count + 0] = fl_sample; 303 buffer[i * stream_channel_count + 0] = fl_sample;
diff --git a/src/audio_core/command_generator.cpp b/src/audio_core/command_generator.cpp
index 27437f1ea..1402ff280 100644
--- a/src/audio_core/command_generator.cpp
+++ b/src/audio_core/command_generator.cpp
@@ -31,7 +31,7 @@ constexpr std::array<f32, AudioCommon::I3DL2REVERB_TAPS> EARLY_GAIN{
31 0.72867f, 0.69794f, 0.5464f, 0.24563f, 0.45214f, 0.44042f}; 31 0.72867f, 0.69794f, 0.5464f, 0.24563f, 0.45214f, 0.44042f};
32 32
33template <std::size_t N> 33template <std::size_t N>
34void ApplyMix(s32* output, const s32* input, s32 gain, s32 sample_count) { 34void ApplyMix(std::span<s32> output, std::span<const s32> input, s32 gain, s32 sample_count) {
35 for (std::size_t i = 0; i < static_cast<std::size_t>(sample_count); i += N) { 35 for (std::size_t i = 0; i < static_cast<std::size_t>(sample_count); i += N) {
36 for (std::size_t j = 0; j < N; j++) { 36 for (std::size_t j = 0; j < N; j++) {
37 output[i + j] += 37 output[i + j] +=
@@ -40,7 +40,8 @@ void ApplyMix(s32* output, const s32* input, s32 gain, s32 sample_count) {
40 } 40 }
41} 41}
42 42
43s32 ApplyMixRamp(s32* output, const s32* input, float gain, float delta, s32 sample_count) { 43s32 ApplyMixRamp(std::span<s32> output, std::span<const s32> input, float gain, float delta,
44 s32 sample_count) {
44 s32 x = 0; 45 s32 x = 0;
45 for (s32 i = 0; i < sample_count; i++) { 46 for (s32 i = 0; i < sample_count; i++) {
46 x = static_cast<s32>(static_cast<float>(input[i]) * gain); 47 x = static_cast<s32>(static_cast<float>(input[i]) * gain);
@@ -50,20 +51,22 @@ s32 ApplyMixRamp(s32* output, const s32* input, float gain, float delta, s32 sam
50 return x; 51 return x;
51} 52}
52 53
53void ApplyGain(s32* output, const s32* input, s32 gain, s32 delta, s32 sample_count) { 54void ApplyGain(std::span<s32> output, std::span<const s32> input, s32 gain, s32 delta,
55 s32 sample_count) {
54 for (s32 i = 0; i < sample_count; i++) { 56 for (s32 i = 0; i < sample_count; i++) {
55 output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15); 57 output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15);
56 gain += delta; 58 gain += delta;
57 } 59 }
58} 60}
59 61
60void ApplyGainWithoutDelta(s32* output, const s32* input, s32 gain, s32 sample_count) { 62void ApplyGainWithoutDelta(std::span<s32> output, std::span<const s32> input, s32 gain,
63 s32 sample_count) {
61 for (s32 i = 0; i < sample_count; i++) { 64 for (s32 i = 0; i < sample_count; i++) {
62 output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15); 65 output[i] = static_cast<s32>((static_cast<s64>(input[i]) * gain + 0x4000) >> 15);
63 } 66 }
64} 67}
65 68
66s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) { 69s32 ApplyMixDepop(std::span<s32> output, s32 first_sample, s32 delta, s32 sample_count) {
67 const bool positive = first_sample > 0; 70 const bool positive = first_sample > 0;
68 auto final_sample = std::abs(first_sample); 71 auto final_sample = std::abs(first_sample);
69 for (s32 i = 0; i < sample_count; i++) { 72 for (s32 i = 0; i < sample_count; i++) {
@@ -128,10 +131,10 @@ constexpr std::array<std::size_t, 20> REVERB_TAP_INDEX_6CH{4, 0, 0, 1, 1, 1, 1,
128 1, 1, 1, 0, 0, 0, 0, 3, 3, 3}; 131 1, 1, 1, 0, 0, 0, 0, 3, 3, 3};
129 132
130template <std::size_t CHANNEL_COUNT> 133template <std::size_t CHANNEL_COUNT>
131void ApplyReverbGeneric(I3dl2ReverbState& state, 134void ApplyReverbGeneric(
132 const std::array<const s32*, AudioCommon::MAX_CHANNEL_COUNT>& input, 135 I3dl2ReverbState& state,
133 const std::array<s32*, AudioCommon::MAX_CHANNEL_COUNT>& output, 136 const std::array<std::span<const s32>, AudioCommon::MAX_CHANNEL_COUNT>& input,
134 s32 sample_count) { 137 const std::array<std::span<s32>, AudioCommon::MAX_CHANNEL_COUNT>& output, s32 sample_count) {
135 138
136 auto GetTapLookup = []() { 139 auto GetTapLookup = []() {
137 if constexpr (CHANNEL_COUNT == 1) { 140 if constexpr (CHANNEL_COUNT == 1) {
@@ -454,8 +457,8 @@ void CommandGenerator::GenerateBiquadFilterCommand([[maybe_unused]] s32 mix_buff
454 "input_mix_buffer={}, output_mix_buffer={}", 457 "input_mix_buffer={}, output_mix_buffer={}",
455 node_id, input_offset, output_offset); 458 node_id, input_offset, output_offset);
456 } 459 }
457 const auto* input = GetMixBuffer(input_offset); 460 std::span<const s32> input = GetMixBuffer(input_offset);
458 auto* output = GetMixBuffer(output_offset); 461 std::span<s32> output = GetMixBuffer(output_offset);
459 462
460 // Biquad filter parameters 463 // Biquad filter parameters
461 const auto [n0, n1, n2] = params.numerator; 464 const auto [n0, n1, n2] = params.numerator;
@@ -548,8 +551,8 @@ void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, E
548 return; 551 return;
549 } 552 }
550 553
551 std::array<const s32*, AudioCommon::MAX_CHANNEL_COUNT> input{}; 554 std::array<std::span<const s32>, AudioCommon::MAX_CHANNEL_COUNT> input{};
552 std::array<s32*, AudioCommon::MAX_CHANNEL_COUNT> output{}; 555 std::array<std::span<s32>, AudioCommon::MAX_CHANNEL_COUNT> output{};
553 556
554 const auto status = params.status; 557 const auto status = params.status;
555 for (s32 i = 0; i < channel_count; i++) { 558 for (s32 i = 0; i < channel_count; i++) {
@@ -584,7 +587,8 @@ void CommandGenerator::GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, E
584 for (s32 i = 0; i < channel_count; i++) { 587 for (s32 i = 0; i < channel_count; i++) {
585 // Only copy if the buffer input and output do not match! 588 // Only copy if the buffer input and output do not match!
586 if ((mix_buffer_offset + params.input[i]) != (mix_buffer_offset + params.output[i])) { 589 if ((mix_buffer_offset + params.input[i]) != (mix_buffer_offset + params.output[i])) {
587 std::memcpy(output[i], input[i], worker_params.sample_count * sizeof(s32)); 590 std::memcpy(output[i].data(), input[i].data(),
591 worker_params.sample_count * sizeof(s32));
588 } 592 }
589 } 593 }
590 } 594 }
@@ -600,8 +604,8 @@ void CommandGenerator::GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset,
600 for (s32 i = 0; i < channel_count; i++) { 604 for (s32 i = 0; i < channel_count; i++) {
601 // TODO(ogniK): Actually implement biquad filter 605 // TODO(ogniK): Actually implement biquad filter
602 if (params.input[i] != params.output[i]) { 606 if (params.input[i] != params.output[i]) {
603 const auto* input = GetMixBuffer(mix_buffer_offset + params.input[i]); 607 std::span<const s32> input = GetMixBuffer(mix_buffer_offset + params.input[i]);
604 auto* output = GetMixBuffer(mix_buffer_offset + params.output[i]); 608 std::span<s32> output = GetMixBuffer(mix_buffer_offset + params.output[i]);
605 ApplyMix<1>(output, input, 32768, worker_params.sample_count); 609 ApplyMix<1>(output, input, 32768, worker_params.sample_count);
606 } 610 }
607 } 611 }
@@ -640,14 +644,15 @@ void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* inf
640 644
641 if (samples_read != static_cast<int>(worker_params.sample_count) && 645 if (samples_read != static_cast<int>(worker_params.sample_count) &&
642 samples_read <= params.sample_count) { 646 samples_read <= params.sample_count) {
643 std::memset(GetMixBuffer(output_index), 0, params.sample_count - samples_read); 647 std::memset(GetMixBuffer(output_index).data(), 0,
648 params.sample_count - samples_read);
644 } 649 }
645 } else { 650 } else {
646 AuxInfoDSP empty{}; 651 AuxInfoDSP empty{};
647 memory.WriteBlock(aux->GetSendInfo(), &empty, sizeof(AuxInfoDSP)); 652 memory.WriteBlock(aux->GetSendInfo(), &empty, sizeof(AuxInfoDSP));
648 memory.WriteBlock(aux->GetRecvInfo(), &empty, sizeof(AuxInfoDSP)); 653 memory.WriteBlock(aux->GetRecvInfo(), &empty, sizeof(AuxInfoDSP));
649 if (output_index != input_index) { 654 if (output_index != input_index) {
650 std::memcpy(GetMixBuffer(output_index), GetMixBuffer(input_index), 655 std::memcpy(GetMixBuffer(output_index).data(), GetMixBuffer(input_index).data(),
651 worker_params.sample_count * sizeof(s32)); 656 worker_params.sample_count * sizeof(s32));
652 } 657 }
653 } 658 }
@@ -665,7 +670,7 @@ ServerSplitterDestinationData* CommandGenerator::GetDestinationData(s32 splitter
665} 670}
666 671
667s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, 672s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples,
668 const s32* data, u32 sample_count, u32 write_offset, 673 std::span<const s32> data, u32 sample_count, u32 write_offset,
669 u32 write_count) { 674 u32 write_count) {
670 if (max_samples == 0) { 675 if (max_samples == 0) {
671 return 0; 676 return 0;
@@ -675,14 +680,14 @@ s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u3
675 return 0; 680 return 0;
676 } 681 }
677 682
678 std::size_t data_offset{}; 683 s32 data_offset{};
679 u32 remaining = sample_count; 684 u32 remaining = sample_count;
680 while (remaining > 0) { 685 while (remaining > 0) {
681 // Get position in buffer 686 // Get position in buffer
682 const auto base = send_buffer + (offset * sizeof(u32)); 687 const auto base = send_buffer + (offset * sizeof(u32));
683 const auto samples_to_grab = std::min(max_samples - offset, remaining); 688 const auto samples_to_grab = std::min(max_samples - offset, remaining);
684 // Write to output 689 // Write to output
685 memory.WriteBlock(base, (data + data_offset), samples_to_grab * sizeof(u32)); 690 memory.WriteBlock(base, (data.data() + data_offset), samples_to_grab * sizeof(u32));
686 offset = (offset + samples_to_grab) % max_samples; 691 offset = (offset + samples_to_grab) % max_samples;
687 remaining -= samples_to_grab; 692 remaining -= samples_to_grab;
688 data_offset += samples_to_grab; 693 data_offset += samples_to_grab;
@@ -695,7 +700,7 @@ s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u3
695} 700}
696 701
697s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, 702s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples,
698 s32* out_data, u32 sample_count, u32 read_offset, 703 std::span<s32> out_data, u32 sample_count, u32 read_offset,
699 u32 read_count) { 704 u32 read_count) {
700 if (max_samples == 0) { 705 if (max_samples == 0) {
701 return 0; 706 return 0;
@@ -707,15 +712,16 @@ s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u3
707 } 712 }
708 713
709 u32 remaining = sample_count; 714 u32 remaining = sample_count;
715 s32 data_offset{};
710 while (remaining > 0) { 716 while (remaining > 0) {
711 const auto base = recv_buffer + (offset * sizeof(u32)); 717 const auto base = recv_buffer + (offset * sizeof(u32));
712 const auto samples_to_grab = std::min(max_samples - offset, remaining); 718 const auto samples_to_grab = std::min(max_samples - offset, remaining);
713 std::vector<s32> buffer(samples_to_grab); 719 std::vector<s32> buffer(samples_to_grab);
714 memory.ReadBlock(base, buffer.data(), buffer.size() * sizeof(u32)); 720 memory.ReadBlock(base, buffer.data(), buffer.size() * sizeof(u32));
715 std::memcpy(out_data, buffer.data(), buffer.size() * sizeof(u32)); 721 std::memcpy(out_data.data() + data_offset, buffer.data(), buffer.size() * sizeof(u32));
716 out_data += samples_to_grab;
717 offset = (offset + samples_to_grab) % max_samples; 722 offset = (offset + samples_to_grab) % max_samples;
718 remaining -= samples_to_grab; 723 remaining -= samples_to_grab;
724 data_offset += samples_to_grab;
719 } 725 }
720 726
721 if (read_count != 0) { 727 if (read_count != 0) {
@@ -962,8 +968,8 @@ void CommandGenerator::GenerateMixCommand(std::size_t output_offset, std::size_t
962 node_id, input_offset, output_offset, volume); 968 node_id, input_offset, output_offset, volume);
963 } 969 }
964 970
965 auto* output = GetMixBuffer(output_offset); 971 std::span<s32> output = GetMixBuffer(output_offset);
966 const auto* input = GetMixBuffer(input_offset); 972 std::span<const s32> input = GetMixBuffer(input_offset);
967 973
968 const s32 gain = static_cast<s32>(volume * 32768.0f); 974 const s32 gain = static_cast<s32>(volume * 32768.0f);
969 // Mix with loop unrolling 975 // Mix with loop unrolling
@@ -1155,12 +1161,14 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
1155 return samples_processed; 1161 return samples_processed;
1156} 1162}
1157 1163
1158s32* CommandGenerator::GetMixBuffer(std::size_t index) { 1164std::span<s32> CommandGenerator::GetMixBuffer(std::size_t index) {
1159 return mix_buffer.data() + (index * worker_params.sample_count); 1165 return std::span<s32>(mix_buffer.data() + (index * worker_params.sample_count),
1166 worker_params.sample_count);
1160} 1167}
1161 1168
1162const s32* CommandGenerator::GetMixBuffer(std::size_t index) const { 1169std::span<const s32> CommandGenerator::GetMixBuffer(std::size_t index) const {
1163 return mix_buffer.data() + (index * worker_params.sample_count); 1170 return std::span<const s32>(mix_buffer.data() + (index * worker_params.sample_count),
1171 worker_params.sample_count);
1164} 1172}
1165 1173
1166std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const { 1174std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const {
@@ -1171,15 +1179,15 @@ std::size_t CommandGenerator::GetTotalMixBufferCount() const {
1171 return worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT; 1179 return worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT;
1172} 1180}
1173 1181
1174s32* CommandGenerator::GetChannelMixBuffer(s32 channel) { 1182std::span<s32> CommandGenerator::GetChannelMixBuffer(s32 channel) {
1175 return GetMixBuffer(worker_params.mix_buffer_count + channel); 1183 return GetMixBuffer(worker_params.mix_buffer_count + channel);
1176} 1184}
1177 1185
1178const s32* CommandGenerator::GetChannelMixBuffer(s32 channel) const { 1186std::span<const s32> CommandGenerator::GetChannelMixBuffer(s32 channel) const {
1179 return GetMixBuffer(worker_params.mix_buffer_count + channel); 1187 return GetMixBuffer(worker_params.mix_buffer_count + channel);
1180} 1188}
1181 1189
1182void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, 1190void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::span<s32> output,
1183 VoiceState& dsp_state, s32 channel, 1191 VoiceState& dsp_state, s32 channel,
1184 s32 target_sample_rate, s32 sample_count, 1192 s32 target_sample_rate, s32 sample_count,
1185 s32 node_id) { 1193 s32 node_id) {
@@ -1191,7 +1199,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1191 node_id, channel, in_params.sample_format, sample_count, in_params.sample_rate, 1199 node_id, channel, in_params.sample_format, sample_count, in_params.sample_rate,
1192 in_params.mix_id, in_params.splitter_info_id); 1200 in_params.mix_id, in_params.splitter_info_id);
1193 } 1201 }
1194 ASSERT_OR_EXECUTE(output != nullptr, { return; }); 1202 ASSERT_OR_EXECUTE(output.data() != nullptr, { return; });
1195 1203
1196 const auto resample_rate = static_cast<s32>( 1204 const auto resample_rate = static_cast<s32>(
1197 static_cast<float>(in_params.sample_rate) / static_cast<float>(target_sample_rate) * 1205 static_cast<float>(in_params.sample_rate) / static_cast<float>(target_sample_rate) *
@@ -1208,6 +1216,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1208 } 1216 }
1209 1217
1210 std::size_t temp_mix_offset{}; 1218 std::size_t temp_mix_offset{};
1219 s32 samples_output{};
1211 auto samples_remaining = sample_count; 1220 auto samples_remaining = sample_count;
1212 while (samples_remaining > 0) { 1221 while (samples_remaining > 0) {
1213 const auto samples_to_output = std::min(samples_remaining, min_required_samples); 1222 const auto samples_to_output = std::min(samples_remaining, min_required_samples);
@@ -1296,20 +1305,21 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
1296 1305
1297 if (in_params.behavior_flags.is_pitch_and_src_skipped.Value()) { 1306 if (in_params.behavior_flags.is_pitch_and_src_skipped.Value()) {
1298 // No need to resample 1307 // No need to resample
1299 std::memcpy(output, sample_buffer.data(), samples_read * sizeof(s32)); 1308 std::memcpy(output.data() + samples_output, sample_buffer.data(),
1309 samples_read * sizeof(s32));
1300 } else { 1310 } else {
1301 std::fill(sample_buffer.begin() + temp_mix_offset, 1311 std::fill(sample_buffer.begin() + temp_mix_offset,
1302 sample_buffer.begin() + temp_mix_offset + (samples_to_read - samples_read), 1312 sample_buffer.begin() + temp_mix_offset + (samples_to_read - samples_read),
1303 0); 1313 0);
1304 AudioCore::Resample(output, sample_buffer.data(), resample_rate, dsp_state.fraction, 1314 AudioCore::Resample(output.data() + samples_output, sample_buffer.data(), resample_rate,
1305 samples_to_output); 1315 dsp_state.fraction, samples_to_output);
1306 // Resample 1316 // Resample
1307 for (std::size_t i = 0; i < AudioCommon::MAX_SAMPLE_HISTORY; i++) { 1317 for (std::size_t i = 0; i < AudioCommon::MAX_SAMPLE_HISTORY; i++) {
1308 dsp_state.sample_history[i] = sample_buffer[samples_to_read + i]; 1318 dsp_state.sample_history[i] = sample_buffer[samples_to_read + i];
1309 } 1319 }
1310 } 1320 }
1311 output += samples_to_output;
1312 samples_remaining -= samples_to_output; 1321 samples_remaining -= samples_to_output;
1322 samples_output += samples_to_output;
1313 } 1323 }
1314} 1324}
1315 1325
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h
index 673e4fbef..ac034b0a5 100644
--- a/src/audio_core/command_generator.h
+++ b/src/audio_core/command_generator.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <span>
8#include "audio_core/common.h" 9#include "audio_core/common.h"
9#include "audio_core/voice_context.h" 10#include "audio_core/voice_context.h"
10#include "common/common_types.h" 11#include "common/common_types.h"
@@ -41,10 +42,10 @@ public:
41 void PreCommand(); 42 void PreCommand();
42 void PostCommand(); 43 void PostCommand();
43 44
44 [[nodiscard]] s32* GetChannelMixBuffer(s32 channel); 45 [[nodiscard]] std::span<s32> GetChannelMixBuffer(s32 channel);
45 [[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const; 46 [[nodiscard]] std::span<const s32> GetChannelMixBuffer(s32 channel) const;
46 [[nodiscard]] s32* GetMixBuffer(std::size_t index); 47 [[nodiscard]] std::span<s32> GetMixBuffer(std::size_t index);
47 [[nodiscard]] const s32* GetMixBuffer(std::size_t index) const; 48 [[nodiscard]] std::span<const s32> GetMixBuffer(std::size_t index) const;
48 [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const; 49 [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const;
49 50
50 [[nodiscard]] std::size_t GetTotalMixBufferCount() const; 51 [[nodiscard]] std::size_t GetTotalMixBufferCount() const;
@@ -77,10 +78,11 @@ private:
77 void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); 78 void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
78 [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); 79 [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
79 80
80 s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, 81 s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples,
81 u32 sample_count, u32 write_offset, u32 write_count); 82 std::span<const s32> data, u32 sample_count, u32 write_offset,
82 s32 ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, s32* out_data, 83 u32 write_count);
83 u32 sample_count, u32 read_offset, u32 read_count); 84 s32 ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples,
85 std::span<s32> out_data, u32 sample_count, u32 read_offset, u32 read_count);
84 86
85 void InitializeI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state, 87 void InitializeI3dl2Reverb(I3dl2ReverbParams& info, I3dl2ReverbState& state,
86 std::vector<u8>& work_buffer); 88 std::vector<u8>& work_buffer);
@@ -90,8 +92,9 @@ private:
90 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); 92 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
91 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset, 93 s32 DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 sample_start_offset,
92 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset); 94 s32 sample_end_offset, s32 sample_count, s32 channel, std::size_t mix_offset);
93 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, VoiceState& dsp_state, 95 void DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, std::span<s32> output,
94 s32 channel, s32 target_sample_rate, s32 sample_count, s32 node_id); 96 VoiceState& dsp_state, s32 channel, s32 target_sample_rate,
97 s32 sample_count, s32 node_id);
95 98
96 AudioCommon::AudioRendererParameter& worker_params; 99 AudioCommon::AudioRendererParameter& worker_params;
97 VoiceContext& voice_context; 100 VoiceContext& voice_context;
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp
index a69543696..cc55b290c 100644
--- a/src/audio_core/sink_context.cpp
+++ b/src/audio_core/sink_context.cpp
@@ -15,10 +15,17 @@ std::size_t SinkContext::GetCount() const {
15void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) { 15void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) {
16 ASSERT(in.type == SinkTypes::Device); 16 ASSERT(in.type == SinkTypes::Device);
17 17
18 has_downmix_coefs = in.device.down_matrix_enabled; 18 if (in.device.down_matrix_enabled) {
19 if (has_downmix_coefs) {
20 downmix_coefficients = in.device.down_matrix_coef; 19 downmix_coefficients = in.device.down_matrix_coef;
20 } else {
21 downmix_coefficients = {
22 1.0f, // front
23 0.707f, // center
24 0.0f, // lfe
25 0.707f, // back
26 };
21 } 27 }
28
22 in_use = in.in_use; 29 in_use = in.in_use;
23 use_count = in.device.input_count; 30 use_count = in.device.input_count;
24 buffers = in.device.input; 31 buffers = in.device.input;
@@ -34,10 +41,6 @@ std::vector<u8> SinkContext::OutputBuffers() const {
34 return buffer_ret; 41 return buffer_ret;
35} 42}
36 43
37bool SinkContext::HasDownMixingCoefficients() const {
38 return has_downmix_coefs;
39}
40
41const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const { 44const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const {
42 return downmix_coefficients; 45 return downmix_coefficients;
43} 46}
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h
index 9e2b69785..254961fe2 100644
--- a/src/audio_core/sink_context.h
+++ b/src/audio_core/sink_context.h
@@ -84,7 +84,6 @@ public:
84 [[nodiscard]] bool InUse() const; 84 [[nodiscard]] bool InUse() const;
85 [[nodiscard]] std::vector<u8> OutputBuffers() const; 85 [[nodiscard]] std::vector<u8> OutputBuffers() const;
86 86
87 [[nodiscard]] bool HasDownMixingCoefficients() const;
88 [[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const; 87 [[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const;
89 88
90private: 89private:
@@ -92,7 +91,6 @@ private:
92 s32 use_count{}; 91 s32 use_count{};
93 std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; 92 std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{};
94 std::size_t sink_count{}; 93 std::size_t sink_count{};
95 bool has_downmix_coefs{false};
96 DownmixCoefficients downmix_coefficients{}; 94 DownmixCoefficients downmix_coefficients{};
97}; 95};
98} // namespace AudioCore 96} // namespace AudioCore