SDL_mixer: Stop/Start/Pause/Resume for Fluidsynth

From 252c6c835a0049a5181d1356aa4e6239af831ea9 Mon Sep 17 00:00:00 2001
From: "Stephen E. Baker" <[EMAIL REDACTED]>
Date: Sun, 4 Feb 2024 21:30:08 -0500
Subject: [PATCH] Stop/Start/Pause/Resume for Fluidsynth

The fluidsynth player would resume from the point when the track
was stopped instead of the beginning when Play was called. This
was the desired behaviour for the unsupported Pause/Resume
functions, so I moved the definitions to those functions and
added new Start/Stop functions that seek to the beginning of the
track before playing.

When paused SDL_mixer should return true for IsPlaying. Fix
supplied by Wohlstand.
---
 src/codecs/music_fluidsynth.c | 31 ++++++++++++++++++++++++++++---
 1 file changed, 28 insertions(+), 3 deletions(-)

diff --git a/src/codecs/music_fluidsynth.c b/src/codecs/music_fluidsynth.c
index aeb6e784..a86f0e5e 100644
--- a/src/codecs/music_fluidsynth.c
+++ b/src/codecs/music_fluidsynth.c
@@ -39,6 +39,7 @@ typedef struct {
 #if (FLUIDSYNTH_VERSION_MAJOR >= 2)
     void (*delete_fluid_player)(fluid_player_t*);
     void (*delete_fluid_synth)(fluid_synth_t*);
+    int (*fluid_player_seek)(fluid_player_t *, int);
 #else
     int (*delete_fluid_player)(fluid_player_t*);
     int (*delete_fluid_synth)(fluid_synth_t*);
@@ -85,6 +86,7 @@ static int FLUIDSYNTH_Load()
 #if (FLUIDSYNTH_VERSION_MAJOR >= 2)
         FUNCTION_LOADER(delete_fluid_player, void (*)(fluid_player_t*))
         FUNCTION_LOADER(delete_fluid_synth, void (*)(fluid_synth_t*))
+        FUNCTION_LOADER(fluid_player_seek, int (*)(fluid_player_t *, int))
 #else
         FUNCTION_LOADER(delete_fluid_player, int (*)(fluid_player_t*))
         FUNCTION_LOADER(delete_fluid_synth, int (*)(fluid_synth_t*))
@@ -135,6 +137,7 @@ typedef struct {
     void *buffer;
     int buffer_size;
     int volume;
+    SDL_bool is_paused;
 } FLUIDSYNTH_Music;
 
 static void FLUIDSYNTH_Delete(void *context);
@@ -277,14 +280,25 @@ static int FLUIDSYNTH_Play(void *context, int play_count)
 {
     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
     fluidsynth.fluid_player_set_loop(music->player, play_count);
+#if (FLUIDSYNTH_VERSION_MAJOR >= 2)
+    fluidsynth.fluid_player_seek(music->player, 0);
+#endif
     fluidsynth.fluid_player_play(music->player);
+    music->is_paused = SDL_FALSE;
     return 0;
 }
 
+static void FLUIDSYNTH_Resume(void *context)
+{
+    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
+    fluidsynth.fluid_player_play(music->player);
+    music->is_paused = SDL_FALSE;
+}
+
 static SDL_bool FLUIDSYNTH_IsPlaying(void *context)
 {
     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
-    return fluidsynth.fluid_player_get_status(music->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
+    return music->is_paused || fluidsynth.fluid_player_get_status(music->player) == FLUID_PLAYER_PLAYING ? SDL_TRUE : SDL_FALSE;
 }
 
 static int FLUIDSYNTH_GetSome(void *context, void *data, int bytes, SDL_bool *done)
@@ -316,6 +330,17 @@ static void FLUIDSYNTH_Stop(void *context)
 {
     FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
     fluidsynth.fluid_player_stop(music->player);
+#if (FLUIDSYNTH_VERSION_MAJOR >= 2)
+    fluidsynth.fluid_player_seek(music->player, 0);
+#endif
+    music->is_paused = SDL_FALSE;
+}
+
+static void FLUIDSYNTH_Pause(void *context)
+{
+    FLUIDSYNTH_Music *music = (FLUIDSYNTH_Music *)context;
+    fluidsynth.fluid_player_stop(music->player);
+    music->is_paused = SDL_TRUE;
 }
 
 static void FLUIDSYNTH_Delete(void *context)
@@ -367,8 +392,8 @@ Mix_MusicInterface Mix_MusicInterface_FLUIDSYNTH =
     NULL,   /* GetMetaTag */
     NULL,   /* GetNumTracks */
     NULL,   /* StartTrack */
-    NULL,   /* Pause */
-    NULL,   /* Resume */
+    FLUIDSYNTH_Pause,
+    FLUIDSYNTH_Resume,
     FLUIDSYNTH_Stop,
     FLUIDSYNTH_Delete,
     NULL,   /* Close */