Attached is a patch for SDL_mixer against the latest CVS. It adds two
functions to the library:
void Mix_ChannelFinished(void (*callback)(int channel));
This registers a callback that is called when a channel finishes playing
(including all looping it was commanded to do). Without this, you have to
poll to figure out if a channel has stopped yet, which isn’t as elegant.
The callback is given the number of the channel that has finished. Calling
this function with a NULL argument turns off the callback.
Mix_Chunk *Mix_GetChunk(int channel);
This returns the Mix_Chunk * associated with a channel, or NULL if there
isn’t one (or the channel number is bogus). This, in conjunction with the
above callback, makes it very easy to use a throw-away sample in the mixer:
void my_callback(int channel)
{
Mix_FreeChunk(Mix_GetChunk(channel));
}
playwave.c is patched, too. Flip the TEST_MIX_CHANNELFINISHED define in
that file to try out these two new functions.
–ryan.
--- SDL_mixer-virgin/SDL_mixer.h Fri Feb 16 17:46:09 2001
+++ SDL_mixer/SDL_mixer.h Thu Jun 7 12:24:58 2001
@@ -123,6 +123,11 @@
/* Get a pointer to the user data for the current music hook */
extern DECLSPEC void *Mix_GetMusicHookData(void);
+/* Add your own callback when a channel has finished playing. NULL
+ * to disable callback.
+ */
+extern DECLSPEC void Mix_ChannelFinished(void (*channel_finished)(int channel));+
/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
them dynamically to the next sample if requested with a -1 value below.
Returns the number of reserved channels.
@@ -218,6 +223,11 @@
/* Stop music and set external music playback command */
extern DECLSPEC int Mix_SetMusicCMD(const char *command);
+
+/* Get the Mix_Chunk currently associated with a mixer channel
+ Returns NULL if it's an invalid channel, or there's no chunk associated.
+*/
+extern DECLSPEC Mix_Chunk *Mix_GetChunk(int channel);
/* Close the mixer, halting all playing audio */
extern DECLSPEC void Mix_CloseAudio(void);
--- SDL_mixer-virgin/mixer.c Thu May 10 11:17:57 2001
+++ SDL_mixer/mixer.c Thu Jun 7 12:54:25 2001
@@ -61,6 +61,9 @@
static void (*mix_postmix)(void *udata, Uint8 *stream, int len) = NULL;
static void *mix_postmix_data = NULL;
+/* rcg07062001 callback to alert when channels are done playing. */
+static void (*channel_done_callback)(int channel) = NULL;
+
/* Music function declarations */
extern int open_music(SDL_AudioSpec *mixer);
extern void close_music(void);
@@ -139,6 +142,11 @@
mix_channel[i].playing = mix_channel[i].chunk->alen;
}
}
+
+ /* rcg06072001 Alert app if channel is done playing. */
+ if ( (!mix_channel[i].playing) && (channel_done_callback) ) {
+ channel_done_callback(i);
+ }
}
}
}
@@ -437,6 +445,14 @@
return(music_data);
}
+void Mix_ChannelFinished(void (*channel_finished)(int channel))
+{
+ SDL_LockAudio();
+ channel_done_callback = channel_finished;
+ SDL_UnlockAudio();
+}
+
+
/* Reserve the first channels (0 -> n-1) for the application, i.e. don't allocate
them dynamically to the next sample if requested with a -1 value below.
Returns the number of reserved channels.
@@ -710,6 +726,18 @@
}
}
return(status);
+}
+
+/* rcg06072001 Get the chunk associated with a channel. */
+Mix_Chunk *Mix_GetChunk(int channel)
+{
+ Mix_Chunk *retval = NULL;
+
+ if ((channel >= 0) && (channel < num_channels)) {
+ retval = mix_channel[channel].chunk;
+ }
+
+ return(retval);
}
/* Close the mixer, halting all playing audio */
--- SDL_mixer-virgin/playwave.c Thu Apr 5 14:25:56 2001
+++ SDL_mixer/playwave.c Thu Jun 7 12:52:51 2001
@@ -54,7 +54,22 @@
{
fprintf(stderr, "Usage: %s [-8] [-r rate] [-l] [-m] <wavefile>\n", argv0);
}
-
+
+
+/*#define TEST_MIX_CHANNELFINISHED*/
+#ifdef TEST_MIX_CHANNELFINISHED /* rcg06072001 */
+static volatile int channel_is_done = 0;
+static void channel_complete_callback(int chan)
+{
+ Mix_Chunk *done_chunk = Mix_GetChunk(chan);
+ printf("We were just alerted that Mixer channel #%d is done.\n", chan);
+ printf("Channel's chunk pointer is (%p).\n", done_chunk);
+ printf(" Which %s correct.\n", (wave == done_chunk) ? "is" : "is NOT");
+ channel_is_done = 1;
+}
+#endif
+
+
main(int argc, char *argv[])
{
int audio_rate;
@@ -126,10 +141,23 @@
return(2);
}
+#ifdef TEST_MIX_CHANNELFINISHED /* rcg06072001 */
+ setbuf(stdout, NULL);
+ Mix_ChannelFinished(channel_complete_callback);
+#endif
+
/* Play and then exit */
Mix_PlayChannel(0, wave, loops);
+
+#ifdef TEST_MIX_CHANNELFINISHED /* rcg06072001 */
+ while (!channel_is_done) {
+ SDL_Delay(100);
+ }
+#else
while ( Mix_Playing(0) ) {
SDL_Delay(100);
}
+#endif
+
return(0);
}