diff options
Diffstat (limited to 'src/audio_core/hle/mixers.cpp')
| -rw-r--r-- | src/audio_core/hle/mixers.cpp | 65 |
1 files changed, 38 insertions, 27 deletions
diff --git a/src/audio_core/hle/mixers.cpp b/src/audio_core/hle/mixers.cpp index 18335f7f0..a661a7b27 100644 --- a/src/audio_core/hle/mixers.cpp +++ b/src/audio_core/hle/mixers.cpp | |||
| @@ -20,11 +20,9 @@ void Mixers::Reset() { | |||
| 20 | state = {}; | 20 | state = {}; |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | DspStatus Mixers::Tick(DspConfiguration& config, | 23 | DspStatus Mixers::Tick(DspConfiguration& config, const IntermediateMixSamples& read_samples, |
| 24 | const IntermediateMixSamples& read_samples, | 24 | IntermediateMixSamples& write_samples, |
| 25 | IntermediateMixSamples& write_samples, | 25 | const std::array<QuadFrame32, 3>& input) { |
| 26 | const std::array<QuadFrame32, 3>& input) | ||
| 27 | { | ||
| 28 | ParseConfig(config); | 26 | ParseConfig(config); |
| 29 | 27 | ||
| 30 | AuxReturn(read_samples); | 28 | AuxReturn(read_samples); |
| @@ -73,13 +71,15 @@ void Mixers::ParseConfig(DspConfiguration& config) { | |||
| 73 | if (config.output_format_dirty) { | 71 | if (config.output_format_dirty) { |
| 74 | config.output_format_dirty.Assign(0); | 72 | config.output_format_dirty.Assign(0); |
| 75 | state.output_format = config.output_format; | 73 | state.output_format = config.output_format; |
| 76 | LOG_TRACE(Audio_DSP, "mixers output_format = %zu", static_cast<size_t>(config.output_format)); | 74 | LOG_TRACE(Audio_DSP, "mixers output_format = %zu", |
| 75 | static_cast<size_t>(config.output_format)); | ||
| 77 | } | 76 | } |
| 78 | 77 | ||
| 79 | if (config.headphones_connected_dirty) { | 78 | if (config.headphones_connected_dirty) { |
| 80 | config.headphones_connected_dirty.Assign(0); | 79 | config.headphones_connected_dirty.Assign(0); |
| 81 | // Do nothing. | 80 | // Do nothing. |
| 82 | // (Note: Whether headphones are connected does affect coefficients used for surround sound.) | 81 | // (Note: Whether headphones are connected does affect coefficients used for surround |
| 82 | // sound.) | ||
| 83 | LOG_TRACE(Audio_DSP, "mixers headphones_connected=%hu", config.headphones_connected); | 83 | LOG_TRACE(Audio_DSP, "mixers headphones_connected=%hu", config.headphones_connected); |
| 84 | } | 84 | } |
| 85 | 85 | ||
| @@ -94,11 +94,10 @@ static s16 ClampToS16(s32 value) { | |||
| 94 | return static_cast<s16>(MathUtil::Clamp(value, -32768, 32767)); | 94 | return static_cast<s16>(MathUtil::Clamp(value, -32768, 32767)); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| 97 | static std::array<s16, 2> AddAndClampToS16(const std::array<s16, 2>& a, const std::array<s16, 2>& b) { | 97 | static std::array<s16, 2> AddAndClampToS16(const std::array<s16, 2>& a, |
| 98 | return { | 98 | const std::array<s16, 2>& b) { |
| 99 | ClampToS16(static_cast<s32>(a[0]) + static_cast<s32>(b[0])), | 99 | return {ClampToS16(static_cast<s32>(a[0]) + static_cast<s32>(b[0])), |
| 100 | ClampToS16(static_cast<s32>(a[1]) + static_cast<s32>(b[1])) | 100 | ClampToS16(static_cast<s32>(a[1]) + static_cast<s32>(b[1]))}; |
| 101 | }; | ||
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples) { | 103 | void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& samples) { |
| @@ -106,27 +105,33 @@ void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& sample | |||
| 106 | 105 | ||
| 107 | switch (state.output_format) { | 106 | switch (state.output_format) { |
| 108 | case OutputFormat::Mono: | 107 | case OutputFormat::Mono: |
| 109 | std::transform(current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | 108 | std::transform( |
| 110 | [gain](const std::array<s16, 2>& accumulator, const std::array<s32, 4>& sample) -> std::array<s16, 2> { | 109 | current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), |
| 110 | [gain](const std::array<s16, 2>& accumulator, | ||
| 111 | const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||
| 111 | // Downmix to mono | 112 | // Downmix to mono |
| 112 | s16 mono = ClampToS16(static_cast<s32>((gain * sample[0] + gain * sample[1] + gain * sample[2] + gain * sample[3]) / 2)); | 113 | s16 mono = ClampToS16(static_cast<s32>( |
| 114 | (gain * sample[0] + gain * sample[1] + gain * sample[2] + gain * sample[3]) / | ||
| 115 | 2)); | ||
| 113 | // Mix into current frame | 116 | // Mix into current frame |
| 114 | return AddAndClampToS16(accumulator, { mono, mono }); | 117 | return AddAndClampToS16(accumulator, {mono, mono}); |
| 115 | }); | 118 | }); |
| 116 | return; | 119 | return; |
| 117 | 120 | ||
| 118 | case OutputFormat::Surround: | 121 | case OutputFormat::Surround: |
| 119 | // TODO(merry): Implement surround sound. | 122 | // TODO(merry): Implement surround sound. |
| 120 | // fallthrough | 123 | // fallthrough |
| 121 | 124 | ||
| 122 | case OutputFormat::Stereo: | 125 | case OutputFormat::Stereo: |
| 123 | std::transform(current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), | 126 | std::transform( |
| 124 | [gain](const std::array<s16, 2>& accumulator, const std::array<s32, 4>& sample) -> std::array<s16, 2> { | 127 | current_frame.begin(), current_frame.end(), samples.begin(), current_frame.begin(), |
| 128 | [gain](const std::array<s16, 2>& accumulator, | ||
| 129 | const std::array<s32, 4>& sample) -> std::array<s16, 2> { | ||
| 125 | // Downmix to stereo | 130 | // Downmix to stereo |
| 126 | s16 left = ClampToS16(static_cast<s32>(gain * sample[0] + gain * sample[2])); | 131 | s16 left = ClampToS16(static_cast<s32>(gain * sample[0] + gain * sample[2])); |
| 127 | s16 right = ClampToS16(static_cast<s32>(gain * sample[1] + gain * sample[3])); | 132 | s16 right = ClampToS16(static_cast<s32>(gain * sample[1] + gain * sample[3])); |
| 128 | // Mix into current frame | 133 | // Mix into current frame |
| 129 | return AddAndClampToS16(accumulator, { left, right }); | 134 | return AddAndClampToS16(accumulator, {left, right}); |
| 130 | }); | 135 | }); |
| 131 | return; | 136 | return; |
| 132 | } | 137 | } |
| @@ -135,12 +140,14 @@ void Mixers::DownmixAndMixIntoCurrentFrame(float gain, const QuadFrame32& sample | |||
| 135 | } | 140 | } |
| 136 | 141 | ||
| 137 | void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) { | 142 | void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) { |
| 138 | // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to QuadFrame32. | 143 | // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to |
| 144 | // QuadFrame32. | ||
| 139 | 145 | ||
| 140 | if (state.mixer1_enabled) { | 146 | if (state.mixer1_enabled) { |
| 141 | for (size_t sample = 0; sample < samples_per_frame; sample++) { | 147 | for (size_t sample = 0; sample < samples_per_frame; sample++) { |
| 142 | for (size_t channel = 0; channel < 4; channel++) { | 148 | for (size_t channel = 0; channel < 4; channel++) { |
| 143 | state.intermediate_mix_buffer[1][sample][channel] = read_samples.mix1.pcm32[channel][sample]; | 149 | state.intermediate_mix_buffer[1][sample][channel] = |
| 150 | read_samples.mix1.pcm32[channel][sample]; | ||
| 144 | } | 151 | } |
| 145 | } | 152 | } |
| 146 | } | 153 | } |
| @@ -148,14 +155,17 @@ void Mixers::AuxReturn(const IntermediateMixSamples& read_samples) { | |||
| 148 | if (state.mixer2_enabled) { | 155 | if (state.mixer2_enabled) { |
| 149 | for (size_t sample = 0; sample < samples_per_frame; sample++) { | 156 | for (size_t sample = 0; sample < samples_per_frame; sample++) { |
| 150 | for (size_t channel = 0; channel < 4; channel++) { | 157 | for (size_t channel = 0; channel < 4; channel++) { |
| 151 | state.intermediate_mix_buffer[2][sample][channel] = read_samples.mix2.pcm32[channel][sample]; | 158 | state.intermediate_mix_buffer[2][sample][channel] = |
| 159 | read_samples.mix2.pcm32[channel][sample]; | ||
| 152 | } | 160 | } |
| 153 | } | 161 | } |
| 154 | } | 162 | } |
| 155 | } | 163 | } |
| 156 | 164 | ||
| 157 | void Mixers::AuxSend(IntermediateMixSamples& write_samples, const std::array<QuadFrame32, 3>& input) { | 165 | void Mixers::AuxSend(IntermediateMixSamples& write_samples, |
| 158 | // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to QuadFrame32. | 166 | const std::array<QuadFrame32, 3>& input) { |
| 167 | // NOTE: read_samples.mix{1,2}.pcm32 annoyingly have their dimensions in reverse order to | ||
| 168 | // QuadFrame32. | ||
| 159 | 169 | ||
| 160 | state.intermediate_mix_buffer[0] = input[0]; | 170 | state.intermediate_mix_buffer[0] = input[0]; |
| 161 | 171 | ||
| @@ -184,7 +194,8 @@ void Mixers::MixCurrentFrame() { | |||
| 184 | current_frame.fill({}); | 194 | current_frame.fill({}); |
| 185 | 195 | ||
| 186 | for (size_t mix = 0; mix < 3; mix++) { | 196 | for (size_t mix = 0; mix < 3; mix++) { |
| 187 | DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix], state.intermediate_mix_buffer[mix]); | 197 | DownmixAndMixIntoCurrentFrame(state.intermediate_mixer_volume[mix], |
| 198 | state.intermediate_mix_buffer[mix]); | ||
| 188 | } | 199 | } |
| 189 | 200 | ||
| 190 | // TODO(merry): Compressor. (We currently assume a disabled compressor.) | 201 | // TODO(merry): Compressor. (We currently assume a disabled compressor.) |