From 15a0f4c559a60ca4523ce78276a5df496fdda334 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Thu, 18 Dec 2025 17:38:05 -0500
Subject: [PATCH] api: Added MIX_SetTrackLoops
Fixes #742.
---
include/SDL3_mixer/SDL_mixer.h | 30 ++++++++++++++++++++++++++++++
src/SDL_mixer.c | 21 +++++++++++++++++++++
src/SDL_mixer.exports | 1 +
src/SDL_mixer.sym | 1 +
4 files changed, 53 insertions(+)
diff --git a/include/SDL3_mixer/SDL_mixer.h b/include/SDL3_mixer/SDL_mixer.h
index 56cba974..08036df7 100644
--- a/include/SDL3_mixer/SDL_mixer.h
+++ b/include/SDL3_mixer/SDL_mixer.h
@@ -1331,6 +1331,36 @@ extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetTrackPlaybackPosition(MIX_Track *track
*/
extern SDL_DECLSPEC bool SDLCALL MIX_TrackLooping(MIX_Track *track);
+/**
+ * Change the number of times a currently-playing track will loop.
+ *
+ * This replaces any previously-set remaining loops. A value of 1 will loop to
+ * the start of playback one time. Zero will not loop at all. A value of -1
+ * requests infinite loops. If the input is not seekable and `num_loops` isn't
+ * zero, this function will report success but the track will stop at the
+ * point it should loop.
+ *
+ * The new loop count replaces any previous state, even if the track has
+ * already looped.
+ *
+ * This has no effect on a track that is fading out or stopped, and will
+ * return false. Stopped tracks can specify a loop count while starting via
+ * MIX_PROP_PLAY_LOOPS_NUMBER. This function alters that count in the middle
+ * of playback.
+ *
+ * \param track the track to configure.
+ * \param num_loops new number of times to loop. Zero to disable looping, -1
+ * to loop infinitely.
+ * \returns true on success, false on error; call SDL_GetError() for details.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL_mixer 3.0.0.
+ *
+ * \sa MIX_TrackLooping
+ */
+extern SDL_DECLSPEC bool MIX_SetTrackLoops(MIX_Track *track, int num_loops);
+
/**
* Query the MIX_Audio assigned to a track.
*
diff --git a/src/SDL_mixer.c b/src/SDL_mixer.c
index 333119ff..432cd572 100644
--- a/src/SDL_mixer.c
+++ b/src/SDL_mixer.c
@@ -1893,6 +1893,27 @@ bool MIX_TrackLooping(MIX_Track *track)
return retval;
}
+bool MIX_SetTrackLoops(MIX_Track *track, int num_loops)
+{
+ bool retval = false;
+ if (CheckTrackParam(track)) {
+ if (num_loops < -1) {
+ num_loops = -1; // keep this value consistent if we're looping infinitely.
+ }
+ LockTrack(track);
+ if (track->state == MIX_STATE_STOPPED) {
+ retval = SDL_SetError("Track is not playing");
+ } else if (track->fade_direction < 0) {
+ retval = SDL_SetError("Track is fading out");
+ } else {
+ track->loops_remaining = num_loops;
+ retval = true;
+ }
+ UnlockTrack(track);
+ }
+ return retval;
+}
+
MIX_Audio *MIX_GetTrackAudio(MIX_Track *track)
{
MIX_Audio *retval = NULL;
diff --git a/src/SDL_mixer.exports b/src/SDL_mixer.exports
index 88379ca2..de6d4065 100644
--- a/src/SDL_mixer.exports
+++ b/src/SDL_mixer.exports
@@ -84,4 +84,5 @@ _MIX_DestroyAudioDecoder
_MIX_GetAudioDecoderProperties
_MIX_DecodeAudio
_MIX_GetAudioDecoderFormat
+_MIX_SetTrackLoops
# extra symbols go here (don't modify this line)
diff --git a/src/SDL_mixer.sym b/src/SDL_mixer.sym
index 02048bf1..0d7a6ddd 100644
--- a/src/SDL_mixer.sym
+++ b/src/SDL_mixer.sym
@@ -85,6 +85,7 @@ SDL3_mixer_0.0.0 {
MIX_GetAudioDecoderProperties;
MIX_DecodeAudio;
MIX_GetAudioDecoderFormat;
+ MIX_SetTrackLoops;
# extra symbols go here (don't modify this line)
local: *;
};