SDL_mixer: Add Mix_PauseGroup and Mix_ResumeGroup functions

From 9ecda53d7d73c69da9616399352c157cda2d664f Mon Sep 17 00:00:00 2001
From: Kelly Gravelyn <[EMAIL REDACTED]>
Date: Tue, 19 Sep 2023 22:54:11 -0700
Subject: [PATCH] Add Mix_PauseGroup and Mix_ResumeGroup functions

---
 include/SDL3_mixer/SDL_mixer.h | 46 ++++++++++++++++++++++++++++++++++
 src/SDL_mixer.sym              |  2 ++
 src/mixer.c                    | 26 +++++++++++++++++++
 3 files changed, 74 insertions(+)

diff --git a/include/SDL3_mixer/SDL_mixer.h b/include/SDL3_mixer/SDL_mixer.h
index da458970..114054ff 100644
--- a/include/SDL3_mixer/SDL_mixer.h
+++ b/include/SDL3_mixer/SDL_mixer.h
@@ -2180,6 +2180,31 @@ extern DECLSPEC Mix_Fading SDLCALL Mix_FadingChannel(int which);
  */
 extern DECLSPEC void SDLCALL Mix_Pause(int channel);
 
+/**
+ * Pause playing of a group of channels by arbitrary tag.
+ *
+ * Pausing a channel will prevent further playback of the assigned chunk but
+ * will maintain the chunk's current mixing position. When resumed, this
+ * channel will continue to mix the chunk where it left off.
+ *
+ * A paused channel can be resumed by calling Mix_Resume() or
+ * Mix_ResumeGroup().
+ *
+ * A paused channel with an expiration will not expire while paused (the
+ * expiration countdown will be adjusted once resumed).
+ *
+ * A tag is an arbitrary number that can be assigned to several mixer
+ * channels, to form groups of channels.
+ *
+ * The default tag for a channel is -1.
+ *
+ * \param tag an arbitrary value, assigned to channels, to search for.
+ * \returns zero, whether any channels were halted or not.
+ *
+ * \since This function is available since SDL_mixer 3.0.0.
+ */
+extern DECLSPEC int SDLCALL Mix_PauseGroup(int tag);
+
 /**
  * Resume a particular channel.
  *
@@ -2198,6 +2223,27 @@ extern DECLSPEC void SDLCALL Mix_Pause(int channel);
  */
 extern DECLSPEC void SDLCALL Mix_Resume(int channel);
 
+/**
+ * Resume playing of a group of channels by arbitrary tag.
+ *
+ * It is legal to resume an unpaused or invalid channel; it causes no effect
+ * and reports no error.
+ *
+ * If the paused channel has an expiration, its expiration countdown resumes
+ * now, as well.
+ *
+ * A tag is an arbitrary number that can be assigned to several mixer
+ * channels, to form groups of channels.
+ *
+ * The default tag for a channel is -1.
+ *
+ * \param tag an arbitrary value, assigned to channels, to search for.
+ * \returns zero, whether any channels were resumed or not.
+ *
+ * \since This function is available since SDL_mixer 3.0.0.
+ */
+extern DECLSPEC int SDLCALL Mix_ResumeGroup(int tag);
+
 /**
  * Query whether a particular channel is paused.
  *
diff --git a/src/SDL_mixer.sym b/src/SDL_mixer.sym
index 61a98bda..006df9f6 100644
--- a/src/SDL_mixer.sym
+++ b/src/SDL_mixer.sym
@@ -60,6 +60,7 @@ SDL3_mixer_0.0.0 {
     Mix_OpenAudio;
     Mix_OpenAudioDevice;
     Mix_Pause;
+    Mix_PauseGroup;
     Mix_PauseAudio;
     Mix_PauseMusic;
     Mix_Paused;
@@ -76,6 +77,7 @@ SDL3_mixer_0.0.0 {
     Mix_RegisterEffect;
     Mix_ReserveChannels;
     Mix_Resume;
+    Mix_ResumeGroup;
     Mix_ResumeMusic;
     Mix_RewindMusic;
     Mix_SetDistance;
diff --git a/src/mixer.c b/src/mixer.c
index de4c7942..442b2416 100644
--- a/src/mixer.c
+++ b/src/mixer.c
@@ -1415,6 +1415,19 @@ void Mix_Pause(int which)
     }
 }
 
+/* Pause playing of a particular group of channels */
+int Mix_PauseGroup(int tag)
+{
+    int i;
+
+    for (i=0; i<num_channels; ++i) {
+        if (mix_channel[i].tag == tag) {
+            Mix_Pause(i);
+        }
+    }
+    return(0);
+}
+
 /* Resume a paused channel */
 void Mix_Resume(int which)
 {
@@ -1441,6 +1454,19 @@ void Mix_Resume(int which)
     Mix_UnlockAudio();
 }
 
+/* Resume playing of a particular group of channels */
+int Mix_ResumeGroup(int tag)
+{
+    int i;
+
+    for (i=0; i<num_channels; ++i) {
+        if (mix_channel[i].tag == tag) {
+            Mix_Resume(i);
+        }
+    }
+    return(0);
+}
+
 int Mix_Paused(int which)
 {
     if (which < 0) {