From a5fdf3d05b4be04d58095aa12ae5168dbf3e17ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 24 Mar 2023 13:59:27 +0100 Subject: [PATCH] Add samplerate argument to NativeMix --- Common/System/NativeApp.h | 3 +-- Core/HLE/__sceAudio.cpp | 1 + Core/HLE/__sceAudio.h | 3 +++ Qt/QtMain.cpp | 17 +++++++++-------- SDL/SDLMain.cpp | 5 +++-- UI/NativeApp.cpp | 13 +++---------- Windows/DSoundStream.cpp | 2 +- Windows/WASAPIStream.cpp | 8 ++++---- Windows/WindowsAudio.h | 4 ++-- android/jni/AndroidAudio.h | 4 +++- android/jni/OpenSLContext.cpp | 2 +- ios/AudioEngine.mm | 9 +++++---- ios/iOSCoreAudio.mm | 4 ++-- 13 files changed, 38 insertions(+), 37 deletions(-) diff --git a/Common/System/NativeApp.h b/Common/System/NativeApp.h index bb0c7af962..d1286a8d74 100644 --- a/Common/System/NativeApp.h +++ b/Common/System/NativeApp.h @@ -75,8 +75,7 @@ void NativeRender(GraphicsContext *graphicsContext); // the rest of the game, so be careful with synchronization. // Returns the number of samples actually output. The app should do everything it can // to fill the buffer completely. -int NativeMix(short *audio, int num_samples); -void NativeSetMixer(void* mixer); +int NativeMix(short *audio, int num_samples, int sampleRateHz); // Called when it's time to shutdown. After this has been called, // no more calls to any other function will be made from the framework diff --git a/Core/HLE/__sceAudio.cpp b/Core/HLE/__sceAudio.cpp index f05ad9dfca..93966df598 100644 --- a/Core/HLE/__sceAudio.cpp +++ b/Core/HLE/__sceAudio.cpp @@ -482,6 +482,7 @@ void __PushExternalAudio(const s32 *audio, int numSamples) { resampler.Clear(); } } + #ifndef MOBILE_DEVICE void __StartLogAudio(const Path& filename) { if (!m_logAudio) { diff --git a/Core/HLE/__sceAudio.h b/Core/HLE/__sceAudio.h index f26ae0dc77..c4050587f1 100644 --- a/Core/HLE/__sceAudio.h +++ b/Core/HLE/__sceAudio.h @@ -41,6 +41,9 @@ void __AudioShutdown(); void __AudioSetOutputFrequency(int freq); void __AudioSetSRCFrequency(int freq); +typedef void(*AudioUserCallback); +void __AudioSetUserCallback(AudioUserCallback callback); + // May return SCE_ERROR_AUDIO_CHANNEL_BUSY if buffer too large u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking); void __AudioWakeThreads(AudioChannel &chan, int result, int step); diff --git a/Qt/QtMain.cpp b/Qt/QtMain.cpp index 02f2e91fc4..36a15643dc 100644 --- a/Qt/QtMain.cpp +++ b/Qt/QtMain.cpp @@ -54,6 +54,13 @@ #include #include +// Audio +#define AUDIO_FREQ 44100 +#define AUDIO_CHANNELS 2 +#define AUDIO_SAMPLES 2048 +#define AUDIO_SAMPLESIZE 16 +#define AUDIO_BUFFERS 5 + MainUI *emugl = nullptr; static float refreshRate = 60.f; static int browseFileEvent = -1; @@ -69,7 +76,7 @@ SDL_AudioSpec g_retFmt; static SDL_AudioDeviceID audioDev = 0; extern void mixaudio(void *userdata, Uint8 *stream, int len) { - NativeMix((short *)stream, len / 4); + NativeMix((short *)stream, len / 4, AUDIO_FREQ); } static void InitSDLAudioDevice() { @@ -726,12 +733,6 @@ void MainUI::updateAccelerometer() { } #ifndef SDL -// Audio -#define AUDIO_FREQ 44100 -#define AUDIO_CHANNELS 2 -#define AUDIO_SAMPLES 2048 -#define AUDIO_SAMPLESIZE 16 -#define AUDIO_BUFFERS 5 MainAudio::~MainAudio() { if (feed != nullptr) { @@ -770,7 +771,7 @@ void MainAudio::run() { void MainAudio::timerEvent(QTimerEvent *) { memset(mixbuf, 0, mixlen); - size_t frames = NativeMix((short *)mixbuf, AUDIO_BUFFERS*AUDIO_SAMPLES); + size_t frames = NativeMix((short *)mixbuf, AUDIO_BUFFERS*AUDIO_SAMPLES, AUDIO_FREQ); if (frames > 0) feed->write(mixbuf, sizeof(short) * AUDIO_CHANNELS * frames); } diff --git a/SDL/SDLMain.cpp b/SDL/SDLMain.cpp index 8aadab0be5..b9158d7925 100644 --- a/SDL/SDLMain.cpp +++ b/SDL/SDLMain.cpp @@ -74,6 +74,7 @@ static int g_QuitRequested = 0; static int g_DesktopWidth = 0; static int g_DesktopHeight = 0; static float g_RefreshRate = 60.f; +static int g_sampleRate = 44100; static SDL_AudioSpec g_retFmt; @@ -92,7 +93,7 @@ int getDisplayNumber(void) { } void sdl_mixaudio_callback(void *userdata, Uint8 *stream, int len) { - NativeMix((short *)stream, len / (2 * 2)); + NativeMix((short *)stream, len / (2 * 2), g_sampleRate); } static SDL_AudioDeviceID audioDev = 0; @@ -101,7 +102,7 @@ static SDL_AudioDeviceID audioDev = 0; static void InitSDLAudioDevice(const std::string &name = "") { SDL_AudioSpec fmt; memset(&fmt, 0, sizeof(fmt)); - fmt.freq = 44100; + fmt.freq = g_sampleRate; fmt.format = AUDIO_S16; fmt.channels = 2; fmt.samples = 256; diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index daebaccc90..436c38a1c0 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -203,12 +203,6 @@ public: } }; -#ifdef _WIN32 -int Win32Mix(short *buffer, int numSamples, int bits, int rate) { - return NativeMix(buffer, numSamples); -} -#endif - // globals static LogListener *logger = nullptr; Path boot_filename; @@ -235,9 +229,8 @@ std::string NativeQueryConfig(std::string query) { } } -int NativeMix(short *audio, int num_samples) { - int sample_rate = System_GetPropertyInt(SYSPROP_AUDIO_SAMPLE_RATE); - return __AudioMix(audio, num_samples, sample_rate > 0 ? sample_rate : 44100); +int NativeMix(short *audio, int numSamples, int sampleRateHz) { + return __AudioMix(audio, numSamples, sampleRateHz); } // This is called before NativeInit so we do a little bit of initialization here. @@ -859,7 +852,7 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) { #if PPSSPP_PLATFORM(UWP) winAudioBackend->Init(0, &Win32Mix, 44100); #else - winAudioBackend->Init(MainWindow::GetHWND(), &Win32Mix, 44100); + winAudioBackend->Init(MainWindow::GetHWND(), &NativeMix, 44100); #endif #endif diff --git a/Windows/DSoundStream.cpp b/Windows/DSoundStream.cpp index 899897dfbd..9c12d7e346 100644 --- a/Windows/DSoundStream.cpp +++ b/Windows/DSoundStream.cpp @@ -124,7 +124,7 @@ int DSoundAudioBackend::RunThread() { int numBytesToRender = RoundDown128(ModBufferSize(currentPos_ - lastPos_)); if (numBytesToRender >= 256) { - int numBytesRendered = 4 * (*callback_)(realtimeBuffer_, numBytesToRender >> 2, 16, 44100); + int numBytesRendered = 4 * (*callback_)(realtimeBuffer_, numBytesToRender >> 2, 44100); //We need to copy the full buffer, regardless of what the mixer claims to have filled //If we don't do this then the sound will loop if the sound stops and the mixer writes only zeroes numBytesRendered = numBytesToRender; diff --git a/Windows/WASAPIStream.cpp b/Windows/WASAPIStream.cpp index ffc9e7abe6..2844934eb5 100644 --- a/Windows/WASAPIStream.cpp +++ b/Windows/WASAPIStream.cpp @@ -501,11 +501,11 @@ void WASAPIAudioThread::Run() { int chans = deviceFormat_->Format.nChannels; switch (format_) { case Format::IEEE_FLOAT: - callback_(shortBuf_, pNumAvFrames, 16, sampleRate_); + callback_(shortBuf_, pNumAvFrames, sampleRate_); if (chans == 1) { float *ptr = (float *)pData; memset(ptr, 0, pNumAvFrames * chans * sizeof(float)); - for (UINT32 i = 0; i < pNumAvFrames; i++) { + for (uint32_t i = 0; i < pNumAvFrames; i++) { ptr[i * chans + 0] = 0.5f * ((float)shortBuf_[i * 2] + (float)shortBuf_[i * 2 + 1]) * (1.0f / 32768.0f); } } else if (chans == 2) { @@ -513,14 +513,14 @@ void WASAPIAudioThread::Run() { } else if (chans > 2) { float *ptr = (float *)pData; memset(ptr, 0, pNumAvFrames * chans * sizeof(float)); - for (UINT32 i = 0; i < pNumAvFrames; i++) { + for (uint32_t i = 0; i < pNumAvFrames; i++) { ptr[i * chans + 0] = (float)shortBuf_[i * 2] * (1.0f / 32768.0f); ptr[i * chans + 1] = (float)shortBuf_[i * 2 + 1] * (1.0f / 32768.0f); } } break; case Format::PCM16: - callback_((short *)pData, pNumAvFrames, 16, sampleRate_); + callback_((short *)pData, pNumAvFrames, sampleRate_); break; } } diff --git a/Windows/WindowsAudio.h b/Windows/WindowsAudio.h index 18c3899e20..d655529a21 100644 --- a/Windows/WindowsAudio.h +++ b/Windows/WindowsAudio.h @@ -3,8 +3,8 @@ #include "Common/CommonWindows.h" #include "Core/ConfigValues.h" -// Always 2 channels. -typedef int(*StreamCallback)(short *buffer, int numSamples, int bits, int rate); +// Always 2 channels, 16-bit audio. +typedef int (*StreamCallback)(short *buffer, int numSamples, int rate); // Note that the backend may override the passed in sample rate. The actual sample rate // should be returned by GetSampleRate though. diff --git a/android/jni/AndroidAudio.h b/android/jni/AndroidAudio.h index 45fb7f4c8f..50d0a26d28 100644 --- a/android/jni/AndroidAudio.h +++ b/android/jni/AndroidAudio.h @@ -3,7 +3,7 @@ #include #include -typedef int (*AndroidAudioCallback)(short *buffer, int num_samples); +typedef int (*AndroidAudioCallback)(short *buffer, int numSamples, int sampleRateHz); class AudioContext { public: @@ -12,6 +12,8 @@ public: virtual bool AudioRecord_Start(int sampleRate) { return false; }; virtual bool AudioRecord_Stop() { return false; }; + int SampleRate() const { return sampleRate; } + virtual ~AudioContext() {} protected: diff --git a/android/jni/OpenSLContext.cpp b/android/jni/OpenSLContext.cpp index ce568536d7..5a67b71484 100644 --- a/android/jni/OpenSLContext.cpp +++ b/android/jni/OpenSLContext.cpp @@ -50,7 +50,7 @@ void OpenSLContext::BqPlayerCallback(SLAndroidSimpleBufferQueueItf bq) { return; } - int renderedFrames = audioCallback(buffer[curBuffer], framesPerBuffer); + int renderedFrames = audioCallback(buffer[curBuffer], framesPerBuffer, SampleRate()); int sizeInBytes = framesPerBuffer * 2 * sizeof(short); int byteCount = (framesPerBuffer - renderedFrames) * 4; diff --git a/ios/AudioEngine.mm b/ios/AudioEngine.mm index 818e8cbe5e..8090d7a93b 100644 --- a/ios/AudioEngine.mm +++ b/ios/AudioEngine.mm @@ -19,7 +19,7 @@ static volatile BOOL done = 0; #define SAMPLE_SIZE 44100 static short stream[SAMPLE_SIZE]; -int NativeMix(short *audio, int num_samples); +int NativeMix(short *audio, int numSamples, int sampleRateHz); @interface AudioEngine () @@ -120,11 +120,12 @@ int NativeMix(short *audio, int num_samples); - (void)audioLoop { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){ + const int sampleRateHz = 44100; while (!done) { size_t frames_ready; if (![self playing]) - frames_ready = NativeMix(stream, SAMPLE_SIZE / 2); + frames_ready = NativeMix(stream, SAMPLE_SIZE / 2, sampleRateHz); else frames_ready = 0; @@ -132,12 +133,12 @@ int NativeMix(short *audio, int num_samples); { const size_t bytes_ready = frames_ready * sizeof(short) * 2; alSourcei(source, AL_BUFFER, 0); - alBufferData(buffer, AL_FORMAT_STEREO16, stream, bytes_ready, 44100); + alBufferData(buffer, AL_FORMAT_STEREO16, stream, bytes_ready, sampleRateHz); alSourcei(source, AL_BUFFER, buffer); alSourcePlay(source); // TODO: Maybe this could get behind? - usleep((1000000 * frames_ready) / 44100); + usleep((1000000 * frames_ready) / sampleRateHz); } else usleep(100); diff --git a/ios/iOSCoreAudio.mm b/ios/iOSCoreAudio.mm index b4f828f570..8743ab7953 100644 --- a/ios/iOSCoreAudio.mm +++ b/ios/iOSCoreAudio.mm @@ -30,7 +30,7 @@ AudioComponentInstance audioInstance = nil; -int NativeMix(short *audio, int num_samples); +int NativeMix(short *audio, int numSamples, int sampleRate); OSStatus iOSCoreAudioCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, @@ -41,7 +41,7 @@ OSStatus iOSCoreAudioCallback(void *inRefCon, { // see if we have any sound to play short *output = (short *)ioData->mBuffers[0].mData; - UInt32 framesReady = NativeMix(output, inNumberFrames); + UInt32 framesReady = NativeMix(output, inNumberFrames, SAMPLE_RATE); if (framesReady == 0) { // oops, we don't currently have any sound, so return silence