diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerX64.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerX64.cpp index a30295b5..97b2c14c 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerX64.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompilerX64.cpp @@ -114,13 +114,13 @@ void* ATTR_MS_ABI PPCRecompiler_virtualHLE(PPCInterpreter_t* hCPU, uint32 hleFun void ATTR_MS_ABI PPCRecompiler_getTBL(PPCInterpreter_t* hCPU, uint32 gprIndex) { - uint64 coreTime = coreinit::coreinit_getTimerTick(); + uint64 coreTime = coreinit::OSGetSystemTime(); hCPU->gpr[gprIndex] = (uint32)(coreTime&0xFFFFFFFF); } void ATTR_MS_ABI PPCRecompiler_getTBU(PPCInterpreter_t* hCPU, uint32 gprIndex) { - uint64 coreTime = coreinit::coreinit_getTimerTick(); + uint64 coreTime = coreinit::OSGetSystemTime(); hCPU->gpr[gprIndex] = (uint32)((coreTime>>32)&0xFFFFFFFF); } diff --git a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp index a8f81901..f592cc9e 100644 --- a/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp +++ b/src/Cafe/HW/Latte/Core/LatteCommandProcessor.cpp @@ -799,7 +799,7 @@ LatteCMDPtr LatteCP_itHLESampleTimer(LatteCMDPtr cmd, uint32 nWords) { cemu_assert_debug(nWords == 1); MPTR timerMPTR = (MPTR)LatteReadCMD(); - memory_writeU64(timerMPTR, coreinit::coreinit_getTimerTick()); + memory_writeU64(timerMPTR, coreinit::OSGetSystemTime()); return cmd; } diff --git a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp index 0d427e34..86035973 100644 --- a/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp +++ b/src/Cafe/HW/Latte/Core/LatteShaderCache.cpp @@ -209,7 +209,7 @@ class BootSoundPlayer try { - bootSndAudioDev = IAudioAPI::CreateDeviceFromConfig(true, sampleRate, nChannels, samplesPerBlock, bitsPerSample); + bootSndAudioDev = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::TV, sampleRate, nChannels, samplesPerBlock, bitsPerSample); if(!bootSndAudioDev) return; } diff --git a/src/Cafe/IOSU/legacy/iosu_acp.cpp b/src/Cafe/IOSU/legacy/iosu_acp.cpp index f5144ee6..6a9e6b89 100644 --- a/src/Cafe/IOSU/legacy/iosu_acp.cpp +++ b/src/Cafe/IOSU/legacy/iosu_acp.cpp @@ -469,7 +469,7 @@ namespace iosu entry->ukn0C = 0; entry->sizeA = _swapEndianU64(0); // ukn entry->sizeB = _swapEndianU64(dirSize); - entry->time = _swapEndianU64((coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK)); + entry->time = _swapEndianU64((coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK)); sprintf(entry->path, "%susr/save/%08x/%08x/meta/", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF)); count++; } @@ -504,7 +504,7 @@ namespace iosu entry->ukn0C = 0; entry->sizeA = _swapEndianU64(0); entry->sizeB = _swapEndianU64(0); - entry->time = _swapEndianU64((coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK)); + entry->time = _swapEndianU64((coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK)); sprintf(entry->path, "%susr/save/%08x/%08x/meta/", devicePath, (uint32)(titleId >> 32), (uint32)(titleId & 0xFFFFFFFF)); count++; } @@ -584,7 +584,7 @@ namespace iosu uint64 _ACPGetTimestamp() { - return coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK; + return coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK; } nnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType) diff --git a/src/Cafe/OS/libs/camera/camera.cpp b/src/Cafe/OS/libs/camera/camera.cpp index 03e01bfc..efb8013d 100644 --- a/src/Cafe/OS/libs/camera/camera.cpp +++ b/src/Cafe/OS/libs/camera/camera.cpp @@ -186,7 +186,7 @@ namespace camera if (g_cameraCounter == 0) { coreinit::OSCreateAlarm(g_alarm_camera.GetPtr()); - coreinit::OSSetPeriodicAlarm(g_alarm_camera.GetPtr(), coreinit::coreinit_getOSTime(), (uint64)ESPRESSO_TIMER_CLOCK / 60ull, RPLLoader_MakePPCCallable(ppcCAMUpdate60)); + coreinit::OSSetPeriodicAlarm(g_alarm_camera.GetPtr(), coreinit::OSGetTime(), (uint64)ESPRESSO_TIMER_CLOCK / 60ull, RPLLoader_MakePPCCallable(ppcCAMUpdate60)); } g_cameraCounter++; diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp index f7e58115..ae2d1e63 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Alarm.cpp @@ -166,7 +166,7 @@ namespace coreinit void alarm_update() { cemu_assert_debug(!__OSHasSchedulerLock()); - uint64 currentTick = coreinit::coreinit_getOSTime(); + uint64 currentTick = coreinit::OSGetTime(); if (!OSHostAlarm::quickCheckForAlarm(currentTick)) return; __OSLockScheduler(); @@ -233,7 +233,7 @@ namespace coreinit if (period == 0) return; - uint64 currentTime = coreinit_getOSTime(); + uint64 currentTime = OSGetTime(); uint64 ticksSinceStart = currentTime - startTime; uint64 numPeriods = ticksSinceStart / period; @@ -267,7 +267,7 @@ namespace coreinit void OSSetAlarm(OSAlarm_t* alarm, uint64 delayInTicks, MPTR handlerFunc) { __OSLockScheduler(); - __OSInitiateAlarm(alarm, coreinit_getOSTime() + delayInTicks, 0, handlerFunc, false); + __OSInitiateAlarm(alarm, OSGetTime() + delayInTicks, 0, handlerFunc, false); __OSUnlockScheduler(); } @@ -310,7 +310,7 @@ namespace coreinit while( true ) { OSWaitEvent(g_alarmEvent.GetPtr()); - uint64 currentTick = coreinit_getOSTime(); + uint64 currentTick = OSGetTime(); while (true) { // get alarm to fire diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp index 5201d441..3d235107 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Spinlock.cpp @@ -86,11 +86,11 @@ namespace coreinit else { // loop until lock acquired or timeout occurred - uint64 timeoutValue = coreinit_getTimerTick() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout); + uint64 timeoutValue = OSGetSystemTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout); while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread)) { OSYieldThread(); - if (coreinit_getTimerTick() >= timeoutValue) + if (OSGetSystemTime() >= timeoutValue) { return false; } @@ -182,11 +182,11 @@ namespace coreinit else { // loop until lock acquired or timeout occurred - uint64 timeoutValue = coreinit_getTimerTick() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout); + uint64 timeoutValue = OSGetSystemTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout); while (!spinlock->ownerThread.atomic_compare_exchange(nullptr, currentThread)) { OSYieldThread(); - if (coreinit_getTimerTick() >= timeoutValue) + if (OSGetSystemTime() >= timeoutValue) { return false; } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp index c144c384..e81cc577 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Synchronization.cpp @@ -73,8 +73,6 @@ namespace coreinit } } - uint64 coreinit_getOSTime(); - bool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout) { __OSLockScheduler(); @@ -95,14 +93,14 @@ namespace coreinit // workaround for a bad implementation in some Unity games (like Qube Directors Cut, see FEventWiiU::Wait) // where the the return value of OSWaitEventWithTimeout is ignored and instead the game measures the elapsed time to determine if a timeout occurred - timeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout) + if (timeout < 0x00FFFFFFFFFFFFFFULL) + timeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout) WaitEventWithTimeoutData data; data.thread = OSGetCurrentThread(); data.threadQueue = &event->threadQueue; data.hasTimeout = false; - - auto hostAlarm = coreinit::OSHostAlarmCreate(coreinit::coreinit_getOSTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data); + auto hostAlarm = coreinit::OSHostAlarmCreate(OSGetTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data); event->threadQueue.queueAndWait(OSGetCurrentThread()); coreinit::OSHostAlarmDestroy(hostAlarm); if (data.hasTimeout) diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp index db457047..870d1850 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp @@ -655,7 +655,7 @@ namespace coreinit StackAllocator _threadQueue; OSInitThreadQueue(_threadQueue.GetPointer()); __OSLockScheduler(); - OSHostAlarm* hostAlarm = OSHostAlarmCreate(coreinit_getOSTime() + ticks, 0, _OSSleepTicks_alarmHandler, _threadQueue.GetPointer()); + OSHostAlarm* hostAlarm = OSHostAlarmCreate(OSGetTime() + ticks, 0, _OSSleepTicks_alarmHandler, _threadQueue.GetPointer()); _threadQueue.GetPointer()->queueAndWait(OSGetCurrentThread()); OSHostAlarmDestroy(hostAlarm); __OSUnlockScheduler(); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Time.cpp b/src/Cafe/OS/libs/coreinit/coreinit_Time.cpp index d6fc27b2..50a404f4 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Time.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_Time.cpp @@ -3,38 +3,32 @@ namespace coreinit { - - uint64 coreinit_getTimerTick() + uint64 coreinit_GetMFTB() { // bus clock is 1/5th of core clock // timer clock is 1/4th of bus clock return PPCInterpreter_getMainCoreCycleCounter() / 20ULL; } - uint64 coreinit_getOSTime() + uint64 OSGetSystemTime() { - return coreinit_getTimerTick() + ppcCyclesSince2000TimerClock; - } - - void export_OSGetTick(PPCInterpreter_t* hCPU) - { - uint64 osTime = coreinit_getOSTime(); - osLib_returnFromFunction(hCPU, (uint32)osTime); + return coreinit_GetMFTB(); } uint64 OSGetTime() { - return coreinit_getOSTime(); + return OSGetSystemTime() + ppcCyclesSince2000TimerClock; } - void export_OSGetSystemTime(PPCInterpreter_t* hCPU) + uint32 OSGetSystemTick() { - osLib_returnFromFunction64(hCPU, coreinit_getTimerTick()); + return static_cast(coreinit_GetMFTB()); } - void export_OSGetSystemTick(PPCInterpreter_t* hCPU) + uint32 OSGetTick() { - osLib_returnFromFunction(hCPU, (uint32)coreinit_getTimerTick()); + uint64 osTime = OSGetTime(); + return static_cast(osTime); } uint32 getLeapDaysUntilYear(uint32 year) @@ -360,14 +354,13 @@ namespace coreinit void InitializeTimeAndCalendar() { cafeExportRegister("coreinit", OSGetTime, LogType::Placeholder); - osLib_addFunction("coreinit", "OSGetSystemTime", export_OSGetSystemTime); - osLib_addFunction("coreinit", "OSGetTick", export_OSGetTick); - osLib_addFunction("coreinit", "OSGetSystemTick", export_OSGetSystemTick); + cafeExportRegister("coreinit", OSGetSystemTime, LogType::Placeholder); + cafeExportRegister("coreinit", OSGetTick, LogType::Placeholder); + cafeExportRegister("coreinit", OSGetSystemTick, LogType::Placeholder); cafeExportRegister("coreinit", OSTicksToCalendarTime, LogType::Placeholder); cafeExportRegister("coreinit", OSCalendarTimeToTicks, LogType::Placeholder); - //timeTest(); } }; \ No newline at end of file diff --git a/src/Cafe/OS/libs/coreinit/coreinit_Time.h b/src/Cafe/OS/libs/coreinit/coreinit_Time.h index 3aa92b99..380ccf1d 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_Time.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_Time.h @@ -40,25 +40,21 @@ namespace coreinit inline TimerTicks ConvertNsToTimerTicks(uint64 ns) { - return ((GetTimerClock() / 31250LL) * ((TimerTicks)ns) / 32000LL); + return static_cast((static_cast(GetTimerClock()) / 31250ULL) * (ns) / 32000ULL); } inline TimerTicks ConvertMsToTimerTicks(uint64 ms) { - return (TimerTicks)ms * GetTimerClock() / 1000LL; + return static_cast(ms * static_cast(GetTimerClock()) / 1000ULL); } }; void OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct); + + uint64 OSGetSystemTime(); uint64 OSGetTime(); - - uint64 coreinit_getOSTime(); - uint64 coreinit_getTimerTick(); - - static uint64 OSGetSystemTime() - { - return coreinit_getTimerTick(); - } + uint32 OSGetSystemTick(); + uint32 OSGetTick(); void InitializeTimeAndCalendar(); }; diff --git a/src/Cafe/OS/libs/dmae/dmae.cpp b/src/Cafe/OS/libs/dmae/dmae.cpp index 6b3e8d0d..7c513784 100644 --- a/src/Cafe/OS/libs/dmae/dmae.cpp +++ b/src/Cafe/OS/libs/dmae/dmae.cpp @@ -11,7 +11,7 @@ uint64 dmaeRetiredTimestamp = 0; uint64 dmae_getTimestamp() { - return coreinit::coreinit_getTimerTick(); + return coreinit::OSGetSystemTime(); } void dmae_setRetiredTimestamp(uint64 timestamp) diff --git a/src/Cafe/OS/libs/gx2/GX2.cpp b/src/Cafe/OS/libs/gx2/GX2.cpp index c2ea34a4..593d31fb 100644 --- a/src/Cafe/OS/libs/gx2/GX2.cpp +++ b/src/Cafe/OS/libs/gx2/GX2.cpp @@ -322,7 +322,7 @@ uint64 _prevReturnedGPUTime = 0; uint64 Latte_GetTime() { - uint64 gpuTime = coreinit::coreinit_getTimerTick(); + uint64 gpuTime = coreinit::OSGetSystemTime(); gpuTime *= 20000ULL; if (gpuTime <= _prevReturnedGPUTime) gpuTime = _prevReturnedGPUTime + 1; // avoid ever returning identical timestamps diff --git a/src/Cafe/OS/libs/gx2/GX2_Misc.cpp b/src/Cafe/OS/libs/gx2/GX2_Misc.cpp index 2111238a..3c7ea3f9 100644 --- a/src/Cafe/OS/libs/gx2/GX2_Misc.cpp +++ b/src/Cafe/OS/libs/gx2/GX2_Misc.cpp @@ -54,7 +54,7 @@ void gx2Export_GX2GetGPUTimeout(PPCInterpreter_t* hCPU) void gx2Export_GX2SampleTopGPUCycle(PPCInterpreter_t* hCPU) { cemuLog_log(LogType::GX2, "GX2SampleTopGPUCycle(0x{:08x})", hCPU->gpr[3]); - memory_writeU64(hCPU->gpr[3], coreinit::coreinit_getTimerTick()); + memory_writeU64(hCPU->gpr[3], coreinit::OSGetSystemTime()); osLib_returnFromFunction(hCPU, 0); } diff --git a/src/Cafe/OS/libs/nn_acp/nn_acp.cpp b/src/Cafe/OS/libs/nn_acp/nn_acp.cpp index 37ea471f..9cde0213 100644 --- a/src/Cafe/OS/libs/nn_acp/nn_acp.cpp +++ b/src/Cafe/OS/libs/nn_acp/nn_acp.cpp @@ -315,7 +315,7 @@ namespace acp ppcDefineParamU32BEPtr(timestamp64, 0); ppcDefineParamU32BEPtr(ukn, 1); // probably timezone or offset? Could also be a bool for success/failed - uint64 t = coreinit::coreinit_getOSTime() + (uint64)((sint64)(ppcCyclesSince2000_UTC - ppcCyclesSince2000) / 20LL); + uint64 t = coreinit::OSGetTime() + (uint64)((sint64)(ppcCyclesSince2000_UTC - ppcCyclesSince2000) / 20LL); timestamp64[0] = (uint32)(t >> 32); timestamp64[1] = (uint32)(t & 0xFFFFFFFF); diff --git a/src/Cafe/OS/libs/nsyshid/Skylander.cpp b/src/Cafe/OS/libs/nsyshid/Skylander.cpp index 9fab17b6..78337962 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,26 @@ namespace nsyshid Device::WriteResult SkylanderPortalDevice::Write(WriteMessage* message) { + if (message->length != 64) { + cemu_assert_error(); + } + + if (!g_portalAudio) + { + // 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::CreateDeviceFromConfig(IAudioAPI::AudioType::Portal, 8000, 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 +626,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 +650,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/padscore/padscore.cpp b/src/Cafe/OS/libs/padscore/padscore.cpp index 0a577b97..2f359748 100644 --- a/src/Cafe/OS/libs/padscore/padscore.cpp +++ b/src/Cafe/OS/libs/padscore/padscore.cpp @@ -760,7 +760,7 @@ namespace padscore void start() { OSCreateAlarm(&g_padscore.alarm); - const uint64 start_tick = coreinit::coreinit_getOSTime(); + const uint64 start_tick = coreinit::OSGetTime(); const uint64 period_tick = coreinit::EspressoTime::GetTimerClock() / 200; // every 5ms MPTR handler = PPCInterpreter_makeCallableExportDepr(TickFunction); OSSetPeriodicAlarm(&g_padscore.alarm, start_tick, period_tick, handler); diff --git a/src/Cafe/OS/libs/snd_core/ax_out.cpp b/src/Cafe/OS/libs/snd_core/ax_out.cpp index a88807f2..fe32cfb4 100644 --- a/src/Cafe/OS/libs/snd_core/ax_out.cpp +++ b/src/Cafe/OS/libs/snd_core/ax_out.cpp @@ -404,7 +404,7 @@ namespace snd_core { try { - g_tvAudio = IAudioAPI::CreateDeviceFromConfig(true, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); + g_tvAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::TV, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); } catch (std::runtime_error& ex) { @@ -417,7 +417,7 @@ namespace snd_core { try { - g_padAudio = IAudioAPI::CreateDeviceFromConfig(false, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); + g_padAudio = IAudioAPI::CreateDeviceFromConfig(IAudioAPI::AudioType::Gamepad, 48000, snd_core::AX_SAMPLES_PER_3MS_48KHZ * AX_FRAMES_PER_GROUP, 16); if(g_padAudio) g_padVolume = g_padAudio->GetVolume(); } @@ -442,6 +442,11 @@ namespace snd_core g_padAudio->Stop(); g_padAudio.reset(); } + if (g_portalAudio) + { + g_portalAudio->Stop(); + g_portalAudio.reset(); + } } void AXOut_updateDevicePlayState(bool isPlaying) @@ -462,6 +467,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/Cafe/OS/libs/vpad/vpad.cpp b/src/Cafe/OS/libs/vpad/vpad.cpp index ded4304d..21c1c9e5 100644 --- a/src/Cafe/OS/libs/vpad/vpad.cpp +++ b/src/Cafe/OS/libs/vpad/vpad.cpp @@ -267,7 +267,7 @@ namespace vpad { if (channel <= 1 && vpadDelayEnabled) { - uint64 currentTime = coreinit::coreinit_getOSTime(); + uint64 currentTime = coreinit::OSGetTime(); const auto dif = currentTime - vpad::g_vpad.controller_data[channel].drcLastCallTime; if (dif <= (ESPRESSO_TIMER_CLOCK / 60ull)) { @@ -1149,7 +1149,7 @@ namespace vpad void start() { coreinit::OSCreateAlarm(&g_vpad.alarm); - const uint64 start_tick = coreinit::coreinit_getOSTime(); + const uint64 start_tick = coreinit::OSGetTime(); const uint64 period_tick = coreinit::EspressoTime::GetTimerClock() * 5 / 1000; const MPTR handler = PPCInterpreter_makeCallableExportDepr(TickFunction); coreinit::OSSetPeriodicAlarm(&g_vpad.alarm, start_tick, period_tick, handler); diff --git a/src/audio/IAudioAPI.cpp b/src/audio/IAudioAPI.cpp index 587526ab..c8b66b6d 100644 --- a/src/audio/IAudioAPI.cpp +++ b/src/audio/IAudioAPI.cpp @@ -13,13 +13,14 @@ 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; std::array IAudioAPI::s_availableApis{}; IAudioAPI::IAudioAPI(uint32 samplerate, uint32 channels, uint32 samples_per_block, uint32 bits_per_sample) - : m_samplerate(samplerate), m_channels(channels), m_samplesPerBlock(samples_per_block), m_bitsPerSample(bits_per_sample) + : m_samplerate(samplerate), m_channels(channels), m_samplesPerBlock(samples_per_block), m_bitsPerSample(bits_per_sample) { m_bytesPerBlock = samples_per_block * channels * (bits_per_sample / 8); InitWFX(m_samplerate, m_channels, m_bitsPerSample); @@ -80,7 +81,7 @@ void IAudioAPI::InitializeStatic() #if BOOST_OS_WINDOWS s_availableApis[DirectSound] = true; s_availableApis[XAudio2] = XAudio2API::InitializeStatic(); - if(!s_availableApis[XAudio2]) // don't try to initialize the older lib if the newer version is available + if (!s_availableApis[XAudio2]) // don't try to initialize the older lib if the newer version is available s_availableApis[XAudio27] = XAudio27API::InitializeStatic(); #endif #if HAS_CUBEB @@ -97,30 +98,29 @@ bool IAudioAPI::IsAudioAPIAvailable(AudioAPI api) return false; } -AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(bool TV, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample) +AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample) { - auto& config = GetConfig(); - sint32 channels = CemuConfig::AudioChannelsToNChannels(TV ? config.tv_channels : config.pad_channels); + sint32 channels = CemuConfig::AudioChannelsToNChannels(AudioTypeToChannels(type)); return CreateDeviceFromConfig(TV, rate, channels, samples_per_block, bits_per_sample); } -AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(bool TV, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample) +AudioAPIPtr IAudioAPI::CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample) { AudioAPIPtr audioAPIDev; auto& config = GetConfig(); const auto audio_api = (IAudioAPI::AudioAPI)config.audio_api; - auto& selectedDevice = TV ? config.tv_device : config.pad_device; + auto selectedDevice = GetDeviceFromType(type); - if(selectedDevice.empty()) + if (selectedDevice.empty()) return {}; 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; }); + 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; } @@ -137,7 +137,7 @@ AudioAPIPtr IAudioAPI::CreateDevice(AudioAPI api, const DeviceDescriptionPtr& de if (!IsAudioAPIAvailable(api)) return {}; - switch(api) + switch (api) { #if BOOST_OS_WINDOWS case DirectSound: @@ -157,11 +157,11 @@ AudioAPIPtr IAudioAPI::CreateDevice(AudioAPI api, const DeviceDescriptionPtr& de } #endif #if HAS_CUBEB - case Cubeb: - { - const auto tmp = std::dynamic_pointer_cast(device); - return std::make_unique(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample); - } + case Cubeb: + { + const auto tmp = std::dynamic_pointer_cast(device); + return std::make_unique(tmp->GetDeviceId(), samplerate, channels, samples_per_block, bits_per_sample); + } #endif default: throw std::runtime_error(fmt::format("invalid audio api: {}", api)); @@ -172,8 +172,8 @@ std::vector IAudioAPI::GetDevices(AudioAPI api) { if (!IsAudioAPIAvailable(api)) return {}; - - switch(api) + + switch (api) { #if BOOST_OS_WINDOWS case DirectSound: @@ -209,3 +209,35 @@ uint32 IAudioAPI::GetAudioDelay() const { return m_audioDelayOverride > 0 ? m_audioDelayOverride : s_audioDelay; } + +AudioChannels IAudioAPI::AudioTypeToChannels(AudioType type) +{ + auto& config = GetConfig(); + switch (type) + { + case TV: + return config.tv_channels; + case Gamepad: + return config.pad_channels; + case Portal: + return config.portal_channels; + default: + return kMono; + } +} + +std::wstring IAudioAPI::GetDeviceFromType(AudioType type) +{ + auto& config = GetConfig(); + switch (type) + { + case TV: + return config.tv_device; + case Gamepad: + return config.pad_device; + case Portal: + return config.portal_device; + default: + return L""; + } +} diff --git a/src/audio/IAudioAPI.h b/src/audio/IAudioAPI.h index 8fb510db..43105370 100644 --- a/src/audio/IAudioAPI.h +++ b/src/audio/IAudioAPI.h @@ -4,6 +4,8 @@ #include #endif +#include "config/CemuConfig.h" + class IAudioAPI { friend class GeneralSettings2; @@ -30,6 +32,13 @@ public: using DeviceDescriptionPtr = std::shared_ptr; + enum AudioType + { + TV = 0, + Gamepad, + Portal + }; + enum AudioAPI { DirectSound = 0, @@ -62,8 +71,8 @@ public: static void InitializeStatic(); static bool IsAudioAPIAvailable(AudioAPI api); - static std::unique_ptr CreateDeviceFromConfig(bool TV, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample); - static std::unique_ptr CreateDeviceFromConfig(bool TV, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample); + static std::unique_ptr CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 samples_per_block, sint32 bits_per_sample); + static std::unique_ptr CreateDeviceFromConfig(AudioType type, sint32 rate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample); static std::unique_ptr CreateDevice(AudioAPI api, const DeviceDescriptionPtr& device, sint32 samplerate, sint32 channels, sint32 samples_per_block, sint32 bits_per_sample); static std::vector GetDevices(AudioAPI api); @@ -84,6 +93,8 @@ protected: private: static uint32 s_audioDelay; void InitWFX(sint32 samplerate, sint32 channels, sint32 bits_per_sample); + static AudioChannels AudioTypeToChannels(AudioType type); + static std::wstring GetDeviceFromType(AudioType type); }; @@ -93,3 +104,5 @@ extern AudioAPIPtr g_tvAudio; extern AudioAPIPtr g_padAudio; extern std::atomic_int32_t g_padVolume; + +extern AudioAPIPtr g_portalAudio; diff --git a/src/config/CemuConfig.cpp b/src/config/CemuConfig.cpp index 6bb7ac34..86f8b478 100644 --- a/src/config/CemuConfig.cpp +++ b/src/config/CemuConfig.cpp @@ -275,9 +275,11 @@ void CemuConfig::Load(XMLConfigParser& parser) tv_channels = audio.get("TVChannels", kStereo); pad_channels = audio.get("PadChannels", kStereo); input_channels = audio.get("InputChannels", kMono); + portal_channels = audio.get("PortalChannels", kMono); tv_volume = audio.get("TVVolume", 20); pad_volume = audio.get("PadVolume", 0); input_volume = audio.get("InputVolume", 20); + portal_volume = audio.get("PortalVolume", 20); const auto tv = audio.get("TVDevice", ""); try @@ -309,6 +311,16 @@ void CemuConfig::Load(XMLConfigParser& parser) cemuLog_log(LogType::Force, "config load error: can't load input device: {}", input_device_name); } + const auto portal_device_name = audio.get("PortalDevice", ""); + try + { + portal_device = boost::nowide::widen(portal_device_name); + } + catch (const std::exception&) + { + cemuLog_log(LogType::Force, "config load error: can't load input device: {}", portal_device_name); + } + // account auto acc = parser.get("Account"); account.m_persistent_id = acc.get("PersistentId", account.m_persistent_id); @@ -508,12 +520,15 @@ void CemuConfig::Save(XMLConfigParser& parser) audio.set("TVChannels", tv_channels); audio.set("PadChannels", pad_channels); audio.set("InputChannels", input_channels); + audio.set("InputChannels", portal_channels); audio.set("TVVolume", tv_volume); audio.set("PadVolume", pad_volume); audio.set("InputVolume", input_volume); + audio.set("PortalVolume", portal_volume); audio.set("TVDevice", boost::nowide::narrow(tv_device).c_str()); audio.set("PadDevice", boost::nowide::narrow(pad_device).c_str()); audio.set("InputDevice", boost::nowide::narrow(input_device).c_str()); + audio.set("PortalDevice", boost::nowide::narrow(portal_device).c_str()); // account auto acc = config.set("Account"); diff --git a/src/config/CemuConfig.h b/src/config/CemuConfig.h index 62665f6d..0696301f 100644 --- a/src/config/CemuConfig.h +++ b/src/config/CemuConfig.h @@ -479,9 +479,9 @@ struct CemuConfig // audio sint32 audio_api = 0; sint32 audio_delay = 2; - AudioChannels tv_channels = kStereo, pad_channels = kStereo, input_channels = kMono; - sint32 tv_volume = 50, pad_volume = 0, input_volume = 50; - std::wstring tv_device{ L"default" }, pad_device, input_device; + AudioChannels tv_channels = kStereo, pad_channels = kStereo, input_channels = kMono, portal_channels = kMono; + sint32 tv_volume = 50, pad_volume = 0, input_volume = 50, portal_volume = 50; + std::wstring tv_device{ L"default" }, pad_device, input_device, portal_device; // account struct diff --git a/src/gui/GeneralSettings2.cpp b/src/gui/GeneralSettings2.cpp index 9b763229..dafa32f8 100644 --- a/src/gui/GeneralSettings2.cpp +++ b/src/gui/GeneralSettings2.cpp @@ -542,6 +542,47 @@ wxPanel* GeneralSettings2::AddAudioPage(wxNotebook* notebook) audio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5); } + { + auto box = new wxStaticBox(audio_panel, wxID_ANY, _("Trap Team Portal")); + auto box_sizer = new wxStaticBoxSizer(box, wxVERTICAL); + + auto portal_audio_row = new wxFlexGridSizer(0, 3, 0, 0); + portal_audio_row->SetFlexibleDirection(wxBOTH); + portal_audio_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + + portal_audio_row->Add(new wxStaticText(box, wxID_ANY, _("Device")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_portal_device = new wxChoice(box, wxID_ANY, wxDefaultPosition); + m_portal_device->SetMinSize(wxSize(300, -1)); + m_portal_device->SetToolTip(_("Select the active audio output device for Wii U GamePad")); + portal_audio_row->Add(m_portal_device, 0, wxEXPAND | wxALL, 5); + portal_audio_row->AddSpacer(0); + + m_portal_device->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioDeviceSelected, this); + + const wxString audio_channel_drc_choices[] = { _("Mono") }; // mono for now only + + portal_audio_row->Add(new wxStaticText(box, wxID_ANY, _("Channels")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_portal_channels = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, std::size(audio_channel_drc_choices), audio_channel_drc_choices); + + m_portal_channels->SetSelection(0); // set default to mono + + m_portal_channels->Bind(wxEVT_CHOICE, &GeneralSettings2::OnAudioChannelsSelected, this); + portal_audio_row->Add(m_portal_channels, 0, wxEXPAND | wxALL, 5); + portal_audio_row->AddSpacer(0); + + portal_audio_row->Add(new wxStaticText(box, wxID_ANY, _("Volume")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); + m_portal_volume = new wxSlider(box, wxID_ANY, 100, 0, 100); + portal_audio_row->Add(m_portal_volume, 0, wxEXPAND | wxALL, 5); + auto audio_pad_volume_text = new wxStaticText(box, wxID_ANY, "100%"); + portal_audio_row->Add(audio_pad_volume_text, 0, wxALIGN_CENTER_VERTICAL | wxALL | wxALIGN_RIGHT, 5); + + m_portal_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnSliderChangedPercent, this, wxID_ANY, wxID_ANY, new wxControlObject(audio_pad_volume_text)); + m_portal_volume->Bind(wxEVT_SLIDER, &GeneralSettings2::OnVolumeChanged, this); + + box_sizer->Add(portal_audio_row, 1, wxEXPAND, 5); + audio_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5); + } + audio_panel->SetSizerAndFit(audio_panel_sizer); return audio_panel; } @@ -989,10 +1030,12 @@ void GeneralSettings2::StoreConfig() config.pad_channels = kStereo; // (AudioChannels)m_pad_channels->GetSelection(); //config.input_channels = (AudioChannels)m_input_channels->GetSelection(); config.input_channels = kMono; // (AudioChannels)m_input_channels->GetSelection(); + config.portal_channels = kMono; // (AudioChannels)m_portal_channels->GetSelection(); config.tv_volume = m_tv_volume->GetValue(); config.pad_volume = m_pad_volume->GetValue(); config.input_volume = m_input_volume->GetValue(); + config.portal_volume = m_portal_volume->GetValue(); config.tv_device.clear(); const auto tv_device = m_tv_device->GetSelection(); @@ -1021,6 +1064,15 @@ void GeneralSettings2::StoreConfig() config.input_device = device_description->GetDescription()->GetIdentifier(); } + config.portal_device.clear(); + const auto portal_device = m_portal_device->GetSelection(); + if (portal_device != wxNOT_FOUND && portal_device != 0 && m_portal_device->HasClientObjectData()) + { + const auto* device_description = (wxDeviceDescription*)m_portal_device->GetClientObject(portal_device); + if (device_description) + config.portal_device = device_description->GetDescription()->GetIdentifier(); + } + // graphics config.graphic_api = (GraphicAPI)m_graphic_api->GetSelection(); @@ -1131,11 +1183,16 @@ void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event) g_padVolume = event.GetInt(); } } - else + else if (event.GetEventObject() == m_tv_volume) { if (g_tvAudio) g_tvAudio->SetVolume(event.GetInt()); } + else + { + if(g_portalAudio) + g_portalAudio->SetVolume(event.GetInt()); + } } @@ -1195,10 +1252,12 @@ void GeneralSettings2::UpdateAudioDeviceList() m_tv_device->Clear(); m_pad_device->Clear(); m_input_device->Clear(); + m_portal_device->Clear(); m_tv_device->Append(_("Disabled")); m_pad_device->Append(_("Disabled")); m_input_device->Append(_("Disabled")); + m_portal_device->Append(_("Disabled")); const auto audio_api = (IAudioAPI::AudioAPI)GetConfig().audio_api; const auto devices = IAudioAPI::GetDevices(audio_api); @@ -1206,6 +1265,7 @@ void GeneralSettings2::UpdateAudioDeviceList() { m_tv_device->Append(device->GetName(), new wxDeviceDescription(device)); m_pad_device->Append(device->GetName(), new wxDeviceDescription(device)); + m_portal_device->Append(device->GetName(), new wxDeviceDescription(device)); } const auto input_audio_api = IAudioInputAPI::Cubeb; //(IAudioAPI::AudioAPI)GetConfig().input_audio_api; @@ -1225,6 +1285,8 @@ void GeneralSettings2::UpdateAudioDeviceList() m_input_device->SetSelection(0); + m_portal_device->SetSelection(0); + // todo reset global instance of audio device } @@ -1658,6 +1720,7 @@ void GeneralSettings2::ApplyConfig() m_pad_channels->SetSelection(0); //m_input_channels->SetSelection(config.pad_channels); m_input_channels->SetSelection(0); + m_portal_channels->SetSelection(0); SendSliderEvent(m_tv_volume, config.tv_volume); @@ -1708,6 +1771,22 @@ void GeneralSettings2::ApplyConfig() else m_input_device->SetSelection(0); + SendSliderEvent(m_portal_volume, config.portal_volume); + if (!config.portal_device.empty() && m_portal_device->HasClientObjectData()) + { + for (uint32 i = 0; i < m_portal_device->GetCount(); ++i) + { + const auto device_description = (wxDeviceDescription*)m_portal_device->GetClientObject(i); + if (device_description && config.portal_device == device_description->GetDescription()->GetIdentifier()) + { + m_portal_device->SetSelection(i); + break; + } + } + } + else + m_portal_device->SetSelection(0); + // account UpdateOnlineAccounts(); m_active_account->SetSelection(0); @@ -1866,6 +1945,42 @@ void GeneralSettings2::UpdateAudioDevice() } } } + + // skylander portal audio device + { + const auto selection = m_portal_device->GetSelection(); + if (selection == wxNOT_FOUND) + { + cemu_assert_debug(false); + return; + } + + g_portalAudio.reset(); + + if (m_portal_device->HasClientObjectData()) + { + const auto description = (wxDeviceDescription*)m_portal_device->GetClientObject(selection); + if (description) + { + sint32 channels; + if (m_game_launched && g_portalAudio) + channels = g_portalAudio->GetChannels(); + else + channels = 1; + + try + { + g_portalAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 8000, 1, 32, 16); + g_portalAudio->SetVolume(m_portal_volume->GetValue()); + } + catch (std::runtime_error& ex) + { + cemuLog_log(LogType::Force, "can't initialize pad audio: {}", ex.what()); + } + } + } + + } } void GeneralSettings2::OnAudioDeviceSelected(wxCommandEvent& event) @@ -1895,6 +2010,13 @@ void GeneralSettings2::OnAudioChannelsSelected(wxCommandEvent& event) config.pad_channels = (AudioChannels)obj->GetSelection(); } + else if (obj == m_portal_channels) + { + if (config.portal_channels == (AudioChannels)obj->GetSelection()) + return; + + config.portal_channels = (AudioChannels)obj->GetSelection(); + } else cemu_assert_debug(false); diff --git a/src/gui/GeneralSettings2.h b/src/gui/GeneralSettings2.h index 7fbfecc1..a37b9c1b 100644 --- a/src/gui/GeneralSettings2.h +++ b/src/gui/GeneralSettings2.h @@ -63,9 +63,9 @@ private: // Audio wxChoice* m_audio_api; wxSlider *m_audio_latency; - wxSlider *m_tv_volume, *m_pad_volume, *m_input_volume; - wxChoice *m_tv_channels, *m_pad_channels, *m_input_channels; - wxChoice *m_tv_device, *m_pad_device, *m_input_device; + wxSlider *m_tv_volume, *m_pad_volume, *m_input_volume, *m_portal_volume; + wxChoice *m_tv_channels, *m_pad_channels, *m_input_channels, *m_portal_channels; + wxChoice *m_tv_device, *m_pad_device, *m_input_device, *m_portal_device; // Account wxButton* m_create_account, * m_delete_account; diff --git a/src/gui/dialogs/SaveImport/SaveImportWindow.cpp b/src/gui/dialogs/SaveImport/SaveImportWindow.cpp index b31f24b2..1b1fecbf 100644 --- a/src/gui/dialogs/SaveImport/SaveImportWindow.cpp +++ b/src/gui/dialogs/SaveImport/SaveImportWindow.cpp @@ -304,7 +304,7 @@ void SaveImportWindow::OnImport(wxCommandEvent& event) auto new_node = info_node.append_child("account"); new_node.append_attribute("persistentId").set_value(new_persistend_id_string.c_str()); auto timestamp = new_node.append_child("timestamp"); - timestamp.text().set(fmt::format("{:016x}", coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK).c_str()); // TODO time not initialized yet? + timestamp.text().set(fmt::format("{:016x}", coreinit::OSGetTime() / ESPRESSO_TIMER_CLOCK).c_str()); // TODO time not initialized yet? if(!doc.save_file(saveinfo.c_str())) cemuLog_log(LogType::Force, "couldn't insert save entry in saveinfo.xml: {}", _pathToUtf8(saveinfo));