diff --git a/Source/Core/AudioCommon/Mixer.cpp b/Source/Core/AudioCommon/Mixer.cpp index ae52dc7bb2..18d899e3cd 100644 --- a/Source/Core/AudioCommon/Mixer.cpp +++ b/Source/Core/AudioCommon/Mixer.cpp @@ -52,6 +52,7 @@ void Mixer::DoState(PointerWrap& p) m_dma_mixer.DoState(p); m_streaming_mixer.DoState(p); m_wiimote_speaker_mixer.DoState(p); + m_skylander_portal_mixer.DoState(p); for (auto& mixer : m_gba_mixers) mixer.DoState(p); } @@ -183,6 +184,8 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples) timing_variance); m_wiimote_speaker_mixer.Mix(m_scratch_buffer.data(), available_samples, false, emulation_speed, timing_variance); + m_skylander_portal_mixer.Mix(m_scratch_buffer.data(), available_samples, false, emulation_speed, + timing_variance); for (auto& mixer : m_gba_mixers) { mixer.Mix(m_scratch_buffer.data(), available_samples, false, emulation_speed, @@ -202,6 +205,7 @@ unsigned int Mixer::Mix(short* samples, unsigned int num_samples) m_dma_mixer.Mix(samples, num_samples, true, emulation_speed, timing_variance); m_streaming_mixer.Mix(samples, num_samples, true, emulation_speed, timing_variance); m_wiimote_speaker_mixer.Mix(samples, num_samples, true, emulation_speed, timing_variance); + m_skylander_portal_mixer.Mix(samples, num_samples, true, emulation_speed, timing_variance); for (auto& mixer : m_gba_mixers) mixer.Mix(samples, num_samples, true, emulation_speed, timing_variance); m_is_stretching = false; @@ -316,6 +320,30 @@ void Mixer::PushWiimoteSpeakerSamples(const short* samples, unsigned int num_sam } } +void Mixer::PushSkylanderPortalSamples(const u8* samples, unsigned int num_samples) +{ + // Skylander samples are always supplied as 64 bytes, 32 x 16 bit samples + // The portal speaker is 1 channel, so duplicate and play as stereo audio + static constexpr u32 MAX_PORTAL_SPEAKER_SAMPLES = 32; + std::array samples_stereo; + + ASSERT_MSG(AUDIO, num_samples <= MAX_PORTAL_SPEAKER_SAMPLES, + "num_samples is not less or equal to 32: {} > {}", num_samples, + MAX_PORTAL_SPEAKER_SAMPLES); + + if (num_samples <= MAX_PORTAL_SPEAKER_SAMPLES) + { + for (unsigned int i = 0; i < num_samples; ++i) + { + s16 sample = static_cast(samples[i * 2 + 1]) << 8 | static_cast(samples[i * 2]); + samples_stereo[i * 2] = sample; + samples_stereo[i * 2 + 1] = sample; + } + + m_skylander_portal_mixer.PushSamples(samples_stereo.data(), num_samples); + } +} + void Mixer::PushGBASamples(int device_number, const short* samples, unsigned int num_samples) { m_gba_mixers[device_number].PushSamples(samples, num_samples); diff --git a/Source/Core/AudioCommon/Mixer.h b/Source/Core/AudioCommon/Mixer.h index 11039443ca..c27ff311c3 100644 --- a/Source/Core/AudioCommon/Mixer.h +++ b/Source/Core/AudioCommon/Mixer.h @@ -30,6 +30,7 @@ public: void PushStreamingSamples(const short* samples, unsigned int num_samples); void PushWiimoteSpeakerSamples(const short* samples, unsigned int num_samples, unsigned int sample_rate_divisor); + void PushSkylanderPortalSamples(const u8* samples, unsigned int num_samples); void PushGBASamples(int device_number, const short* samples, unsigned int num_samples); unsigned int GetSampleRate() const { return m_sampleRate; } @@ -97,6 +98,7 @@ private: MixerFifo m_dma_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 32000, false}; MixerFifo m_streaming_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, false}; MixerFifo m_wiimote_speaker_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 3000, true}; + MixerFifo m_skylander_portal_mixer{this, FIXED_SAMPLE_RATE_DIVIDEND / 8000, true}; std::array m_gba_mixers{MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true}, MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true}, MixerFifo{this, FIXED_SAMPLE_RATE_DIVIDEND / 48000, true}, diff --git a/Source/Core/Core/IOS/USB/Emulated/Skylander.cpp b/Source/Core/Core/IOS/USB/Emulated/Skylander.cpp index 2552cfa79b..5138fb0f66 100644 --- a/Source/Core/Core/IOS/USB/Emulated/Skylander.cpp +++ b/Source/Core/Core/IOS/USB/Emulated/Skylander.cpp @@ -7,6 +7,7 @@ #include #include +#include "AudioCommon/AudioCommon.h" #include "Common/Logging/Log.h" #include "Common/Random.h" #include "Common/StringUtil.h" @@ -903,15 +904,21 @@ int SkylanderUSB::SubmitTransfer(std::unique_ptr cmd) s32 expected_count; u64 expected_time_us; // Audio requests are 64 bytes long, are the only Interrupt requests longer than 32 bytes, - // echo the request as the response and respond after 1ms + // echo the request as the response and respond immediately if (cmd->length > 32 && cmd->length <= 64) { + // Play audio through Portal Mixer + // Audio is unsigned 16 bit, supplied as 64 bytes which is 32 samples + SoundStream* sound_stream = system.GetSoundStream(); + sound_stream->GetMixer()->PushSkylanderPortalSamples(buf, cmd->length / 2); + std::array audio_interrupt_response = {}; u8* audio_buf = audio_interrupt_response.data(); memcpy(audio_buf, buf, cmd->length); - expected_time_us = 1000; + expected_time_us = 0; expected_count = cmd->length; ScheduleTransfer(std::move(cmd), audio_interrupt_response, expected_count, expected_time_us); + return 0; } // If some data was requested from the Control Message, then the Interrupt message needs to diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 8eb59fe938..23128039ce 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -96,7 +96,7 @@ static size_t s_state_writes_in_queue; static std::condition_variable s_state_write_queue_is_empty; // Don't forget to increase this after doing changes on the savestate system -constexpr u32 STATE_VERSION = 159; // Last changed in PR 11640 +constexpr u32 STATE_VERSION = 160; // Last changed in PR 11644 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,