diff options
Diffstat (limited to '')
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 30 | ||||
| -rw-r--r-- | src/audio_core/command_generator.cpp | 86 | ||||
| -rw-r--r-- | src/audio_core/command_generator.h | 23 | ||||
| -rw-r--r-- | src/audio_core/sink_context.cpp | 15 | ||||
| -rw-r--r-- | src/audio_core/sink_context.h | 2 |
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 | ||
| 33 | template <std::size_t N> | 33 | template <std::size_t N> |
| 34 | void ApplyMix(s32* output, const s32* input, s32 gain, s32 sample_count) { | 34 | void 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 | ||
| 43 | s32 ApplyMixRamp(s32* output, const s32* input, float gain, float delta, s32 sample_count) { | 43 | s32 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 | ||
| 53 | void ApplyGain(s32* output, const s32* input, s32 gain, s32 delta, s32 sample_count) { | 54 | void 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 | ||
| 60 | void ApplyGainWithoutDelta(s32* output, const s32* input, s32 gain, s32 sample_count) { | 62 | void 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 | ||
| 66 | s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) { | 69 | s32 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 | ||
| 130 | template <std::size_t CHANNEL_COUNT> | 133 | template <std::size_t CHANNEL_COUNT> |
| 131 | void ApplyReverbGeneric(I3dl2ReverbState& state, | 134 | void 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 | ||
| 667 | s32 CommandGenerator::WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, | 672 | s32 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 | ||
| 697 | s32 CommandGenerator::ReadAuxBuffer(AuxInfoDSP& recv_info, VAddr recv_buffer, u32 max_samples, | 702 | s32 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 | ||
| 1158 | s32* CommandGenerator::GetMixBuffer(std::size_t index) { | 1164 | std::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 | ||
| 1162 | const s32* CommandGenerator::GetMixBuffer(std::size_t index) const { | 1169 | std::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 | ||
| 1166 | std::size_t CommandGenerator::GetMixChannelBufferOffset(s32 channel) const { | 1174 | std::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 | ||
| 1174 | s32* CommandGenerator::GetChannelMixBuffer(s32 channel) { | 1182 | std::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 | ||
| 1178 | const s32* CommandGenerator::GetChannelMixBuffer(s32 channel) const { | 1186 | std::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 | ||
| 1182 | void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* output, | 1190 | void 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 { | |||
| 15 | void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) { | 15 | void 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 | ||
| 37 | bool SinkContext::HasDownMixingCoefficients() const { | ||
| 38 | return has_downmix_coefs; | ||
| 39 | } | ||
| 40 | |||
| 41 | const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const { | 44 | const 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 | ||
| 90 | private: | 89 | private: |
| @@ -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 |