SDL_mixer: Updated for new SDL3 audio API.

From e35fc585b6b0847a41250f3a3ee894835e18fbee Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 3 Aug 2023 22:43:06 -0400
Subject: [PATCH] Updated for new SDL3 audio API.

This makes two API changes to SDL mixer.

First, Mix_OpenAudio is simplified, and can even be called as
`Mix_OpenAudio(0, NULL);` and probably get the exact desired result in
most use cases.

Second, Mix_OpenAudioDevice is gone, as redundant.

This is squash-merged from Pull Request #538.
---
 examples/playmus.c             |  38 ++++----
 examples/playwave.c            |  34 ++++---
 include/SDL3/SDL_mixer.h       | 168 ++++-----------------------------
 src/codecs/load_aiff.c         |   1 -
 src/codecs/load_voc.c          |   2 -
 src/codecs/music_drflac.c      |  15 ++-
 src/codecs/music_drmp3.c       |  15 ++-
 src/codecs/music_flac.c        |  12 +--
 src/codecs/music_fluidsynth.c  |  11 ++-
 src/codecs/music_gme.c         |  12 +--
 src/codecs/music_modplug.c     |  13 ++-
 src/codecs/music_mpg123.c      |  16 +++-
 src/codecs/music_ogg.c         |  12 +--
 src/codecs/music_ogg_stb.c     |  15 ++-
 src/codecs/music_opus.c        |  13 ++-
 src/codecs/music_timidity.c    |   5 +-
 src/codecs/music_wav.c         |  25 +++--
 src/codecs/music_wavpack.c     |  11 ++-
 src/codecs/music_xmp.c         |  12 +--
 src/codecs/timidity/timidity.c |   6 +-
 src/mixer.c                    |  87 ++++++++++-------
 src/music.c                    |   2 +-
 22 files changed, 202 insertions(+), 323 deletions(-)

diff --git a/examples/playmus.c b/examples/playmus.c
index 54751609..cd8fbbc5 100644
--- a/examples/playmus.c
+++ b/examples/playmus.c
@@ -113,10 +113,6 @@ static void IntHandler(int sig)
 
 int main(int argc, char *argv[])
 {
-    int audio_rate;
-    Uint16 audio_format;
-    int audio_channels;
-    int audio_buffers;
     int audio_volume = MIX_MAX_VOLUME;
     int looping = 0;
     int interactive = 0;
@@ -128,31 +124,31 @@ int main(int argc, char *argv[])
     const char *tag_album = NULL;
     const char *tag_copyright = NULL;
     double loop_start, loop_end, loop_length, current_position;
+    SDL_AudioSpec spec;
 
     (void) argc;
 
     /* Initialize variables */
-    audio_rate = MIX_DEFAULT_FREQUENCY;
-    audio_format = MIX_DEFAULT_FORMAT;
-    audio_channels = MIX_DEFAULT_CHANNELS;
-    audio_buffers = 4096;
+    spec.freq = MIX_DEFAULT_FREQUENCY;
+    spec.format = MIX_DEFAULT_FORMAT;
+    spec.channels = MIX_DEFAULT_CHANNELS;
 
     /* Check command line usage */
     for (i=1; argv[i] && (*argv[i] == '-'); ++i) {
         if ((SDL_strcmp(argv[i], "-r") == 0) && argv[i+1]) {
             ++i;
-            audio_rate = SDL_atoi(argv[i]);
+            spec.freq = SDL_atoi(argv[i]);
         } else
         if (SDL_strcmp(argv[i], "-m") == 0) {
-            audio_channels = 1;
+            spec.channels = 1;
         } else
         if ((SDL_strcmp(argv[i], "-c") == 0) && argv[i+1]) {
             ++i;
-            audio_channels = SDL_atoi(argv[i]);
+            spec.channels = SDL_atoi(argv[i]);
         } else
         if ((SDL_strcmp(argv[i], "-b") == 0) && argv[i+1]) {
             ++i;
-            audio_buffers = SDL_atoi(argv[i]);
+            /*ignored now. audio_buffers = SDL_atoi(argv[i]); */
         } else
         if ((SDL_strcmp(argv[i], "-v") == 0) && argv[i+1]) {
             ++i;
@@ -165,10 +161,10 @@ int main(int argc, char *argv[])
             interactive = 1;
         } else
         if (SDL_strcmp(argv[i], "-8") == 0) {
-            audio_format = SDL_AUDIO_U8;
+            spec.format = SDL_AUDIO_U8;
         } else
         if (SDL_strcmp(argv[i], "-f32") == 0) {
-            audio_format = SDL_AUDIO_F32;
+            spec.format = SDL_AUDIO_F32;
         } else
         if (SDL_strcmp(argv[i], "-rwops") == 0) {
             rwops = 1;
@@ -194,16 +190,16 @@ int main(int argc, char *argv[])
 #endif
 
     /* Open the audio device */
-    if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, audio_buffers) < 0) {
+
+    if (Mix_OpenAudio(0, &spec) < 0) {
         SDL_Log("Couldn't open audio: %s\n", SDL_GetError());
         return(2);
     } else {
-        Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
-        SDL_Log("Opened audio at %d Hz %d bit%s %s %d bytes audio buffer\n", audio_rate,
-            (audio_format&0xFF),
-            (SDL_AUDIO_ISFLOAT(audio_format) ? " (float)" : ""),
-            (audio_channels > 2) ? "surround" : (audio_channels > 1) ? "stereo" : "mono",
-            audio_buffers);
+        Mix_QuerySpec(&spec.freq, &spec.format, &spec.channels);
+        SDL_Log("Opened audio at %d Hz %d bit%s %s audio buffer\n", spec.freq,
+            (spec.format&0xFF),
+            (SDL_AUDIO_ISFLOAT(spec.format) ? " (float)" : ""),
+            (spec.channels > 2) ? "surround" : (spec.channels > 1) ? "stereo" : "mono");
     }
     audio_open = 1;
 
diff --git a/examples/playwave.c b/examples/playwave.c
index 82011057..4bfffcfa 100644
--- a/examples/playwave.c
+++ b/examples/playwave.c
@@ -357,9 +357,7 @@ static void flip_sample(Mix_Chunk *wave)
 
 int main(int argc, char *argv[])
 {
-    int audio_rate;
-    Uint16 audio_format;
-    int audio_channels;
+    SDL_AudioSpec spec;
     int loops = 0;
     int i;
     int reverse_stereo = 0;
@@ -374,31 +372,31 @@ int main(int argc, char *argv[])
     output_test_warnings();
 
     /* Initialize variables */
-    audio_rate = MIX_DEFAULT_FREQUENCY;
-    audio_format = MIX_DEFAULT_FORMAT;
-    audio_channels = MIX_DEFAULT_CHANNELS;
+    spec.freq = MIX_DEFAULT_FREQUENCY;
+    spec.format = MIX_DEFAULT_FORMAT;
+    spec.channels = MIX_DEFAULT_CHANNELS;
 
     /* Check command line usage */
     for (i=1; argv[i] && (*argv[i] == '-'); ++i) {
         if ((SDL_strcmp(argv[i], "-r") == 0) && argv[i+1]) {
             ++i;
-            audio_rate = SDL_atoi(argv[i]);
+            spec.freq = SDL_atoi(argv[i]);
         } else
         if (SDL_strcmp(argv[i], "-m") == 0) {
-            audio_channels = 1;
+            spec.channels = 1;
         } else
         if ((SDL_strcmp(argv[i], "-c") == 0) && argv[i+1]) {
             ++i;
-            audio_channels = SDL_atoi(argv[i]);
+            spec.channels = SDL_atoi(argv[i]);
         } else
         if (SDL_strcmp(argv[i], "-l") == 0) {
             loops = -1;
         } else
         if (SDL_strcmp(argv[i], "-8") == 0) {
-            audio_format = SDL_AUDIO_U8;
+            spec.format = SDL_AUDIO_U8;
         } else
         if (SDL_strcmp(argv[i], "-f32") == 0) {
-            audio_format = SDL_AUDIO_F32;
+            spec.format = SDL_AUDIO_F32;
         } else
         if (SDL_strcmp(argv[i], "-f") == 0) { /* rcg06122001 flip stereo */
             reverse_stereo = 1;
@@ -426,16 +424,16 @@ int main(int argc, char *argv[])
 #endif
 
     /* Open the audio device */
-    if (Mix_OpenAudio(audio_rate, audio_format, audio_channels, 4096) < 0) {
+    if (Mix_OpenAudio(0, &spec) < 0) {
         SDL_Log("Couldn't open audio: %s\n", SDL_GetError());
         CleanUp(2);
     } else {
-        Mix_QuerySpec(&audio_rate, &audio_format, &audio_channels);
-        SDL_Log("Opened audio at %d Hz %d bit%s %s", audio_rate,
-            (audio_format&0xFF),
-            (SDL_AUDIO_ISFLOAT(audio_format) ? " (float)" : ""),
-            (audio_channels > 2) ? "surround" :
-            (audio_channels > 1) ? "stereo" : "mono");
+        Mix_QuerySpec(&spec.freq, &spec.format, &spec.channels);
+        SDL_Log("Opened audio at %d Hz %d bit%s %s", spec.freq,
+            (spec.format&0xFF),
+            (SDL_AUDIO_ISFLOAT(spec.format) ? " (float)" : ""),
+            (spec.channels > 2) ? "surround" :
+            (spec.channels > 1) ? "stereo" : "mono");
         if (loops) {
           SDL_Log(" (looping)\n");
         } else {
diff --git a/include/SDL3/SDL_mixer.h b/include/SDL3/SDL_mixer.h
index cf0e7a3a..eb9cb253 100644
--- a/include/SDL3/SDL_mixer.h
+++ b/include/SDL3/SDL_mixer.h
@@ -272,7 +272,7 @@ typedef enum {
 typedef struct _Mix_Music Mix_Music;
 
 /**
- * Open the default audio device for playback.
+ * Open an audio device for playback.
  *
  * An audio device is what generates sound, so the app must open one to make
  * noise.
@@ -282,164 +282,36 @@ typedef struct _Mix_Music Mix_Music;
  * You are free to (and encouraged to!) initialize it yourself before calling
  * this function, as this gives your program more control over the process.
  *
- * This function might cover all of an application's needs, but for those that
- * need more flexibility, the more powerful version of this function is
- * Mix_OpenAudioDevice(). This function is equivalent to calling:
- *
- * ```c
- * Mix_OpenAudioDevice(frequency, format, nchannels, chunksize, NULL,
- *                     SDL_AUDIO_ALLOW_FREQUENCY_CHANGE |
- *                     SDL_AUDIO_ALLOW_CHANNELS_CHANGE);
- * ```
- *
  * If you aren't particularly concerned with the specifics of the audio
- * device, and your data isn't in a specific format, the values you use here
- * can just be reasonable defaults. SDL_mixer will convert audio data you feed
- * it to the correct format on demand.
+ * device, and your data isn't in a specific format, you can pass a NULL for
+ * the `spec` parameter and SDL_mixer will choose a reasonable default.
+ * SDL_mixer will convert audio data you feed it to the hardware's format
+ * behind the scenes.
  *
  * That being said, if you have control of your audio data and you know its
- * format ahead of time, you can save CPU time by opening the audio device in
+ * format ahead of time, you may save CPU time by opening the audio device in
  * that exact format so SDL_mixer does not have to spend time converting
  * anything behind the scenes, and can just pass the data straight through to
- * the hardware. On some platforms, where the hardware only supports specific
- * settings, you might have to be careful to make everything match, but your
- * own data is often easier to control, so aim to open the device for what you
- * need.
+ * the hardware.
  *
  * The other reason to care about specific formats: if you plan to touch the
  * mix buffer directly (with Mix_SetPostMix, a registered effect, or
  * Mix_HookMusic), you might have code that expects it to be in a specific
  * format, and you should specify that here.
  *
- * The audio device frequency is specified in Hz; in modern times, 48000 is
- * often a reasonable default.
- *
- * The audio device format is one of SDL's SDL_AUDIO_* constants.
- * SDL_AUDIO_S16SYS (16-bit audio) is probably a safe default. More modern
- * systems may prefer SDL_AUDIO_F32SYS (32-bit floating point audio).
- *
- * The audio device channels are generally 1 for mono output, or 2 for stereo,
- * but the brave can try surround sound configs with 4 (quad), 6 (5.1), 7
- * (6.1) or 8 (7.1).
- *
- * The audio device's chunk size is the number of sample frames (one sample
- * per frame for mono output, two samples per frame in a stereo setup, etc)
- * that are fed to the device at once. The lower the number, the lower the
- * latency, but you risk dropouts if it gets too low. 2048 is often a
- * reasonable default, but your app might want to experiment with 1024 or
- * 4096.
- *
- * You may only have one audio device open at a time; if you want to change a
- * setting, you must close the device and reopen it, which is not something
- * you can do seamlessly during playback.
- *
- * This function does not allow you to select a specific audio device on the
- * system, it always chooses the best default it can on your behalf (which, in
- * many cases, is exactly what you want anyhow). If you must choose a specific
- * device, you can do so with Mix_OpenAudioDevice() instead.
- *
- * If this function reports success, you are ready to start making noise! Load
- * some audio data and start playing!
- *
- * The app can use Mix_QuerySpec() to determine the final device settings.
- *
- * When done with an audio device, probably at the end of the program, the app
- * should dispose of the device with Mix_CloseAudio().
- *
- * \param frequency the frequency to playback audio at (in Hz).
- * \param format audio format, one of SDL's SDL_AUDIO_* values.
- * \param channels number of channels (1 is mono, 2 is stereo, etc).
- * \param chunksize audio buffer size in sample FRAMES (total samples divided
- *                  by channel count).
- * \returns 0 if successful, -1 on error.
- *
- * \since This function is available since SDL_mixer 2.0.0.
- *
- * \sa Mix_OpenAudioDevice
- * \sa Mix_CloseAudio
- */
-extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int channels, int chunksize);
-
-
-/**
- * Open a specific audio device for playback.
- *
- * (A slightly simpler version of this function is available in
- * Mix_OpenAudio(), which still might meet most applications' needs.)
- *
- * An audio device is what generates sound, so the app must open one to make
- * noise.
- *
- * This function will check if SDL's audio system is initialized, and if not,
- * it will initialize it by calling `SDL_Init(SDL_INIT_AUDIO)` on your behalf.
- * You are free to (and encouraged to!) initialize it yourself before calling
- * this function, as this gives your program more control over the process.
- *
- * If you aren't particularly concerned with the specifics of the audio
- * device, and your data isn't in a specific format, the values you use here
- * can just be reasonable defaults. SDL_mixer will convert audio data you feed
- * it to the correct format on demand.
- *
- * That being said, if you have control of your audio data and you know its
- * format ahead of time, you can save CPU time by opening the audio device in
- * that exact format so SDL_mixer does not have to spend time converting
- * anything behind the scenes, and can just pass the data straight through to
- * the hardware. On some platforms, where the hardware only supports specific
- * settings, you might have to be careful to make everything match, but your
- * own data is often easier to control, so aim to open the device for what you
- * need.
- *
- * The other reason to care about specific formats: if you plan to touch the
- * mix buffer directly (with Mix_SetPostMix, a registered effect, or
- * Mix_HookMusic), you might have code that expects it to be in a specific
- * format, and you should specify that here.
- *
- * The audio device frequency is specified in Hz; in modern times, 48000 is
- * often a reasonable default.
- *
- * The audio device format is one of SDL's SDL_AUDIO_* constants.
- * SDL_AUDIO_S16SYS (16-bit audio) is probably a safe default. More modern
- * systems may prefer SDL_AUDIO_F32SYS (32-bit floating point audio).
- *
- * The audio device channels are generally 1 for mono output, or 2 for stereo,
- * but the brave can try surround sound configs with 4 (quad), 6 (5.1), 7
- * (6.1) or 8 (7.1).
- *
- * The audio device's chunk size is the number of sample frames (one sample
- * per frame for mono output, two samples per frame in a stereo setup, etc)
- * that are fed to the device at once. The lower the number, the lower the
- * latency, but you risk dropouts if it gets too low. 2048 is often a
- * reasonable default, but your app might want to experiment with 1024 or
- * 4096.
- *
  * You may only have one audio device open at a time; if you want to change a
  * setting, you must close the device and reopen it, which is not something
  * you can do seamlessly during playback.
  *
  * This function allows you to select specific audio hardware on the system
- * with the `device` parameter. If you specify NULL, SDL_mixer will choose the
+ * with the `devid` parameter. If you specify 0, SDL_mixer will choose the
  * best default it can on your behalf (which, in many cases, is exactly what
- * you want anyhow). SDL_mixer does not offer a mechanism to determine device
- * names to open, but you can use SDL_GetNumAudioDevices() to get a count of
- * available devices and then SDL_GetAudioDeviceName() in a loop to obtain a
- * list. If you do this, be sure to call `SDL_Init(SDL_INIT_AUDIO)` first to
- * initialize SDL's audio system!
- *
- * The `allowed_changes` parameter specifies what settings are flexible. These
- * are the `SDL_AUDIO_ALLOW_*` flags from SDL. These tell SDL_mixer that the
- * app doesn't mind if a specific setting changes. For example, the app might
- * need stereo data in Sint16 format, but if the sample rate or chunk size
- * changes, the app can handle that. In that case, the app would specify
- * `SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_SAMPLES_CHANGE`. In this
- * case, if the system's hardware requires something other than the requested
- * format, SDL_mixer can select what the hardware demands instead of the app.
- * If the `SDL_AUDIO_ALLOW_` flag is not specified, SDL_mixer must convert
- * data behind the scenes between what the app demands and what the hardware
- * requires. If your app needs precisely what is requested, specify zero for
- * `allowed_changes`.
- *
- * If changes were allowed, the app can use Mix_QuerySpec() to determine the
- * final device settings.
+ * you want anyhow). This is equivalent to specifying
+ * `SDL_AUDIO_DEVICE_DEFAULT_OUTPUT`, but is less wordy. SDL_mixer does not
+ * offer a mechanism to determine device IDs to open, but you can use
+ * SDL_GetAudioOutputDevices() to get a list of available devices. If you do
+ * this, be sure to call `SDL_Init(SDL_INIT_AUDIO)` first to initialize SDL's
+ * audio system!
  *
  * If this function reports success, you are ready to start making noise! Load
  * some audio data and start playing!
@@ -447,14 +319,8 @@ extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int chan
  * When done with an audio device, probably at the end of the program, the app
  * should dispose of the device with Mix_CloseDevice().
  *
- * \param frequency the frequency to playback audio at (in Hz).
- * \param format audio format, one of SDL's SDL_AUDIO_* values.
- * \param channels number of channels (1 is mono, 2 is stereo, etc).
- * \param chunksize audio buffer size in sample FRAMES (total samples divided
- *                  by channel count).
- * \param device the device name to open, or NULL to choose a reasonable
- *               default.
- * \param allowed_changes Allow change flags (see SDL_AUDIO_ALLOW_* flags)
+ * \param devid the device name to open, or 0 for a reasonable default.
+ * \param spec the audio format you'd like SDL_mixer to work in.
  * \returns 0 if successful, -1 on error.
  *
  * \since This function is available since SDL_mixer 2.0.2.
@@ -463,7 +329,7 @@ extern DECLSPEC int SDLCALL Mix_OpenAudio(int frequency, Uint16 format, int chan
  * \sa Mix_CloseDevice
  * \sa Mix_QuerySpec
  */
-extern DECLSPEC int SDLCALL Mix_OpenAudioDevice(int frequency, Uint16 format, int channels, int chunksize, const char* device, int allowed_changes);
+extern DECLSPEC int SDLCALL Mix_OpenAudio(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec);
 
 /**
  * Suspend or resume the whole audio output.
diff --git a/src/codecs/load_aiff.c b/src/codecs/load_aiff.c
index 85584f0d..48a533d0 100644
--- a/src/codecs/load_aiff.c
+++ b/src/codecs/load_aiff.c
@@ -227,7 +227,6 @@ SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, SDL_bool freesrc,
             goto done;
     }
     spec->channels = (Uint8) channels;
-    spec->samples = 4096;       /* Good default buffer size */
 
     *audio_len = channels * numsamples * (samplesize / 8);
     *audio_buf = (Uint8 *)SDL_malloc(*audio_len);
diff --git a/src/codecs/load_voc.c b/src/codecs/load_voc.c
index 8ccd8229..927b9270 100644
--- a/src/codecs/load_voc.c
+++ b/src/codecs/load_voc.c
@@ -450,8 +450,6 @@ SDL_AudioSpec *Mix_LoadVOC_RW (SDL_RWops *src, SDL_bool freesrc,
         fillptr = ((Uint8 *) ptr) + (*audio_len - v.rest);
     }
 
-    spec->samples = (Uint16)(*audio_len / v.size);
-
     /* Don't return a buffer that isn't a multiple of samplesize */
     samplesize = ((spec->format & 0xFF)/8)*spec->channels;
     *audio_len &= (Uint32) ~(samplesize-1);
diff --git a/src/codecs/music_drflac.c b/src/codecs/music_drflac.c
index 841373dc..8daba79d 100644
--- a/src/codecs/music_drflac.c
+++ b/src/codecs/music_drflac.c
@@ -161,6 +161,7 @@ static int DRFLAC_Seek(void *context, double position);
 static void *DRFLAC_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
 {
     DRFLAC_Music *music;
+    SDL_AudioSpec srcspec;
 
     music = (DRFLAC_Music *)SDL_calloc(1, sizeof(DRFLAC_Music));
     if (!music) {
@@ -184,12 +185,10 @@ static void *DRFLAC_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
     }
 
     /* We should have channels and sample rate set up here */
-    music->stream = SDL_CreateAudioStream(SDL_AUDIO_S16SYS,
-                                          (Uint8)music->channels,
-                                          music->sample_rate,
-                                          music_spec.format,
-                                          music_spec.channels,
-                                          music_spec.freq);
+    srcspec.format = SDL_AUDIO_S16SYS;
+    srcspec.channels = music->channels;
+    srcspec.freq = music->sample_rate;
+    music->stream = SDL_CreateAudioStream(&srcspec, &music_spec);
     if (!music->stream) {
         SDL_OutOfMemory();
         drflac_close(music->dec);
@@ -197,7 +196,7 @@ static void *DRFLAC_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
         return NULL;
     }
 
-    music->buffer_size = music_spec.samples * sizeof(drflac_int16) * music->channels;
+    music->buffer_size = 4096/*music_spec.samples*/ * sizeof(drflac_int16) * music->channels;
     music->buffer = (drflac_int16*)SDL_calloc(1, music->buffer_size);
     if (!music->buffer) {
         drflac_close(music->dec);
@@ -277,7 +276,7 @@ static int DRFLAC_GetSome(void *context, void *data, int bytes, SDL_bool *done)
         }
     }
 
-    amount = drflac_read_pcm_frames_s16(music->dec, music_spec.samples, music->buffer);
+    amount = drflac_read_pcm_frames_s16(music->dec, 4096/*music_spec.samples*/, music->buffer);
     if (amount > 0) {
         if (music->loop && (music->play_count != 1) &&
             ((Sint64)music->dec->currentPCMFrame >= music->loop_end)) {
diff --git a/src/codecs/music_drmp3.c b/src/codecs/music_drmp3.c
index f6ba73f2..79345707 100644
--- a/src/codecs/music_drmp3.c
+++ b/src/codecs/music_drmp3.c
@@ -82,6 +82,7 @@ static int DRMP3_Seek(void *context, double position);
 static void *DRMP3_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
 {
     DRMP3_Music *music;
+    SDL_AudioSpec srcspec;
 
     music = (DRMP3_Music *)SDL_calloc(1, sizeof(DRMP3_Music));
     if (!music) {
@@ -111,12 +112,10 @@ static void *DRMP3_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
     }
 
     music->channels = music->dec.channels;
-    music->stream = SDL_CreateAudioStream(SDL_AUDIO_S16SYS,
-                                          (Uint8)music->channels,
-                                          (int)music->dec.sampleRate,
-                                          music_spec.format,
-                                          music_spec.channels,
-                                          music_spec.freq);
+    srcspec.format = SDL_AUDIO_S16SYS;
+    srcspec.channels = music->channels;
+    srcspec.freq = (int)music->dec.sampleRate;
+    music->stream = SDL_CreateAudioStream(&srcspec, &music_spec);
     if (!music->stream) {
         SDL_OutOfMemory();
         drmp3_uninit(&music->dec);
@@ -124,7 +123,7 @@ static void *DRMP3_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
         return NULL;
     }
 
-    music->buffer_size = music_spec.samples * sizeof(drmp3_int16) * music->channels;
+    music->buffer_size = 4096/*music_spec.samples*/ * sizeof(drmp3_int16) * music->channels;
     music->buffer = (drmp3_int16*)SDL_calloc(1, music->buffer_size);
     if (!music->buffer) {
         drmp3_uninit(&music->dec);
@@ -182,7 +181,7 @@ static int DRMP3_GetSome(void *context, void *data, int bytes, SDL_bool *done)
         return 0;
     }
 
-    amount = drmp3_read_pcm_frames_s16(&music->dec, music_spec.samples, music->buffer);
+    amount = drmp3_read_pcm_frames_s16(&music->dec, 4096/*music_spec.samples*/, music->buffer);
     if (amount > 0) {
         if (SDL_PutAudioStreamData(music->stream, music->buffer, (int)amount * sizeof(drmp3_int16) * music->channels) < 0) {
             return -1;
diff --git a/src/codecs/music_flac.c b/src/codecs/music_flac.c
index 089dd763..80fbcb76 100644
--- a/src/codecs/music_flac.c
+++ b/src/codecs/music_flac.c
@@ -372,6 +372,8 @@ static void flac_metadata_music_cb(
     (void)decoder;
 
     if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
+        SDL_AudioSpec srcspec;
+
         music->sample_rate = metadata->data.stream_info.sample_rate;
         music->channels = metadata->data.stream_info.channels;
         music->bits_per_sample = metadata->data.stream_info.bits_per_sample;
@@ -388,12 +390,10 @@ static void flac_metadata_music_cb(
 
         /* We check for NULL stream later when we get data */
         SDL_assert(!music->stream);
-        music->stream = SDL_CreateAudioStream(SDL_AUDIO_S16SYS,
-                                              (Uint8)channels,
-                                              (int)music->sample_rate,
-                                              music_spec.format,
-                                              music_spec.channels,
-                                              music_spec.freq);
+        srcspec.format = SDL_AUDIO_S16SYS;
+        srcspec.channels = channels;
+        srcspec.freq = (int)music->sample_rate;
+        music->stream = SDL_CreateAudioStream(&srcspec, &music_spec);
     } else if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) {
         FLAC__uint32 i;
 
diff --git a/src/codecs/music_fluidsynth.c b/src/codecs/music_fluidsynth.c
index 9cbbadfd..671c1d50 100644
--- a/src/codecs/music_fluidsynth.c
+++ b/src/codecs/music_fluidsynth.c
@@ -171,6 +171,7 @@ static int FLUIDSYNTH_Open(const SDL_AudioSpec *spec)
 
 static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
 {
+    SDL_AudioSpec srcspec;
     SDL_RWops *src = (SDL_RWops *)data;
     FLUIDSYNTH_Music *music;
     double samplerate; /* as set by the lib. */
@@ -186,7 +187,7 @@ static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
     }
 
     music->volume = MIX_MAX_VOLUME;
-    music->buffer_size = music_spec.samples * sizeof(Sint16) * channels;
+    music->buffer_size = 4096/*music_spec.samples*/ * sizeof(Sint16) * channels;
     music->synth_write = fluidsynth.fluid_synth_write_s16;
     if (music_spec.format & 0x0020) { /* 32 bit. */
         src_format = SDL_AUDIO_F32SYS;
@@ -234,8 +235,10 @@ static FLUIDSYNTH_Music *FLUIDSYNTH_LoadMusic(void *data)
         goto fail;
     }
 
-    if (!(music->stream = SDL_CreateAudioStream(src_format, channels, (int) samplerate,
-                          music_spec.format, music_spec.channels, music_spec.freq))) {
+    srcspec.format = src_format;
+    srcspec.channels = channels;
+    srcspec.freq = (int) samplerate;
+    if (!(music->stream = SDL_CreateAudioStream(&srcspec, &music_spec))) {
         goto fail;
     }
 
@@ -296,7 +299,7 @@ static int FLUIDSYNTH_GetSome(void *context, void *data, int bytes, SDL_bool *do
         return filled;
     }
 
-    if (music->synth_write(music->synth, music_spec.samples, music->buffer, 0, 2, music->buffer, 1, 2) != FLUID_OK) {
+    if (music->synth_write(music->synth, 4096/*music_spec.samples*/, music->buffer, 0, 2, music->buffer, 1, 2) != FLUID_OK) {
         Mix_SetError("Error generating FluidSynth audio");
         return -1;
     }
diff --git a/src/codecs/music_gme.c b/src/codecs/music_gme.c
index d724bda3..9332c555 100644
--- a/src/codecs/music_gme.c
+++ b/src/codecs/music_gme.c
@@ -207,6 +207,7 @@ static int initialize_from_track_info(GME_Music *music, int track)
 
 static void *GME_CreateFromRW(struct SDL_RWops *src, SDL_bool freesrc)
 {
+    SDL_AudioSpec srcspec;
     void *mem = 0;
     size_t size;
     GME_Music *music;
@@ -222,17 +223,16 @@ static void *GME_CreateFromRW(struct SDL_RWops *src, SDL_bool freesrc)
     music->tempo = 1.0;
     music->gain = 1.0;
 
-    music->stream = SDL_CreateAudioStream(SDL_AUDIO_S16SYS, 2,
-                                          music_spec.freq,
-                                          music_spec.format,
-                                          music_spec.channels,
-                                          music_spec.freq);
+    srcspec.format = SDL_AUDIO_S16SYS;
+    srcspec.channels = 2;
+    srcspec.freq = music_spec.freq;
+    music->stream = SDL_CreateAudioStream(&srcspec, &music_spec);
     if (!music->stream) {
         GME_Delete(music);
         return NULL;
     }
 
-    music->buffer_size = music_spec.samples * sizeof(Sint16) * 2/*channels*/ * music_spec.channels;
+    music->buffer_size = 4096/*music_spec.samples*/ * sizeof(Sint16) * 2/*channels*/ * music_spec.channels;
     music->buffer = SDL_malloc(music->buffer_size);
     if (!music->buffer) {
         SDL_OutOfMemory();
diff --git a/src/codecs/music_modplug.c b/src/codecs/music_modplug.c
index ef8be2ea..091fb24d 100644
--- a/src/codecs/music_modplug.c
+++ b/src/codecs/music_modplug.c
@@ -163,6 +163,7 @@ static int MODPLUG_Open(const SDL_AudioSpec *spec)
 /* Load a modplug stream from an SDL_RWops object */
 void *MODPLUG_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
 {
+    SDL_AudioSpec srcspec;
     MODPLUG_Music *music;
     void *buffer;
     size_t size;
@@ -175,18 +176,16 @@ void *MODPLUG_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
 
     music->volume = MIX_MAX_VOLUME;
 
-    music->stream = SDL_CreateAudioStream((settings.mBits == 8) ? SDL_AUDIO_U8 : SDL_AUDIO_S16SYS,
-                                          (Uint8)settings.mChannels,
-                                          settings.mFrequency,
-                                          music_spec.format,
-                                          music_spec.channels,
-                                          music_spec.freq);
+    srcspec.format = (settings.mBits == 8) ? SDL_AUDIO_U8 : SDL_AUDIO_S16SYS;
+    srcspec.channels = settings.mChannels;
+    srcspec.freq = settings.mFrequency;
+    music->stream = SDL_CreateAudioStream(&srcspec, &music_spec);
     if (!music->stream) {
         MODPLUG_Delete(music);
         return NULL;
     }
 
-    music->buffer_size = music_spec.samples * (settings.mBits / 8) * settings.mChannels;
+    music->buffer_size = 4096/*music_spec.samples*/ * (settings.mBits / 8) * settings.mChannels;
     music->buffer = SDL_malloc((size_t)music->buffer_size);
     if (!music->buffer) {
         MODPLUG_Delete(music);
diff --git a/src/codecs/music_mpg123.c b/src/codecs/music_mpg123.c
index 7b06312b..a2f18a78 100644
--- a/src/codecs/music_mpg123.c
+++ b/src/codecs/music_mpg123.c
@@ -224,6 +224,7 @@ static int MPG123_Open(const SDL_AudioSpec *spec)
 
 static void *MPG123_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
 {
+    SDL_AudioSpec srcspec;
     MPG123_Music *music;
     int result, format, channels, encoding;
     long rate;
@@ -249,7 +250,7 @@ static void *MPG123_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
     }
 
     /* Just assume 16-bit 2 channel audio for now */
-    music->buffer_size = music_spec.samples * sizeof(Sint16) * 2;
+    music->buffer_size = 4096/*music_spec.samples*/ * sizeof(Sint16) * 2;
     music->buffer = (unsigned char *)SDL_malloc(music->buffer_size);
     if (!music->buffer) {
         MPG123_Delete(music);
@@ -315,8 +316,10 @@ static void *MPG123_CreateFromRW(SDL_RWops *src, SDL_bool freesrc)
     SDL_assert(format != -1);
     music->sample

(Patch may be truncated, please check the link at the top of this post.)