diff options
| -rw-r--r-- | src/audio_core/audio_out.cpp | 4 | ||||
| -rw-r--r-- | src/audio_core/audio_out.h | 3 | ||||
| -rw-r--r-- | src/audio_core/audio_renderer.cpp | 110 | ||||
| -rw-r--r-- | src/audio_core/audio_renderer.h | 20 | ||||
| -rw-r--r-- | src/audio_core/behavior_info.h | 30 | ||||
| -rw-r--r-- | src/audio_core/command_generator.h | 14 | ||||
| -rw-r--r-- | src/audio_core/common.h | 2 | ||||
| -rw-r--r-- | src/audio_core/effect_context.h | 26 | ||||
| -rw-r--r-- | src/audio_core/mix_context.h | 26 | ||||
| -rw-r--r-- | src/audio_core/sink_context.cpp | 18 | ||||
| -rw-r--r-- | src/audio_core/sink_context.h | 13 | ||||
| -rw-r--r-- | src/audio_core/stream.cpp | 9 | ||||
| -rw-r--r-- | src/audio_core/stream.h | 21 |
13 files changed, 194 insertions, 102 deletions
diff --git a/src/audio_core/audio_out.cpp b/src/audio_core/audio_out.cpp index 8619a3f03..fe3a898ad 100644 --- a/src/audio_core/audio_out.cpp +++ b/src/audio_core/audio_out.cpp | |||
| @@ -43,6 +43,10 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream, | |||
| 43 | return stream->GetTagsAndReleaseBuffers(max_count); | 43 | return stream->GetTagsAndReleaseBuffers(max_count); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) { | ||
| 47 | return stream->GetTagsAndReleaseBuffers(); | ||
| 48 | } | ||
| 49 | |||
| 46 | void AudioOut::StartStream(StreamPtr stream) { | 50 | void AudioOut::StartStream(StreamPtr stream) { |
| 47 | stream->Play(); | 51 | stream->Play(); |
| 48 | } | 52 | } |
diff --git a/src/audio_core/audio_out.h b/src/audio_core/audio_out.h index b07588287..6ce08cd0d 100644 --- a/src/audio_core/audio_out.h +++ b/src/audio_core/audio_out.h | |||
| @@ -31,6 +31,9 @@ public: | |||
| 31 | /// Returns a vector of recently released buffers specified by tag for the specified stream | 31 | /// Returns a vector of recently released buffers specified by tag for the specified stream |
| 32 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); | 32 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count); |
| 33 | 33 | ||
| 34 | /// Returns a vector of all recently released buffers specified by tag for the specified stream | ||
| 35 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream); | ||
| 36 | |||
| 34 | /// Starts an audio stream for playback | 37 | /// Starts an audio stream for playback |
| 35 | void StartStream(StreamPtr stream); | 38 | void StartStream(StreamPtr stream); |
| 36 | 39 | ||
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 | } |
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h index 2fd93e058..a85219045 100644 --- a/src/audio_core/audio_renderer.h +++ b/src/audio_core/audio_renderer.h | |||
| @@ -36,16 +36,10 @@ class Memory; | |||
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | namespace AudioCore { | 38 | namespace AudioCore { |
| 39 | using DSPStateHolder = std::array<VoiceState*, 6>; | 39 | using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>; |
| 40 | 40 | ||
| 41 | class AudioOut; | 41 | class AudioOut; |
| 42 | 42 | ||
| 43 | struct RendererInfo { | ||
| 44 | u64_le elasped_frame_count{}; | ||
| 45 | INSERT_PADDING_WORDS(2); | ||
| 46 | }; | ||
| 47 | static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size"); | ||
| 48 | |||
| 49 | class AudioRenderer { | 43 | class AudioRenderer { |
| 50 | public: | 44 | public: |
| 51 | AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, | 45 | AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_, |
| @@ -53,14 +47,14 @@ public: | |||
| 53 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); | 47 | std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number); |
| 54 | ~AudioRenderer(); | 48 | ~AudioRenderer(); |
| 55 | 49 | ||
| 56 | ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, | 50 | [[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params, |
| 57 | std::vector<u8>& output_params); | 51 | std::vector<u8>& output_params); |
| 58 | void QueueMixedBuffer(Buffer::Tag tag); | 52 | void QueueMixedBuffer(Buffer::Tag tag); |
| 59 | void ReleaseAndQueueBuffers(); | 53 | void ReleaseAndQueueBuffers(); |
| 60 | u32 GetSampleRate() const; | 54 | [[nodiscard]] u32 GetSampleRate() const; |
| 61 | u32 GetSampleCount() const; | 55 | [[nodiscard]] u32 GetSampleCount() const; |
| 62 | u32 GetMixBufferCount() const; | 56 | [[nodiscard]] u32 GetMixBufferCount() const; |
| 63 | Stream::State GetStreamState() const; | 57 | [[nodiscard]] Stream::State GetStreamState() const; |
| 64 | 58 | ||
| 65 | private: | 59 | private: |
| 66 | BehaviorInfo behavior_info{}; | 60 | BehaviorInfo behavior_info{}; |
diff --git a/src/audio_core/behavior_info.h b/src/audio_core/behavior_info.h index 512a4ebe3..5a96bf75e 100644 --- a/src/audio_core/behavior_info.h +++ b/src/audio_core/behavior_info.h | |||
| @@ -43,22 +43,22 @@ public: | |||
| 43 | void ClearError(); | 43 | void ClearError(); |
| 44 | void UpdateFlags(u64_le dest_flags); | 44 | void UpdateFlags(u64_le dest_flags); |
| 45 | void SetUserRevision(u32_le revision); | 45 | void SetUserRevision(u32_le revision); |
| 46 | u32_le GetUserRevision() const; | 46 | [[nodiscard]] u32_le GetUserRevision() const; |
| 47 | u32_le GetProcessRevision() const; | 47 | [[nodiscard]] u32_le GetProcessRevision() const; |
| 48 | 48 | ||
| 49 | bool IsAdpcmLoopContextBugFixed() const; | 49 | [[nodiscard]] bool IsAdpcmLoopContextBugFixed() const; |
| 50 | bool IsSplitterSupported() const; | 50 | [[nodiscard]] bool IsSplitterSupported() const; |
| 51 | bool IsLongSizePreDelaySupported() const; | 51 | [[nodiscard]] bool IsLongSizePreDelaySupported() const; |
| 52 | bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; | 52 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const; |
| 53 | bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; | 53 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const; |
| 54 | bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; | 54 | [[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const; |
| 55 | bool IsElapsedFrameCountSupported() const; | 55 | [[nodiscard]] bool IsElapsedFrameCountSupported() const; |
| 56 | bool IsMemoryPoolForceMappingEnabled() const; | 56 | [[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const; |
| 57 | bool IsFlushVoiceWaveBuffersSupported() const; | 57 | [[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const; |
| 58 | bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; | 58 | [[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const; |
| 59 | bool IsVoicePitchAndSrcSkippedSupported() const; | 59 | [[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const; |
| 60 | bool IsMixInParameterDirtyOnlyUpdateSupported() const; | 60 | [[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const; |
| 61 | bool IsSplitterBugFixed() const; | 61 | [[nodiscard]] bool IsSplitterBugFixed() const; |
| 62 | void CopyErrorInfo(OutParams& dst); | 62 | void CopyErrorInfo(OutParams& dst); |
| 63 | 63 | ||
| 64 | private: | 64 | private: |
diff --git a/src/audio_core/command_generator.h b/src/audio_core/command_generator.h index 53e57748b..87ece00c4 100644 --- a/src/audio_core/command_generator.h +++ b/src/audio_core/command_generator.h | |||
| @@ -39,13 +39,13 @@ public: | |||
| 39 | void PreCommand(); | 39 | void PreCommand(); |
| 40 | void PostCommand(); | 40 | void PostCommand(); |
| 41 | 41 | ||
| 42 | s32* GetChannelMixBuffer(s32 channel); | 42 | [[nodiscard]] s32* GetChannelMixBuffer(s32 channel); |
| 43 | const s32* GetChannelMixBuffer(s32 channel) const; | 43 | [[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const; |
| 44 | s32* GetMixBuffer(std::size_t index); | 44 | [[nodiscard]] s32* GetMixBuffer(std::size_t index); |
| 45 | const s32* GetMixBuffer(std::size_t index) const; | 45 | [[nodiscard]] const s32* GetMixBuffer(std::size_t index) const; |
| 46 | std::size_t GetMixChannelBufferOffset(s32 channel) const; | 46 | [[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const; |
| 47 | 47 | ||
| 48 | std::size_t GetTotalMixBufferCount() const; | 48 | [[nodiscard]] std::size_t GetTotalMixBufferCount() const; |
| 49 | 49 | ||
| 50 | private: | 50 | private: |
| 51 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); | 51 | void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel); |
| @@ -73,7 +73,7 @@ private: | |||
| 73 | void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 73 | void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 74 | void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 74 | void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 75 | void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); | 75 | void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled); |
| 76 | ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); | 76 | [[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index); |
| 77 | 77 | ||
| 78 | s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, | 78 | s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data, |
| 79 | u32 sample_count, u32 write_offset, u32 write_count); | 79 | u32 sample_count, u32 write_offset, u32 write_count); |
diff --git a/src/audio_core/common.h b/src/audio_core/common.h index 7b4a1e9e8..ec59a3ba9 100644 --- a/src/audio_core/common.h +++ b/src/audio_core/common.h | |||
| @@ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6; | |||
| 22 | constexpr std::size_t MAX_WAVE_BUFFERS = 4; | 22 | constexpr std::size_t MAX_WAVE_BUFFERS = 4; |
| 23 | constexpr std::size_t MAX_SAMPLE_HISTORY = 4; | 23 | constexpr std::size_t MAX_SAMPLE_HISTORY = 4; |
| 24 | constexpr u32 STREAM_SAMPLE_RATE = 48000; | 24 | constexpr u32 STREAM_SAMPLE_RATE = 48000; |
| 25 | constexpr u32 STREAM_NUM_CHANNELS = 6; | 25 | constexpr u32 STREAM_NUM_CHANNELS = 2; |
| 26 | constexpr s32 NO_SPLITTER = -1; | 26 | constexpr s32 NO_SPLITTER = -1; |
| 27 | constexpr s32 NO_MIX = 0x7fffffff; | 27 | constexpr s32 NO_MIX = 0x7fffffff; |
| 28 | constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); | 28 | constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min(); |
diff --git a/src/audio_core/effect_context.h b/src/audio_core/effect_context.h index 2c4ce53ef..03c5a0f04 100644 --- a/src/audio_core/effect_context.h +++ b/src/audio_core/effect_context.h | |||
| @@ -189,11 +189,11 @@ public: | |||
| 189 | 189 | ||
| 190 | virtual void Update(EffectInfo::InParams& in_params) = 0; | 190 | virtual void Update(EffectInfo::InParams& in_params) = 0; |
| 191 | virtual void UpdateForCommandGeneration() = 0; | 191 | virtual void UpdateForCommandGeneration() = 0; |
| 192 | UsageState GetUsage() const; | 192 | [[nodiscard]] UsageState GetUsage() const; |
| 193 | EffectType GetType() const; | 193 | [[nodiscard]] EffectType GetType() const; |
| 194 | bool IsEnabled() const; | 194 | [[nodiscard]] bool IsEnabled() const; |
| 195 | s32 GetMixID() const; | 195 | [[nodiscard]] s32 GetMixID() const; |
| 196 | s32 GetProcessingOrder() const; | 196 | [[nodiscard]] s32 GetProcessingOrder() const; |
| 197 | 197 | ||
| 198 | protected: | 198 | protected: |
| 199 | UsageState usage{UsageState::Invalid}; | 199 | UsageState usage{UsageState::Invalid}; |
| @@ -257,10 +257,10 @@ public: | |||
| 257 | 257 | ||
| 258 | void Update(EffectInfo::InParams& in_params) override; | 258 | void Update(EffectInfo::InParams& in_params) override; |
| 259 | void UpdateForCommandGeneration() override; | 259 | void UpdateForCommandGeneration() override; |
| 260 | VAddr GetSendInfo() const; | 260 | [[nodiscard]] VAddr GetSendInfo() const; |
| 261 | VAddr GetSendBuffer() const; | 261 | [[nodiscard]] VAddr GetSendBuffer() const; |
| 262 | VAddr GetRecvInfo() const; | 262 | [[nodiscard]] VAddr GetRecvInfo() const; |
| 263 | VAddr GetRecvBuffer() const; | 263 | [[nodiscard]] VAddr GetRecvBuffer() const; |
| 264 | 264 | ||
| 265 | private: | 265 | private: |
| 266 | VAddr send_info{}; | 266 | VAddr send_info{}; |
| @@ -309,10 +309,10 @@ public: | |||
| 309 | explicit EffectContext(std::size_t effect_count); | 309 | explicit EffectContext(std::size_t effect_count); |
| 310 | ~EffectContext(); | 310 | ~EffectContext(); |
| 311 | 311 | ||
| 312 | std::size_t GetCount() const; | 312 | [[nodiscard]] std::size_t GetCount() const; |
| 313 | EffectBase* GetInfo(std::size_t i); | 313 | [[nodiscard]] EffectBase* GetInfo(std::size_t i); |
| 314 | EffectBase* RetargetEffect(std::size_t i, EffectType effect); | 314 | [[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect); |
| 315 | const EffectBase* GetInfo(std::size_t i) const; | 315 | [[nodiscard]] const EffectBase* GetInfo(std::size_t i) const; |
| 316 | 316 | ||
| 317 | private: | 317 | private: |
| 318 | std::size_t effect_count{}; | 318 | std::size_t effect_count{}; |
diff --git a/src/audio_core/mix_context.h b/src/audio_core/mix_context.h index 6a588eeb4..68bc673c6 100644 --- a/src/audio_core/mix_context.h +++ b/src/audio_core/mix_context.h | |||
| @@ -62,17 +62,17 @@ public: | |||
| 62 | ServerMixInfo(); | 62 | ServerMixInfo(); |
| 63 | ~ServerMixInfo(); | 63 | ~ServerMixInfo(); |
| 64 | 64 | ||
| 65 | const ServerMixInfo::InParams& GetInParams() const; | 65 | [[nodiscard]] const ServerMixInfo::InParams& GetInParams() const; |
| 66 | ServerMixInfo::InParams& GetInParams(); | 66 | [[nodiscard]] ServerMixInfo::InParams& GetInParams(); |
| 67 | 67 | ||
| 68 | bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, | 68 | bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in, |
| 69 | BehaviorInfo& behavior_info, SplitterContext& splitter_context, | 69 | BehaviorInfo& behavior_info, SplitterContext& splitter_context, |
| 70 | EffectContext& effect_context); | 70 | EffectContext& effect_context); |
| 71 | bool HasAnyConnection() const; | 71 | [[nodiscard]] bool HasAnyConnection() const; |
| 72 | void Cleanup(); | 72 | void Cleanup(); |
| 73 | void SetEffectCount(std::size_t count); | 73 | void SetEffectCount(std::size_t count); |
| 74 | void ResetEffectProcessingOrder(); | 74 | void ResetEffectProcessingOrder(); |
| 75 | s32 GetEffectOrder(std::size_t i) const; | 75 | [[nodiscard]] s32 GetEffectOrder(std::size_t i) const; |
| 76 | 76 | ||
| 77 | private: | 77 | private: |
| 78 | std::vector<s32> effect_processing_order; | 78 | std::vector<s32> effect_processing_order; |
| @@ -91,15 +91,15 @@ public: | |||
| 91 | void SortInfo(); | 91 | void SortInfo(); |
| 92 | bool TsortInfo(SplitterContext& splitter_context); | 92 | bool TsortInfo(SplitterContext& splitter_context); |
| 93 | 93 | ||
| 94 | std::size_t GetCount() const; | 94 | [[nodiscard]] std::size_t GetCount() const; |
| 95 | ServerMixInfo& GetInfo(std::size_t i); | 95 | [[nodiscard]] ServerMixInfo& GetInfo(std::size_t i); |
| 96 | const ServerMixInfo& GetInfo(std::size_t i) const; | 96 | [[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const; |
| 97 | ServerMixInfo& GetSortedInfo(std::size_t i); | 97 | [[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i); |
| 98 | const ServerMixInfo& GetSortedInfo(std::size_t i) const; | 98 | [[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const; |
| 99 | ServerMixInfo& GetFinalMixInfo(); | 99 | [[nodiscard]] ServerMixInfo& GetFinalMixInfo(); |
| 100 | const ServerMixInfo& GetFinalMixInfo() const; | 100 | [[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const; |
| 101 | EdgeMatrix& GetEdgeMatrix(); | 101 | [[nodiscard]] EdgeMatrix& GetEdgeMatrix(); |
| 102 | const EdgeMatrix& GetEdgeMatrix() const; | 102 | [[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const; |
| 103 | 103 | ||
| 104 | private: | 104 | private: |
| 105 | void CalcMixBufferOffset(); | 105 | void CalcMixBufferOffset(); |
diff --git a/src/audio_core/sink_context.cpp b/src/audio_core/sink_context.cpp index 0882b411a..cdb47ba81 100644 --- a/src/audio_core/sink_context.cpp +++ b/src/audio_core/sink_context.cpp | |||
| @@ -12,10 +12,16 @@ std::size_t SinkContext::GetCount() const { | |||
| 12 | return sink_count; | 12 | return sink_count; |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | void SinkContext::UpdateMainSink(SinkInfo::InParams& in) { | 15 | void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) { |
| 16 | ASSERT(in.type == SinkTypes::Device); | ||
| 17 | |||
| 18 | downmix = in.device.down_matrix_enabled; | ||
| 19 | if (downmix) { | ||
| 20 | downmix_coefficients = in.device.down_matrix_coef; | ||
| 21 | } | ||
| 16 | in_use = in.in_use; | 22 | in_use = in.in_use; |
| 17 | use_count = in.device.input_count; | 23 | use_count = in.device.input_count; |
| 18 | std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT); | 24 | buffers = in.device.input; |
| 19 | } | 25 | } |
| 20 | 26 | ||
| 21 | bool SinkContext::InUse() const { | 27 | bool SinkContext::InUse() const { |
| @@ -28,4 +34,12 @@ std::vector<u8> SinkContext::OutputBuffers() const { | |||
| 28 | return buffer_ret; | 34 | return buffer_ret; |
| 29 | } | 35 | } |
| 30 | 36 | ||
| 37 | bool SinkContext::HasDownMixingCoefficients() const { | ||
| 38 | return downmix; | ||
| 39 | } | ||
| 40 | |||
| 41 | const std::array<float_le, 4>& SinkContext::GetDownmixCoefficients() const { | ||
| 42 | return downmix_coefficients; | ||
| 43 | } | ||
| 44 | |||
| 31 | } // namespace AudioCore | 45 | } // namespace AudioCore |
diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h index d7aa72ba7..5a757a4ef 100644 --- a/src/audio_core/sink_context.h +++ b/src/audio_core/sink_context.h | |||
| @@ -74,16 +74,21 @@ public: | |||
| 74 | explicit SinkContext(std::size_t sink_count); | 74 | explicit SinkContext(std::size_t sink_count); |
| 75 | ~SinkContext(); | 75 | ~SinkContext(); |
| 76 | 76 | ||
| 77 | std::size_t GetCount() const; | 77 | [[nodiscard]] std::size_t GetCount() const; |
| 78 | 78 | ||
| 79 | void UpdateMainSink(SinkInfo::InParams& in); | 79 | void UpdateMainSink(const SinkInfo::InParams& in); |
| 80 | bool InUse() const; | 80 | [[nodiscard]] bool InUse() const; |
| 81 | std::vector<u8> OutputBuffers() const; | 81 | [[nodiscard]] std::vector<u8> OutputBuffers() const; |
| 82 | |||
| 83 | [[nodiscard]] bool HasDownMixingCoefficients() const; | ||
| 84 | [[nodiscard]] const std::array<float_le, 4>& GetDownmixCoefficients() const; | ||
| 82 | 85 | ||
| 83 | private: | 86 | private: |
| 84 | bool in_use{false}; | 87 | bool in_use{false}; |
| 85 | s32 use_count{}; | 88 | s32 use_count{}; |
| 86 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; | 89 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; |
| 87 | std::size_t sink_count{}; | 90 | std::size_t sink_count{}; |
| 91 | bool downmix{false}; | ||
| 92 | std::array<float_le, 4> downmix_coefficients{}; | ||
| 88 | }; | 93 | }; |
| 89 | } // namespace AudioCore | 94 | } // namespace AudioCore |
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 4bbb1e0c4..3f11b84ae 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -136,4 +136,13 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count) | |||
| 136 | return tags; | 136 | return tags; |
| 137 | } | 137 | } |
| 138 | 138 | ||
| 139 | std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() { | ||
| 140 | std::vector<Buffer::Tag> tags; | ||
| 141 | while (!released_buffers.empty()) { | ||
| 142 | tags.push_back(released_buffers.front()->GetTag()); | ||
| 143 | released_buffers.pop(); | ||
| 144 | } | ||
| 145 | return tags; | ||
| 146 | } | ||
| 147 | |||
| 139 | } // namespace AudioCore | 148 | } // namespace AudioCore |
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h index 6437b8591..71c2d0b4f 100644 --- a/src/audio_core/stream.h +++ b/src/audio_core/stream.h | |||
| @@ -57,37 +57,40 @@ public: | |||
| 57 | bool QueueBuffer(BufferPtr&& buffer); | 57 | bool QueueBuffer(BufferPtr&& buffer); |
| 58 | 58 | ||
| 59 | /// Returns true if the audio stream contains a buffer with the specified tag | 59 | /// Returns true if the audio stream contains a buffer with the specified tag |
| 60 | bool ContainsBuffer(Buffer::Tag tag) const; | 60 | [[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const; |
| 61 | 61 | ||
| 62 | /// Returns a vector of recently released buffers specified by tag | 62 | /// Returns a vector of recently released buffers specified by tag |
| 63 | std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); | 63 | [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count); |
| 64 | |||
| 65 | /// Returns a vector of all recently released buffers specified by tag | ||
| 66 | [[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(); | ||
| 64 | 67 | ||
| 65 | void SetVolume(float volume); | 68 | void SetVolume(float volume); |
| 66 | 69 | ||
| 67 | float GetVolume() const { | 70 | [[nodiscard]] float GetVolume() const { |
| 68 | return game_volume; | 71 | return game_volume; |
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | /// Returns true if the stream is currently playing | 74 | /// Returns true if the stream is currently playing |
| 72 | bool IsPlaying() const { | 75 | [[nodiscard]] bool IsPlaying() const { |
| 73 | return state == State::Playing; | 76 | return state == State::Playing; |
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | /// Returns the number of queued buffers | 79 | /// Returns the number of queued buffers |
| 77 | std::size_t GetQueueSize() const { | 80 | [[nodiscard]] std::size_t GetQueueSize() const { |
| 78 | return queued_buffers.size(); | 81 | return queued_buffers.size(); |
| 79 | } | 82 | } |
| 80 | 83 | ||
| 81 | /// Gets the sample rate | 84 | /// Gets the sample rate |
| 82 | u32 GetSampleRate() const { | 85 | [[nodiscard]] u32 GetSampleRate() const { |
| 83 | return sample_rate; | 86 | return sample_rate; |
| 84 | } | 87 | } |
| 85 | 88 | ||
| 86 | /// Gets the number of channels | 89 | /// Gets the number of channels |
| 87 | u32 GetNumChannels() const; | 90 | [[nodiscard]] u32 GetNumChannels() const; |
| 88 | 91 | ||
| 89 | /// Get the state | 92 | /// Get the state |
| 90 | State GetState() const; | 93 | [[nodiscard]] State GetState() const; |
| 91 | 94 | ||
| 92 | private: | 95 | private: |
| 93 | /// Plays the next queued buffer in the audio stream, starting playback if necessary | 96 | /// Plays the next queued buffer in the audio stream, starting playback if necessary |
| @@ -97,7 +100,7 @@ private: | |||
| 97 | void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); | 100 | void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {}); |
| 98 | 101 | ||
| 99 | /// Gets the number of core cycles when the specified buffer will be released | 102 | /// Gets the number of core cycles when the specified buffer will be released |
| 100 | std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; | 103 | [[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const; |
| 101 | 104 | ||
| 102 | u32 sample_rate; ///< Sample rate of the stream | 105 | u32 sample_rate; ///< Sample rate of the stream |
| 103 | Format format; ///< Format of the stream | 106 | Format format; ///< Format of the stream |