From 317e44c25c145f89071d45637f1d01af552d6147 Mon Sep 17 00:00:00 2001 From: Joshua de Reeper Date: Tue, 21 Jan 2025 19:11:39 +0100 Subject: [PATCH] Play portal audio via Cemu output --- src/Cafe/OS/libs/nsyshid/Skylander.cpp | 65 +++++++++++++++++++++----- src/Cafe/OS/libs/snd_core/ax_out.cpp | 8 ++++ src/audio/IAudioAPI.cpp | 1 + src/audio/IAudioAPI.h | 2 + 4 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/Cafe/OS/libs/nsyshid/Skylander.cpp b/src/Cafe/OS/libs/nsyshid/Skylander.cpp index 9fab17b6..74202115 100644 --- a/src/Cafe/OS/libs/nsyshid/Skylander.cpp +++ b/src/Cafe/OS/libs/nsyshid/Skylander.cpp @@ -6,6 +6,8 @@ #include "Backend.h" #include "Common/FileStream.h" +#include "audio/IAudioAPI.h" +#include "config/CemuConfig.h" namespace nsyshid { @@ -558,6 +560,45 @@ namespace nsyshid Device::WriteResult SkylanderPortalDevice::Write(WriteMessage* message) { + if (message->length != 64) { + cemu_assert_error(); + } + + if (!g_portalAudio) + { + auto& config = GetConfig(); + auto& selectedDevice = L"default"; + + const auto audio_api = (IAudioAPI::AudioAPI)config.audio_api; + IAudioAPI::DeviceDescriptionPtr device_description; + if (IAudioAPI::IsAudioAPIAvailable(audio_api)) + { + auto devices = IAudioAPI::GetDevices(audio_api); + const auto it = std::find_if(devices.begin(), devices.end(), [&selectedDevice](const auto& d) { + return d->GetIdentifier() == selectedDevice; + }); + if (it != devices.end()) + { + device_description = *it; + } + } + if (!device_description) + throw std::runtime_error("failed to find selected device while trying to create audio device"); + + // Portal audio is mono channel, 16 bit audio. + // Audio is unsigned 16 bit, supplied as 64 bytes which is 32 samples per block + g_portalAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)GetConfig().audio_api, device_description, 8000, 1, 32, 16); + } + std::array mono_samples; + for (unsigned int i = 0; i < mono_samples.size(); ++i) + { + sint16 sample = static_cast(message->data[i * 2 + 1]) << 8 | static_cast(message->data[i * 2]); + mono_samples[i] = sample; + } + if (g_portalAudio) + { + g_portalAudio->FeedBlock(mono_samples.data()); + } message->bytesWritten = message->length; return Device::WriteResult::Success; } @@ -604,20 +645,20 @@ namespace nsyshid *(uint16be*)(currentWritePtr + 7) = 0x001D; // wDescriptorLength currentWritePtr = currentWritePtr + 9; // endpoint descriptor 1 - *(uint8*)(currentWritePtr + 0) = 7; // bLength - *(uint8*)(currentWritePtr + 1) = 0x05; // bDescriptorType - *(uint8*)(currentWritePtr + 2) = 0x81; // bEndpointAddress - *(uint8*)(currentWritePtr + 3) = 0x03; // bmAttributes + *(uint8*)(currentWritePtr + 0) = 7; // bLength + *(uint8*)(currentWritePtr + 1) = 0x05; // bDescriptorType + *(uint8*)(currentWritePtr + 2) = 0x81; // bEndpointAddress + *(uint8*)(currentWritePtr + 3) = 0x03; // bmAttributes *(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize - *(uint8*)(currentWritePtr + 6) = 0x01; // bInterval + *(uint8*)(currentWritePtr + 6) = 0x01; // bInterval currentWritePtr = currentWritePtr + 7; // endpoint descriptor 2 - *(uint8*)(currentWritePtr + 0) = 7; // bLength - *(uint8*)(currentWritePtr + 1) = 0x05; // bDescriptorType - *(uint8*)(currentWritePtr + 2) = 0x02; // bEndpointAddress - *(uint8*)(currentWritePtr + 3) = 0x03; // bmAttributes + *(uint8*)(currentWritePtr + 0) = 7; // bLength + *(uint8*)(currentWritePtr + 1) = 0x05; // bDescriptorType + *(uint8*)(currentWritePtr + 2) = 0x02; // bEndpointAddress + *(uint8*)(currentWritePtr + 3) = 0x03; // bmAttributes *(uint16be*)(currentWritePtr + 4) = 0x0040; // wMaxPacketSize - *(uint8*)(currentWritePtr + 6) = 0x01; // bInterval + *(uint8*)(currentWritePtr + 6) = 0x01; // bInterval currentWritePtr = currentWritePtr + 7; cemu_assert_debug((currentWritePtr - configurationDescriptor) == 0x29); @@ -628,8 +669,8 @@ namespace nsyshid } bool SkylanderPortalDevice::SetIdle(uint8 ifIndex, - uint8 reportId, - uint8 duration) + uint8 reportId, + uint8 duration) { return true; } diff --git a/src/Cafe/OS/libs/snd_core/ax_out.cpp b/src/Cafe/OS/libs/snd_core/ax_out.cpp index a88807f2..667dcd8d 100644 --- a/src/Cafe/OS/libs/snd_core/ax_out.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_out.cpp @@ -462,6 +462,14 @@ namespace snd_core else g_padAudio->Stop(); } + + if (g_portalAudio) + { + if (isPlaying) + g_portalAudio->Play(); + else + g_portalAudio->Stop(); + } } // called periodically to check for AX updates diff --git a/src/audio/IAudioAPI.cpp b/src/audio/IAudioAPI.cpp index 587526ab..395c9e2a 100644 --- a/src/audio/IAudioAPI.cpp +++ b/src/audio/IAudioAPI.cpp @@ -13,6 +13,7 @@ std::shared_mutex g_audioMutex; AudioAPIPtr g_tvAudio; AudioAPIPtr g_padAudio; +AudioAPIPtr g_portalAudio; std::atomic_int32_t g_padVolume = 0; uint32 IAudioAPI::s_audioDelay = 2; diff --git a/src/audio/IAudioAPI.h b/src/audio/IAudioAPI.h index 8fb510db..796c7fc3 100644 --- a/src/audio/IAudioAPI.h +++ b/src/audio/IAudioAPI.h @@ -93,3 +93,5 @@ extern AudioAPIPtr g_tvAudio; extern AudioAPIPtr g_padAudio; extern std::atomic_int32_t g_padVolume; + +extern AudioAPIPtr g_portalAudio;