SDL: Improve audio compatibility in PSP. Now it supports more formats and frequencies

From f3255df9c0e774083514c99511dd72c96a9dd4d8 Mon Sep 17 00:00:00 2001
From: Francisco Javier Trujillo Mata <[EMAIL REDACTED]>
Date: Wed, 17 Nov 2021 23:50:41 +0100
Subject: [PATCH] Improve audio compatibility in PSP. Now it supports more
 formats and frequencies

---
 src/audio/psp/SDL_pspaudio.c | 73 +++++++++++++++++++++---------------
 1 file changed, 43 insertions(+), 30 deletions(-)

diff --git a/src/audio/psp/SDL_pspaudio.c b/src/audio/psp/SDL_pspaudio.c
index 52fee7d4682..d68d3f49e6f 100644
--- a/src/audio/psp/SDL_pspaudio.c
+++ b/src/audio/psp/SDL_pspaudio.c
@@ -45,51 +45,55 @@ static int
 PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
 {
     int format, mixlen, i;
+
     this->hidden = (struct SDL_PrivateAudioData *)
         SDL_malloc(sizeof(*this->hidden));
     if (this->hidden == NULL) {
         return SDL_OutOfMemory();
     }
     SDL_zerop(this->hidden);
-    switch (this->spec.format & 0xff) {
-        case 8:
-        case 16:
-            this->spec.format = AUDIO_S16LSB;
-            break;
-        default:
-            return SDL_SetError("Unsupported audio format");
-    }
+
+    /* device only natively supports S16LSB */
+    this->spec.format = AUDIO_S16LSB;
 
     /* The sample count must be a multiple of 64. */
     this->spec.samples = PSP_AUDIO_SAMPLE_ALIGN(this->spec.samples);
-    this->spec.freq = 44100;
-
-    /* Update the fragment size as size in bytes. */
-    SDL_CalculateAudioSpec(&this->spec);
-
-    /* Allocate the mixing buffer.  Its size and starting address must
-       be a multiple of 64 bytes.  Our sample count is already a multiple of
-       64, so spec->size should be a multiple of 64 as well. */
-    mixlen = this->spec.size * NUM_BUFFERS;
-    this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
-    if (this->hidden->rawbuf == NULL) {
-        return SDL_SetError("Couldn't allocate mixing buffer");
-    }
 
     /* Setup the hardware channel. */
     if (this->spec.channels == 1) {
         format = PSP_AUDIO_FORMAT_MONO;
     } else {
-        this->spec.channels = 2;
         format = PSP_AUDIO_FORMAT_STEREO;
     }
-    this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
+
+    /*  PSP has some limitations with the Audio. It fully supports 44.1KHz (Mono & Stereo),
+        however with frequencies differents than 44.1KHz, it just supports Stereo,
+        so a resampler must be done for these scenarios */
+    if (this->spec.freq == 44100) {
+        this->hidden->channel = sceAudioChReserve(PSP_AUDIO_NEXT_CHANNEL, this->spec.samples, format);
+    } else {
+        this->hidden->channel = sceAudioSRCChReserve(this->spec.samples, this->spec.freq, 2);
+        this->spec.channels = 2;  /* we're forcing the hardware to stereo. */
+    }
+    
     if (this->hidden->channel < 0) {
         free(this->hidden->rawbuf);
         this->hidden->rawbuf = NULL;
         return SDL_SetError("Couldn't reserve hardware channel");
     }
 
+    /* Update the fragment size as size in bytes. */
+    SDL_CalculateAudioSpec(&this->spec);
+
+    /* Allocate the mixing buffer.  Its size and starting address must
+       be a multiple of 64 bytes.  Our sample count is already a multiple of
+       64, so spec->size should be a multiple of 64 as well. */
+    mixlen = this->spec.size * NUM_BUFFERS;
+    this->hidden->rawbuf = (Uint8 *) memalign(64, mixlen);
+    if (this->hidden->rawbuf == NULL) {
+        return SDL_SetError("Couldn't allocate mixing buffer");
+    }
+
     SDL_memset(this->hidden->rawbuf, 0, mixlen);
     for (i = 0; i < NUM_BUFFERS; i++) {
         this->hidden->mixbufs[i] = &this->hidden->rawbuf[i * this->spec.size];
@@ -101,11 +105,12 @@ PSPAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
 
 static void PSPAUDIO_PlayDevice(_THIS)
 {
-    Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
-
-    if (this->spec.channels == 1) {
-        sceAudioOutputBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, mixbuf);
+    if (this->spec.freq != 44100){
+        Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
+        SDL_assert(this->spec.channels == 2);
+        sceAudioSRCOutputBlocking(PSP_AUDIO_VOLUME_MAX, mixbuf);
     } else {
+        Uint8 *mixbuf = this->hidden->mixbufs[this->hidden->next_buffer];
         sceAudioOutputPannedBlocking(this->hidden->channel, PSP_AUDIO_VOLUME_MAX, PSP_AUDIO_VOLUME_MAX, mixbuf);
     }
 
@@ -126,10 +131,18 @@ static Uint8 *PSPAUDIO_GetDeviceBuf(_THIS)
 static void PSPAUDIO_CloseDevice(_THIS)
 {
     if (this->hidden->channel >= 0) {
-        sceAudioChRelease(this->hidden->channel);
+        if (this->spec.freq != 44100){
+            sceAudioSRCChRelease();
+        } else {
+            sceAudioChRelease(this->hidden->channel);
+        }
+        this->hidden->channel = -1;
+    }
+
+    if (this->hidden->rawbuf != NULL) {
+        free(this->hidden->rawbuf);
+        this->hidden->rawbuf = NULL;
     }
-    free(this->hidden->rawbuf); /* this uses memalign(), not SDL_malloc(). */
-    SDL_free(this->hidden);
 }
 
 static void PSPAUDIO_ThreadInit(_THIS)