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 | 17 | ||||
| -rw-r--r-- | src/audio_core/stream.cpp | 10 | ||||
| -rw-r--r-- | src/audio_core/stream.h | 21 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 24 | ||||
| -rw-r--r-- | src/yuzu/applets/controller.cpp | 123 | ||||
| -rw-r--r-- | src/yuzu/applets/controller.h | 17 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 138 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.h | 13 |
18 files changed, 407 insertions, 209 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..e1ded84e0 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, s32{std::numeric_limits<s16>::min()}, | ||
| 21 | 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..b29b47890 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 | has_downmix_coefs = in.device.down_matrix_enabled; | ||
| 19 | if (has_downmix_coefs) { | ||
| 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 has_downmix_coefs; | ||
| 39 | } | ||
| 40 | |||
| 41 | const DownmixCoefficients& 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..e2e7880b7 100644 --- a/src/audio_core/sink_context.h +++ b/src/audio_core/sink_context.h | |||
| @@ -11,6 +11,8 @@ | |||
| 11 | 11 | ||
| 12 | namespace AudioCore { | 12 | namespace AudioCore { |
| 13 | 13 | ||
| 14 | using DownmixCoefficients = std::array<float_le, 4>; | ||
| 15 | |||
| 14 | enum class SinkTypes : u8 { | 16 | enum class SinkTypes : u8 { |
| 15 | Invalid = 0, | 17 | Invalid = 0, |
| 16 | Device = 1, | 18 | Device = 1, |
| @@ -50,7 +52,7 @@ public: | |||
| 50 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; | 52 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; |
| 51 | INSERT_UNION_PADDING_BYTES(1); | 53 | INSERT_UNION_PADDING_BYTES(1); |
| 52 | bool down_matrix_enabled; | 54 | bool down_matrix_enabled; |
| 53 | std::array<float_le, 4> down_matrix_coef; | 55 | DownmixCoefficients down_matrix_coef; |
| 54 | }; | 56 | }; |
| 55 | static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); | 57 | static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size"); |
| 56 | 58 | ||
| @@ -74,16 +76,21 @@ public: | |||
| 74 | explicit SinkContext(std::size_t sink_count); | 76 | explicit SinkContext(std::size_t sink_count); |
| 75 | ~SinkContext(); | 77 | ~SinkContext(); |
| 76 | 78 | ||
| 77 | std::size_t GetCount() const; | 79 | [[nodiscard]] std::size_t GetCount() const; |
| 80 | |||
| 81 | void UpdateMainSink(const SinkInfo::InParams& in); | ||
| 82 | [[nodiscard]] bool InUse() const; | ||
| 83 | [[nodiscard]] std::vector<u8> OutputBuffers() const; | ||
| 78 | 84 | ||
| 79 | void UpdateMainSink(SinkInfo::InParams& in); | 85 | [[nodiscard]] bool HasDownMixingCoefficients() const; |
| 80 | bool InUse() const; | 86 | [[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const; |
| 81 | std::vector<u8> OutputBuffers() const; | ||
| 82 | 87 | ||
| 83 | private: | 88 | private: |
| 84 | bool in_use{false}; | 89 | bool in_use{false}; |
| 85 | s32 use_count{}; | 90 | s32 use_count{}; |
| 86 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; | 91 | std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{}; |
| 87 | std::size_t sink_count{}; | 92 | std::size_t sink_count{}; |
| 93 | bool has_downmix_coefs{false}; | ||
| 94 | DownmixCoefficients downmix_coefficients{}; | ||
| 88 | }; | 95 | }; |
| 89 | } // namespace AudioCore | 96 | } // namespace AudioCore |
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 4bbb1e0c4..41bc2f4d6 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp | |||
| @@ -136,4 +136,14 @@ 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 | tags.reserve(released_buffers.size()); | ||
| 142 | while (!released_buffers.empty()) { | ||
| 143 | tags.push_back(released_buffers.front()->GetTag()); | ||
| 144 | released_buffers.pop(); | ||
| 145 | } | ||
| 146 | return tags; | ||
| 147 | } | ||
| 148 | |||
| 139 | } // namespace AudioCore | 149 | } // 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 |
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 983210197..100e90d82 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include "common/fiber.h" | 5 | #include "common/fiber.h" |
| 6 | #include "common/microprofile.h" | 6 | #include "common/microprofile.h" |
| 7 | #include "common/scope_exit.h" | ||
| 7 | #include "common/thread.h" | 8 | #include "common/thread.h" |
| 8 | #include "core/arm/exclusive_monitor.h" | 9 | #include "core/arm/exclusive_monitor.h" |
| 9 | #include "core/core.h" | 10 | #include "core/core.h" |
| @@ -343,6 +344,16 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 343 | data.initialized = true; | 344 | data.initialized = true; |
| 344 | const bool sc_sync = !is_async_gpu && !is_multicore; | 345 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 345 | bool sc_sync_first_use = sc_sync; | 346 | bool sc_sync_first_use = sc_sync; |
| 347 | |||
| 348 | // Cleanup | ||
| 349 | SCOPE_EXIT({ | ||
| 350 | data.host_context->Exit(); | ||
| 351 | data.enter_barrier.reset(); | ||
| 352 | data.exit_barrier.reset(); | ||
| 353 | data.initialized = false; | ||
| 354 | MicroProfileOnThreadExit(); | ||
| 355 | }); | ||
| 356 | |||
| 346 | /// Running | 357 | /// Running |
| 347 | while (running_mode) { | 358 | while (running_mode) { |
| 348 | data.is_running = false; | 359 | data.is_running = false; |
| @@ -351,6 +362,12 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 351 | system.GPU().ObtainContext(); | 362 | system.GPU().ObtainContext(); |
| 352 | sc_sync_first_use = false; | 363 | sc_sync_first_use = false; |
| 353 | } | 364 | } |
| 365 | |||
| 366 | // Abort if emulation was killed before the session really starts | ||
| 367 | if (!system.IsPoweredOn()) { | ||
| 368 | return; | ||
| 369 | } | ||
| 370 | |||
| 354 | auto& scheduler = system.Kernel().CurrentScheduler(); | 371 | auto& scheduler = system.Kernel().CurrentScheduler(); |
| 355 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 372 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 356 | data.is_running = true; | 373 | data.is_running = true; |
| @@ -360,13 +377,6 @@ void CpuManager::RunThread(std::size_t core) { | |||
| 360 | data.exit_barrier->Wait(); | 377 | data.exit_barrier->Wait(); |
| 361 | data.is_paused = false; | 378 | data.is_paused = false; |
| 362 | } | 379 | } |
| 363 | /// Time to cleanup | ||
| 364 | data.host_context->Exit(); | ||
| 365 | data.enter_barrier.reset(); | ||
| 366 | data.exit_barrier.reset(); | ||
| 367 | data.initialized = false; | ||
| 368 | |||
| 369 | MicroProfileOnThreadExit(); | ||
| 370 | } | 380 | } |
| 371 | 381 | ||
| 372 | } // namespace Core | 382 | } // namespace Core |
diff --git a/src/yuzu/applets/controller.cpp b/src/yuzu/applets/controller.cpp index 8ecfec770..6944478f3 100644 --- a/src/yuzu/applets/controller.cpp +++ b/src/yuzu/applets/controller.cpp | |||
| @@ -72,40 +72,6 @@ bool IsControllerCompatible(Settings::ControllerType controller_type, | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | /// Maps the controller type combobox index to Controller Type enum | ||
| 76 | constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { | ||
| 77 | switch (index) { | ||
| 78 | case 0: | ||
| 79 | default: | ||
| 80 | return Settings::ControllerType::ProController; | ||
| 81 | case 1: | ||
| 82 | return Settings::ControllerType::DualJoyconDetached; | ||
| 83 | case 2: | ||
| 84 | return Settings::ControllerType::LeftJoycon; | ||
| 85 | case 3: | ||
| 86 | return Settings::ControllerType::RightJoycon; | ||
| 87 | case 4: | ||
| 88 | return Settings::ControllerType::Handheld; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | /// Maps the Controller Type enum to controller type combobox index | ||
| 93 | constexpr int GetIndexFromControllerType(Settings::ControllerType type) { | ||
| 94 | switch (type) { | ||
| 95 | case Settings::ControllerType::ProController: | ||
| 96 | default: | ||
| 97 | return 0; | ||
| 98 | case Settings::ControllerType::DualJoyconDetached: | ||
| 99 | return 1; | ||
| 100 | case Settings::ControllerType::LeftJoycon: | ||
| 101 | return 2; | ||
| 102 | case Settings::ControllerType::RightJoycon: | ||
| 103 | return 3; | ||
| 104 | case Settings::ControllerType::Handheld: | ||
| 105 | return 4; | ||
| 106 | } | ||
| 107 | } | ||
| 108 | |||
| 109 | } // namespace | 75 | } // namespace |
| 110 | 76 | ||
| 111 | QtControllerSelectorDialog::QtControllerSelectorDialog( | 77 | QtControllerSelectorDialog::QtControllerSelectorDialog( |
| @@ -184,6 +150,11 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( | |||
| 184 | // This avoids unintentionally changing the states of elements while loading them in. | 150 | // This avoids unintentionally changing the states of elements while loading them in. |
| 185 | SetSupportedControllers(); | 151 | SetSupportedControllers(); |
| 186 | DisableUnsupportedPlayers(); | 152 | DisableUnsupportedPlayers(); |
| 153 | |||
| 154 | for (std::size_t player_index = 0; player_index < NUM_PLAYERS; ++player_index) { | ||
| 155 | SetEmulatedControllers(player_index); | ||
| 156 | } | ||
| 157 | |||
| 187 | LoadConfiguration(); | 158 | LoadConfiguration(); |
| 188 | 159 | ||
| 189 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { | 160 | for (std::size_t i = 0; i < NUM_PLAYERS; ++i) { |
| @@ -223,8 +194,8 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( | |||
| 223 | 194 | ||
| 224 | if (i == 0) { | 195 | if (i == 0) { |
| 225 | connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), | 196 | connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), |
| 226 | [this](int index) { | 197 | [this, i](int index) { |
| 227 | UpdateDockedState(GetControllerTypeFromIndex(index) == | 198 | UpdateDockedState(GetControllerTypeFromIndex(index, i) == |
| 228 | Settings::ControllerType::Handheld); | 199 | Settings::ControllerType::Handheld); |
| 229 | }); | 200 | }); |
| 230 | } | 201 | } |
| @@ -281,8 +252,8 @@ void QtControllerSelectorDialog::LoadConfiguration() { | |||
| 281 | (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); | 252 | (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); |
| 282 | player_groupboxes[index]->setChecked(connected); | 253 | player_groupboxes[index]->setChecked(connected); |
| 283 | connected_controller_checkboxes[index]->setChecked(connected); | 254 | connected_controller_checkboxes[index]->setChecked(connected); |
| 284 | emulated_controllers[index]->setCurrentIndex( | 255 | emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( |
| 285 | GetIndexFromControllerType(Settings::values.players.GetValue()[index].controller_type)); | 256 | Settings::values.players.GetValue()[index].controller_type, index)); |
| 286 | } | 257 | } |
| 287 | 258 | ||
| 288 | UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); | 259 | UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); |
| @@ -338,7 +309,7 @@ bool QtControllerSelectorDialog::CheckIfParametersMet() { | |||
| 338 | } | 309 | } |
| 339 | 310 | ||
| 340 | const auto compatible = IsControllerCompatible( | 311 | const auto compatible = IsControllerCompatible( |
| 341 | GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex()), | 312 | GetControllerTypeFromIndex(emulated_controllers[index]->currentIndex(), index), |
| 342 | parameters); | 313 | parameters); |
| 343 | 314 | ||
| 344 | // If any controller is found to be incompatible, return false early. | 315 | // If any controller is found to be incompatible, return false early. |
| @@ -422,6 +393,63 @@ void QtControllerSelectorDialog::SetSupportedControllers() { | |||
| 422 | } | 393 | } |
| 423 | } | 394 | } |
| 424 | 395 | ||
| 396 | void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index) { | ||
| 397 | auto& pairs = index_controller_type_pairs[player_index]; | ||
| 398 | |||
| 399 | pairs.clear(); | ||
| 400 | emulated_controllers[player_index]->clear(); | ||
| 401 | |||
| 402 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 403 | Settings::ControllerType::ProController); | ||
| 404 | emulated_controllers[player_index]->addItem(tr("Pro Controller")); | ||
| 405 | |||
| 406 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 407 | Settings::ControllerType::DualJoyconDetached); | ||
| 408 | emulated_controllers[player_index]->addItem(tr("Dual Joycons")); | ||
| 409 | |||
| 410 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 411 | Settings::ControllerType::LeftJoycon); | ||
| 412 | emulated_controllers[player_index]->addItem(tr("Left Joycon")); | ||
| 413 | |||
| 414 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 415 | Settings::ControllerType::RightJoycon); | ||
| 416 | emulated_controllers[player_index]->addItem(tr("Right Joycon")); | ||
| 417 | |||
| 418 | if (player_index == 0) { | ||
| 419 | pairs.emplace_back(emulated_controllers[player_index]->count(), | ||
| 420 | Settings::ControllerType::Handheld); | ||
| 421 | emulated_controllers[player_index]->addItem(tr("Handheld")); | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( | ||
| 426 | int index, std::size_t player_index) const { | ||
| 427 | const auto& pairs = index_controller_type_pairs[player_index]; | ||
| 428 | |||
| 429 | const auto it = std::find_if(pairs.begin(), pairs.end(), | ||
| 430 | [index](const auto& pair) { return pair.first == index; }); | ||
| 431 | |||
| 432 | if (it == pairs.end()) { | ||
| 433 | return Settings::ControllerType::ProController; | ||
| 434 | } | ||
| 435 | |||
| 436 | return it->second; | ||
| 437 | } | ||
| 438 | |||
| 439 | int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, | ||
| 440 | std::size_t player_index) const { | ||
| 441 | const auto& pairs = index_controller_type_pairs[player_index]; | ||
| 442 | |||
| 443 | const auto it = std::find_if(pairs.begin(), pairs.end(), | ||
| 444 | [type](const auto& pair) { return pair.second == type; }); | ||
| 445 | |||
| 446 | if (it == pairs.end()) { | ||
| 447 | return 0; | ||
| 448 | } | ||
| 449 | |||
| 450 | return it->first; | ||
| 451 | } | ||
| 452 | |||
| 425 | void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) { | 453 | void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) { |
| 426 | if (!player_groupboxes[player_index]->isChecked()) { | 454 | if (!player_groupboxes[player_index]->isChecked()) { |
| 427 | connected_controller_icons[player_index]->setStyleSheet(QString{}); | 455 | connected_controller_icons[player_index]->setStyleSheet(QString{}); |
| @@ -430,7 +458,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 430 | } | 458 | } |
| 431 | 459 | ||
| 432 | const QString stylesheet = [this, player_index] { | 460 | const QString stylesheet = [this, player_index] { |
| 433 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex())) { | 461 | switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), |
| 462 | player_index)) { | ||
| 434 | case Settings::ControllerType::ProController: | 463 | case Settings::ControllerType::ProController: |
| 435 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); | 464 | return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); |
| 436 | case Settings::ControllerType::DualJoyconDetached: | 465 | case Settings::ControllerType::DualJoyconDetached: |
| @@ -446,6 +475,12 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 446 | } | 475 | } |
| 447 | }(); | 476 | }(); |
| 448 | 477 | ||
| 478 | if (stylesheet.isEmpty()) { | ||
| 479 | connected_controller_icons[player_index]->setStyleSheet(QString{}); | ||
| 480 | player_labels[player_index]->show(); | ||
| 481 | return; | ||
| 482 | } | ||
| 483 | |||
| 449 | const QString theme = [] { | 484 | const QString theme = [] { |
| 450 | if (QIcon::themeName().contains(QStringLiteral("dark"))) { | 485 | if (QIcon::themeName().contains(QStringLiteral("dark"))) { |
| 451 | return QStringLiteral("_dark"); | 486 | return QStringLiteral("_dark"); |
| @@ -463,8 +498,8 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) | |||
| 463 | void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { | 498 | void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { |
| 464 | auto& player = Settings::values.players.GetValue()[player_index]; | 499 | auto& player = Settings::values.players.GetValue()[player_index]; |
| 465 | 500 | ||
| 466 | const auto controller_type = | 501 | const auto controller_type = GetControllerTypeFromIndex( |
| 467 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()); | 502 | emulated_controllers[player_index]->currentIndex(), player_index); |
| 468 | const auto player_connected = player_groupboxes[player_index]->isChecked() && | 503 | const auto player_connected = player_groupboxes[player_index]->isChecked() && |
| 469 | controller_type != Settings::ControllerType::Handheld; | 504 | controller_type != Settings::ControllerType::Handheld; |
| 470 | 505 | ||
| @@ -507,8 +542,8 @@ void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) | |||
| 507 | 542 | ||
| 508 | void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { | 543 | void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { |
| 509 | if (!player_groupboxes[player_index]->isChecked() || | 544 | if (!player_groupboxes[player_index]->isChecked() || |
| 510 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex()) == | 545 | GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), |
| 511 | Settings::ControllerType::Handheld) { | 546 | player_index) == Settings::ControllerType::Handheld) { |
| 512 | led_patterns_boxes[player_index][0]->setChecked(false); | 547 | led_patterns_boxes[player_index][0]->setChecked(false); |
| 513 | led_patterns_boxes[player_index][1]->setChecked(false); | 548 | led_patterns_boxes[player_index][1]->setChecked(false); |
| 514 | led_patterns_boxes[player_index][2]->setChecked(false); | 549 | led_patterns_boxes[player_index][2]->setChecked(false); |
diff --git a/src/yuzu/applets/controller.h b/src/yuzu/applets/controller.h index 4344e1dd0..7a421d856 100644 --- a/src/yuzu/applets/controller.h +++ b/src/yuzu/applets/controller.h | |||
| @@ -22,6 +22,10 @@ namespace InputCommon { | |||
| 22 | class InputSubsystem; | 22 | class InputSubsystem; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | namespace Settings { | ||
| 26 | enum class ControllerType; | ||
| 27 | } | ||
| 28 | |||
| 25 | namespace Ui { | 29 | namespace Ui { |
| 26 | class QtControllerSelectorDialog; | 30 | class QtControllerSelectorDialog; |
| 27 | } | 31 | } |
| @@ -57,6 +61,15 @@ private: | |||
| 57 | // Sets the controller icons for "Supported Controller Types". | 61 | // Sets the controller icons for "Supported Controller Types". |
| 58 | void SetSupportedControllers(); | 62 | void SetSupportedControllers(); |
| 59 | 63 | ||
| 64 | // Sets the emulated controllers per player. | ||
| 65 | void SetEmulatedControllers(std::size_t player_index); | ||
| 66 | |||
| 67 | // Gets the Controller Type for a given controller combobox index per player. | ||
| 68 | Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; | ||
| 69 | |||
| 70 | // Gets the controller combobox index for a given Controller Type per player. | ||
| 71 | int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; | ||
| 72 | |||
| 60 | // Updates the controller icons per player. | 73 | // Updates the controller icons per player. |
| 61 | void UpdateControllerIcon(std::size_t player_index); | 74 | void UpdateControllerIcon(std::size_t player_index); |
| 62 | 75 | ||
| @@ -114,6 +127,10 @@ private: | |||
| 114 | // Comboboxes with a list of emulated controllers per player. | 127 | // Comboboxes with a list of emulated controllers per player. |
| 115 | std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; | 128 | std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; |
| 116 | 129 | ||
| 130 | /// Pairs of emulated controller index and Controller Type enum per player. | ||
| 131 | std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS> | ||
| 132 | index_controller_type_pairs; | ||
| 133 | |||
| 117 | // Labels representing the number of connected controllers | 134 | // Labels representing the number of connected controllers |
| 118 | // above the "Connected Controllers" checkboxes. | 135 | // above the "Connected Controllers" checkboxes. |
| 119 | std::array<QLabel*, NUM_PLAYERS> connected_controller_labels; | 136 | std::array<QLabel*, NUM_PLAYERS> connected_controller_labels; |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 56ab32a35..918bfb56b 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -27,6 +27,8 @@ | |||
| 27 | #include "yuzu/configuration/input_profiles.h" | 27 | #include "yuzu/configuration/input_profiles.h" |
| 28 | #include "yuzu/util/limitable_input_dialog.h" | 28 | #include "yuzu/util/limitable_input_dialog.h" |
| 29 | 29 | ||
| 30 | using namespace Service::HID; | ||
| 31 | |||
| 30 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> | 32 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> |
| 31 | ConfigureInputPlayer::analog_sub_buttons{{ | 33 | ConfigureInputPlayer::analog_sub_buttons{{ |
| 32 | "up", | 34 | "up", |
| @@ -47,48 +49,12 @@ void UpdateController(Settings::ControllerType controller_type, std::size_t npad | |||
| 47 | } | 49 | } |
| 48 | Service::SM::ServiceManager& sm = system.ServiceManager(); | 50 | Service::SM::ServiceManager& sm = system.ServiceManager(); |
| 49 | 51 | ||
| 50 | auto& npad = | 52 | auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( |
| 51 | sm.GetService<Service::HID::Hid>("hid") | 53 | HidController::NPad); |
| 52 | ->GetAppletResource() | ||
| 53 | ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad); | ||
| 54 | 54 | ||
| 55 | npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); | 55 | npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | /// Maps the controller type combobox index to Controller Type enum | ||
| 59 | constexpr Settings::ControllerType GetControllerTypeFromIndex(int index) { | ||
| 60 | switch (index) { | ||
| 61 | case 0: | ||
| 62 | default: | ||
| 63 | return Settings::ControllerType::ProController; | ||
| 64 | case 1: | ||
| 65 | return Settings::ControllerType::DualJoyconDetached; | ||
| 66 | case 2: | ||
| 67 | return Settings::ControllerType::LeftJoycon; | ||
| 68 | case 3: | ||
| 69 | return Settings::ControllerType::RightJoycon; | ||
| 70 | case 4: | ||
| 71 | return Settings::ControllerType::Handheld; | ||
| 72 | } | ||
| 73 | } | ||
| 74 | |||
| 75 | /// Maps the Controller Type enum to controller type combobox index | ||
| 76 | constexpr int GetIndexFromControllerType(Settings::ControllerType type) { | ||
| 77 | switch (type) { | ||
| 78 | case Settings::ControllerType::ProController: | ||
| 79 | default: | ||
| 80 | return 0; | ||
| 81 | case Settings::ControllerType::DualJoyconDetached: | ||
| 82 | return 1; | ||
| 83 | case Settings::ControllerType::LeftJoycon: | ||
| 84 | return 2; | ||
| 85 | case Settings::ControllerType::RightJoycon: | ||
| 86 | return 3; | ||
| 87 | case Settings::ControllerType::Handheld: | ||
| 88 | return 4; | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | QString GetKeyName(int key_code) { | 58 | QString GetKeyName(int key_code) { |
| 93 | switch (key_code) { | 59 | switch (key_code) { |
| 94 | case Qt::LeftButton: | 60 | case Qt::LeftButton: |
| @@ -453,18 +419,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 453 | connect(ui->groupConnectedController, &QGroupBox::toggled, | 419 | connect(ui->groupConnectedController, &QGroupBox::toggled, |
| 454 | [this](bool checked) { emit Connected(checked); }); | 420 | [this](bool checked) { emit Connected(checked); }); |
| 455 | 421 | ||
| 456 | // Set up controller type. Only Player 1 can choose Handheld. | ||
| 457 | ui->comboControllerType->clear(); | ||
| 458 | |||
| 459 | QStringList controller_types = { | ||
| 460 | tr("Pro Controller"), | ||
| 461 | tr("Dual Joycons"), | ||
| 462 | tr("Left Joycon"), | ||
| 463 | tr("Right Joycon"), | ||
| 464 | }; | ||
| 465 | |||
| 466 | if (player_index == 0) { | 422 | if (player_index == 0) { |
| 467 | controller_types.append(tr("Handheld")); | ||
| 468 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), | 423 | connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), |
| 469 | [this](int index) { | 424 | [this](int index) { |
| 470 | emit HandheldStateChanged(GetControllerTypeFromIndex(index) == | 425 | emit HandheldStateChanged(GetControllerTypeFromIndex(index) == |
| @@ -480,12 +435,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 480 | if (debug) { | 435 | if (debug) { |
| 481 | ui->buttonScreenshot->setEnabled(false); | 436 | ui->buttonScreenshot->setEnabled(false); |
| 482 | ui->buttonHome->setEnabled(false); | 437 | ui->buttonHome->setEnabled(false); |
| 483 | QStringList debug_controller_types = { | 438 | ui->comboControllerType->addItem(tr("Pro Controller")); |
| 484 | tr("Pro Controller"), | ||
| 485 | }; | ||
| 486 | ui->comboControllerType->addItems(debug_controller_types); | ||
| 487 | } else { | 439 | } else { |
| 488 | ui->comboControllerType->addItems(controller_types); | 440 | SetConnectableControllers(); |
| 489 | } | 441 | } |
| 490 | 442 | ||
| 491 | UpdateControllerIcon(); | 443 | UpdateControllerIcon(); |
| @@ -667,7 +619,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | |||
| 667 | return; | 619 | return; |
| 668 | } | 620 | } |
| 669 | 621 | ||
| 670 | ui->comboControllerType->setCurrentIndex(static_cast<int>(player.controller_type)); | 622 | ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type)); |
| 671 | ui->groupConnectedController->setChecked( | 623 | ui->groupConnectedController->setChecked( |
| 672 | player.connected || | 624 | player.connected || |
| 673 | (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); | 625 | (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); |
| @@ -841,6 +793,82 @@ void ConfigureInputPlayer::UpdateUI() { | |||
| 841 | } | 793 | } |
| 842 | } | 794 | } |
| 843 | 795 | ||
| 796 | void ConfigureInputPlayer::SetConnectableControllers() { | ||
| 797 | const auto add_controllers = [this](bool enable_all, | ||
| 798 | Controller_NPad::NpadStyleSet npad_style_set = {}) { | ||
| 799 | index_controller_type_pairs.clear(); | ||
| 800 | ui->comboControllerType->clear(); | ||
| 801 | |||
| 802 | if (enable_all || npad_style_set.pro_controller == 1) { | ||
| 803 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 804 | Settings::ControllerType::ProController); | ||
| 805 | ui->comboControllerType->addItem(tr("Pro Controller")); | ||
| 806 | } | ||
| 807 | |||
| 808 | if (enable_all || npad_style_set.joycon_dual == 1) { | ||
| 809 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 810 | Settings::ControllerType::DualJoyconDetached); | ||
| 811 | ui->comboControllerType->addItem(tr("Dual Joycons")); | ||
| 812 | } | ||
| 813 | |||
| 814 | if (enable_all || npad_style_set.joycon_left == 1) { | ||
| 815 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 816 | Settings::ControllerType::LeftJoycon); | ||
| 817 | ui->comboControllerType->addItem(tr("Left Joycon")); | ||
| 818 | } | ||
| 819 | |||
| 820 | if (enable_all || npad_style_set.joycon_right == 1) { | ||
| 821 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 822 | Settings::ControllerType::RightJoycon); | ||
| 823 | ui->comboControllerType->addItem(tr("Right Joycon")); | ||
| 824 | } | ||
| 825 | |||
| 826 | if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { | ||
| 827 | index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), | ||
| 828 | Settings::ControllerType::Handheld); | ||
| 829 | ui->comboControllerType->addItem(tr("Handheld")); | ||
| 830 | } | ||
| 831 | }; | ||
| 832 | |||
| 833 | Core::System& system{Core::System::GetInstance()}; | ||
| 834 | |||
| 835 | if (!system.IsPoweredOn()) { | ||
| 836 | add_controllers(true); | ||
| 837 | return; | ||
| 838 | } | ||
| 839 | |||
| 840 | Service::SM::ServiceManager& sm = system.ServiceManager(); | ||
| 841 | |||
| 842 | auto& npad = sm.GetService<Hid>("hid")->GetAppletResource()->GetController<Controller_NPad>( | ||
| 843 | HidController::NPad); | ||
| 844 | |||
| 845 | add_controllers(false, npad.GetSupportedStyleSet()); | ||
| 846 | } | ||
| 847 | |||
| 848 | Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { | ||
| 849 | const auto it = | ||
| 850 | std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), | ||
| 851 | [index](const auto& pair) { return pair.first == index; }); | ||
| 852 | |||
| 853 | if (it == index_controller_type_pairs.end()) { | ||
| 854 | return Settings::ControllerType::ProController; | ||
| 855 | } | ||
| 856 | |||
| 857 | return it->second; | ||
| 858 | } | ||
| 859 | |||
| 860 | int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const { | ||
| 861 | const auto it = | ||
| 862 | std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), | ||
| 863 | [type](const auto& pair) { return pair.second == type; }); | ||
| 864 | |||
| 865 | if (it == index_controller_type_pairs.end()) { | ||
| 866 | return -1; | ||
| 867 | } | ||
| 868 | |||
| 869 | return it->first; | ||
| 870 | } | ||
| 871 | |||
| 844 | void ConfigureInputPlayer::UpdateInputDevices() { | 872 | void ConfigureInputPlayer::UpdateInputDevices() { |
| 845 | input_devices = input_subsystem->GetInputDevices(); | 873 | input_devices = input_subsystem->GetInputDevices(); |
| 846 | ui->comboDevices->clear(); | 874 | ui->comboDevices->clear(); |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 23cf6f958..9c30879a2 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <vector> | ||
| 12 | 13 | ||
| 13 | #include <QWidget> | 14 | #include <QWidget> |
| 14 | 15 | ||
| @@ -112,6 +113,15 @@ private: | |||
| 112 | /// Update UI to reflect current configuration. | 113 | /// Update UI to reflect current configuration. |
| 113 | void UpdateUI(); | 114 | void UpdateUI(); |
| 114 | 115 | ||
| 116 | /// Sets the available controllers. | ||
| 117 | void SetConnectableControllers(); | ||
| 118 | |||
| 119 | /// Gets the Controller Type for a given controller combobox index. | ||
| 120 | Settings::ControllerType GetControllerTypeFromIndex(int index) const; | ||
| 121 | |||
| 122 | /// Gets the controller combobox index for a given Controller Type. | ||
| 123 | int GetIndexFromControllerType(Settings::ControllerType type) const; | ||
| 124 | |||
| 115 | /// Update the available input devices. | 125 | /// Update the available input devices. |
| 116 | void UpdateInputDevices(); | 126 | void UpdateInputDevices(); |
| 117 | 127 | ||
| @@ -151,6 +161,9 @@ private: | |||
| 151 | std::unique_ptr<QTimer> timeout_timer; | 161 | std::unique_ptr<QTimer> timeout_timer; |
| 152 | std::unique_ptr<QTimer> poll_timer; | 162 | std::unique_ptr<QTimer> poll_timer; |
| 153 | 163 | ||
| 164 | /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. | ||
| 165 | std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs; | ||
| 166 | |||
| 154 | static constexpr int PLAYER_COUNT = 8; | 167 | static constexpr int PLAYER_COUNT = 8; |
| 155 | std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; | 168 | std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; |
| 156 | 169 | ||