From 7675a97bab3997772d8f20609c5d57109bd3fb53 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Mon, 29 Dec 2025 19:46:51 -0500
Subject: [PATCH] api: Added MIX_GetTaggedTracks().
Fixes #759.
---
include/SDL3_mixer/SDL_mixer.h | 19 +++++++++++++++++++
src/SDL_mixer.c | 31 +++++++++++++++++++++++++++++++
src/SDL_mixer.exports | 1 +
src/SDL_mixer.sym | 1 +
test/testmixer.c | 4 ++++
5 files changed, 56 insertions(+)
diff --git a/include/SDL3_mixer/SDL_mixer.h b/include/SDL3_mixer/SDL_mixer.h
index 11ccaac5..12c0cd01 100644
--- a/include/SDL3_mixer/SDL_mixer.h
+++ b/include/SDL3_mixer/SDL_mixer.h
@@ -1275,6 +1275,25 @@ extern SDL_DECLSPEC void SDLCALL MIX_UntagTrack(MIX_Track *track, const char *ta
*/
extern SDL_DECLSPEC char ** SDLCALL MIX_GetTrackTags(MIX_Track *track, int *count);
+/**
+ * Get all tracks with a specific tag.
+ *
+ * Tracks are not provided in any guaranteed order.
+ *
+ * \param mixer the mixer to query.
+ * \param tag the tag to search.
+ * \param count a pointer filled in with the number of tracks returned, can
+ * be NULL.
+ * \returns an array of the tracks, NULL-terminated, or NULL on
+ * failure; call SDL_GetError() for more information. The returned
+ * pointer hould be freed with SDL_free() when it is no longer needed.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL_mixer 3.0.0.
+ */
+extern SDL_DECLSPEC MIX_Track ** SDLCALL MIX_GetTaggedTracks(MIX_Mixer *mixer, const char *tag, int *count);
+
/**
* Seek a playing track to a new position in its input.
*
diff --git a/src/SDL_mixer.c b/src/SDL_mixer.c
index f119a7b3..48a0e825 100644
--- a/src/SDL_mixer.c
+++ b/src/SDL_mixer.c
@@ -1917,6 +1917,37 @@ char **MIX_GetTrackTags(MIX_Track *track, int *count)
return retval;
}
+MIX_Track **MIX_GetTaggedTracks(MIX_Mixer *mixer, const char *tag, int *count)
+{
+ int dummycount;
+ if (!count) {
+ count = &dummycount;
+ }
+ *count = 0;
+
+ if (!CheckMixerTagParam(mixer, tag)) {
+ return NULL;
+ }
+
+ MIX_TagList *list = (MIX_TagList *) SDL_GetPointerProperty(mixer->track_tags, tag, NULL);
+ if (!list) { // nothing is using this tag?
+ return (MIX_Track **) SDL_calloc(1, sizeof (MIX_Track *)); // just a single NULL entry (or a NULL return if out of memory, works either way).
+ }
+
+ MIX_Track **retval = NULL;
+ SDL_LockRWLockForReading(list->rwlock);
+ const size_t total = list->num_tracks;
+ retval = (MIX_Track **) SDL_malloc(sizeof (*retval) * (total + 1));
+ if (retval) {
+ SDL_memcpy(retval, list->tracks, sizeof (*retval) * total);
+ retval[total] = NULL;
+ *count = (int) total;
+ }
+ SDL_UnlockRWLock(list->rwlock);
+
+ return retval;
+}
+
bool MIX_SetTrackPlaybackPosition(MIX_Track *track, Sint64 frames)
{
diff --git a/src/SDL_mixer.exports b/src/SDL_mixer.exports
index 2f990da1..b9335c78 100644
--- a/src/SDL_mixer.exports
+++ b/src/SDL_mixer.exports
@@ -87,4 +87,5 @@ _MIX_GetAudioDecoderFormat
_MIX_SetTrackLoops
_MIX_GetTrackFadeFrames
_MIX_GetTrackTags
+_MIX_GetTaggedTracks
# extra symbols go here (don't modify this line)
diff --git a/src/SDL_mixer.sym b/src/SDL_mixer.sym
index 51ccaabf..5296e7cb 100644
--- a/src/SDL_mixer.sym
+++ b/src/SDL_mixer.sym
@@ -88,6 +88,7 @@ SDL3_mixer_0.0.0 {
MIX_SetTrackLoops;
MIX_GetTrackFadeFrames;
MIX_GetTrackTags;
+ MIX_GetTaggedTracks;
# extra symbols go here (don't modify this line)
local: *;
};
diff --git a/test/testmixer.c b/test/testmixer.c
index 0f47ef79..e742ffb2 100644
--- a/test/testmixer.c
+++ b/test/testmixer.c
@@ -217,6 +217,10 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
MIX_TagTrack(track1, "Music");
MIX_TagTrack(track1, "NotImportant");
MIX_TagTrack(track1, "Orange");
+ int tagged_count = 77;
+ MIX_Track **tagged = MIX_GetTaggedTracks(mixer, "TopSecret", &tagged_count);
+ SDL_Log("MIX_GetTaggedTracks is %sworking", (tagged && (tagged_count == 1) && (tagged[0] == track1) && (tagged[1] == NULL)) ? "" : "NOT ");
+ SDL_free(tagged);
showtags(track1, "at startup");
MIX_UntagTrack(track1, "TopSecret");
showtags(track1, "after removing 'TopSecret'");