SDL_mixer: api: Added MIX_GetTrackFadeFrames.

From e95dbc6859267b5de559394b79dc1c087ca1c25c Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Sun, 21 Dec 2025 22:03:16 -0500
Subject: [PATCH] api: Added MIX_GetTrackFadeFrames.

Fixes #769.
---
 include/SDL3_mixer/SDL_mixer.h | 24 ++++++++++++++++++++++++
 src/SDL_mixer.c                | 13 +++++++++++++
 src/SDL_mixer.exports          |  1 +
 src/SDL_mixer.sym              |  1 +
 4 files changed, 39 insertions(+)

diff --git a/include/SDL3_mixer/SDL_mixer.h b/include/SDL3_mixer/SDL_mixer.h
index dfa31d7e..69dd2da4 100644
--- a/include/SDL3_mixer/SDL_mixer.h
+++ b/include/SDL3_mixer/SDL_mixer.h
@@ -1315,6 +1315,30 @@ extern SDL_DECLSPEC bool SDLCALL MIX_SetTrackPlaybackPosition(MIX_Track *track,
  */
 extern SDL_DECLSPEC Sint64 SDLCALL MIX_GetTrackPlaybackPosition(MIX_Track *track);
 
+/**
+ * Query whether a given track is fading.
+ *
+ * This specifically checks if the track is _not stopped_ (paused or playing),
+ * and it is fading in or out, and returns the number of frames remaining in
+ * the fade.
+ *
+ * If fading out, the returned value will be negative. When fading in, the
+ * returned value will be positive. If not fading, this function returns zero.
+ *
+ * On various errors (MIX_Init() was not called, the track is NULL), this
+ * returns 0, but there is no mechanism to distinguish errors from tracks that
+ * aren't fading.
+ *
+ * \param track the track to query.
+ * \returns less than 0 if the track is fading out, greater than 0 if fading
+ *          in, zero otherwise.
+ *
+ * \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 Sint64 SDLCALL MIX_GetTrackFadeFrames(MIX_Track *track);
+
 /**
  * Query whether a given track is looping.
  *
diff --git a/src/SDL_mixer.c b/src/SDL_mixer.c
index 9d72b538..73c7b6e4 100644
--- a/src/SDL_mixer.c
+++ b/src/SDL_mixer.c
@@ -1889,6 +1889,19 @@ Sint64 MIX_GetTrackRemaining(MIX_Track *track)
     return retval;
 }
 
+Sint64 MIX_GetTrackFadeFrames(MIX_Track *track)
+{
+    Sint64 retval = 0;
+    if (CheckTrackParam(track)) {
+        LockTrack(track);
+        if (track->state != MIX_STATE_STOPPED) {
+            retval = track->fade_frames * track->fade_direction;
+        }
+        UnlockTrack(track);
+    }
+    return retval;
+}
+
 bool MIX_TrackLooping(MIX_Track *track)
 {
     bool retval = false;
diff --git a/src/SDL_mixer.exports b/src/SDL_mixer.exports
index de6d4065..3e530c11 100644
--- a/src/SDL_mixer.exports
+++ b/src/SDL_mixer.exports
@@ -85,4 +85,5 @@ _MIX_GetAudioDecoderProperties
 _MIX_DecodeAudio
 _MIX_GetAudioDecoderFormat
 _MIX_SetTrackLoops
+_MIX_GetTrackFadeFrames
 # extra symbols go here (don't modify this line)
diff --git a/src/SDL_mixer.sym b/src/SDL_mixer.sym
index 0d7a6ddd..be386d38 100644
--- a/src/SDL_mixer.sym
+++ b/src/SDL_mixer.sym
@@ -86,6 +86,7 @@ SDL3_mixer_0.0.0 {
     MIX_DecodeAudio;
     MIX_GetAudioDecoderFormat;
     MIX_SetTrackLoops;
+    MIX_GetTrackFadeFrames;
     # extra symbols go here (don't modify this line)
   local: *;
 };