SDL: n3dsaudio: Updated (but untested!) for SDL3 audio API.

https://github.com/libsdl-org/SDL/commit/b0d89868c6855f70ca94bc79f9abcb431b4c3350

From b0d89868c6855f70ca94bc79f9abcb431b4c3350 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 21 Jul 2023 10:55:33 -0400
Subject: [PATCH] n3dsaudio: Updated (but untested!) for SDL3 audio API.

---
 src/audio/n3ds/SDL_n3dsaudio.c | 257 ++++++++++++++-------------------
 src/audio/n3ds/SDL_n3dsaudio.h |   6 -
 2 files changed, 108 insertions(+), 155 deletions(-)

diff --git a/src/audio/n3ds/SDL_n3dsaudio.c b/src/audio/n3ds/SDL_n3dsaudio.c
index 1d0bff66ef7c..e43ad087714c 100644
--- a/src/audio/n3ds/SDL_n3dsaudio.c
+++ b/src/audio/n3ds/SDL_n3dsaudio.c
@@ -22,7 +22,7 @@
 
 #ifdef SDL_AUDIO_DRIVER_N3DS
 
-/* N3DS Audio driver */
+// N3DS Audio driver
 
 #include "../SDL_sysaudio.h"
 #include "SDL_n3dsaudio.h"
@@ -32,27 +32,24 @@
 static dspHookCookie dsp_hook;
 static SDL_AudioDevice *audio_device;
 
-static void FreePrivateData(SDL_AudioDevice *_this);
-static int FindAudioFormat(SDL_AudioDevice *_this);
-
-static SDL_INLINE void contextLock(SDL_AudioDevice *_this)
+static SDL_INLINE void contextLock(SDL_AudioDevice *device)
 {
-    LightLock_Lock(&_this->hidden->lock);
+    LightLock_Lock(&device->hidden->lock);
 }
 
-static SDL_INLINE void contextUnlock(SDL_AudioDevice *_this)
+static SDL_INLINE void contextUnlock(SDL_AudioDevice *device)
 {
-    LightLock_Unlock(&_this->hidden->lock);
+    LightLock_Unlock(&device->hidden->lock);
 }
 
-static void N3DSAUD_LockAudio(SDL_AudioDevice *_this)
+static void N3DSAUD_LockAudio(SDL_AudioDevice *device)
 {
-    contextLock(_this);
+    contextLock(device);
 }
 
-static void N3DSAUD_UnlockAudio(SDL_AudioDevice *_this)
+static void N3DSAUD_UnlockAudio(SDL_AudioDevice *device)
 {
-    contextUnlock(_this);
+    contextUnlock(device);
 }
 
 static void N3DSAUD_DspHook(DSP_HookType hook)
@@ -70,36 +67,36 @@ static void AudioFrameFinished(void *device)
 {
     bool shouldBroadcast = false;
     unsigned i;
-    SDL_AudioDevice *_this = (SDL_AudioDevice *)device;
+    SDL_AudioDevice *device = (SDL_AudioDevice *)device;
 
-    contextLock(_this);
+    contextLock(device);
 
     for (i = 0; i < NUM_BUFFERS; i++) {
-        if (_this->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
-            _this->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
+        if (device->hidden->waveBuf[i].status == NDSP_WBUF_DONE) {
+            device->hidden->waveBuf[i].status = NDSP_WBUF_FREE;
             shouldBroadcast = SDL_TRUE;
         }
     }
 
     if (shouldBroadcast) {
-        CondVar_Broadcast(&_this->hidden->cv);
+        CondVar_Broadcast(&device->hidden->cv);
     }
 
-    contextUnlock(_this);
+    contextUnlock(device);
 }
 
-static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
+static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *device)
 {
     Result ndsp_init_res;
     Uint8 *data_vaddr;
     float mix[12];
-    _this->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*_this->hidden));
 
-    if (_this->hidden == NULL) {
+    device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden));
+    if (device->hidden == NULL) {
         return SDL_OutOfMemory();
     }
 
-    /* Initialise the DSP service */
+    // Initialise the DSP service
     ndsp_init_res = ndspInit();
     if (R_FAILED(ndsp_init_res)) {
         if ((R_SUMMARY(ndsp_init_res) == RS_NOTFOUND) && (R_MODULE(ndsp_init_res) == RM_DSP)) {
@@ -110,158 +107,168 @@ static int N3DSAUDIO_OpenDevice(SDL_AudioDevice *_this, const char *devname)
         return -1;
     }
 
-    /* Initialise internal state */
-    LightLock_Init(&_this->hidden->lock);
-    CondVar_Init(&_this->hidden->cv);
+    // Initialise internal state
+    LightLock_Init(&device->hidden->lock);
+    CondVar_Init(&device->hidden->cv);
 
-    if (_this->spec.channels > 2) {
-        _this->spec.channels = 2;
+    if (device->spec.channels > 2) {
+        device->spec.channels = 2;
     }
 
-    /* Should not happen but better be safe. */
-    if (FindAudioFormat(_this) < 0) {
+    Uint32 format = 0;
+    SDL_AudioFormat test_format;
+    const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format);
+    while ((test_format = *(closefmts++)) != 0) {
+        if (test_format == SDL_AUDIO_S8) {  // Signed 8-bit audio supported
+            format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
+            break;
+        } else if (test_format == SDL_AUDIO_S16) {  // Signed 16-bit audio supported
+            format = (device->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
+            break;
+        }
+    }
+
+    if (!test_format) {      // shouldn't happen, but just in case...
         return SDL_SetError("No supported audio format found.");
     }
 
-    /* Update the fragment size as size in bytes */
-    SDL_CalculateAudioSpec(&_this->spec);
+    device->spec.format = test_format;
+
+    // Update the fragment size as size in bytes
+    SDL_UpdatedAudioDeviceFormat(device);
 
-    /* Allocate mixing buffer */
-    if (_this->spec.size >= SDL_MAX_UINT32 / 2) {
+    // Allocate mixing buffer
+    if (device->buffer_size >= SDL_MAX_UINT32 / 2) {
         return SDL_SetError("Mixing buffer is too large.");
     }
 
-    _this->hidden->mixlen = _this->spec.size;
-    _this->hidden->mixbuf = (Uint8 *)SDL_malloc(_this->spec.size);
-    if (_this->hidden->mixbuf == NULL) {
+    device->hidden->mixbuf = (Uint8 *)SDL_malloc(device->buffer_size);
+    if (device->hidden->mixbuf == NULL) {
         return SDL_OutOfMemory();
     }
 
-    SDL_memset(_this->hidden->mixbuf, _this->spec.silence, _this->spec.size);
+    SDL_memset(device->hidden->mixbuf, device->silence_value, device->buffer_size);
 
-    data_vaddr = (Uint8 *)linearAlloc(_this->hidden->mixlen * NUM_BUFFERS);
+    data_vaddr = (Uint8 *)linearAlloc(device->buffer_size * NUM_BUFFERS);
     if (data_vaddr == NULL) {
         return SDL_OutOfMemory();
     }
 
-    SDL_memset(data_vaddr, 0, _this->hidden->mixlen * NUM_BUFFERS);
-    DSP_FlushDataCache(data_vaddr, _this->hidden->mixlen * NUM_BUFFERS);
+    SDL_memset(data_vaddr, 0, device->buffer_size * NUM_BUFFERS);
+    DSP_FlushDataCache(data_vaddr, device->buffer_size * NUM_BUFFERS);
 
-    _this->hidden->nextbuf = 0;
-    _this->hidden->channels = _this->spec.channels;
-    _this->hidden->samplerate = _this->spec.freq;
+    device->hidden->nextbuf = 0;
 
     ndspChnReset(0);
 
     ndspChnSetInterp(0, NDSP_INTERP_LINEAR);
-    ndspChnSetRate(0, _this->spec.freq);
-    ndspChnSetFormat(0, _this->hidden->format);
+    ndspChnSetRate(0, device->spec.freq);
+    ndspChnSetFormat(0, device->hidden->format);
 
-    SDL_memset(mix, 0, sizeof(mix));
-    mix[0] = 1.0;
-    mix[1] = 1.0;
+    SDL_zeroa(mix);
+    mix[0] = mix[1] = 1.0f;
     ndspChnSetMix(0, mix);
 
-    SDL_memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
+    SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
 
+    const int sample_frame_size = device->spec.channels * (SDL_AUDIO_BITSIZE(device->spec.format) / 8);
     for (unsigned i = 0; i < NUM_BUFFERS; i++) {
-        _this->hidden->waveBuf[i].data_vaddr = data_vaddr;
-        _this->hidden->waveBuf[i].nsamples = _this->hidden->mixlen / _this->hidden->bytePerSample;
-        data_vaddr += _this->hidden->mixlen;
+        device->hidden->waveBuf[i].data_vaddr = data_vaddr;
+        device->hidden->waveBuf[i].nsamples = device->buffer_size / sample_frame_size;
+        data_vaddr += device->buffer_size;
     }
 
-    /* Setup callback */
-    audio_device = _this;
-    ndspSetCallback(AudioFrameFinished, _this);
+    // Setup callback
+    audio_device = device;
+    ndspSetCallback(AudioFrameFinished, device);
     dspHook(&dsp_hook, N3DSAUD_DspHook);
 
     return 0;
 }
 
-static int N3DSAUDIO_CaptureFromDevice(SDL_AudioDevice *_this, void *buffer, int buflen)
-{
-    /* Delay to make this sort of simulate real audio input. */
-    SDL_Delay((_this->spec.samples * 1000) / _this->spec.freq);
-
-    /* always return a full buffer of silence. */
-    SDL_memset(buffer, _this->spec.silence, buflen);
-    return buflen;
-}
-
-static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *_this)
+static void N3DSAUDIO_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen)
 {
-    size_t nextbuf;
-    size_t sampleLen;
-    contextLock(_this);
+    contextLock(device);
 
-    nextbuf = _this->hidden->nextbuf;
-    sampleLen = _this->hidden->mixlen;
+    const size_t nextbuf = device->hidden->nextbuf;
 
-    if (_this->hidden->isCancelled ||
-        _this->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
-        contextUnlock(_this);
+    if (device->hidden->isCancelled ||
+        device->hidden->waveBuf[nextbuf].status != NDSP_WBUF_FREE) {
+        contextUnlock(device);
         return;
     }
 
-    _this->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
+    device->hidden->nextbuf = (nextbuf + 1) % NUM_BUFFERS;
 
-    contextUnlock(_this);
+    contextUnlock(device);
 
-    SDL_memcpy((void *)_this->hidden->waveBuf[nextbuf].data_vaddr,
-           _this->hidden->mixbuf, sampleLen);
-    DSP_FlushDataCache(_this->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
+    SDL_memcpy((void *)device->hidden->waveBuf[nextbuf].data_vaddr, buffer, buflen);
+    DSP_FlushDataCache(device->hidden->waveBuf[nextbuf].data_vaddr, sampleLen);
 
-    ndspChnWaveBufAdd(0, &_this->hidden->waveBuf[nextbuf]);
+    ndspChnWaveBufAdd(0, &device->hidden->waveBuf[nextbuf]);
 }
 
-static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *_this)
+static void N3DSAUDIO_WaitDevice(SDL_AudioDevice *device)
 {
-    contextLock(_this);
-    while (!_this->hidden->isCancelled &&
-           _this->hidden->waveBuf[_this->hidden->nextbuf].status != NDSP_WBUF_FREE) {
-        CondVar_Wait(&_this->hidden->cv, &_this->hidden->lock);
+    contextLock(device);
+    while (!device->hidden->isCancelled && !SDL_AtomicGet(&device->shutdown) &&
+           device->hidden->waveBuf[device->hidden->nextbuf].status != NDSP_WBUF_FREE) {
+        CondVar_Wait(&device->hidden->cv, &device->hidden->lock);
     }
-    contextUnlock(_this);
+    contextUnlock(device);
 }
 
-static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *_this)
+static Uint8 *N3DSAUDIO_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size)
 {
-    return _this->hidden->mixbuf;
+    return device->hidden->mixbuf;
 }
 
-static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *_this)
+static void N3DSAUDIO_CloseDevice(SDL_AudioDevice *device)
 {
-    contextLock(_this);
+    if (!device->hidden) {
+        return;
+    }
+
+    contextLock(device);
 
     dspUnhook(&dsp_hook);
     ndspSetCallback(NULL, NULL);
 
-    if (!_this->hidden->isCancelled) {
+    if (!device->hidden->isCancelled) {
         ndspChnReset(0);
-        SDL_memset(_this->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
-        CondVar_Broadcast(&_this->hidden->cv);
+        SDL_memset(device->hidden->waveBuf, 0, sizeof(ndspWaveBuf) * NUM_BUFFERS);
+        CondVar_Broadcast(&device->hidden->cv);
     }
 
-    contextUnlock(_this);
+    contextUnlock(device);
 
     ndspExit();
 
-    FreePrivateData(_this);
+    if (device->hidden->waveBuf[0].data_vaddr) {
+        linearFree((void *)device->hidden->waveBuf[0].data_vaddr);
+    }
+
+    if (device->hidden->mixbuf) {
+        SDL_free(device->hidden->mixbuf);
+        device->hidden->mixbuf = NULL;
+    }
+
+    SDL_free(device->hidden);
+    device->hidden = NULL;
 }
 
-static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *_this)
+static void N3DSAUDIO_ThreadInit(SDL_AudioDevice *device)
 {
     s32 current_priority;
     svcGetThreadPriority(&current_priority, CUR_THREAD_HANDLE);
     current_priority--;
-    /* 0x18 is reserved for video, 0x30 is the default for main thread */
+    // 0x18 is reserved for video, 0x30 is the default for main thread
     current_priority = SDL_clamp(current_priority, 0x19, 0x2F);
     svcSetThreadPriority(CUR_THREAD_HANDLE, current_priority);
 }
 
 static SDL_bool N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
 {
-    /* Set the function pointers */
     impl->OpenDevice = N3DSAUDIO_OpenDevice;
     impl->PlayDevice = N3DSAUDIO_PlayDevice;
     impl->WaitDevice = N3DSAUDIO_WaitDevice;
@@ -272,11 +279,10 @@ static SDL_bool N3DSAUDIO_Init(SDL_AudioDriverImpl *impl)
     impl->UnlockDevice = N3DSAUD_UnlockAudio;
     impl->OnlyHasDefaultOutputDevice = SDL_TRUE;
 
-    /* Should be possible, but micInit would fail */
+    // Should be possible, but micInit would fail
     impl->HasCaptureSupport = SDL_FALSE;
-    impl->CaptureFromDevice = N3DSAUDIO_CaptureFromDevice;
 
-    return SDL_TRUE; /* this audio target is available. */
+    return SDL_TRUE;
 }
 
 AudioBootStrap N3DSAUDIO_bootstrap = {
@@ -286,51 +292,4 @@ AudioBootStrap N3DSAUDIO_bootstrap = {
     0
 };
 
-/**
- * Cleans up all allocated memory, safe to call with null pointers
- */
-static void FreePrivateData(SDL_AudioDevice *_this)
-{
-    if (!_this->hidden) {
-        return;
-    }
-
-    if (_this->hidden->waveBuf[0].data_vaddr) {
-        linearFree((void *)_this->hidden->waveBuf[0].data_vaddr);
-    }
-
-    if (_this->hidden->mixbuf) {
-        SDL_free(_this->hidden->mixbuf);
-        _this->hidden->mixbuf = NULL;
-    }
-
-    SDL_free(_this->hidden);
-    _this->hidden = NULL;
-}
-
-static int FindAudioFormat(SDL_AudioDevice *_this)
-{
-    SDL_AudioFormat test_format;
-    const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(_this->spec.format);
-    while ((test_format = *(closefmts++)) != 0) {
-        _this->spec.format = test_format;
-        switch (test_format) {
-        case SDL_AUDIO_S8:
-            /* Signed 8-bit audio supported */
-            _this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM8 : NDSP_FORMAT_MONO_PCM8;
-            _this->hidden->isSigned = 1;
-            _this->hidden->bytePerSample = _this->spec.channels;
-            return 0;
-        case SDL_AUDIO_S16:
-            /* Signed 16-bit audio supported */
-            _this->hidden->format = (_this->spec.channels == 2) ? NDSP_FORMAT_STEREO_PCM16 : NDSP_FORMAT_MONO_PCM16;
-            _this->hidden->isSigned = 1;
-            _this->hidden->bytePerSample = _this->spec.channels * 2;
-            return 0;
-        }
-    }
-
-    return -1;
-}
-
-#endif /* SDL_AUDIO_DRIVER_N3DS */
+#endif // SDL_AUDIO_DRIVER_N3DS
diff --git a/src/audio/n3ds/SDL_n3dsaudio.h b/src/audio/n3ds/SDL_n3dsaudio.h
index 88b9ffcb524f..83f9ca83c98c 100644
--- a/src/audio/n3ds/SDL_n3dsaudio.h
+++ b/src/audio/n3ds/SDL_n3dsaudio.h
@@ -30,12 +30,6 @@ struct SDL_PrivateAudioData
 {
     /* Speaker data */
     Uint8 *mixbuf;
-    Uint32 mixlen;
-    Uint32 format;
-    Uint32 samplerate;
-    Uint32 channels;
-    Uint8 bytePerSample;
-    Uint32 isSigned;
     Uint32 nextbuf;
     ndspWaveBuf waveBuf[NUM_BUFFERS];
     LightLock lock;