*** empty log message ***
authorStephane Peter <megastep@lokigames.com>
Tue, 26 Oct 1999 02:24:17 +0000
changeset 7e73da9dc4bdc
parent 6 cb0e8db1f996
child 8 d2bf7cf9446c
*** empty log message ***
CHANGES
mixer.c
mixer.h
music.c
     1.1 --- a/CHANGES	Mon Oct 25 14:38:12 1999 +0000
     1.2 +++ b/CHANGES	Tue Oct 26 02:24:17 1999 +0000
     1.3 @@ -3,6 +3,9 @@
     1.4  SOL -   Added autoconf support
     1.5  SP  -   Added MP3 support using SMPEG
     1.6  SP  -   Added fading in/out of music and samples
     1.7 +SP  -   Added dynamic allocation of channels
     1.8 +SP  -   Added channel grouping functions
     1.9 +SP  -   Added expiration delay for samples
    1.10  
    1.11  Initial Key:
    1.12  SOL - Sam Lantinga (hercules@lokigames.com)
     2.1 --- a/mixer.c	Mon Oct 25 14:38:12 1999 +0000
     2.2 +++ b/mixer.c	Tue Oct 26 02:24:17 1999 +0000
     2.3 @@ -22,6 +22,8 @@
     2.4      slouken@devolution.com
     2.5  */
     2.6  
     2.7 +/* $Id$ */
     2.8 +
     2.9  #include <stdio.h>
    2.10  #include <stdlib.h>
    2.11  #include <string.h>
    2.12 @@ -42,11 +44,14 @@
    2.13  	Uint8 *samples;
    2.14  	int volume;
    2.15  	int looping;
    2.16 +	int tag;
    2.17 +	int expire;
    2.18  	Mix_Fading fading;
    2.19  	int fade_volume;
    2.20  	int fade_length;
    2.21  	Uint32 ticks_fade;
    2.22 -} channel[MIX_CHANNELS];
    2.23 +} *channel = NULL;
    2.24 +static int num_channels;
    2.25  
    2.26  #define MUSIC_VOL	64		/* Music volume 0-64 */
    2.27  
    2.28 @@ -54,7 +59,7 @@
    2.29  extern int music_active;
    2.30  extern void music_mixer(void *udata, Uint8 *stream, int len);
    2.31  static void (*mix_music)(void *udata, Uint8 *stream, int len) = music_mixer;
    2.32 -static int num_channels; /* Holds the number of channels actually mixed, for debugging */
    2.33 +static int mixed_channels = 0; /* Holds the number of channels actually mixed, for debugging */
    2.34  static int reserved_channels = 0;
    2.35  void *music_data = NULL;
    2.36  
    2.37 @@ -62,16 +67,24 @@
    2.38  static void mix_channels(void *udata, Uint8 *stream, int len)
    2.39  {
    2.40  	int i, mixable, volume;
    2.41 +	Uint32 sdl_ticks;
    2.42  
    2.43  	/* Grab the channels we need to mix */
    2.44  	SDL_mutexP(mixer_lock);
    2.45 -	num_channels = 0;
    2.46 -	for ( i=0; i<MIX_CHANNELS; ++i ) {
    2.47 -		if ( channel[i].fading != MIX_NO_FADING ) {
    2.48 -			Uint32 ticks = SDL_GetTicks() - channel[i].ticks_fade;
    2.49 +	mixed_channels = 0;
    2.50 +	sdl_ticks = SDL_GetTicks();
    2.51 +	for ( i=0; i<num_channels; ++i ) {
    2.52 +		if ( channel[i].expire > 0 && channel[i].expire < sdl_ticks ) {
    2.53 +			/* Expiration delay for that channel is reached */
    2.54 +			channel[i].playing = 0;
    2.55 +			channel[i].fading = MIX_NO_FADING;
    2.56 +			channel[i].expire = -1;
    2.57 +		} else if ( channel[i].fading != MIX_NO_FADING ) {
    2.58 +			Uint32 ticks = sdl_ticks - channel[i].ticks_fade;
    2.59  			if( ticks > channel[i].fade_length ) {
    2.60  				if( channel[i].fading == MIX_FADING_OUT ) {
    2.61  					channel[i].playing = 0;
    2.62 +					channel[i].expire = -1;
    2.63  					Mix_Volume(i, channel[i].fading); /* Restore the volume */
    2.64  				}
    2.65  				channel[i].fading = MIX_NO_FADING;
    2.66 @@ -85,7 +98,7 @@
    2.67  			}
    2.68  		}
    2.69  		if ( channel[i].playing && !channel[i].paused ) {
    2.70 -		    ++ num_channels;
    2.71 +		    ++ mixed_channels;
    2.72  			mixable = channel[i].playing;
    2.73  			if ( mixable > len ) {
    2.74  				mixable = len;
    2.75 @@ -160,13 +173,18 @@
    2.76  		SDL_DestroyMutex(mixer_lock);
    2.77  		return(-1);
    2.78  	}
    2.79 -	
    2.80 +
    2.81 +	num_channels = MIX_CHANNELS;
    2.82 +	channel = (struct _Mix_Channel *) malloc(num_channels * sizeof(struct _Mix_Channel));
    2.83 +
    2.84  	/* Clear out the audio channels */
    2.85 -	for ( i=0; i<MIX_CHANNELS; ++i ) {
    2.86 +	for ( i=0; i<num_channels; ++i ) {
    2.87  		channel[i].chunk = NULL;
    2.88  		channel[i].playing = 0;
    2.89  		channel[i].looping = 0;
    2.90  		channel[i].volume = SDL_MIX_MAXVOLUME;
    2.91 +		channel[i].tag = -1;
    2.92 +		channel[i].expire = -1;
    2.93  	}
    2.94  	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
    2.95  	audio_opened = 1;
    2.96 @@ -174,6 +192,41 @@
    2.97  	return(0);
    2.98  }
    2.99  
   2.100 +/* Dynamically change the number of channels managed by the mixer.
   2.101 +   If decreasing the number of channels, the upper channels are
   2.102 +   stopped.
   2.103 + */
   2.104 +int Mix_AllocateChannels(int numchans)
   2.105 +{
   2.106 +	if ( numchans<0 || numchans==num_channels )
   2.107 +		return(num_channels);
   2.108 +
   2.109 +	if ( numchans < num_channels ) {
   2.110 +		/* Stop the affected channels */
   2.111 +		int i;
   2.112 +		for(i=numchans; i < num_channels; i++) {
   2.113 +			Mix_HaltChannel(i);
   2.114 +		}
   2.115 +	}
   2.116 +	SDL_mutexP(mixer_lock);
   2.117 +	channel = (struct _Mix_Channel *) realloc(channel, numchans * sizeof(struct _Mix_Channel));
   2.118 +	if ( numchans > num_channels ) {
   2.119 +		/* Initialize the new channels */
   2.120 +		int i;
   2.121 +		for(i=num_channels; i < numchans; i++) {
   2.122 +			channel[i].chunk = NULL;
   2.123 +			channel[i].playing = 0;
   2.124 +			channel[i].looping = 0;
   2.125 +			channel[i].volume = SDL_MIX_MAXVOLUME;
   2.126 +			channel[i].tag = -1;
   2.127 +			channel[i].expire = -1;
   2.128 +		}
   2.129 +	}
   2.130 +	num_channels = numchans;
   2.131 +	SDL_mutexV(mixer_lock);
   2.132 +	return(num_channels);
   2.133 +}
   2.134 +
   2.135  /* Return the actual mixer parameters */
   2.136  int Mix_QuerySpec(int *frequency, Uint16 *format, int *channels)
   2.137  {
   2.138 @@ -304,7 +357,7 @@
   2.139  	if ( chunk ) {
   2.140  		/* Guarantee that this chunk isn't playing */
   2.141  		SDL_mutexP(mixer_lock);
   2.142 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.143 +		for ( i=0; i<num_channels; ++i ) {
   2.144  			if ( chunk == channel[i].chunk ) {
   2.145  				channel[i].playing = 0;
   2.146  			}
   2.147 @@ -347,17 +400,19 @@
   2.148   */
   2.149  int Mix_ReserveChannels(int num)
   2.150  {
   2.151 -	if (num > MIX_CHANNELS)
   2.152 -		num = MIX_CHANNELS;
   2.153 +	if (num > num_channels)
   2.154 +		num = num_channels;
   2.155  	reserved_channels = num;
   2.156  	return num;
   2.157  }
   2.158  
   2.159  /* Play an audio chunk on a specific channel.
   2.160     If the specified channel is -1, play on the first free channel.
   2.161 +   'ticks' is the number of milliseconds at most to play the sample, or -1
   2.162 +   if there is no limit.
   2.163     Returns which channel was used to play the sound.
   2.164  */
   2.165 -int Mix_PlayChannel(int which, Mix_Chunk *chunk, int loops)
   2.166 +int Mix_PlayChannelTimed(int which, Mix_Chunk *chunk, int loops, int ticks)
   2.167  {
   2.168  	int i;
   2.169  
   2.170 @@ -371,11 +426,11 @@
   2.171  	{
   2.172  		/* If which is -1, play on the first free channel */
   2.173  		if ( which == -1 ) {
   2.174 -			for ( i=reserved_channels; i<MIX_CHANNELS; ++i ) {
   2.175 +			for ( i=reserved_channels; i<num_channels; ++i ) {
   2.176  				if ( channel[i].playing <= 0 )
   2.177  					break;
   2.178  			}
   2.179 -			if ( i == MIX_CHANNELS ) {
   2.180 +			if ( i == num_channels ) {
   2.181  				which = -1;
   2.182  			} else {
   2.183  				which = i;
   2.184 @@ -390,6 +445,7 @@
   2.185  			channel[which].chunk = chunk;
   2.186  			channel[which].paused = 0;
   2.187  			channel[which].fading = MIX_NO_FADING;
   2.188 +			channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : -1;
   2.189  		}
   2.190  	}
   2.191  	SDL_mutexV(mixer_lock);
   2.192 @@ -398,8 +454,27 @@
   2.193  	return(which);
   2.194  }
   2.195  
   2.196 +/* Change the expiration delay for a channel */
   2.197 +int Mix_ExpireChannel(int which, int ticks)
   2.198 +{
   2.199 +	int status = 0;
   2.200 +
   2.201 +	if ( which == -1 ) {
   2.202 +		int i;
   2.203 +		for ( i=0; i < num_channels; ++ i ) {
   2.204 +			status += Mix_ExpireChannel(i, ticks);
   2.205 +		}
   2.206 +	} else if ( which < num_channels ) {
   2.207 +		SDL_mutexP(mixer_lock);
   2.208 +		channel[which].expire = (ticks>0) ? (SDL_GetTicks() + ticks) : -1;		
   2.209 +		SDL_mutexV(mixer_lock);
   2.210 +		++ status;
   2.211 +	}
   2.212 +	return(status);
   2.213 +}
   2.214 +
   2.215  /* Fade in a sound on a channel, over ms milliseconds */
   2.216 -int Mix_FadeInChannel(int which, Mix_Chunk *chunk, int loops, int ms)
   2.217 +int Mix_FadeInChannelTimed(int which, Mix_Chunk *chunk, int loops, int ms, int ticks)
   2.218  {
   2.219  	int i;
   2.220  
   2.221 @@ -413,11 +488,11 @@
   2.222  	{
   2.223  		/* If which is -1, play on the first free channel */
   2.224  		if ( which == -1 ) {
   2.225 -			for ( i=reserved_channels; i<MIX_CHANNELS; ++i ) {
   2.226 +			for ( i=reserved_channels; i<num_channels; ++i ) {
   2.227  				if ( channel[i].playing <= 0 )
   2.228  					break;
   2.229  			}
   2.230 -			if ( i == MIX_CHANNELS ) {
   2.231 +			if ( i == num_channels ) {
   2.232  				which = -1;
   2.233  			} else {
   2.234  				which = i;
   2.235 @@ -436,6 +511,7 @@
   2.236  			channel[which].volume = 0;
   2.237  			channel[which].fade_length = ms;
   2.238  			channel[which].ticks_fade = SDL_GetTicks();
   2.239 +			channel[which].expire = (ticks > 0) ? (SDL_GetTicks()+ticks) : -1;
   2.240  		}
   2.241  	}
   2.242  	SDL_mutexV(mixer_lock);
   2.243 @@ -452,10 +528,10 @@
   2.244  
   2.245  	if ( which == -1 ) {
   2.246  		prev_volume = 0;
   2.247 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.248 +		for ( i=0; i<num_channels; ++i ) {
   2.249  			prev_volume += Mix_Volume(i, volume);
   2.250  		}
   2.251 -		prev_volume /= MIX_CHANNELS;
   2.252 +		prev_volume /= num_channels;
   2.253  	} else {
   2.254  		prev_volume = channel[which].volume;
   2.255  		if ( volume < 0 ) {
   2.256 @@ -489,12 +565,13 @@
   2.257  	int i;
   2.258  
   2.259  	if ( which == -1 ) {
   2.260 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.261 +		for ( i=0; i<num_channels; ++i ) {
   2.262  			Mix_HaltChannel(i);
   2.263  		}
   2.264  	} else {
   2.265  		SDL_mutexP(mixer_lock);
   2.266  		channel[which].playing = 0;
   2.267 +		channel[which].expire = -1;
   2.268  		if(channel[which].fading != MIX_NO_FADING) /* Restore volume */
   2.269  			channel[which].volume = channel[which].fade_volume;
   2.270  		channel[which].fading = MIX_NO_FADING;
   2.271 @@ -503,6 +580,19 @@
   2.272  	return(0);
   2.273  }
   2.274  
   2.275 +/* Halt playing of a particular group of channels */
   2.276 +int Mix_HaltGroup(int tag)
   2.277 +{
   2.278 +	int i;
   2.279 +
   2.280 +	for ( i=0; i<num_channels; ++i ) {
   2.281 +		if( channel[i].tag == tag ) {
   2.282 +			Mix_HaltChannel(i);
   2.283 +		}
   2.284 +	}
   2.285 +	return(0);
   2.286 +}
   2.287 +
   2.288  /* Fade out a channel and then stop it automatically */
   2.289  int Mix_FadeOutChannel(int which, int ms)
   2.290  {
   2.291 @@ -512,7 +602,7 @@
   2.292  	if ( which == -1 ) {
   2.293  		int i;
   2.294  
   2.295 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.296 +		for ( i=0; i<num_channels; ++i ) {
   2.297  			status += Mix_FadeOutChannel(i,ms);
   2.298  		}
   2.299  	} else {
   2.300 @@ -531,6 +621,19 @@
   2.301  	return(status);
   2.302  }
   2.303  
   2.304 +/* Halt playing of a particular group of channels */
   2.305 +int Mix_FadeOutGroup(int tag, int ms)
   2.306 +{
   2.307 +	int i;
   2.308 +	int status = 0;
   2.309 +	for ( i=0; i<num_channels; ++i ) {
   2.310 +		if( channel[i].tag == tag ) {
   2.311 +			status += Mix_FadeOutChannel(i,ms);
   2.312 +		}
   2.313 +	}
   2.314 +	return(status);
   2.315 +}
   2.316 +
   2.317  Mix_Fading Mix_FadingChannel(int which)
   2.318  {
   2.319  	return channel[which].fading;
   2.320 @@ -547,7 +650,7 @@
   2.321  	if ( which == -1 ) {
   2.322  		int i;
   2.323  
   2.324 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.325 +		for ( i=0; i<num_channels; ++i ) {
   2.326  			if ( channel[i].playing > 0 ) {
   2.327  				++status;
   2.328  			}
   2.329 @@ -569,6 +672,7 @@
   2.330  			Mix_HaltChannel(-1);
   2.331  			SDL_CloseAudio();
   2.332  			SDL_DestroyMutex(mixer_lock);
   2.333 +			channel = NULL;
   2.334  		}
   2.335  		--audio_opened;
   2.336  	}
   2.337 @@ -577,10 +681,11 @@
   2.338  /* Pause a particular channel (or all) */
   2.339  void Mix_Pause(int which)
   2.340  {
   2.341 +	/* TODO: Handle properly expiring samples */
   2.342  	if ( which == -1 ) {
   2.343  		int i;
   2.344  
   2.345 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.346 +		for ( i=0; i<num_channels; ++i ) {
   2.347  			if ( channel[i].playing > 0 ) {
   2.348  				channel[i].paused = 1;
   2.349  			}
   2.350 @@ -598,7 +703,7 @@
   2.351  	if ( which == -1 ) {
   2.352  		int i;
   2.353  
   2.354 -		for ( i=0; i<MIX_CHANNELS; ++i ) {
   2.355 +		for ( i=0; i<num_channels; ++i ) {
   2.356  			if ( channel[i].playing > 0 ) {
   2.357  				channel[i].paused = 0;
   2.358  			}
   2.359 @@ -609,3 +714,47 @@
   2.360  		}
   2.361  	}
   2.362  }
   2.363 +
   2.364 +/* Change the group of a channel */
   2.365 +int Mix_GroupChannel(int which, int tag)
   2.366 +{
   2.367 +	if ( which < 0 || which > num_channels )
   2.368 +		return(0);
   2.369 +
   2.370 +	SDL_mutexP(mixer_lock);
   2.371 +	channel[which].tag = tag;
   2.372 +	SDL_mutexV(mixer_lock);
   2.373 +	return(1);
   2.374 +}
   2.375 +
   2.376 +/* Assign several consecutive channels to a group */
   2.377 +int Mix_GroupChannels(int from, int to, int tag)
   2.378 +{
   2.379 +	int status = 0;
   2.380 +	for( ; from <= to; ++ from ) {
   2.381 +		status += Mix_GroupChannel(from, tag);
   2.382 +	}
   2.383 +	return(status);
   2.384 +}
   2.385 +
   2.386 +/* Finds the first available channel in a group of channels */
   2.387 +int Mix_GroupAvailable(int tag)
   2.388 +{
   2.389 +	int i;
   2.390 +	for( i=0; i < num_channels; i ++ ) {
   2.391 +		if ( (channel[i].tag==tag || tag==-1) && channel[i].playing<=0 )
   2.392 +			return i;
   2.393 +	}
   2.394 +	return(-1);
   2.395 +}
   2.396 +
   2.397 +int Mix_GroupCount(int tag)
   2.398 +{
   2.399 +	int count = 0;
   2.400 +	int i;
   2.401 +	for( i=0; i < num_channels; i ++ ) {
   2.402 +		if ( channel[i].tag==tag || tag==-1 )
   2.403 +			++ count;
   2.404 +	}
   2.405 +	return(count);
   2.406 +}
     3.1 --- a/mixer.h	Mon Oct 25 14:38:12 1999 +0000
     3.2 +++ b/mixer.h	Tue Oct 26 02:24:17 1999 +0000
     3.3 @@ -64,6 +64,13 @@
     3.4  extern int Mix_OpenAudio(int frequency, Uint16 format, int channels,
     3.5  							int chunksize);
     3.6  
     3.7 +/* Dynamically change the number of channels managed by the mixer.
     3.8 +   If decreasing the number of channels, the upper channels are
     3.9 +   stopped.
    3.10 +   This function returns the new number of allocated channels.
    3.11 + */
    3.12 +extern int Mix_AllocateChannels(int numchans);
    3.13 +
    3.14  /* Find out what the actual audio device parameters are.
    3.15     This function returns 1 if the audio has been opened, 0 otherwise.
    3.16   */
    3.17 @@ -96,18 +103,39 @@
    3.18   */
    3.19  extern int Mix_ReserveChannels(int num);
    3.20  
    3.21 +/* Channel grouping functions */
    3.22 +
    3.23 +/* Attach a tag to a channel. A tag can be assigned to several mixer
    3.24 +   channels, to form groups of channels.
    3.25 +   If 'tag' is -1, the tag is removed (actually -1 is the tag used to
    3.26 +   represent the group of all the channels).
    3.27 +   Returns true if everything was OK.
    3.28 + */
    3.29 +extern int Mix_GroupChannel(int which, int tag);
    3.30 +/* Assign several consecutive channels to a group */
    3.31 +extern int Mix_GroupChannels(int from, int to, int tag);
    3.32 +/* Finds the first available channel in a group of channels */
    3.33 +extern int Mix_GroupAvailable(int tag);
    3.34 +/* Returns the number of channels in a group. This is also a subtle
    3.35 +   way to get the total number of channels when 'tag' is -1
    3.36 + */
    3.37 +extern int Mix_GroupCount(int tag);
    3.38 +
    3.39  /* Play an audio chunk on a specific channel.
    3.40     If the specified channel is -1, play on the first free channel.
    3.41     If 'loops' is greater than zero, loop the sound that many times.
    3.42     If 'loops' is -1, loop inifinitely (~65000 times).
    3.43     Returns which channel was used to play the sound.
    3.44  */
    3.45 -extern int Mix_PlayChannel(int channel, Mix_Chunk *chunk, int loops);
    3.46 +#define Mix_PlayChannel(channel,chunk,loops) Mix_PlayChannelTimed(channel,chunk,loops,-1)
    3.47 +/* The same as above, but the sound is played at most 'ticks' milliseconds */
    3.48 +extern int Mix_PlayChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ticks);
    3.49  extern int Mix_PlayMusic(Mix_Music *music, int loops);
    3.50  
    3.51  /* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */
    3.52  extern int Mix_FadeInMusic(Mix_Music *music, int loops, int ms);
    3.53 -extern int Mix_FadeInChannel(int channel, Mix_Chunk *chunk, int loops, int ms);
    3.54 +#define Mix_FadeInChannel(channel,chunk,loops,ms) Mix_FadeInChannelTimed(channel,chunk,loops,ms,-1)
    3.55 +extern int Mix_FadeInChannelTimed(int channel, Mix_Chunk *chunk, int loops, int ms, int ticks);
    3.56  
    3.57  /* Set the volume in the range of 0-128 of a specific channel or chunk.
    3.58     If the specified channel is -1, set volume for all channels.
    3.59 @@ -120,13 +148,21 @@
    3.60  
    3.61  /* Halt playing of a particular channel */
    3.62  extern int Mix_HaltChannel(int channel);
    3.63 +extern int Mix_HaltGroup(int tag);
    3.64  extern int Mix_HaltMusic(void);
    3.65  
    3.66 +/* Change the expiration delay for a particular channel.
    3.67 +   The sample will stop playing after the 'ticks' milliseconds have elapsed,
    3.68 +   or remove the expiration if 'ticks' is -1
    3.69 +*/
    3.70 +extern int Mix_ExpireChannel(int channel, int ticks);
    3.71 +
    3.72  /* Halt a channel, fading it out progressively till it's silent 
    3.73     The ms parameter indicates the number of milliseconds the fading
    3.74     will take.
    3.75   */
    3.76  extern int Mix_FadeOutChannel(int which, int ms);
    3.77 +extern int Mix_FadeOutGroup(int tag, int ms);
    3.78  extern int Mix_FadeOutMusic(int ms);
    3.79  
    3.80  /* Query the fading status of a channel */
     4.1 --- a/music.c	Mon Oct 25 14:38:12 1999 +0000
     4.2 +++ b/music.c	Tue Oct 26 02:24:17 1999 +0000
     4.3 @@ -53,11 +53,11 @@
     4.4  #endif
     4.5  
     4.6  int music_active = 1;
     4.7 +static int music_stopped = 0;
     4.8  static int music_loops = 0;
     4.9  static char *music_cmd = NULL;
    4.10  static int samplesize;
    4.11  static Mix_Music *music_playing = 0;
    4.12 -static SDL_mutex *music_lock;
    4.13  static int music_volume;
    4.14  static int music_swap8;
    4.15  static int music_swap16;
    4.16 @@ -95,19 +95,27 @@
    4.17  };
    4.18  static int timidity_ok;
    4.19  
    4.20 +static void lowlevel_halt(void);
    4.21 +
    4.22  /* Mixing function */
    4.23  void music_mixer(void *udata, Uint8 *stream, int len)
    4.24  {
    4.25  	int i;
    4.26  
    4.27  	if ( music_playing ) {
    4.28 -		if( music_playing->fading != MIX_NO_FADING ) {
    4.29 +		if ( music_stopped ) {
    4.30 +			/* To avoid concurrency problems and the use of mutexes,
    4.31 +			   the music is always stopped from the sound thread */
    4.32 +			lowlevel_halt(); /* This function sets music_playing to NULL */
    4.33 +			return;
    4.34 +		}	
    4.35 +		if ( music_playing->fading != MIX_NO_FADING ) {
    4.36  			Uint32 ticks = SDL_GetTicks() - music_playing->ticks_fade;
    4.37  			if( ticks > music_playing->fade_length ) {
    4.38  				if ( music_playing->fading == MIX_FADING_OUT ) {
    4.39  					music_volume = music_playing->fade_volume;
    4.40  					music_playing->fading = MIX_NO_FADING;
    4.41 -					Mix_HaltMusic();
    4.42 +					lowlevel_halt();
    4.43  					return;
    4.44  				}
    4.45  				music_playing->fading = MIX_NO_FADING;
    4.46 @@ -253,9 +261,8 @@
    4.47  	used_mixer = *mixer;
    4.48  #endif
    4.49  	music_playing = 0;
    4.50 +	music_stopped = 0;
    4.51  
    4.52 -	/* Initialize the music lock */
    4.53 -	music_lock = SDL_CreateMutex();
    4.54  	if ( music_error ) {
    4.55  		return(-1);
    4.56  	}
    4.57 @@ -368,7 +375,7 @@
    4.58  {
    4.59  	if ( music ) {
    4.60  		/* Caution: If music is playing, mixer will crash */
    4.61 -		if ( music == music_playing ) {
    4.62 +		if ( music == music_playing && !music_stopped ) {
    4.63  			if ( music->fading == MIX_FADING_OUT ) {
    4.64  				/* Wait for the fade out to finish */
    4.65  				while(music->fading == MIX_FADING_OUT)
    4.66 @@ -420,7 +427,7 @@
    4.67  		return(-1);
    4.68  	}
    4.69  	/* If the current music is fading out, wait for the fade to complete */
    4.70 -	while ( music_playing && music_playing->fading==MIX_FADING_OUT ) {
    4.71 +	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
    4.72  		SDL_Delay(100);
    4.73  	}
    4.74  	switch (music->type) {
    4.75 @@ -463,6 +470,7 @@
    4.76  			return(-1);
    4.77  	}
    4.78  	music_active = 1;
    4.79 +	music_stopped = 0;
    4.80  	music_playing = music;
    4.81  	music_playing->fading = MIX_NO_FADING;
    4.82  	return(0);
    4.83 @@ -496,7 +504,7 @@
    4.84  		volume = SDL_MIX_MAXVOLUME;
    4.85  	}
    4.86  	music_volume = volume;
    4.87 -	if ( music_playing ) {
    4.88 +	if ( music_playing && !music_stopped ) {
    4.89  		switch (music_playing->type) {
    4.90  #ifdef CMD_MUSIC
    4.91  		case MUS_CMD:
    4.92 @@ -531,58 +539,63 @@
    4.93  	return(prev_volume);
    4.94  }
    4.95  
    4.96 +static void lowlevel_halt(void)
    4.97 +{
    4.98 +	switch (music_playing->type) {
    4.99 +#ifdef CMD_MUSIC
   4.100 +	case MUS_CMD:
   4.101 +		MusicCMD_Stop(music_playing->data.cmd);
   4.102 +		break;
   4.103 +#endif
   4.104 +#ifdef WAV_MUSIC
   4.105 +	case MUS_WAV:
   4.106 +		WAVStream_Stop();
   4.107 +		break;
   4.108 +#endif
   4.109 +#ifdef MOD_MUSIC
   4.110 +	case MUS_MOD:
   4.111 +		Player_Stop();
   4.112 +		break;
   4.113 +#endif
   4.114 +#ifdef MID_MUSIC
   4.115 +	case MUS_MID:
   4.116 +		Timidity_Stop();
   4.117 +		break;
   4.118 +#endif
   4.119 +#ifdef MP3_MUSIC
   4.120 +	case MUS_MP3:
   4.121 +		SMPEG_stop(music_playing->data.mp3);
   4.122 +		break;
   4.123 +#endif
   4.124 +	default:
   4.125 +		/* Unknown music type?? */
   4.126 +		return;
   4.127 +	}
   4.128 +	if(music_playing->fading != MIX_NO_FADING) /* Restore volume */
   4.129 +		music_volume = music_playing->fade_volume;
   4.130 +	music_playing->fading = MIX_NO_FADING;
   4.131 +	music_playing = 0;
   4.132 +	music_active = 0;
   4.133 +	music_stopped = 0;
   4.134 +}
   4.135 +
   4.136  /* Halt playing of music */
   4.137  int Mix_HaltMusic(void)
   4.138  {
   4.139 -	/* This function can be called both from the main program thread
   4.140 -	   and from the SDL audio thread (when fading), so we need to ensure 
   4.141 -	   that only one thread is running it at once */
   4.142 -	SDL_mutexP(music_lock);
   4.143 -	if ( music_playing ) {
   4.144 -		switch (music_playing->type) {
   4.145 -#ifdef CMD_MUSIC
   4.146 -			case MUS_CMD:
   4.147 -				MusicCMD_Stop(music_playing->data.cmd);
   4.148 -				break;
   4.149 -#endif
   4.150 -#ifdef WAV_MUSIC
   4.151 -			case MUS_WAV:
   4.152 -				WAVStream_Stop();
   4.153 -				break;
   4.154 -#endif
   4.155 -#ifdef MOD_MUSIC
   4.156 -			case MUS_MOD:
   4.157 -				Player_Stop();
   4.158 -				break;
   4.159 -#endif
   4.160 -#ifdef MID_MUSIC
   4.161 -			case MUS_MID:
   4.162 -				Timidity_Stop();
   4.163 -				break;
   4.164 -#endif
   4.165 -#ifdef MP3_MUSIC
   4.166 -		    case MUS_MP3:
   4.167 -				SMPEG_stop(music_playing->data.mp3);
   4.168 -				break;
   4.169 -#endif
   4.170 -			default:
   4.171 -				/* Unknown music type?? */
   4.172 -				SDL_mutexV(music_lock);
   4.173 -				return(-1);
   4.174 -		}
   4.175 -		if(music_playing->fading != MIX_NO_FADING) /* Restore volume */
   4.176 -			music_volume = music_playing->fade_volume;
   4.177 -		music_playing->fading = MIX_NO_FADING;
   4.178 -		music_playing = 0;
   4.179 +	if ( music_playing && !music_stopped ) {
   4.180 +		/* Mark the music to be stopped from the sound thread */
   4.181 +		music_stopped = 1;
   4.182 +		/* Wait for it to be actually stopped */
   4.183 +		while ( music_playing )
   4.184 +			SDL_Delay(10);
   4.185  	}
   4.186 -	SDL_mutexV(music_lock);
   4.187  	return(0);
   4.188  }
   4.189  
   4.190  /* Progressively stop the music */
   4.191  int Mix_FadeOutMusic(int ms)
   4.192  {
   4.193 -	if ( music_playing && music_playing->fading==MIX_NO_FADING ) {
   4.194 +	if ( music_playing && !music_stopped && music_playing->fading==MIX_NO_FADING ) {
   4.195  		if ( music_volume>0 ) {
   4.196  			music_playing->fading = MIX_FADING_OUT;
   4.197  			music_playing->fade_volume = music_volume;
   4.198 @@ -596,7 +609,7 @@
   4.199  
   4.200  Mix_Fading Mix_FadingMusic(void)
   4.201  {
   4.202 -	if( music_playing )
   4.203 +	if( music_playing && !music_stopped )
   4.204  		return music_playing->fading;
   4.205  	return MIX_NO_FADING;
   4.206  }
   4.207 @@ -604,7 +617,7 @@
   4.208  /* Pause/Resume the music stream */
   4.209  void Mix_PauseMusic(void)
   4.210  {
   4.211 -	if ( music_playing ) {
   4.212 +	if ( music_playing && !music_stopped ) {
   4.213  		switch ( music_playing->type ) {
   4.214  #ifdef CMD_MUSIC
   4.215  		case MUS_CMD:
   4.216 @@ -623,7 +636,7 @@
   4.217  
   4.218  void Mix_ResumeMusic(void)
   4.219  {
   4.220 -	if ( music_playing ) {
   4.221 +	if ( music_playing && !music_stopped ) {
   4.222  		switch ( music_playing->type ) {
   4.223  #ifdef CMD_MUSIC
   4.224  		case MUS_CMD:
   4.225 @@ -642,13 +655,14 @@
   4.226  
   4.227  void Mix_RewindMusic(void)
   4.228  {
   4.229 -	if ( music_playing ) {
   4.230 +	if ( music_playing && !music_stopped ) {
   4.231  		switch ( music_playing->type ) {
   4.232  #ifdef MP3_MUSIC
   4.233  		case MUS_MP3:
   4.234  			SMPEG_rewind(music_playing->data.mp3);
   4.235  			break;
   4.236  #endif
   4.237 +			/* TODO: Implement this for other music backends */
   4.238  		}
   4.239  	}
   4.240  }
   4.241 @@ -656,7 +670,7 @@
   4.242  /* Check the status of the music */
   4.243  int Mix_PlayingMusic(void)
   4.244  {
   4.245 -	if ( music_playing ) {
   4.246 +	if ( music_playing && !music_stopped ) {
   4.247  		switch (music_playing->type) {
   4.248  #ifdef CMD_MUSIC
   4.249  			case MUS_CMD: