SDL_mixer: After calling a conversion function, set the value to 0 on error(-1)

From 331080be0109c15c51680cce308199a2298115b9 Mon Sep 17 00:00:00 2001
From: Petar Popovic <[EMAIL REDACTED]>
Date: Mon, 28 Jul 2025 16:37:56 +0200
Subject: [PATCH] After calling a conversion function, set the value to 0 on
 error(-1)

Necessary so that the behavior is the same as when the return value was 0 on error.
---
 src/SDL_mixer.c          | 18 +++++++++++++++---
 src/decoder_fluidsynth.c |  7 +++++--
 src/decoder_gme.c        |  5 ++++-
 src/decoder_timidity.c   | 10 ++++++++--
 src/decoder_xmp.c        | 11 +++++++++--
 5 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/src/SDL_mixer.c b/src/SDL_mixer.c
index a8fd6044..a7c98ef7 100644
--- a/src/SDL_mixer.c
+++ b/src/SDL_mixer.c
@@ -1950,7 +1950,11 @@ static Sint64 GetTrackOptionFramesOrTicks(MIX_Track *track, SDL_PropertiesID opt
         return SDL_GetNumberProperty(options, framesprop, defval);
     } else if (SDL_HasProperty(options, msprop)) {
         const Sint64 val = SDL_GetNumberProperty(options, msprop, defval);
-        return (val < 0) ? val : MIX_TrackMSToFrames(track, val);
+        Sint64 val_frames = MIX_TrackMSToFrames(track, val);
+        if (val_frames == -1) {
+            val_frames = 0;
+        }
+        return (val < 0) ? val : val_frames;
     }
     return defval;
 }
@@ -2118,7 +2122,11 @@ bool MIX_StopAllTracks(MIX_Mixer *mixer, Sint64 fade_out_ms)
     LockMixer(mixer);  // lock the mixer so all tracks stop at the same time.
 
     for (MIX_Track *track = mixer->all_tracks; track != NULL; track = track->next) {
-        StopTrack(track, (fade_out_ms > 0) ? MIX_TrackMSToFrames(track, fade_out_ms) : -1);
+        Sint64 fade_out_frames = MIX_TrackMSToFrames(track, fade_out_ms);
+        if (fade_out_frames == -1) {
+            fade_out_frames = 0;
+        }
+        StopTrack(track, (fade_out_ms > 0) ? fade_out_frames : -1);
     }
 
     UnlockMixer(mixer);
@@ -2141,7 +2149,11 @@ bool MIX_StopTag(MIX_Mixer *mixer, const char *tag, Sint64 fade_out_ms)
 
     const size_t total = list->num_tracks;
     for (size_t i = 0; i < total; i++) {
-        StopTrack(list->tracks[i], (fade_out_ms > 0) ? MIX_TrackMSToFrames(list->tracks[i], fade_out_ms) : -1);
+        Sint64 fade_out_frames = MIX_TrackMSToFrames(list->tracks[i], fade_out_ms);
+        if (fade_out_frames == -1) {
+            fade_out_frames = 0;
+        }
+        StopTrack(list->tracks[i], (fade_out_ms > 0) ? fade_out_frames : -1);
     }
 
     SDL_UnlockRWLock(list->rwlock);
diff --git a/src/decoder_fluidsynth.c b/src/decoder_fluidsynth.c
index f0089590..942a6db5 100644
--- a/src/decoder_fluidsynth.c
+++ b/src/decoder_fluidsynth.c
@@ -338,10 +338,13 @@ static bool SDLCALL FLUIDSYNTH_seek(void *track_userdata, Uint64 frame)
     return SDL_Unsupported();
 #else
     FLUIDSYNTH_TrackData *tdata = (FLUIDSYNTH_TrackData *) track_userdata;
-    const int ticks = (int) MIX_FramesToMS(tdata->freq, frame);
+    Sint64 ticks = MIX_FramesToMS(tdata->freq, frame);
+    if (ticks == -1) {
+        ticks = 0;
+    }
 
     // !!! FIXME: docs say this will fail if a seek was requested and then a second seek happens before we play more of the midi file, since the first seek will still be in progress.
-    return (fluidsynth.fluid_player_seek(tdata->player, ticks) == FLUID_OK);
+    return (fluidsynth.fluid_player_seek(tdata->player, (int)ticks) == FLUID_OK);
 #endif
 }
 
diff --git a/src/decoder_gme.c b/src/decoder_gme.c
index 13bbb2a7..5d8117bb 100644
--- a/src/decoder_gme.c
+++ b/src/decoder_gme.c
@@ -111,7 +111,10 @@ static bool SDLCALL GME_init_audio(SDL_IOStream *io, SDL_AudioSpec *spec, SDL_Pr
         if ((info->intro_length >= 0) && (info->loop_length > 0)) {
             *duration_frames = MIX_DURATION_INFINITE;
         } else if (info->length >= 0) {
-            *duration_frames = (Sint64) MIX_MSToFrames(spec->freq, info->length);
+            *duration_frames = MIX_MSToFrames(spec->freq, info->length);
+            if (*duration_frames == -1) {
+                *duration_frames = 0;
+            }
         }
 
         gme.gme_free_info(info);
diff --git a/src/decoder_timidity.c b/src/decoder_timidity.c
index 29ef6b34..9131ad35 100644
--- a/src/decoder_timidity.c
+++ b/src/decoder_timidity.c
@@ -91,6 +91,9 @@ static bool SDLCALL TIMIDITY_init_audio(SDL_IOStream *io, SDL_AudioSpec *spec, S
     }
 
     song_length_in_frames = MIX_MSToFrames(spec->freq, Timidity_GetSongLength(song));
+    if (song_length_in_frames == -1) {
+        song_length_in_frames = 0;
+    }
     Timidity_FreeSong(song);
 
     *duration_frames = song_length_in_frames;
@@ -138,8 +141,11 @@ static bool SDLCALL TIMIDITY_decode(void *track_userdata, SDL_AudioStream *strea
 static bool SDLCALL TIMIDITY_seek(void *track_userdata, Uint64 frame)
 {
     TIMIDITY_TrackData *tdata = (TIMIDITY_TrackData *) track_userdata;
-    const Uint32 ticks = (Uint32) MIX_FramesToMS(tdata->freq, frame);
-    Timidity_Seek(tdata->song, ticks);  // !!! FIXME: this returns void, what happens if we seek past EOF?
+    Sint64 ticks = MIX_FramesToMS(tdata->freq, frame);
+    if (ticks == -1) {
+        ticks = 0;
+    }
+    Timidity_Seek(tdata->song, (Uint32)ticks);  // !!! FIXME: this returns void, what happens if we seek past EOF?
     return true;
 }
 
diff --git a/src/decoder_xmp.c b/src/decoder_xmp.c
index 282b3391..a2ba7fd8 100644
--- a/src/decoder_xmp.c
+++ b/src/decoder_xmp.c
@@ -177,7 +177,10 @@ static bool SDLCALL XMP_init_audio(SDL_IOStream *io, SDL_AudioSpec *spec, SDL_Pr
     struct xmp_frame_info frame_info;
     libxmp.xmp_get_frame_info(ctx, &frame_info);
 
-    *duration_frames = MIX_MSToFrames(spec->freq, (Uint64) frame_info.total_time);   // closest we can get.
+    *duration_frames = MIX_MSToFrames(spec->freq, (Sint64) frame_info.total_time);   // closest we can get.
+    if (*duration_frames == -1) {
+        *duration_frames = 0;
+    }
 
     libxmp.xmp_stop_module(ctx);
     libxmp.xmp_end_player(ctx);
@@ -256,7 +259,11 @@ static bool SDLCALL XMP_decode(void *track_userdata, SDL_AudioStream *stream)
 static bool SDLCALL XMP_seek(void *track_userdata, Uint64 frame)
 {
     XMP_TrackData *tdata = (XMP_TrackData *) track_userdata;
-    const int err = libxmp.xmp_seek_time(tdata->ctx, (int) MIX_FramesToMS(tdata->freq, frame));
+    Sint64 ms = MIX_FramesToMS(tdata->freq, (Sint64) frame);
+    if (ms == -1) {
+        ms = 0;
+    }
+    const int err = libxmp.xmp_seek_time(tdata->ctx, (int) ms);
     return err ? SetLibXmpError("xmp_seek_time", err) : true;
 }