SDL_mixer: Remap and don't discard buffers also on music_ogg_stb backend.

From 790b35d9504e23d9ff7ec9c7de067e832dc7364b Mon Sep 17 00:00:00 2001
From: "Daniel K. O. (dkosmari)" <[EMAIL REDACTED]>
Date: Mon, 19 Jan 2026 22:13:21 -0300
Subject: [PATCH] Remap and don't discard buffers also on music_ogg_stb
 backend.

---
 src/codecs/music_ogg.c      |   7 +-
 src/codecs/music_ogg_stb.c  |  60 +++++++++--------
 src/codecs/music_opus.c     |   7 +-
 src/codecs/remap_channels.c | 124 ++++++++++++++++++++++++++++++++----
 src/codecs/remap_channels.h |   4 +-
 5 files changed, 160 insertions(+), 42 deletions(-)

diff --git a/src/codecs/music_ogg.c b/src/codecs/music_ogg.c
index 0338ac8cb..a15801628 100644
--- a/src/codecs/music_ogg.c
+++ b/src/codecs/music_ogg.c
@@ -222,8 +222,9 @@ static int OGG_UpdateSection(OGG_music *music)
         return -1;
     }
 
-    /* Note: never shrink the buffer, we just decoded data in there. */
     new_buffer_size = music_spec.samples * (int)sizeof(Sint16) * vi->channels;
+
+    /* Note: never shrink the buffer, we just decoded data in there. */
     if (new_buffer_size > music->buffer_size) {
         char *new_buffer = (char *)SDL_realloc(music->buffer, new_buffer_size);
         if (!new_buffer) {
@@ -408,7 +409,9 @@ static int OGG_GetSome(void *context, void *data, int bytes, SDL_bool *done)
         }
     }
 
-    remap_channels_vorbis((Sint16 *)music->buffer, amount / (int)sizeof(Sint16), music->vi.channels);
+    remap_channels_vorbis_s16((Sint16 *)music->buffer,
+                              amount / (int)sizeof(Sint16),
+                              music->vi.channels);
 
     pcmPos = vorbis.ov_pcm_tell(&music->vf);
     if (music->loop && (music->play_count != 1) && (pcmPos >= music->loop_end)) {
diff --git a/src/codecs/music_ogg_stb.c b/src/codecs/music_ogg_stb.c
index f9b36d46a..c3e7386ec 100644
--- a/src/codecs/music_ogg_stb.c
+++ b/src/codecs/music_ogg_stb.c
@@ -24,6 +24,7 @@
 /* This file supports Ogg Vorbis music streams using a modified stb_vorbis module */
 
 #include "music_ogg.h"
+#include "remap_channels.h"
 #include "utils.h"
 #include "SDL_assert.h"
 
@@ -74,7 +75,6 @@ typedef struct {
     int volume;
     stb_vorbis *vf;
     stb_vorbis_info vi;
-    int section;
     SDL_AudioStream *stream;
     char *buffer;
     int buffer_size;
@@ -123,18 +123,15 @@ static void OGG_Delete(void *context);
 static int OGG_UpdateSection(OGG_music *music)
 {
     stb_vorbis_info vi;
+    int new_buffer_size;
 
     vi = stb_vorbis_get_info(music->vf);
 
     if (vi.channels == music->vi.channels && vi.sample_rate == music->vi.sample_rate) {
         return 0;
     }
-    SDL_memcpy(&music->vi, &vi, sizeof(vi));
 
-    if (music->buffer) {
-        SDL_free(music->buffer);
-        music->buffer = NULL;
-    }
+    music->vi = vi;
 
     if (music->stream) {
         SDL_FreeAudioStream(music->stream);
@@ -144,17 +141,30 @@ static int OGG_UpdateSection(OGG_music *music)
     music->stream = SDL_NewAudioStream(AUDIO_F32SYS, (Uint8)vi.channels, (int)vi.sample_rate,
                                        music_spec.format, music_spec.channels, music_spec.freq);
     if (!music->stream) {
+        SDL_free(music->buffer);
+        music->buffer      = NULL;
+        music->buffer_size = 0;
         return -1;
     }
 
-    music->buffer_size = music_spec.samples * (int)sizeof(float) * vi.channels;
-    if (music->buffer_size <= 0) {
+    new_buffer_size = music_spec.samples * (int)sizeof(float) * vi.channels;
+    if (new_buffer_size <= 0) {
+        music->buffer      = NULL;
+        music->buffer_size = 0;
         return -1;
     }
 
-    music->buffer = (char *)SDL_malloc((size_t)music->buffer_size);
-    if (!music->buffer) {
-        return -1;
+    /* Note: never shrink the buffer, we just decoded data in there. */
+    if (new_buffer_size > music->buffer_size) {
+        char *new_buffer = (char *)SDL_realloc(music->buffer, new_buffer_size);
+        if (!new_buffer) {
+            SDL_free(music->buffer);
+            music->buffer      = NULL;
+            music->buffer_size = 0;
+            return -1;
+        }
+        music->buffer      = new_buffer;
+        music->buffer_size = new_buffer_size;
     }
     return 0;
 }
@@ -175,7 +185,6 @@ static void *OGG_CreateFromRW(SDL_RWops *src, int freesrc)
     }
     music->src = src;
     music->volume = MIX_MAX_VOLUME;
-    music->section = -1;
 
     music->vf = stb_vorbis_open_rwops(src, 0, &error, NULL);
 
@@ -308,8 +317,7 @@ static int OGG_GetSome(void *context, void *data, int bytes, SDL_bool *done)
 {
     OGG_music *music = (OGG_music *)context;
     SDL_bool looped = SDL_FALSE;
-    int filled, amount, result;
-    int section;
+    int filled, amount, samples, result;
     Sint64 pcmPos;
 
     filled = SDL_AudioStreamGet(music->stream, data, bytes);
@@ -323,21 +331,21 @@ static int OGG_GetSome(void *context, void *data, int bytes, SDL_bool *done)
         return 0;
     }
 
-    section = music->section;
-    amount = stb_vorbis_get_samples_float_interleaved(music->vf,
-                                                music->vi.channels,
-                                                (float *)music->buffer,
-                                                music_spec.samples * music->vi.channels);
+    samples = stb_vorbis_get_samples_float_interleaved(music->vf,
+                                                       music->vi.channels,
+                                                       (float *)music->buffer,
+                                                       music->buffer_size / (int)sizeof(float));
 
-    amount *= music->vi.channels * sizeof(float);
-
-    if (section != music->section) {
-        music->section = section;
-        if (OGG_UpdateSection(music) < 0) {
-            return -1;
-        }
+    if (OGG_UpdateSection(music) < 0) {
+        return -1;
     }
 
+    amount = samples * music->vi.channels * sizeof(float);
+
+    remap_channels_vorbis_flt((float *)music->buffer,
+                              samples * music->vi.channels,
+                              music->vi.channels);
+
     pcmPos = stb_vorbis_get_playback_sample_offset(music->vf);
     if (music->loop && (music->play_count != 1) && (pcmPos >= music->loop_end)) {
         amount -= (int)((pcmPos - music->loop_end) * music->vi.channels) * (int)sizeof(float);
diff --git a/src/codecs/music_opus.c b/src/codecs/music_opus.c
index 648d50cb6..4ddae9f14 100644
--- a/src/codecs/music_opus.c
+++ b/src/codecs/music_opus.c
@@ -196,8 +196,9 @@ static int OPUS_UpdateSection(OPUS_music *music)
         return -1;
     }
 
-    /* Note: never shrink the buffer, we just decoded data in there. */
     new_buffer_size = (int)music_spec.samples * (int)sizeof(opus_int16) * op_info->channel_count;
+
+    /* Note: never shrink the buffer, we just decoded data in there. */
     if (new_buffer_size > music->buffer_size) {
         char *new_buffer = (char *)SDL_realloc(music->buffer, (size_t)new_buffer_size);
         if (!new_buffer) {
@@ -387,7 +388,9 @@ static int OPUS_GetSome(void *context, void *data, int bytes, SDL_bool *done)
     }
 
     if (music->op_info->mapping_family == 1) {
-        remap_channels_vorbis((Sint16 *)music->buffer, samples * music->op_info->channel_count, music->op_info->channel_count);
+        remap_channels_vorbis_s16((Sint16 *)music->buffer,
+                                  samples * music->op_info->channel_count,
+                                  music->op_info->channel_count);
     }
 
     pcmPos = opus.op_pcm_tell(music->of);
diff --git a/src/codecs/remap_channels.c b/src/codecs/remap_channels.c
index 552b06c1d..9c057e6dd 100644
--- a/src/codecs/remap_channels.c
+++ b/src/codecs/remap_channels.c
@@ -107,7 +107,7 @@
 #include "remap_channels.h"
 
 
-static void remap_channels_vorbis_3(Sint16 *samples, int num_samples)
+static void remap_channels_vorbis_3_s16(Sint16 *samples, int num_samples)
 {
     /* Note: this isn't perfect, because we map FC to LFE */
     int i;
@@ -119,7 +119,19 @@ static void remap_channels_vorbis_3(Sint16 *samples, int num_samples)
     }
 }
 
-static void remap_channels_vorbis_5(Sint16 *samples, int num_samples)
+static void remap_channels_vorbis_3_flt(float *samples, int num_samples)
+{
+    /* Note: this isn't perfect, because we map FC to LFE */
+    int i;
+    for (i = 0; i < num_samples; i += 3) {
+        float FC = samples[i + 1];
+        float FR = samples[i + 2];
+        samples[i + 1] = FR;
+        samples[i + 2] = FC;
+    }
+}
+
+static void remap_channels_vorbis_5_s16(Sint16 *samples, int num_samples)
 {
     /* Note: this isn't perfect, because we map FC to LFE. */
     int i;
@@ -131,7 +143,19 @@ static void remap_channels_vorbis_5(Sint16 *samples, int num_samples)
     }
 }
 
-static void remap_channels_vorbis_5_1(Sint16 *samples, int num_samples)
+static void remap_channels_vorbis_5_flt(float *samples, int num_samples)
+{
+    /* Note: this isn't perfect, because we map FC to LFE. */
+    int i;
+    for (i = 0; i < num_samples; i += 5) {
+        float FC = samples[i + 1];
+        float FR = samples[i + 2];
+        samples[i + 1] = FR;
+        samples[i + 2] = FC;
+    }
+}
+
+static void remap_channels_vorbis_5_1_s16(Sint16 *samples, int num_samples)
 {
     int i;
     for (i = 0; i < num_samples; i += 6) {
@@ -148,7 +172,24 @@ static void remap_channels_vorbis_5_1(Sint16 *samples, int num_samples)
     }
 }
 
-static void remap_channels_vorbis_7(Sint16 *samples, int num_samples)
+static void remap_channels_vorbis_5_1_flt(float *samples, int num_samples)
+{
+    int i;
+    for (i = 0; i < num_samples; i += 6) {
+        float FC  = samples[i + 1];
+        float FR  = samples[i + 2];
+        float RL  = samples[i + 3];
+        float RR  = samples[i + 4];
+        float LFE = samples[i + 5];
+        samples[i + 1] = FR;
+        samples[i + 2] = FC;
+        samples[i + 3] = LFE;
+        samples[i + 4] = RL;
+        samples[i + 5] = RR;
+    }
+}
+
+static void remap_channels_vorbis_7_s16(Sint16 *samples, int num_samples)
 {
     int i = 0;
     for (i = 0; i < num_samples; i += 7) {
@@ -167,7 +208,26 @@ static void remap_channels_vorbis_7(Sint16 *samples, int num_samples)
     }
 }
 
-static void remap_channels_vorbis_7_1(Sint16 *samples, int num_samples)
+static void remap_channels_vorbis_7_flt(float *samples, int num_samples)
+{
+    int i = 0;
+    for (i = 0; i < num_samples; i += 7) {
+        float FC  = samples[i + 1];
+        float FR  = samples[i + 2];
+        float SL  = samples[i + 3];
+        float SR  = samples[i + 4];
+        float RC  = samples[i + 5];
+        float LFE = samples[i + 6];
+        samples[i + 1] = FR;
+        samples[i + 2] = FC;
+        samples[i + 3] = LFE;
+        samples[i + 4] = RC;
+        samples[i + 5] = SL;
+        samples[i + 6] = SR;
+    }
+}
+
+static void remap_channels_vorbis_7_1_s16(Sint16 *samples, int num_samples)
 {
     int i = 0;
     for (i = 0; i < num_samples; i += 8) {
@@ -188,23 +248,65 @@ static void remap_channels_vorbis_7_1(Sint16 *samples, int num_samples)
     }
 }
 
-void remap_channels_vorbis(Sint16 *samples, int num_samples, int num_channels)
+static void remap_channels_vorbis_7_1_flt(float *samples, int num_samples)
+{
+    int i = 0;
+    for (i = 0; i < num_samples; i += 8) {
+        float FC  = samples[i + 1];
+        float FR  = samples[i + 2];
+        float SL  = samples[i + 3];
+        float SR  = samples[i + 4];
+        float RL  = samples[i + 5];
+        float RR  = samples[i + 6];
+        float LFE = samples[i + 7];
+        samples[i + 1] = FR;
+        samples[i + 2] = FC;
+        samples[i + 3] = LFE;
+        samples[i + 4] = RL;
+        samples[i + 5] = RR;
+        samples[i + 6] = SL;
+        samples[i + 7] = SR;
+    }
+}
+
+void remap_channels_vorbis_s16(Sint16 *samples, int num_samples, int num_channels)
+{
+    switch (num_channels) {
+    case 3:
+        remap_channels_vorbis_3_s16(samples, num_samples);
+        break;
+    case 5:
+        remap_channels_vorbis_5_s16(samples, num_samples);
+        break;
+    case 6:
+        remap_channels_vorbis_5_1_s16(samples, num_samples);
+        break;
+    case 7:
+        remap_channels_vorbis_7_s16(samples, num_samples);
+        break;
+    case 8:
+        remap_channels_vorbis_7_1_s16(samples, num_samples);
+        break;
+    }
+}
+
+void remap_channels_vorbis_flt(float *samples, int num_samples, int num_channels)
 {
     switch (num_channels) {
     case 3:
-        remap_channels_vorbis_3(samples, num_samples);
+        remap_channels_vorbis_3_flt(samples, num_samples);
         break;
     case 5:
-        remap_channels_vorbis_5(samples, num_samples);
+        remap_channels_vorbis_5_flt(samples, num_samples);
         break;
     case 6:
-        remap_channels_vorbis_5_1(samples, num_samples);
+        remap_channels_vorbis_5_1_flt(samples, num_samples);
         break;
     case 7:
-        remap_channels_vorbis_7(samples, num_samples);
+        remap_channels_vorbis_7_flt(samples, num_samples);
         break;
     case 8:
-        remap_channels_vorbis_7_1(samples, num_samples);
+        remap_channels_vorbis_7_1_flt(samples, num_samples);
         break;
     }
 }
diff --git a/src/codecs/remap_channels.h b/src/codecs/remap_channels.h
index 235364871..3f5d03bb3 100644
--- a/src/codecs/remap_channels.h
+++ b/src/codecs/remap_channels.h
@@ -24,6 +24,8 @@
 
 #include "SDL_types.h"
 
-extern void remap_channels_vorbis(Sint16 *samples, int num_samples, int num_channels);
+extern void remap_channels_vorbis_s16(Sint16 *samples, int num_samples, int num_channels);
+
+extern void remap_channels_vorbis_flt(float *samples, int num_samples, int num_channels);
 
 #endif /* CHANNEL_REMAP_H_ */