# HG changeset patch # User Masonwheeler # Date 1304128376 25200 # Node ID 10ced1337f977e5950623414eab39d0a764533b7 # Parent 7a95f36a8bbfa2132548bf13e63f9d051d735dcd Phase 1 of music integration. diff -r 7a95f36a8bbf -r 10ced1337f97 SDL_mixer.h --- a/SDL_mixer.h Thu Feb 17 13:35:14 2011 -0800 +++ b/SDL_mixer.h Fri Apr 29 18:52:56 2011 -0700 @@ -188,8 +188,7 @@ extern DECLSPEC int SDLCALL Mix_GetNumMusicDecoders(void); extern DECLSPEC const char * SDLCALL Mix_GetMusicDecoder(int index); -/* Find out the music format of a mixer music, or the currently playing - music, if 'music' is NULL. +/* Find out the music format of a mixer music. */ extern DECLSPEC Mix_MusicType SDLCALL Mix_GetMusicType(const Mix_Music *music); @@ -204,7 +203,7 @@ If 'mix_func' is NULL, the default music player is re-enabled. */ extern DECLSPEC void SDLCALL Mix_HookMusic(void (*mix_func) - (void *udata, Uint8 *stream, int len), void *arg); + (void *udata, Mix_Music *music_playing, Uint8 *stream, int len, int channel), void *arg); /* Add your own callback when the music has finished playing. This callback is only called if the music finishes naturally. @@ -509,18 +508,23 @@ Returns true if everything was OK. */ extern DECLSPEC int SDLCALL Mix_GroupChannel(int which, int tag); + /* Assign several consecutive channels to a group */ extern DECLSPEC int SDLCALL Mix_GroupChannels(int from, int to, int tag); + /* Finds the first available channel in a group of channels, returning -1 if none are available. */ extern DECLSPEC int SDLCALL Mix_GroupAvailable(int tag); + /* Returns the number of channels in a group. This is also a subtle way to get the total number of channels when 'tag' is -1 */ extern DECLSPEC int SDLCALL Mix_GroupCount(int tag); + /* Finds the "oldest" sample playing in a group of channels */ extern DECLSPEC int SDLCALL Mix_GroupOldest(int tag); + /* Finds the "most recent" (i.e. last) sample playing in a group of channels */ extern DECLSPEC int SDLCALL Mix_GroupNewer(int tag); @@ -531,13 +535,14 @@ Returns which channel was used to play the sound. */ #define Mix_PlayChannel(channel,chunk,loops) Mix_PlayChannelTimed(channel,chunk,loops,-1) + /* The same as above, but the sound is played at most 'ticks' milliseconds */ extern DECLSPEC int SDLCALL Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks); -extern DECLSPEC int SDLCALL Mix_PlayMusic(Mix_Music *music, int loops); +extern DECLSPEC int SDLCALL Mix_PlayMusic(Mix_Music *music, int loops, int channel); /* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */ -extern DECLSPEC int SDLCALL Mix_FadeInMusic(Mix_Music *music, int loops, int ms); -extern DECLSPEC int SDLCALL Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position); +extern DECLSPEC int SDLCALL Mix_FadeInMusic(Mix_Music *music, int loops, int ms, int channel); +extern DECLSPEC int SDLCALL Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, int channel, double position); #define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1) extern DECLSPEC int SDLCALL Mix_FadeInChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ms, int ticks); @@ -548,12 +553,12 @@ */ extern DECLSPEC int SDLCALL Mix_Volume(int channel, int volume); extern DECLSPEC int SDLCALL Mix_VolumeChunk(Mix_Chunk *chunk, int volume); -extern DECLSPEC int SDLCALL Mix_VolumeMusic(int volume); +extern DECLSPEC int SDLCALL Mix_VolumeMusic(int volume, int channel); /* Halt playing of a particular channel */ extern DECLSPEC int SDLCALL Mix_HaltChannel(int channel); extern DECLSPEC int SDLCALL Mix_HaltGroup(int tag); -extern DECLSPEC int SDLCALL Mix_HaltMusic(void); +extern DECLSPEC int SDLCALL Mix_HaltMusic(Mix_Music *music); /* Change the expiration delay for a particular channel. The sample will stop playing after the 'ticks' milliseconds have elapsed, @@ -567,10 +572,10 @@ */ extern DECLSPEC int SDLCALL Mix_FadeOutChannel(int which, int ms); extern DECLSPEC int SDLCALL Mix_FadeOutGroup(int tag, int ms); -extern DECLSPEC int SDLCALL Mix_FadeOutMusic(int ms); +extern DECLSPEC int SDLCALL Mix_FadeOutMusic(int ms, int channel); /* Query the fading status of a channel */ -extern DECLSPEC Mix_Fading SDLCALL Mix_FadingMusic(void); +extern DECLSPEC Mix_Fading SDLCALL Mix_FadingMusic(int channel); extern DECLSPEC Mix_Fading SDLCALL Mix_FadingChannel(int which); /* Pause/Resume a particular channel */ @@ -579,10 +584,11 @@ extern DECLSPEC int SDLCALL Mix_Paused(int channel); /* Pause/Resume the music stream */ -extern DECLSPEC void SDLCALL Mix_PauseMusic(void); -extern DECLSPEC void SDLCALL Mix_ResumeMusic(void); -extern DECLSPEC void SDLCALL Mix_RewindMusic(void); -extern DECLSPEC int SDLCALL Mix_PausedMusic(void); +#define Mix_PauseMusic(channel) Mix_Pause(channel) +#define Mix_ResumeMusic(channel) Mix_Resume(channel) +#define Mix_PausedMusic(channel) Mix_Paused(channel) + +extern DECLSPEC void SDLCALL Mix_RewindMusic(int channel); /* Set the current position in the music stream. This returns 0 if successful, or -1 if it failed or isn't implemented. @@ -590,16 +596,16 @@ order number) and for OGG, FLAC, MP3_MAD, and MODPLUG music (set position in seconds), at the moment. */ -extern DECLSPEC int SDLCALL Mix_SetMusicPosition(double position); +extern DECLSPEC int SDLCALL Mix_SetMusicPosition(double position, int channel); /* Check the status of a specific channel. If the specified channel is -1, check all channels. */ extern DECLSPEC int SDLCALL Mix_Playing(int channel); -extern DECLSPEC int SDLCALL Mix_PlayingMusic(void); +extern DECLSPEC int SDLCALL Mix_PlayingMusic(int channel); /* Stop music and set external music playback command */ -extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command); +extern DECLSPEC int SDLCALL Mix_SetMusicCMD(const char *command, int channel); /* Synchro value is set by MikMod from modules while playing */ extern DECLSPEC int SDLCALL Mix_SetSynchroValue(int value); diff -r 7a95f36a8bbf -r 10ced1337f97 effect_position.c --- a/effect_position.c Thu Feb 17 13:35:14 2011 -0800 +++ b/effect_position.c Fri Apr 29 18:52:56 2011 -0700 @@ -614,14 +614,14 @@ Uint16 swapr = (Uint16) ((Sint16) (((float) sampr * args->right_f) * args->distance_f) + 32768); - if (args->room_angle == 180) { - *(ptr++) = (Uint16) SDL_SwapLE16(swapr); - *(ptr++) = (Uint16) SDL_SwapLE16(swapl); - } - else { - *(ptr++) = (Uint16) SDL_SwapLE16(swapl); - *(ptr++) = (Uint16) SDL_SwapLE16(swapr); - } + if (args->room_angle == 180) { + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + } + else { + *(ptr++) = (Uint16) SDL_SwapLE16(swapl); + *(ptr++) = (Uint16) SDL_SwapLE16(swapr); + } } } static void _Eff_position_u16lsb_c4(int chan, void *stream, int len, void *udata) diff -r 7a95f36a8bbf -r 10ced1337f97 mixer.c --- a/mixer.c Thu Feb 17 13:35:14 2011 -0800 +++ b/mixer.c Fri Apr 29 18:52:56 2011 -0700 @@ -62,23 +62,33 @@ struct _Mix_effectinfo *next; } effect_info; -static struct _Mix_Channel { +typedef struct { Mix_Chunk *chunk; + Uint8 *samples; + Uint32 start_time; + int fade_volume; + Uint32 fade_length; + Uint32 ticks_fade; +} Mix_Sound; + +typedef struct { + SDL_bool is_music; + union{ + Mix_Sound *sound; + Mix_Music *music; + }; int playing; int paused; - Uint8 *samples; int volume; + int fade_volume_reset; int looping; int tag; Uint32 expire; - Uint32 start_time; Mix_Fading fading; - int fade_volume; - int fade_volume_reset; - Uint32 fade_length; - Uint32 ticks_fade; effect_info *effects; -} *mix_channel = NULL; +} _Mix_Channel; + +static _Mix_Channel *mix_channel = NULL; static effect_info *posteffects = NULL; @@ -99,14 +109,33 @@ /* Support for user defined music functions, plus the default one */ extern int volatile music_active; -extern void music_mixer(void *udata, Uint8 *stream, int len); -static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer; +extern void music_mixer(void *udata, Mix_Music * music_playing, Uint8 *stream, int len, int channel); +static void (*mix_music)(void *udata, Mix_Music * music_playing, Uint8 *stream, int len, int channel) = music_mixer; static void *music_data = NULL; /* rcg06042009 report available decoders at runtime. */ static const char **chunk_decoders = NULL; static int num_decoders = 0; +void _HaltAllMusic(void) +{ + int i; + for ( i=0; i= 0 && which < num_channels ) { + Uint32 sdl_ticks = SDL_GetTicks(); + if (Mix_Playing(which)) + _Mix_channel_done_playing(which); + if (!mix_channel[which].is_music) { + Mix_FreeChunk(mix_channel[which].sound->chunk); + free(mix_channel[which].sound); + mix_channel[which].sound = NULL; + mix_channel[which].music = music; + mix_channel[which].is_music = SDL_TRUE; + } + mix_channel[which].playing = 1; + mix_channel[which].looping = -1; + mix_channel[which].paused = 0; + if (is_fading){ + mix_channel[which].fading = MIX_FADING_IN; + mix_channel[which].fade_volume_reset = mix_channel[which].volume; + mix_channel[which].volume = 0; + } else { + mix_channel[which].fading = MIX_NO_FADING; + } + } + } + SDL_UnlockAudio(); +} -static void *Mix_DoEffects(int chan, void *snd, int len) +void *Mix_DoEffects(int chan, void *snd, int len) { int posteffect = (chan == MIX_CHANNEL_POST); effect_info *e = ((posteffect) ? posteffects : mix_channel[chan].effects); @@ -258,12 +319,94 @@ return(buf); } +static void do_mix_channel(void* udata, Uint8 *stream, int len, _Mix_Channel* channel, Mix_Sound *sound, int i, Uint32 sdl_ticks) +{ + Uint8 *mix_input; + + if ( channel->expire > 0 && channel->expire < sdl_ticks ) { + /* Expiration delay for that channel is reached */ + channel->playing = 0; + channel->fading = MIX_NO_FADING; + channel->expire = 0; + _Mix_channel_done_playing(i); + } else if ( channel->fading != MIX_NO_FADING ) { + Uint32 ticks = sdl_ticks - sound->ticks_fade; + if( ticks > sound->fade_length ) { + Mix_Volume(i, channel->fade_volume_reset); /* Restore the volume */ + if( channel->fading == MIX_FADING_OUT ) { + channel->playing = 0; + channel->expire = 0; + _Mix_channel_done_playing(i); + } + channel->fading = MIX_NO_FADING; + } else { + if( channel->fading == MIX_FADING_OUT ) { + Mix_Volume(i, (sound->fade_volume * (sound->fade_length-ticks)) + / sound->fade_length ); + } else { + Mix_Volume(i, (sound->fade_volume * ticks) / sound->fade_length ); + } + } + } + if ( channel->playing > 0 ) { + int index = 0; + int remaining = len; + int volume, mixable; + while (channel->playing > 0 && index < len) { + volume = (channel->volume * sound->chunk->volume) / MIX_MAX_VOLUME; + mixable = channel->playing; + + remaining = len - index; + if ( mixable > remaining ) { + mixable = remaining; + } + + mix_input = Mix_DoEffects(i, sound->samples, mixable); + SDL_MixAudio(stream+index,mix_input,mixable,volume); + if (mix_input != sound->samples) + free(mix_input); + + sound->samples += mixable; + channel->playing -= mixable; + index += mixable; + + /* rcg06072001 Alert app if channel is done playing. */ + if (!channel->playing && !channel->looping) { + _Mix_channel_done_playing(i); + } + } + + /* If looping the sample and we are at its end, make sure + we will still return a full buffer */ + while ( channel->looping && index < len ) { + int alen = sound->chunk->alen; + remaining = len - index; + if (remaining > alen) { + remaining = alen; + } + + mix_input = Mix_DoEffects(i, sound->chunk->abuf, remaining); + SDL_MixAudio(stream+index, mix_input, remaining, volume); + if (mix_input != sound->chunk->abuf) + free(mix_input); + + --channel->looping; + sound->samples = sound->chunk->abuf + remaining; + channel->playing = sound->chunk->alen - remaining; + index += remaining; + } + if ( ! channel->playing && channel->looping ) { + --channel->looping; + sound->samples = sound->chunk->abuf; + channel->playing = sound->chunk->alen; + } + } +} /* Mixing function */ static void mix_channels(void *udata, Uint8 *stream, int len) { - Uint8 *mix_input; - int i, mixable, volume = SDL_MIX_MAXVOLUME; + int i; Uint32 sdl_ticks; #if SDL_VERSION_ATLEAST(1, 3, 0) @@ -272,90 +415,17 @@ #endif /* Mix the music (must be done before the channels are added) */ - if ( music_active || (mix_music != music_mixer) ) { - mix_music(music_data, stream, len); + for ( i=0; i 0 && mix_channel[i].expire < sdl_ticks ) { - /* Expiration delay for that channel is reached */ - mix_channel[i].playing = 0; - mix_channel[i].fading = MIX_NO_FADING; - mix_channel[i].expire = 0; - _Mix_channel_done_playing(i); - } else if ( mix_channel[i].fading != MIX_NO_FADING ) { - Uint32 ticks = sdl_ticks - mix_channel[i].ticks_fade; - if( ticks > mix_channel[i].fade_length ) { - Mix_Volume(i, mix_channel[i].fade_volume_reset); /* Restore the volume */ - if( mix_channel[i].fading == MIX_FADING_OUT ) { - mix_channel[i].playing = 0; - mix_channel[i].expire = 0; - _Mix_channel_done_playing(i); - } - mix_channel[i].fading = MIX_NO_FADING; - } else { - if( mix_channel[i].fading == MIX_FADING_OUT ) { - Mix_Volume(i, (mix_channel[i].fade_volume * (mix_channel[i].fade_length-ticks)) - / mix_channel[i].fade_length ); - } else { - Mix_Volume(i, (mix_channel[i].fade_volume * ticks) / mix_channel[i].fade_length ); - } - } - } - if ( mix_channel[i].playing > 0 ) { - int index = 0; - int remaining = len; - while (mix_channel[i].playing > 0 && index < len) { - remaining = len - index; - volume = (mix_channel[i].volume*mix_channel[i].chunk->volume) / MIX_MAX_VOLUME; - mixable = mix_channel[i].playing; - if ( mixable > remaining ) { - mixable = remaining; - } - - mix_input = Mix_DoEffects(i, mix_channel[i].samples, mixable); - SDL_MixAudio(stream+index,mix_input,mixable,volume); - if (mix_input != mix_channel[i].samples) - free(mix_input); - - mix_channel[i].samples += mixable; - mix_channel[i].playing -= mixable; - index += mixable; - - /* rcg06072001 Alert app if channel is done playing. */ - if (!mix_channel[i].playing && !mix_channel[i].looping) { - _Mix_channel_done_playing(i); - } - } - - /* If looping the sample and we are at its end, make sure - we will still return a full buffer */ - while ( mix_channel[i].looping && index < len ) { - int alen = mix_channel[i].chunk->alen; - remaining = len - index; - if (remaining > alen) { - remaining = alen; - } - - mix_input = Mix_DoEffects(i, mix_channel[i].chunk->abuf, remaining); - SDL_MixAudio(stream+index, mix_input, remaining, volume); - if (mix_input != mix_channel[i].chunk->abuf) - free(mix_input); - - --mix_channel[i].looping; - mix_channel[i].samples = mix_channel[i].chunk->abuf + remaining; - mix_channel[i].playing = mix_channel[i].chunk->alen - remaining; - index += remaining; - } - if ( ! mix_channel[i].playing && mix_channel[i].looping ) { - --mix_channel[i].looping; - mix_channel[i].samples = mix_channel[i].chunk->abuf; - mix_channel[i].playing = mix_channel[i].chunk->alen; - } - } + if ((! mix_channel[i].is_music) && ( ! mix_channel[i].paused )) { + do_mix_channel(udata, stream, len, &mix_channel[i], mix_channel[i].sound, i, sdl_ticks); } } @@ -377,6 +447,23 @@ } #endif +void _Mix_InitChannel(int i) +{ + Mix_Sound * sound = (Mix_Sound *) malloc(sizeof(Mix_Sound)); + mix_channel[i].sound = sound; + mix_channel[i].is_music = SDL_FALSE; + sound->chunk = NULL; + mix_channel[i].playing = 0; + mix_channel[i].looping = 0; + mix_channel[i].volume = SDL_MIX_MAXVOLUME; + sound->fade_volume = SDL_MIX_MAXVOLUME; + mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME; + mix_channel[i].fading = MIX_NO_FADING; + mix_channel[i].tag = -1; + mix_channel[i].expire = 0; + mix_channel[i].effects = NULL; + mix_channel[i].paused = 0; +} /* Open the mixer with a certain desired audio format */ int Mix_OpenAudio(int frequency, Uint16 format, int nchannels, int chunksize) @@ -418,23 +505,12 @@ } num_channels = MIX_CHANNELS; - mix_channel = (struct _Mix_Channel *) malloc(num_channels * sizeof(struct _Mix_Channel)); + mix_channel = (_Mix_Channel *) malloc(num_channels * sizeof(_Mix_Channel)); /* Clear out the audio channels */ for ( i=0; i num_channels ) { /* Initialize the new channels */ int i; for(i=num_channels; i < numchans; i++) { - mix_channel[i].chunk = NULL; - mix_channel[i].playing = 0; - mix_channel[i].looping = 0; - mix_channel[i].volume = SDL_MIX_MAXVOLUME; - mix_channel[i].fade_volume = SDL_MIX_MAXVOLUME; - mix_channel[i].fade_volume_reset = SDL_MIX_MAXVOLUME; - mix_channel[i].fading = MIX_NO_FADING; - mix_channel[i].tag = -1; - mix_channel[i].expire = 0; - mix_channel[i].effects = NULL; - mix_channel[i].paused = 0; + _Mix_InitChannel(i); } } num_channels = numchans; @@ -703,7 +769,7 @@ SDL_LockAudio(); if ( mix_channel ) { for ( i=0; ichunk )) { mix_channel[i].playing = 0; } } @@ -733,7 +799,7 @@ /* Add your own music player or mixer function. If 'mix_func' is NULL, the default music player is re-enabled. */ -void Mix_HookMusic(void (*mix_func)(void *udata, Uint8 *stream, int len), +void Mix_HookMusic(void (*mix_func)(void *udata, Mix_Music *music_playing, Uint8 *stream, int len, int channel), void *arg) { SDL_LockAudio(); @@ -782,6 +848,74 @@ return chunk->alen; } +int _Mix_SetupChunk(int which, Mix_Chunk* chunk, int loops, int ticks, int fade_in) +{ + /* Lock the mixer while modifying the playing channels */ + SDL_LockAudio(); + { + /* If which is -1, play on the first free channel */ + if ( which == -1 ) { + int i; + for ( i=reserved_channels; i= 0 && which < num_channels ) { + Uint32 sdl_ticks = SDL_GetTicks(); + if (Mix_Playing(which)) + _Mix_channel_done_playing(which); + if (mix_channel[which].is_music) { + Mix_FreeMusic(mix_channel[which].music); + mix_channel[which].music = NULL; + mix_channel[which].sound = (Mix_Sound *) malloc(sizeof(Mix_Sound)); + mix_channel[which].is_music = SDL_FALSE; + } + mix_channel[which].sound->samples = chunk->abuf; + mix_channel[which].playing = chunk->alen; + mix_channel[which].looping = loops; + mix_channel[which].sound->chunk = chunk; + mix_channel[which].paused = 0; + mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0; + if (fade_in){ + mix_channel[which].fading = MIX_FADING_IN; + mix_channel[which].sound->fade_volume = mix_channel[which].volume; + mix_channel[which].fade_volume_reset = mix_channel[which].volume; + mix_channel[which].volume = 0; + mix_channel[which].sound->fade_length = (Uint32)fade_in; + mix_channel[which].sound->start_time = mix_channel[which].sound->ticks_fade = sdl_ticks; + } else { + mix_channel[which].fading = MIX_NO_FADING; + mix_channel[which].sound->start_time = sdl_ticks; + } + } + } + SDL_UnlockAudio(); + return(which); +} + +SDL_bool _Mix_ValidateChunk(Mix_Chunk *chunk) +{ + /* Don't play null pointers :-) */ + if ( chunk == NULL ) { + Mix_SetError("Tried to play a NULL chunk"); + return(SDL_FALSE); + } + if ( !checkchunkintegral(chunk)) { + Mix_SetError("Tried to play a chunk with a bad frame"); + return(SDL_FALSE); + } + return(SDL_TRUE); +} + /* Play an audio chunk on a specific channel. If the specified channel is -1, play on the first free channel. 'ticks' is the number of milliseconds at most to play the sample, or -1 @@ -790,54 +924,12 @@ */ int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks) { - int i; - - /* Don't play null pointers :-) */ - if ( chunk == NULL ) { - Mix_SetError("Tried to play a NULL chunk"); - return(-1); - } - if ( !checkchunkintegral(chunk)) { - Mix_SetError("Tried to play a chunk with a bad frame"); + if (! _Mix_ValidateChunk(chunk)){ return(-1); } - /* Lock the mixer while modifying the playing channels */ - SDL_LockAudio(); - { - /* If which is -1, play on the first free channel */ - if ( which == -1 ) { - for ( i=reserved_channels; i= 0 && which < num_channels ) { - Uint32 sdl_ticks = SDL_GetTicks(); - if (Mix_Playing(which)) - _Mix_channel_done_playing(which); - mix_channel[which].samples = chunk->abuf; - mix_channel[which].playing = chunk->alen; - mix_channel[which].looping = loops; - mix_channel[which].chunk = chunk; - mix_channel[which].paused = 0; - mix_channel[which].fading = MIX_NO_FADING; - mix_channel[which].start_time = sdl_ticks; - mix_channel[which].expire = (ticks>0) ? (sdl_ticks + ticks) : 0; - } - } - SDL_UnlockAudio(); - /* Return the channel on which the sound is being played */ - return(which); + return _Mix_SetupChunk(which, chunk, loops, ticks, 0); } /* Change the expiration delay for a channel */ @@ -862,56 +954,12 @@ /* Fade in a sound on a channel, over ms milliseconds */ int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks) { - int i; - - /* Don't play null pointers :-) */ - if ( chunk == NULL ) { - return(-1); - } - if ( !checkchunkintegral(chunk)) { - Mix_SetError("Tried to play a chunk with a bad frame"); + if (! _Mix_ValidateChunk(chunk)){ return(-1); } - /* Lock the mixer while modifying the playing channels */ - SDL_LockAudio(); - { - /* If which is -1, play on the first free channel */ - if ( which == -1 ) { - for ( i=reserved_channels; i= 0 && which < num_channels ) { - Uint32 sdl_ticks = SDL_GetTicks(); - if (Mix_Playing(which)) - _Mix_channel_done_playing(which); - mix_channel[which].samples = chunk->abuf; - mix_channel[which].playing = chunk->alen; - mix_channel[which].looping = loops; - mix_channel[which].chunk = chunk; - mix_channel[which].paused = 0; - mix_channel[which].fading = MIX_FADING_IN; - mix_channel[which].fade_volume = mix_channel[which].volume; - mix_channel[which].fade_volume_reset = mix_channel[which].volume; - mix_channel[which].volume = 0; - mix_channel[which].fade_length = (Uint32)ms; - mix_channel[which].start_time = mix_channel[which].ticks_fade = sdl_ticks; - mix_channel[which].expire = (ticks > 0) ? (sdl_ticks+ticks) : 0; - } - } - SDL_UnlockAudio(); - /* Return the channel on which the sound is being played */ - return(which); + return _Mix_SetupChunk(which, chunk, loops, ticks, ms); } /* Set volume of a particular channel */ @@ -963,8 +1011,10 @@ } else if ( which < num_channels ) { SDL_LockAudio(); if (mix_channel[which].playing) { - _Mix_channel_done_playing(which); - mix_channel[which].playing = 0; + if (mix_channel[which].is_music) + Mix_HaltMusic(mix_channel[which].music); + else _Mix_channel_done_playing(which); + mix_channel[which].playing = 0; } mix_channel[which].expire = 0; if(mix_channel[which].fading != MIX_NO_FADING) /* Restore volume */ @@ -975,6 +1025,23 @@ return(0); } +void _WaitForChannelFade(int channel) +{ + while ((mix_channel[channel].playing) && (mix_channel[channel].fading == MIX_FADING_OUT)) + { + SDL_UnlockAudio(); + SDL_Delay(100); + SDL_LockAudio(); + } +} + +Mix_Music* _ChannelPlayingMusic(int channel) +{ + if ((mix_channel[channel].playing) && (mix_channel[channel].is_music)) + return mix_channel[channel].music; + else return NULL; +} + /* Halt playing of a particular group of channels */ int Mix_HaltGroup(int tag) { @@ -1006,14 +1073,18 @@ if ( mix_channel[which].playing && (mix_channel[which].volume > 0) && (mix_channel[which].fading != MIX_FADING_OUT) ) { - mix_channel[which].fade_volume = mix_channel[which].volume; - mix_channel[which].fading = MIX_FADING_OUT; - mix_channel[which].fade_length = ms; - mix_channel[which].ticks_fade = SDL_GetTicks(); + if (mix_channel[which].is_music) { + Mix_FadeOutMusic(ms, which); + } else { + mix_channel[which].sound->fade_volume = mix_channel[which].volume; + mix_channel[which].fading = MIX_FADING_OUT; + mix_channel[which].sound->fade_length = ms; + mix_channel[which].sound->ticks_fade = SDL_GetTicks(); - /* only change fade_volume_reset if we're not fading. */ - if (mix_channel[which].fading == MIX_NO_FADING) { - mix_channel[which].fade_volume_reset = mix_channel[which].volume; + /* only change fade_volume_reset if we're not fading. */ + if (mix_channel[which].fading == MIX_NO_FADING) { + mix_channel[which].fade_volume_reset = mix_channel[which].volume; + } } ++status; } @@ -1077,8 +1148,8 @@ { Mix_Chunk *retval = NULL; - if ((channel >= 0) && (channel < num_channels)) { - retval = mix_channel[channel].chunk; + if ((channel >= 0) && (channel < num_channels) && (! mix_channel[channel].is_music)) { + retval = mix_channel[channel].sound->chunk; } return(retval); @@ -1227,8 +1298,8 @@ int i; for( i=0; i < num_channels; i ++ ) { if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0 - && mix_channel[i].start_time <= mintime ) { - mintime = mix_channel[i].start_time; + && (! mix_channel[i].is_music) && mix_channel[i].sound->start_time <= mintime ) { + mintime = mix_channel[i].sound->start_time; chan = i; } } @@ -1243,8 +1314,8 @@ int i; for( i=0; i < num_channels; i ++ ) { if ( (mix_channel[i].tag==tag || tag==-1) && mix_channel[i].playing > 0 - && mix_channel[i].start_time >= maxtime ) { - maxtime = mix_channel[i].start_time; + && (! mix_channel[i].is_music) && mix_channel[i].sound->start_time >= maxtime ) { + maxtime = mix_channel[i].sound->start_time; chan = i; } } diff -r 7a95f36a8bbf -r 10ced1337f97 music.c --- a/music.c Thu Feb 17 13:35:14 2011 -0800 +++ b/music.c Fri Apr 29 18:52:56 2011 -0700 @@ -75,13 +75,18 @@ #endif -int volatile music_active = 1; static int volatile music_stopped = 0; static int music_loops = 0; static char *music_cmd = NULL; -static Mix_Music * volatile music_playing = NULL; static int music_volume = MIX_MAX_VOLUME; +extern SDL_bool _MusicIsPlaying(Mix_Music * song); +extern void *Mix_DoEffects(int chan, void *snd, int len); +extern void _WaitForChannelFade(int channel); +extern Mix_Music* _ChannelPlayingMusic(int channel); +extern void _HaltAllMusic(void); +extern void _StartMusic(int channel, int is_fading, Mix_Music* music); + struct _Mix_Music { Mix_MusicType type; union { @@ -98,12 +103,12 @@ struct MODULE *module; #endif #ifdef MID_MUSIC -#ifdef USE_TIMIDITY_MIDI - MidiSong *midi; -#endif -#ifdef USE_NATIVE_MIDI - NativeMidiSong *nativemidi; -#endif + #ifdef USE_TIMIDITY_MIDI + MidiSong *midi; + #endif + #ifdef USE_NATIVE_MIDI + NativeMidiSong *nativemidi; + #endif #endif #ifdef OGG_MUSIC OGG_music *ogg; @@ -123,14 +128,15 @@ int fade_steps; int error; }; + #ifdef MID_MUSIC -#ifdef USE_TIMIDITY_MIDI -static int timidity_ok; -static int samplesize; -#endif -#ifdef USE_NATIVE_MIDI -static int native_midi_ok; -#endif + #ifdef USE_TIMIDITY_MIDI + static int timidity_ok; + static int samplesize; + #endif + #ifdef USE_NATIVE_MIDI + static int native_midi_ok; + #endif #endif /* Used to calculate fading steps */ @@ -164,12 +170,12 @@ } /* Local low-level functions prototypes */ -static void music_internal_initialize_volume(void); -static void music_internal_volume(int volume); -static int music_internal_play(Mix_Music *music, double position); -static int music_internal_position(double position); -static int music_internal_playing(); -static void music_internal_halt(void); +static void music_internal_initialize_volume(Mix_Music *music_playing); +static void music_internal_volume(Mix_Music *music_playing, int volume); +static int music_internal_play(Mix_Music *music, double position, int channel); +static int music_internal_position(double position, Mix_Music *music_playing); +static int music_internal_playing(Mix_Music *music_playing); +static void music_internal_halt(Mix_Music *music); /* Support for hooking when the music has finished */ @@ -185,22 +191,22 @@ /* If music isn't playing, halt it if no looping is required, restart it */ /* otherwhise. NOP if the music is playing */ -static int music_halt_or_loop (void) +static int music_halt_or_loop (Mix_Music * music_playing, int channel) { /* Restart music if it has to loop */ - if (!music_internal_playing()) + if (!music_internal_playing(music_playing)) { /* Restart music if it has to loop at a high level */ if (music_loops && --music_loops) { Mix_Fading current_fade = music_playing->fading; - music_internal_play(music_playing, 0.0); + music_internal_play(music_playing, 0.0, channel); music_playing->fading = current_fade; } else { - music_internal_halt(); + music_internal_halt(music_playing); if (music_finished_hook) music_finished_hook(); @@ -214,101 +220,107 @@ /* Mixing function */ -void music_mixer(void *udata, Uint8 *stream, int len) +void music_mixer(void *udata, Mix_Music * music_playing, Uint8 *master_stream, int len, int channel) { int left = 0; + Uint8 * stream; + Uint8 * mix_input; - if ( music_playing && music_active ) { - /* Handle fading */ - if ( music_playing->fading != MIX_NO_FADING ) { - if ( music_playing->fade_step++ < music_playing->fade_steps ) { - int volume; - int fade_step = music_playing->fade_step; - int fade_steps = music_playing->fade_steps; + /* Handle fading */ + if ( music_playing->fading != MIX_NO_FADING ) { + if ( music_playing->fade_step++ < music_playing->fade_steps ) { + int volume; + int fade_step = music_playing->fade_step; + int fade_steps = music_playing->fade_steps; - if ( music_playing->fading == MIX_FADING_OUT ) { - volume = (music_volume * (fade_steps-fade_step)) / fade_steps; - } else { /* Fading in */ - volume = (music_volume * fade_step) / fade_steps; + if ( music_playing->fading == MIX_FADING_OUT ) { + volume = (music_volume * (fade_steps-fade_step)) / fade_steps; + } else { /* Fading in */ + volume = (music_volume * fade_step) / fade_steps; + } + music_internal_volume(music_playing, volume); + } else { + if ( music_playing->fading == MIX_FADING_OUT ) { + music_internal_halt(music_playing); + if ( music_finished_hook ) { + music_finished_hook(); } - music_internal_volume(volume); - } else { - if ( music_playing->fading == MIX_FADING_OUT ) { - music_internal_halt(); - if ( music_finished_hook ) { - music_finished_hook(); - } - return; - } - music_playing->fading = MIX_NO_FADING; + return; } + music_playing->fading = MIX_NO_FADING; } - - if (music_halt_or_loop() == 0) - return; - - - switch (music_playing->type) { + } + + if (music_halt_or_loop(music_playing, channel) == 0) + return; + + stream = (Uint8*) malloc(len); + + switch (music_playing->type) { #ifdef CMD_MUSIC - case MUS_CMD: - /* The playing is done externally */ - break; + case MUS_CMD: + /* The playing is done externally */ + break; #endif #ifdef WAV_MUSIC - case MUS_WAV: - left = WAVStream_PlaySome(stream, len); - break; + case MUS_WAV: + left = WAVStream_PlaySome(stream, len); + break; #endif #ifdef MODPLUG_MUSIC - case MUS_MODPLUG: - left = modplug_playAudio(music_playing->data.modplug, stream, len); - break; + case MUS_MODPLUG: + left = modplug_playAudio(music_playing->data.modplug, stream, len); + break; #endif #ifdef MOD_MUSIC - case MUS_MOD: - left = MOD_playAudio(music_playing->data.module, stream, len); - break; + case MUS_MOD: + left = MOD_playAudio(music_playing->data.module, stream, len); + break; #endif #ifdef MID_MUSIC #ifdef USE_TIMIDITY_MIDI - case MUS_MID: - if ( timidity_ok ) { - int samples = len / samplesize; - Timidity_PlaySome(stream, samples); - } - break; + case MUS_MID: + if ( timidity_ok ) { + int samples = len / samplesize; + Timidity_PlaySome(stream, samples); + } + break; #endif #endif #ifdef OGG_MUSIC - case MUS_OGG: - - left = OGG_playAudio(music_playing->data.ogg, stream, len); - break; + case MUS_OGG: + + left = OGG_playAudio(music_playing->data.ogg, stream, len); + break; #endif #ifdef FLAC_MUSIC - case MUS_FLAC: - left = FLAC_playAudio(music_playing->data.flac, stream, len); - break; + case MUS_FLAC: + left = FLAC_playAudio(music_playing->data.flac, stream, len); + break; #endif #ifdef MP3_MUSIC - case MUS_MP3: - left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len)); - break; + case MUS_MP3: + left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len)); + break; #endif #ifdef MP3_MAD_MUSIC - case MUS_MP3_MAD: - left = mad_getSamples(music_playing->data.mp3_mad, stream, len); - break; + case MUS_MP3_MAD: + left = mad_getSamples(music_playing->data.mp3_mad, stream, len); + break; #endif - default: - /* Unknown music type?? */ - break; - } + default: + /* Unknown music type?? */ + break; } + mix_input = Mix_DoEffects(channel, stream, len); + SDL_MixAudio(master_stream,mix_input,len,Mix_VolumeMusic(-1, channel)); + if (mix_input != stream) + free(mix_input); + free(stream); /* Handle seamless music looping */ - if (left > 0 && left < len && music_halt_or_loop()) { - music_mixer(udata, stream+(len-left), left); + if (left > 0 && left < len && music_halt_or_loop(music_playing, channel)) { + music_mixer(udata, music_playing, master_stream+(len-left), left, channel); } } @@ -370,9 +382,7 @@ add_music_decoder("MP3"); #endif - music_playing = NULL; music_stopped = 0; - Mix_VolumeMusic(SDL_MIX_MAXVOLUME); /* Calculate the number of ms for each callback */ ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq); @@ -578,15 +588,15 @@ if ( music ) { /* Stop the music if it's currently playing */ SDL_LockAudio(); - if ( music == music_playing ) { + if ( _MusicIsPlaying(music) ) { /* Wait for any fade out to finish */ while ( music->fading == MIX_FADING_OUT ) { SDL_UnlockAudio(); SDL_Delay(100); SDL_LockAudio(); } - if ( music == music_playing ) { - music_internal_halt(); + if ( _MusicIsPlaying(music) ) { + music_internal_halt(music); } } SDL_UnlockAudio(); @@ -653,8 +663,7 @@ } } -/* Find out the music format of a mixer music, or the currently playing - music, if 'music' is NULL. +/* Find out the music format of a mixer music. */ Mix_MusicType Mix_GetMusicType(const Mix_Music *music) { @@ -662,31 +671,22 @@ if ( music ) { type = music->type; - } else { - SDL_LockAudio(); - if ( music_playing ) { - type = music_playing->type; - } - SDL_UnlockAudio(); } return(type); } /* Play a music chunk. Returns 0, or -1 if there was an error. */ -static int music_internal_play(Mix_Music *music, double position) +static int music_internal_play(Mix_Music *music, double position, int channel) { int retval = 0; /* Note the music we're playing */ - if ( music_playing ) { - music_internal_halt(); - } - music_playing = music; + Mix_HaltChannel(channel); /* Set the initial volume */ if ( music->type != MUS_MOD ) { - music_internal_initialize_volume(); + music_internal_initialize_volume(music); } /* Set up for playback */ @@ -704,7 +704,7 @@ #ifdef MODPLUG_MUSIC case MUS_MODPLUG: /* can't set volume until file is loaded, so finally set it now */ - music_internal_initialize_volume(); + music_internal_initialize_volume(music); modplug_play(music->data.modplug); break; #endif @@ -743,7 +743,7 @@ case MUS_MP3: smpeg.SMPEG_enableaudio(music->data.mp3,1); smpeg.SMPEG_enablevideo(music->data.mp3,0); - smpeg.SMPEG_play(music_playing->data.mp3); + smpeg.SMPEG_play(music->data.mp3); break; #endif #ifdef MP3_MAD_MUSIC @@ -760,22 +760,19 @@ /* Set the playback position, note any errors if an offset is used */ if ( retval == 0 ) { if ( position > 0.0 ) { - if ( music_internal_position(position) < 0 ) { + if ( music_internal_position(position, music) < 0 ) { Mix_SetError("Position not implemented for music type"); retval = -1; } } else { - music_internal_position(0.0); + music_internal_position(0.0, music); } } - - /* If the setup failed, we're not playing any music anymore */ - if ( retval < 0 ) { - music_playing = NULL; - } + _StartMusic(channel, music->fading == MIX_FADING_IN, music); return(retval); } -int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position) + +int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, int channel, double position) { int retval; @@ -802,29 +799,24 @@ /* Play the puppy */ SDL_LockAudio(); /* If the current music is fading out, wait for the fade to complete */ - while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) { - SDL_UnlockAudio(); - SDL_Delay(100); - SDL_LockAudio(); - } - music_active = 1; + _WaitForChannelFade(channel); music_loops = loops; - retval = music_internal_play(music, position); + retval = music_internal_play(music, position, channel); SDL_UnlockAudio(); return(retval); } -int Mix_FadeInMusic(Mix_Music *music, int loops, int ms) +int Mix_FadeInMusic(Mix_Music *music, int loops, int ms, int channel) { - return Mix_FadeInMusicPos(music, loops, ms, 0.0); + return Mix_FadeInMusicPos(music, loops, ms, channel, 0.0); } -int Mix_PlayMusic(Mix_Music *music, int loops) +int Mix_PlayMusic(Mix_Music *music, int loops, int channel) { - return Mix_FadeInMusicPos(music, loops, 0, 0.0); + return Mix_FadeInMusicPos(music, loops, 0, channel, 0.0); } /* Set the playing music position */ -int music_internal_position(double position) +int music_internal_position(double position, Mix_Music *music_playing) { int retval = 0; @@ -871,18 +863,21 @@ } return(retval); } -int Mix_SetMusicPosition(double position) + +int Mix_SetMusicPosition(double position, int channel) { int retval; + Mix_Music* music; SDL_LockAudio(); - if ( music_playing ) { - retval = music_internal_position(position); + music = _ChannelPlayingMusic(channel); + if ( music ) { + retval = music_internal_position(position, music); if ( retval < 0 ) { Mix_SetError("Position not implemented for music type"); } } else { - Mix_SetError("Music isn't playing"); + Mix_SetError("No music playing on channel %d", channel); retval = -1; } SDL_UnlockAudio(); @@ -891,17 +886,17 @@ } /* Set the music's initial volume */ -static void music_internal_initialize_volume(void) +static void music_internal_initialize_volume(Mix_Music *music_playing) { if ( music_playing->fading == MIX_FADING_IN ) { - music_internal_volume(0); + music_internal_volume(music_playing, 0); } else { - music_internal_volume(music_volume); + music_internal_volume(music_playing, music_volume); } } /* Set the music volume */ -static void music_internal_volume(int volume) +static void music_internal_volume(Mix_Music *music_playing, int volume) { switch (music_playing->type) { #ifdef CMD_MUSIC @@ -963,9 +958,10 @@ break; } } -int Mix_VolumeMusic(int volume) +int Mix_VolumeMusic(int volume, int channel) { int prev_volume; + Mix_Music* music_playing; prev_volume = music_volume; if ( volume < 0 ) { @@ -976,15 +972,16 @@ } music_volume = volume; SDL_LockAudio(); + music_playing = _ChannelPlayingMusic(channel); if ( music_playing ) { - music_internal_volume(music_volume); + music_internal_volume(music_playing, music_volume); } SDL_UnlockAudio(); return(prev_volume); } /* Halt playing of music */ -static void music_internal_halt(void) +static void music_internal_halt(Mix_Music * music_playing) { switch (music_playing->type) { #ifdef CMD_MUSIC @@ -1048,21 +1045,29 @@ music_playing->fading = MIX_NO_FADING; music_playing = NULL; } -int Mix_HaltMusic(void) +int Mix_HaltMusic(Mix_Music *music) { - SDL_LockAudio(); - if ( music_playing ) { - music_internal_halt(); + if (music){ + SDL_LockAudio(); + if ( _MusicIsPlaying(music)) { + music_internal_halt(music); + } + SDL_UnlockAudio(); } - SDL_UnlockAudio(); return(0); } /* Progressively stop the music */ -int Mix_FadeOutMusic(int ms) +int Mix_FadeOutMusic(int ms, int channel) { int retval = 0; + Mix_Music* music_playing = _ChannelPlayingMusic(channel); + + if (!music_playing){ + SDL_SetError("No music playing on channel %d", channel); + return 0; + } if ( ms_per_step == 0 ) { SDL_SetError("Audio device hasn't been opened"); @@ -1070,27 +1075,27 @@ } if (ms <= 0) { /* just halt immediately. */ - Mix_HaltMusic(); + Mix_HaltMusic(music_playing); return 1; } SDL_LockAudio(); if ( music_playing) { - int fade_steps = (ms + ms_per_step - 1)/ms_per_step; - if ( music_playing->fading == MIX_NO_FADING ) { - music_playing->fade_step = 0; - } else { - int step; - int old_fade_steps = music_playing->fade_steps; - if ( music_playing->fading == MIX_FADING_OUT ) { - step = music_playing->fade_step; - } else { - step = old_fade_steps - - music_playing->fade_step + 1; - } - music_playing->fade_step = (step * fade_steps) - / old_fade_steps; - } + int fade_steps = (ms + ms_per_step - 1)/ms_per_step; + if ( music_playing->fading == MIX_NO_FADING ) { + music_playing->fade_step = 0; + } else { + int step; + int old_fade_steps = music_playing->fade_steps; + if ( music_playing->fading == MIX_FADING_OUT ) { + step = music_playing->fade_step; + } else { + step = old_fade_steps + - music_playing->fade_step + 1; + } + music_playing->fade_step = (step * fade_steps) + / old_fade_steps; + } music_playing->fading = MIX_FADING_OUT; music_playing->fade_steps = fade_steps; retval = 1; @@ -1100,11 +1105,13 @@ return(retval); } -Mix_Fading Mix_FadingMusic(void) +Mix_Fading Mix_FadingMusic(int channel) { Mix_Fading fading = MIX_NO_FADING; + Mix_Music* music_playing; SDL_LockAudio(); + music_playing = _ChannelPlayingMusic(channel); if ( music_playing ) { fading = music_playing->fading; } @@ -1113,29 +1120,13 @@ return(fading); } -/* Pause/Resume the music stream */ -void Mix_PauseMusic(void) +void Mix_RewindMusic(int channel) { - music_active = 0; -} - -void Mix_ResumeMusic(void) -{ - music_active = 1; -} - -void Mix_RewindMusic(void) -{ - Mix_SetMusicPosition(0.0); -} - -int Mix_PausedMusic(void) -{ - return (music_active == 0); + Mix_SetMusicPosition(0.0, channel); } /* Check the status of the music */ -static int music_internal_playing() +static int music_internal_playing(Mix_Music *music_playing) { int playing = 1; switch (music_playing->type) { @@ -1216,13 +1207,16 @@ } return(playing); } -int Mix_PlayingMusic(void) + +int Mix_PlayingMusic(int channel) { int playing = 0; + Mix_Music* music_playing; SDL_LockAudio(); + music_playing = _ChannelPlayingMusic(channel); if ( music_playing ) { - playing = music_internal_playing(); + playing = music_internal_playing(music_playing); } SDL_UnlockAudio(); @@ -1230,9 +1224,9 @@ } /* Set the external music playback command */ -int Mix_SetMusicCMD(const char *command) +int Mix_SetMusicCMD(const char *command, int channel) { - Mix_HaltMusic(); + Mix_HaltMusic(_ChannelPlayingMusic(channel)); if ( music_cmd ) { free(music_cmd); music_cmd = NULL; @@ -1263,7 +1257,7 @@ /* Uninitialize the music players */ void close_music(void) { - Mix_HaltMusic(); + _HaltAllMusic(); #ifdef CMD_MUSIC Mix_SetMusicCMD(NULL); #endif diff -r 7a95f36a8bbf -r 10ced1337f97 music_modplug.c --- a/music_modplug.c Thu Feb 17 13:35:14 2011 -0800 +++ b/music_modplug.c Fri Apr 29 18:52:56 2011 -0700 @@ -58,7 +58,7 @@ settings.mBassRange=50; settings.mSurroundDepth=0; settings.mSurroundDelay=10; - settings.mLoopCount=0; + settings.mLoopCount=-1; ModPlug_SetSettings(&settings); return 0; }