From 349b73acec6237806088445b045af73a04206b8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Mar 2023 17:19:57 +0100 Subject: [PATCH] Move the resampler usage to a common file, AudioCommon. (#17176) * Move the resampler usage to a common file, AudioCommon. Ports that don't want to use the resampler can now simply exclude that file and provide their own implementation. Next up, libretro will be converted to do it that way. * Android.mk typo * libretro makefile fix * libretro buildfix * libretro: try a different approach for the temporary solution * duh * double duh --- CMakeLists.txt | 7 ++++ Common/System/System.h | 12 +++++++ Core/HLE/__sceAudio.cpp | 54 ++++++------------------------- Core/HLE/__sceAudio.h | 12 +------ Core/HW/StereoResampler.cpp | 4 --- Core/HW/StereoResampler.h | 4 --- UI/AudioCommon.cpp | 31 ++++++++++++++++++ UI/AudioCommon.h | 5 +++ UI/BackgroundAudio.cpp | 5 +-- UI/EmuScreen.cpp | 2 +- UI/NativeApp.cpp | 1 + UI/UI.vcxproj | 2 ++ UI/UI.vcxproj.filters | 2 ++ UWP/UI_UWP/UI_UWP.vcxproj | 2 ++ UWP/UI_UWP/UI_UWP.vcxproj.filters | 2 ++ android/jni/Android.mk | 1 + headless/Headless.cpp | 3 ++ libretro/libretro.cpp | 42 +++++++++++++++++++++--- unittest/UnitTest.cpp | 3 ++ 19 files changed, 123 insertions(+), 71 deletions(-) create mode 100644 UI/AudioCommon.cpp create mode 100644 UI/AudioCommon.h 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() {