From 43205a9d8feffea3d30bfd5ac86d7138d329b672 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Wed, 1 Mar 2023 10:27:47 -0500
Subject: [PATCH] audio: U16 audio support was removed from SDL3, so manage it
here now.
---
src/dynapi/SDL_dynapi_procs.h | 14 +-
src/sdl2_compat.c | 248 ++++++++++++++++++++++++++++++----
src/sdl2_compat.h | 7 +
src/sdl3_syms.h | 14 +-
4 files changed, 244 insertions(+), 39 deletions(-)
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index be85563..2863898 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -677,13 +677,13 @@ SDL_DYNAPI_PROC(void,SDL_UnlockJoysticks,(void),(),)
SDL_DYNAPI_PROC(void,SDL_GetMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),)
SDL_DYNAPI_PROC(int,SDL_SetMemoryFunctions,(SDL_malloc_func a, SDL_calloc_func b, SDL_realloc_func c, SDL_free_func d),(a,b,c,d),return)
SDL_DYNAPI_PROC(int,SDL_GetNumAllocations,(void),(),return)
-SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_NewAudioStream,(const SDL_AudioFormat a, const Uint8 b, const int c, const SDL_AudioFormat d, const Uint8 e, const int f),(a,b,c,d,e,f),return)
-SDL_DYNAPI_PROC(int,SDL_AudioStreamPut,(SDL_AudioStream *a, const void *b, int c),(a,b,c),return)
-SDL_DYNAPI_PROC(int,SDL_AudioStreamGet,(SDL_AudioStream *a, void *b, int c),(a,b,c),return)
-SDL_DYNAPI_PROC(void,SDL_AudioStreamClear,(SDL_AudioStream *a),(a),)
-SDL_DYNAPI_PROC(int,SDL_AudioStreamAvailable,(SDL_AudioStream *a),(a),return)
-SDL_DYNAPI_PROC(void,SDL_FreeAudioStream,(SDL_AudioStream *a),(a),)
-SDL_DYNAPI_PROC(int,SDL_AudioStreamFlush,(SDL_AudioStream *a),(a),return)
+SDL_DYNAPI_PROC(SDL2_AudioStream*,SDL_NewAudioStream,(const SDL_AudioFormat a, const Uint8 b, const int c, const SDL_AudioFormat d, const Uint8 e, const int f),(a,b,c,d,e,f),return)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamPut,(SDL2_AudioStream *a, const void *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamGet,(SDL2_AudioStream *a, void *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(void,SDL_AudioStreamClear,(SDL2_AudioStream *a),(a),)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamAvailable,(SDL2_AudioStream *a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_FreeAudioStream,(SDL2_AudioStream *a),(a),)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamFlush,(SDL2_AudioStream *a),(a),return)
SDL_DYNAPI_PROC(float,SDL_acosf,(float a),(a),return)
SDL_DYNAPI_PROC(float,SDL_asinf,(float a),(a),return)
SDL_DYNAPI_PROC(float,SDL_atanf,(float a),(a),return)
diff --git a/src/sdl2_compat.c b/src/sdl2_compat.c
index 02baab4..a6abb05 100644
--- a/src/sdl2_compat.c
+++ b/src/sdl2_compat.c
@@ -635,6 +635,9 @@ BOOL WINAPI _DllMainCRTStartup(HANDLE dllhandle, DWORD reason, LPVOID reserved)
#error Please define an init procedure for your platform.
#endif
+/* removed in SDL3 (no U16 audio formats supported) */
+#define SDL2_AUDIO_U16LSB 0x0010 /* Unsigned 16-bit samples */
+#define SDL2_AUDIO_U16MSB 0x1010 /* As above, but big-endian byte order */
/* removed in SDL3 (which only uses SDL_WINDOW_HIDDEN now). */
#define SDL2_WINDOW_SHOWN 0x000000004
@@ -1068,6 +1071,7 @@ typedef struct EventFilterWrapperData
/* Some SDL2 state we need to keep... */
+/* !!! FIXME: unify coding convention on the globals: some are MyVariableName and some are my_variable_name */
static SDL2_EventFilter EventFilter2 = NULL;
static void *EventFilterUserData2 = NULL;
static SDL_mutex *EventWatchListMutex = NULL;
@@ -3210,9 +3214,31 @@ SDL_GL_GetSwapInterval(void)
return val;
}
+/* !!! FIXME: move these up with the other globals. */
static SDL_AudioDeviceID g_audio_id = 0;
static SDL_AudioSpec g_audio_spec;
+DECLSPEC SDL_AudioDeviceID SDLCALL
+SDL_OpenAudioDevice(const char *device, int iscapture, const SDL_AudioSpec *desired, SDL_AudioSpec *obtained, int allowed_changes)
+{
+ SDL_AudioSpec desired3;
+ SDL_memcpy(&desired3, desired, sizeof (SDL_AudioSpec));
+
+ if ((desired3.format == SDL2_AUDIO_U16LSB) || (desired3.format == SDL2_AUDIO_U16MSB)) {
+ if (allowed_changes & SDL_AUDIO_ALLOW_FORMAT_CHANGE) {
+ desired3.format = AUDIO_S16SYS; /* just pick a supported format instead. */
+ } else {
+ /* technically we should convert this behind the scenes, but all of this is getting
+ replaced with a different interface in SDL3 soon, so it's not worth
+ hooking the audio callback to manage it before that work is done. */
+ SDL3_SetError("U16 audio unsupported");
+ return 0;
+ }
+ }
+
+ return SDL3_OpenAudioDevice(device, iscapture, &desired3, obtained, allowed_changes);
+}
+
DECLSPEC int SDLCALL
SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
{
@@ -3253,6 +3279,189 @@ SDL_OpenAudio(SDL_AudioSpec *desired, SDL_AudioSpec *obtained)
return -1;
}
+/* this converts the buffer in-place. The buffer size does not change. */
+static Sint16 *AudioUi16LSBToSi16Sys(Uint16 *buffer, const size_t num_samples)
+{
+ size_t i;
+ const Uint16 *src = buffer;
+ Sint16 *dst = (Sint16 *) buffer;
+
+ for (i = 0; i < num_samples; i++) {
+ dst[i] = (Sint16) (SDL_SwapLE16(src[i]) ^ 0x8000);
+ }
+
+ return dst;
+}
+
+/* this converts the buffer in-place. The buffer size does not change. */
+static Sint16 *AudioUi16MSBToSi16Sys(Uint16 *buffer, const size_t num_samples)
+{
+ size_t i;
+ const Uint16 *src = buffer;
+ Sint16 *dst = (Sint16 *) buffer;
+
+ for (i = 0; i < num_samples; i++) {
+ dst[i] = (Sint16) (SDL_SwapBE16(src[i]) ^ 0x8000);
+ }
+
+ return dst;
+}
+
+/* this converts the buffer in-place. The buffer size does not change. */
+static Uint16 *AudioSi16SysToUi16LSB(Sint16 *buffer, const size_t num_samples)
+{
+ size_t i;
+ const Sint16 *src = buffer;
+ Uint16 *dst = (Uint16 *) buffer;
+
+ for (i = 0; i < num_samples; i++) {
+ dst[i] = SDL_SwapLE16(((Uint16) src[i]) ^ 0x8000);
+ }
+
+ return dst;
+}
+/* this converts the buffer in-place. The buffer size does not change. */
+static Uint16 *AudioSi16SysToUi16MSB(Sint16 *buffer, const size_t num_samples)
+{
+ size_t i;
+ const Sint16 *src = buffer;
+ Uint16 *dst = (Uint16 *) buffer;
+
+ for (i = 0; i < num_samples; i++) {
+ dst[i] = SDL_SwapBE16(((Uint16) src[i]) ^ 0x8000);
+ }
+
+ return dst;
+}
+
+DECLSPEC SDL2_AudioStream * SDLCALL
+SDL_NewAudioStream(const SDL_AudioFormat real_src_format, const Uint8 src_channels, const int src_rate, const SDL_AudioFormat real_dst_format, const Uint8 dst_channels, const int dst_rate)
+{
+ SDL_AudioFormat src_format = real_src_format;
+ SDL_AudioFormat dst_format = real_dst_format;
+ SDL2_AudioStream *retval = SDL_malloc(sizeof (SDL2_AudioStream));
+ if (!retval) {
+ SDL3_OutOfMemory();
+ return NULL;
+ }
+
+ /* SDL3 removed U16 audio formats. Convert to S16SYS. */
+ if ((src_format == SDL2_AUDIO_U16LSB) || (src_format == SDL2_AUDIO_U16MSB)) {
+ src_format = AUDIO_S16SYS;
+ }
+ if ((dst_format == SDL2_AUDIO_U16LSB) || (dst_format == SDL2_AUDIO_U16MSB)) {
+ dst_format = AUDIO_S16SYS;
+ }
+
+ retval->stream3 = SDL3_CreateAudioStream(src_format, src_channels, src_rate, dst_format, dst_channels, dst_rate);
+ if (retval->stream3 == NULL) {
+ SDL_free(retval);
+ return NULL;
+ }
+
+ retval->src_format = real_src_format;
+ retval->dst_format = real_dst_format;
+ return retval;
+}
+
+DECLSPEC int SDLCALL
+SDL_AudioStreamPut(SDL2_AudioStream *stream2, const void *buf, int len)
+{
+ int retval;
+
+ /* SDL3 removed U16 audio formats. Convert to S16SYS. */
+ if (stream2 && buf && len && ((stream2->src_format == SDL2_AUDIO_U16LSB) || (stream2->src_format == SDL2_AUDIO_U16MSB))) {
+ const Uint32 tmpsamples = len / sizeof (Uint16);
+ Sint16 *tmpbuf = (Sint16 *) SDL3_malloc(len);
+ if (!tmpbuf) {
+ return SDL3_OutOfMemory();
+ }
+ SDL_memcpy(tmpbuf, buf, len);
+ if (stream2->src_format == SDL2_AUDIO_U16LSB) {
+ AudioUi16LSBToSi16Sys((Uint16 *) tmpbuf, tmpsamples);
+ } else if (stream2->src_format == SDL2_AUDIO_U16MSB) {
+ AudioUi16MSBToSi16Sys((Uint16 *) tmpbuf, tmpsamples);
+ }
+ retval = SDL3_PutAudioStreamData(stream2->stream3, tmpbuf, len);
+ SDL_free(tmpbuf);
+ } else {
+ retval = SDL3_PutAudioStreamData(stream2->stream3, buf, len);
+ }
+
+ return retval;
+}
+
+DECLSPEC int SDLCALL
+SDL_AudioStreamGet(SDL2_AudioStream *stream2, void *buf, int len)
+{
+ const int retval = stream2 ? SDL3_GetAudioStreamData(stream2->stream3, buf, len) : SDL3_InvalidParamError("stream");
+
+ if (retval > 0) {
+ /* SDL3 removed U16 audio formats. Convert to S16SYS. */
+ SDL_assert(stream2 != NULL);
+ SDL_assert(buf != NULL);
+ SDL_assert(len > 0);
+ if ((stream2->dst_format == SDL2_AUDIO_U16LSB) || (stream2->dst_format == SDL2_AUDIO_U16MSB)) {
+ if (stream2->dst_format == SDL2_AUDIO_U16LSB) {
+ AudioSi16SysToUi16LSB((Sint16 *) buf, retval / sizeof (Sint16));
+ } else if (stream2->dst_format == SDL2_AUDIO_U16MSB) {
+ AudioSi16SysToUi16MSB((Sint16 *) buf, retval / sizeof (Sint16));
+ }
+ }
+ }
+
+ return retval;
+}
+
+DECLSPEC int SDLCALL
+SDL_AudioStreamClear(SDL2_AudioStream *stream2)
+{
+ return SDL3_ClearAudioStream(stream2 ? stream2->stream3 : NULL);
+}
+
+DECLSPEC int SDLCALL
+SDL_AudioStreamAvailable(SDL2_AudioStream *stream2)
+{
+ return SDL3_GetAudioStreamAvailable(stream2 ? stream2->stream3 : NULL);
+}
+
+DECLSPEC void SDLCALL
+SDL_FreeAudioStream(SDL2_AudioStream *stream2)
+{
+ if (stream2) {
+ SDL3_DestroyAudioStream(stream2->stream3);
+ SDL3_free(stream2);
+ }
+}
+
+DECLSPEC int SDLCALL
+SDL_AudioStreamFlush(SDL2_AudioStream *stream2)
+{
+ return SDL3_FlushAudioStream(stream2 ? stream2->stream3 : NULL);
+}
+
+DECLSPEC void SDLCALL
+SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format, Uint32 len, int volume)
+{
+ /* SDL3 removed U16 audio formats. Convert to S16SYS. */
+ if ((format == SDL2_AUDIO_U16LSB) || (format == SDL2_AUDIO_U16MSB)) {
+ const Uint32 tmpsamples = len / sizeof (Uint16);
+ Sint16 *tmpbuf = (Sint16 *) SDL3_malloc(len);
+ if (tmpbuf) { /* if malloc fails, oh well, no mixed audio for you. */
+ SDL_memcpy(tmpbuf, src, len);
+ if (format == SDL2_AUDIO_U16LSB) {
+ AudioUi16LSBToSi16Sys((Uint16 *) tmpbuf, tmpsamples);
+ } else if (format == SDL2_AUDIO_U16MSB) {
+ AudioUi16MSBToSi16Sys((Uint16 *) tmpbuf, tmpsamples);
+ }
+ SDL3_MixAudioFormat(dst, src, AUDIO_S16SYS, tmpsamples * sizeof (Sint16), volume);
+ SDL3_free(tmpbuf);
+ }
+ } else {
+ SDL3_MixAudioFormat(dst, src, format, len, volume);
+ }
+}
+
/*
* Moved here from SDL_mixer.c, since it relies on internals of an opened
* audio device (and is deprecated, by the way!).
@@ -3262,7 +3471,7 @@ SDL_MixAudio(Uint8 *dst, const Uint8 *src, Uint32 len, int volume)
{
/* Mix the user-level audio format */
if (g_audio_id > 0) {
- SDL3_MixAudioFormat(dst, src, g_audio_spec.format, len, volume); /* FIXME: is this correct ?? */
+ SDL_MixAudioFormat(dst, src, g_audio_spec.format, len, volume); /* call the sdl2-compat version, since it needs to handle U16 audio data. */
}
}
@@ -4221,12 +4430,6 @@ SDL_SetWindowMaximumSize(SDL_Window *window, int max_w, int max_h)
SDL3_SetWindowMaximumSize(window, max_w, max_h);
}
-DECLSPEC void SDLCALL
-SDL_MixAudioFormat(Uint8 *dst, const Uint8 *src, SDL_AudioFormat format, Uint32 len, int volume)
-{
- SDL3_MixAudioFormat(dst, src, format, len, volume);
-}
-
DECLSPEC void SDLCALL
SDL_hid_close(SDL_hid_device * dev)
{
@@ -4444,12 +4647,6 @@ SDL_GameControllerSetPlayerIndex(SDL_GameController *gamecontroller, int player_
SDL3_SetGamepadPlayerIndex(gamecontroller, player_index);
}
-DECLSPEC void SDLCALL
-SDL_AudioStreamClear(SDL_AudioStream *stream)
-{
- SDL3_ClearAudioStream(stream);
-}
-
DECLSPEC void SDLCALL
SDL_JoystickGetGUIDString(SDL_JoystickGUID guid, char *pszGUID, int cbGUID)
{
@@ -4873,15 +5070,16 @@ SDL_SIMDFree(void *ptr)
}
+/* !!! FIXME: move this all up with the other audio functions */
static SDL_bool
SDL_IsSupportedAudioFormat(const SDL_AudioFormat fmt)
{
switch (fmt) {
case AUDIO_U8:
case AUDIO_S8:
- case AUDIO_U16LSB:
+ case SDL2_AUDIO_U16LSB:
case AUDIO_S16LSB:
- case AUDIO_U16MSB:
+ case SDL2_AUDIO_U16MSB:
case AUDIO_S16MSB:
case AUDIO_S32LSB:
case AUDIO_S32MSB:
@@ -5010,12 +5208,10 @@ SDL_BuildAudioCVT(SDL_AudioCVT *cvt,
return cvt->needed;
}
-
DECLSPEC int SDLCALL
SDL_ConvertAudio(SDL_AudioCVT *cvt)
{
-
- SDL_AudioStream *stream;
+ SDL2_AudioStream *stream2;
SDL_AudioFormat src_format, dst_format;
int src_channels, src_rate;
int dst_channels, dst_rate;
@@ -5044,9 +5240,10 @@ SDL_ConvertAudio(SDL_AudioCVT *cvt)
dst_rate = ap.dst_rate;
}
- stream = SDL3_CreateAudioStream(src_format, src_channels, src_rate,
+ /* don't use the SDL3 stream directly; we want the U16 support in the sdl2-compat layer */
+ stream2 = SDL_NewAudioStream(src_format, src_channels, src_rate,
dst_format, dst_channels, dst_rate);
- if (stream == NULL) {
+ if (stream2 == NULL) {
goto failure;
}
@@ -5061,8 +5258,8 @@ SDL_ConvertAudio(SDL_AudioCVT *cvt)
}
/* Run the audio converter */
- if (SDL3_PutAudioStreamData(stream, cvt->buf, src_len) < 0 ||
- SDL3_FlushAudioStream(stream) < 0) {
+ if (SDL_AudioStreamPut(stream2, cvt->buf, src_len) < 0 ||
+ SDL_AudioStreamFlush(stream2) < 0) {
goto failure;
}
@@ -5070,18 +5267,19 @@ SDL_ConvertAudio(SDL_AudioCVT *cvt)
dst_len = dst_len & ~(dst_samplesize - 1);
/* Get back in the same buffer */
- real_dst_len = SDL3_GetAudioStreamData(stream, cvt->buf, dst_len);
+ real_dst_len = SDL_AudioStreamGet(stream2, cvt->buf, dst_len);
if (real_dst_len < 0) {
goto failure;
}
cvt->len_cvt = real_dst_len;
- SDL3_DestroyAudioStream(stream);
+ SDL_FreeAudioStream(stream2);
+
return 0;
failure:
- SDL3_DestroyAudioStream(stream);
+ SDL_FreeAudioStream(stream2);
return -1;
}
diff --git a/src/sdl2_compat.h b/src/sdl2_compat.h
index b771794..2156577 100644
--- a/src/sdl2_compat.h
+++ b/src/sdl2_compat.h
@@ -89,4 +89,11 @@ typedef struct SDL_AudioCVT
int filter_index; /**< Current audio conversion function */
} SDL_AUDIOCVT_PACKED SDL_AudioCVT;
+typedef struct SDL2_AudioStream
+{
+ SDL_AudioStream *stream3;
+ SDL_AudioFormat src_format;
+ SDL_AudioFormat dst_format;
+} SDL2_AudioStream;
+
#endif /* sdl2_compat_h */
diff --git a/src/sdl3_syms.h b/src/sdl3_syms.h
index 49fe544..5c1fb10 100644
--- a/src/sdl3_syms.h
+++ b/src/sdl3_syms.h
@@ -102,7 +102,7 @@ SDL3_SYM_PASSTHROUGH(const char*,GetAudioDriver,(int a),(a),return)
SDL3_SYM_PASSTHROUGH(const char*,GetCurrentAudioDriver,(void),(),return)
SDL3_SYM_PASSTHROUGH(int,GetNumAudioDevices,(int a),(a),return)
SDL3_SYM_PASSTHROUGH(const char*,GetAudioDeviceName,(int a, int b),(a,b),return)
-SDL3_SYM_PASSTHROUGH(SDL_AudioDeviceID,OpenAudioDevice,(const char *a, int b, const SDL_AudioSpec *c, SDL_AudioSpec *d, int e),(a,b,c,d,e),return)
+SDL3_SYM(SDL_AudioDeviceID,OpenAudioDevice,(const char *a, int b, const SDL_AudioSpec *c, SDL_AudioSpec *d, int e),(a,b,c,d,e),return)
SDL3_SYM(SDL_AudioStatus,GetAudioDeviceStatus,(SDL_AudioDeviceID a),(a),return)
SDL3_SYM(int,PlayAudioDevice,(SDL_AudioDeviceID a),(a),return)
SDL3_SYM(int,PauseAudioDevice,(SDL_AudioDeviceID a),(a),return)
@@ -599,13 +599,13 @@ SDL3_SYM_PASSTHROUGH(SDL_bool,Vulkan_CreateSurface,(SDL_Window *a, VkInstance b,
SDL3_SYM_PASSTHROUGH(void,GetMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),)
SDL3_SYM_PASSTHROUGH(int,SetMemoryFunctions,(SDL_malloc_func a, SDL_calloc_func b, SDL_realloc_func c, SDL_free_func d),(a,b,c,d),return)
SDL3_SYM_PASSTHROUGH(int,GetNumAllocations,(void),(),return)
-SDL3_SYM_RENAMED(SDL_AudioStream*,NewAudioStream,CreateAudioStream,(const SDL_AudioFormat a, const Uint8 b, const int c, const SDL_AudioFormat d, const Uint8 e, const int f),(a,b,c,d,e,f),return)
-SDL3_SYM_RENAMED(int,AudioStreamPut,PutAudioStreamData,(SDL_AudioStream *a, const void *b, int c),(a,b,c),return)
-SDL3_SYM_RENAMED(int,AudioStreamGet,GetAudioStreamData,(SDL_AudioStream *a, void *b, int c),(a,b,c),return)
+SDL3_SYM(SDL_AudioStream*,CreateAudioStream,(const SDL_AudioFormat a, const Uint8 b, const int c, const SDL_AudioFormat d, const Uint8 e, const int f),(a,b,c,d,e,f),return)
+SDL3_SYM(int,PutAudioStreamData,(SDL_AudioStream *a, const void *b, int c),(a,b,c),return)
+SDL3_SYM(int,GetAudioStreamData,(SDL_AudioStream *a, void *b, int c),(a,b,c),return)
SDL3_SYM(int,ClearAudioStream,(SDL_AudioStream *a),(a),return)
-SDL3_SYM_RENAMED(int,AudioStreamAvailable,GetAudioStreamAvailable,(SDL_AudioStream *a),(a),return)
-SDL3_SYM_RENAMED(void,FreeAudioStream,DestroyAudioStream,(SDL_AudioStream *a),(a),)
-SDL3_SYM_RENAMED(int,AudioStreamFlush,FlushAudioStream,(SDL_AudioStream *a),(a),return)
+SDL3_SYM(int,GetAudioStreamAvailable,(SDL_AudioStream *a),(a),return)
+SDL3_SYM(void,DestroyAudioStream,(SDL_AudioStream *a),(a),)
+SDL3_SYM(int,FlushAudioStream,(SDL_AudioStream *a),(a),return)
SDL3_SYM_PASSTHROUGH(float,acosf,(float a),(a),return)
SDL3_SYM_PASSTHROUGH(float,asinf,(float a),(a),return)
SDL3_SYM_PASSTHROUGH(float,atanf,(float a),(a),return)