diff --git a/CMakeLists.txt b/CMakeLists.txt index e1c826ce24..c8f58a7653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1293,6 +1293,13 @@ if(WIN32) target_link_libraries(Common winmm d3d9 dsound) endif() +if(NOT LIBRETRO) + list(APPEND NativeAppSource + UI/AudioCommon.h + UI/AudioCommon.cpp + ) +endif() + list(APPEND NativeAppSource android/jni/TestRunner.cpp UI/DiscordIntegration.cpp diff --git a/Common/System/System.h b/Common/System/System.h index 795493ae44..71bcb1cb71 100644 --- a/Common/System/System.h +++ b/Common/System/System.h @@ -191,5 +191,17 @@ bool System_GetPropertyBool(SystemProperty prop); void System_Notify(SystemNotification notification); std::vector System_GetCameraDeviceList(); + bool System_AudioRecordingIsAvailable(); bool System_AudioRecordingState(); + +// For these functions, most platforms will use the implementation provided in UI/AudioCommon.cpp, +// no need to implement separately. +void System_AudioGetDebugStats(char *buf, size_t bufSize); +void System_AudioClear(); +// These samples really have 16 bits of value, but can be a little out of range. +void System_AudioPushSamples(const int32_t *audio, int numSamples); + +inline void System_AudioResetStatCounters() { + return System_AudioGetDebugStats(nullptr, 0); +} diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index 0b2b66e0ce..f757465a32 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -23,6 +23,7 @@ #include "Common/Serialize/Serializer.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/Data/Collections/FixedSizeQueue.h" +#include "Common/System/System.h" #ifdef _M_SSE #include @@ -44,38 +45,8 @@ #include "Core/HLE/sceAudio.h" #include "Core/HLE/sceKernel.h" #include "Core/HLE/sceKernelThread.h" -#include "Core/HW/StereoResampler.h" #include "Core/Util/AudioFormat.h" -StereoResampler resampler; - -// numFrames is number of stereo frames. -// This is called from *outside* the emulator thread. -int __AudioMix(short *outstereo, int numFrames, int sampleRate) { - return resampler.Mix(outstereo, numFrames, false, sampleRate); -} - -void __AudioGetDebugStats(char *buf, size_t bufSize) { - resampler.GetAudioDebugStats(buf, bufSize); -} - -void __AudioClear() { - resampler.Clear(); -} - -void __AudioPushSamples(const s32 *audio, int numSamples) { - if (audio) { - resampler.PushSamples(audio, numSamples); - } else { - resampler.Clear(); - } -} - -void __AudioResetStatCounters() { - resampler.ResetStatCounters(); -} - - // Should be used to lock anything related to the outAudioQueue. // atomic locks are used on the lock. TODO: make this lock-free std::atomic_flag atomicLock_; @@ -92,7 +63,6 @@ int srcFrequency = 0; const int hwSampleRate = 44100; const int hwBlockSize = 64; -const int hostAttemptBlockSize = 512; static int audioIntervalCycles; static int audioHostIntervalCycles; @@ -109,11 +79,6 @@ static bool m_logAudio; static int chanQueueMaxSizeFactor; static int chanQueueMinSizeFactor; -// Accessor for libretro -int __AudioGetHostAttemptBlockSize() { - return hostAttemptBlockSize; -} - static void hleAudioUpdate(u64 userdata, int cyclesLate) { // Schedule the next cycle first. __AudioUpdate() may consume cycles. CoreTiming::ScheduleEvent(audioIntervalCycles - cyclesLate, eventAudioUpdate, 0); @@ -131,12 +96,13 @@ static void hleHostAudioUpdate(u64 userdata, int cyclesLate) { static void __AudioCPUMHzChange() { audioIntervalCycles = (int)(usToCycles(1000000ULL) * hwBlockSize / hwSampleRate); - audioHostIntervalCycles = (int)(usToCycles(1000000ULL) * hostAttemptBlockSize / hwSampleRate); + + // Soon to be removed. + audioHostIntervalCycles = (int)(usToCycles(1000000ULL) * 512 / hwSampleRate); } - void __AudioInit() { - __AudioResetStatCounters(); + System_AudioResetStatCounters(); mixFrequency = 44100; srcFrequency = 0; @@ -159,7 +125,7 @@ void __AudioInit() { clampedMixBuffer = new s16[hwBlockSize * 2]; memset(mixBuffer, 0, hwBlockSize * 2 * sizeof(s32)); - __AudioClear(); + System_AudioClear(); CoreTiming::RegisterMHzChangeCallback(&__AudioCPUMHzChange); } @@ -184,16 +150,16 @@ void __AudioDoState(PointerWrap &p) { if (s >= 2) { // TODO: Next time we bump, get rid of this. It's kinda useless. - StereoResampler::DoState(p); + auto s = p.Section("resampler", 1); if (p.mode == p.MODE_READ) { - __AudioClear(); + System_AudioClear(); } } else { // Only to preserve the previous file format. Might cause a slight audio glitch on upgrades? FixedSizeQueue outAudioQueue; outAudioQueue.DoState(p); - __AudioClear(); + System_AudioClear(); } int chanCount = ARRAY_SIZE(chans); @@ -455,7 +421,7 @@ void __AudioUpdate(bool resetRecording) { } if (g_Config.bEnableSound) { - __AudioPushSamples(mixBuffer, hwBlockSize); + System_AudioPushSamples(mixBuffer, hwBlockSize); #ifndef MOBILE_DEVICE if (g_Config.bSaveLoadResetsAVdumping && resetRecording) { __StopLogAudio(); diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index 380f2efdea..d757e1d8bd 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -46,21 +46,11 @@ u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking); void __AudioWakeThreads(AudioChannel &chan, int result, int step); void __AudioWakeThreads(AudioChannel &chan, int result); -// Resampler API, to be extracted -int __AudioMix(short *outstereo, int numSamples, int sampleRate); -void __AudioGetDebugStats(char *buf, size_t bufSize); -void __AudioClear(); -void __AudioPushSamples(const s32 *audio, int numSamples); // Should not be used in-game, only at the menu! -void __AudioResetStatCounters(); - -int __AudioGetHostAttemptBlockSize(); - // Audio Dumping stuff void __StartLogAudio(const Path &filename); void __StopLogAudio(); -class WAVDump -{ +class WAVDump { public: static void Reset(); }; diff --git a/Core/HW/StereoResampler.cpp b/Core/HW/StereoResampler.cpp index f33f2bc1aa..6abf607eda 100644 --- a/Core/HW/StereoResampler.cpp +++ b/Core/HW/StereoResampler.cpp @@ -343,7 +343,3 @@ void StereoResampler::ResetStatCounters() { outputSampleCount_ = 0; startTime_ = time_now_d(); } - -void StereoResampler::DoState(PointerWrap &p) { - auto s = p.Section("resampler", 1); -} diff --git a/Core/HW/StereoResampler.h b/Core/HW/StereoResampler.h index 13cdb1a2b1..071d7337f7 100644 --- a/Core/HW/StereoResampler.h +++ b/Core/HW/StereoResampler.h @@ -22,7 +22,6 @@ #include #include -#include "Common/Serialize/Serializer.h" #include "Common/CommonTypes.h" struct AudioDebugStats; @@ -41,9 +40,6 @@ public: void Clear(); - // TODO: Get rid of this. - static void DoState(PointerWrap &p); - void GetAudioDebugStats(char *buf, size_t bufSize); void ResetStatCounters(); diff --git a/UI/AudioCommon.cpp b/UI/AudioCommon.cpp new file mode 100644 index 0000000000..a06d0a4469 --- /dev/null +++ b/UI/AudioCommon.cpp @@ -0,0 +1,31 @@ +#include "Common/System/System.h" +#include "Core/HW/StereoResampler.h" // TODO: doesn't belong in Core/HW... +#include "UI/AudioCommon.h" + +StereoResampler g_resampler; + +// numFrames is number of stereo frames. +// This is called from *outside* the emulator thread. +int __AudioMix(int16_t *outstereo, int numFrames, int sampleRate) { + return g_resampler.Mix(outstereo, numFrames, false, sampleRate); +} + +void System_AudioGetDebugStats(char *buf, size_t bufSize) { + if (buf) { + g_resampler.GetAudioDebugStats(buf, bufSize); + } else { + g_resampler.ResetStatCounters(); + } +} + +void System_AudioClear() { + g_resampler.Clear(); +} + +void System_AudioPushSamples(const s32 *audio, int numSamples) { + if (audio) { + g_resampler.PushSamples(audio, numSamples); + } else { + g_resampler.Clear(); + } +} diff --git a/UI/AudioCommon.h b/UI/AudioCommon.h new file mode 100644 index 0000000000..ff2c1a03b9 --- /dev/null +++ b/UI/AudioCommon.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +int __AudioMix(int16_t *outstereo, int numFrames, int sampleRate); diff --git a/UI/BackgroundAudio.cpp b/UI/BackgroundAudio.cpp index 49284a2af4..bc3fc19e0c 100644 --- a/UI/BackgroundAudio.cpp +++ b/UI/BackgroundAudio.cpp @@ -7,6 +7,7 @@ #include "Common/CommonTypes.h" #include "Common/Data/Format/RIFF.h" #include "Common/Log.h" +#include "Common/System/System.h" #include "Common/Serialize/SerializeFuncs.h" #include "Common/TimeUtil.h" #include "Common/Data/Collections/FixedSizeQueue.h" @@ -344,7 +345,7 @@ bool BackgroundAudio::Play() { // Immediately stop the sound if it is turned off while playing. if (!g_Config.bEnableSound) { Clear(true); - __AudioClear(); + System_AudioClear(); return true; } @@ -393,7 +394,7 @@ bool BackgroundAudio::Play() { } } - __AudioPushSamples(buffer, sz); + System_AudioPushSamples(buffer, sz); if (at3Reader_ && fadingOut_ && volume_ <= 0.0f) { Clear(true); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 19b17a7a46..41f92282c5 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1266,7 +1266,7 @@ Invalid / Unknown (%d) static void DrawAudioDebugStats(UIContext *ctx, const Bounds &bounds) { FontID ubuntu24("UBUNTU24"); char statbuf[4096] = { 0 }; - __AudioGetDebugStats(statbuf, sizeof(statbuf)); + System_AudioGetDebugStats(statbuf, sizeof(statbuf)); ctx->Flush(); ctx->BindFontTexture(); diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index a43a72f22a..6cc4b029e5 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -106,6 +106,7 @@ #include "Core/ThreadPools.h" #include "GPU/GPUInterface.h" +#include "UI/AudioCommon.h" #include "UI/BackgroundAudio.h" #include "UI/ControlMappingScreen.h" #include "UI/DiscordIntegration.h" diff --git a/UI/UI.vcxproj b/UI/UI.vcxproj index f4c85a7185..1e3e4da897 100644 --- a/UI/UI.vcxproj +++ b/UI/UI.vcxproj @@ -61,6 +61,7 @@ + @@ -68,6 +69,7 @@ + diff --git a/UI/UI.vcxproj.filters b/UI/UI.vcxproj.filters index 2a80b85da1..a8cacd92f9 100644 --- a/UI/UI.vcxproj.filters +++ b/UI/UI.vcxproj.filters @@ -82,6 +82,7 @@ Views + @@ -165,6 +166,7 @@ Views + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj b/UWP/UI_UWP/UI_UWP.vcxproj index 9e892566ca..be821a08ec 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj +++ b/UWP/UI_UWP/UI_UWP.vcxproj @@ -265,6 +265,7 @@ + @@ -300,6 +301,7 @@ + diff --git a/UWP/UI_UWP/UI_UWP.vcxproj.filters b/UWP/UI_UWP/UI_UWP.vcxproj.filters index e88e172b3d..7e97a9da89 100644 --- a/UWP/UI_UWP/UI_UWP.vcxproj.filters +++ b/UWP/UI_UWP/UI_UWP.vcxproj.filters @@ -33,6 +33,7 @@ + @@ -68,5 +69,6 @@ + \ No newline at end of file diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 28775b9b2f..3aef9bcf5a 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -715,6 +715,7 @@ LOCAL_SRC_FILES := \ $(SRC)/android/jni/AndroidVulkanContext.cpp \ $(SRC)/android/jni/AndroidAudio.cpp \ $(SRC)/android/jni/OpenSLContext.cpp \ + $(SRC)/UI/AudioCommon.cpp \ $(SRC)/UI/BackgroundAudio.cpp \ $(SRC)/UI/DiscordIntegration.cpp \ $(SRC)/UI/ChatScreen.cpp \ diff --git a/headless/Headless.cpp b/headless/Headless.cpp index b49eb7b4bc..41bef6df75 100644 --- a/headless/Headless.cpp +++ b/headless/Headless.cpp @@ -119,6 +119,9 @@ bool System_MakeRequest(SystemRequestType type, int requestId, const std::string void System_InputBoxGetString(const std::string &title, const std::string &defaultValue, std::function cb) { cb(false, ""); } void System_AskForPermission(SystemPermission permission) {} PermissionStatus System_GetPermissionStatus(SystemPermission permission) { return PERMISSION_STATUS_GRANTED; } +void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; } +void System_AudioClear() {} +void System_AudioPushSamples(const s32 *audio, int numSamples) {} int printUsage(const char *progname, const char *reason) { diff --git a/libretro/libretro.cpp b/libretro/libretro.cpp index dea29a92a9..453ac93eba 100644 --- a/libretro/libretro.cpp +++ b/libretro/libretro.cpp @@ -32,6 +32,7 @@ #include "Core/HLE/sceUtility.h" #include "Core/HLE/__sceAudio.h" #include "Core/HW/MemoryStick.h" +#include "Core/HW/StereoResampler.h" #include "Core/Host.h" #include "Core/MemMap.h" #include "Core/System.h" @@ -46,6 +47,8 @@ #include "GPU/Common/TextureScalerCommon.h" #include "GPU/Common/PresentationCommon.h" +#include "UI/AudioCommon.h" + #include "libretro/libretro.h" #include "libretro/LibretroGraphicsContext.h" #include "libretro/libretro_core_options.h" @@ -388,11 +391,8 @@ class LibretroHost : public Host LibretroHost() {} void UpdateSound() override { - int hostAttemptBlockSize = __AudioGetHostAttemptBlockSize(); - const int blockSizeMax = 512; - static int16_t audio[blockSizeMax * 2]; - assert(hostAttemptBlockSize <= blockSizeMax); - + const int hostAttemptBlockSize = 512; + static int16_t audio[hostAttemptBlockSize * 2]; int samples = __AudioMix(audio, hostAttemptBlockSize, SAMPLERATE); AudioBufferWrite(audio, samples); } @@ -1881,6 +1881,38 @@ void NativeResized() {} void System_Toast(const char *str) {} + +// Temporary, to keep the old behavior before changing it. + +StereoResampler g_resampler; + +// numFrames is number of stereo frames. +// This is called from *outside* the emulator thread. +int __AudioMix(int16_t *outstereo, int numFrames, int sampleRate) { + return g_resampler.Mix(outstereo, numFrames, false, sampleRate); +} + +void System_AudioGetDebugStats(char *buf, size_t bufSize) { + if (buf) { + g_resampler.GetAudioDebugStats(buf, bufSize); + } else { + g_resampler.ResetStatCounters(); + } +} + +void System_AudioClear() { + g_resampler.Clear(); +} + +void System_AudioPushSamples(const int32_t *audio, int numSamples) { + if (audio) { + g_resampler.PushSamples(audio, numSamples); + } else { + g_resampler.Clear(); + } +} + + #if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS) std::vector System_GetCameraDeviceList() { return std::vector(); } bool System_AudioRecordingIsAvailable() { return false; } diff --git a/unittest/UnitTest.cpp b/unittest/UnitTest.cpp index 89ce7551c8..e89637a185 100644 --- a/unittest/UnitTest.cpp +++ b/unittest/UnitTest.cpp @@ -88,6 +88,9 @@ bool System_GetPropertyBool(SystemProperty prop) { } } void System_Notify(SystemNotification notification) {} +void System_AudioGetDebugStats(char *buf, size_t bufSize) { if (buf) buf[0] = '\0'; } +void System_AudioClear() {} +void System_AudioPushSamples(const s32 *audio, int numSamples) {} #if PPSSPP_PLATFORM(ANDROID) JNIEnv *getEnv() {