Added fading in/out of music and samples.
authorStephane Peter <megastep@lokigames.com>
Sat, 23 Oct 1999 03:31:21 +0000
changeset 45c4485704b30
parent 3 f6dabb779e45
child 5 ebdf63084644
Added fading in/out of music and samples.
mixer.c
mixer.h
music.c
playmus.c
     1.1 --- a/mixer.c	Sat Oct 23 00:39:09 1999 +0000
     1.2 +++ b/mixer.c	Sat Oct 23 03:31:21 1999 +0000
     1.3 @@ -42,6 +42,10 @@
     1.4  	Uint8 *samples;
     1.5  	int volume;
     1.6  	int looping;
     1.7 +	Mix_Fading fading;
     1.8 +	int fade_volume;
     1.9 +	int fade_length;
    1.10 +	Uint32 ticks_fade;
    1.11  } channel[MIX_CHANNELS];
    1.12  
    1.13  #define MUSIC_VOL	64		/* Music volume 0-64 */
    1.14 @@ -63,6 +67,23 @@
    1.15  	SDL_mutexP(mixer_lock);
    1.16  	num_channels = 0;
    1.17  	for ( i=0; i<MIX_CHANNELS; ++i ) {
    1.18 +		if ( channel[i].fading != MIX_NO_FADING ) {
    1.19 +			Uint32 ticks = SDL_GetTicks() - channel[i].ticks_fade;
    1.20 +			if( ticks > channel[i].fade_length ) {
    1.21 +				if( channel[i].fading == MIX_FADING_OUT ) {
    1.22 +					channel[i].playing = 0;
    1.23 +					Mix_Volume(i, channel[i].fading); /* Restore the volume */
    1.24 +				}
    1.25 +				channel[i].fading = MIX_NO_FADING;
    1.26 +			} else {
    1.27 +				if( channel[i].fading == MIX_FADING_OUT ) {
    1.28 +					Mix_Volume(i, (channel[i].fade_volume * (channel[i].fade_length-ticks))
    1.29 +							   / channel[i].fade_length );
    1.30 +				} else {
    1.31 +					Mix_Volume(i, (channel[i].fade_volume * ticks) / channel[i].fade_length );
    1.32 +				}
    1.33 +			}
    1.34 +		}
    1.35  		if ( channel[i].playing && !channel[i].paused ) {
    1.36  		    ++ num_channels;
    1.37  			mixable = channel[i].playing;
    1.38 @@ -368,6 +389,53 @@
    1.39  			channel[which].looping = loops;
    1.40  			channel[which].chunk = chunk;
    1.41  			channel[which].paused = 0;
    1.42 +			channel[which].fading = MIX_NO_FADING;
    1.43 +		}
    1.44 +	}
    1.45 +	SDL_mutexV(mixer_lock);
    1.46 +
    1.47 +	/* Return the channel on which the sound is being played */
    1.48 +	return(which);
    1.49 +}
    1.50 +
    1.51 +/* Fade in a sound on a channel, over ms milliseconds */
    1.52 +int Mix_FadeInChannel(int which, Mix_Chunk *chunk, int loops, int ms)
    1.53 +{
    1.54 +	int i;
    1.55 +
    1.56 +	/* Don't play null pointers :-) */
    1.57 +	if ( chunk == NULL ) {
    1.58 +		return(-1);
    1.59 +	}
    1.60 +
    1.61 +	/* Lock the mixer while modifying the playing channels */
    1.62 +	SDL_mutexP(mixer_lock);
    1.63 +	{
    1.64 +		/* If which is -1, play on the first free channel */
    1.65 +		if ( which == -1 ) {
    1.66 +			for ( i=reserved_channels; i<MIX_CHANNELS; ++i ) {
    1.67 +				if ( channel[i].playing <= 0 )
    1.68 +					break;
    1.69 +			}
    1.70 +			if ( i == MIX_CHANNELS ) {
    1.71 +				which = -1;
    1.72 +			} else {
    1.73 +				which = i;
    1.74 +			}
    1.75 +		}
    1.76 +
    1.77 +		/* Queue up the audio data for this channel */
    1.78 +		if ( which >= 0 ) {
    1.79 +			channel[which].samples = chunk->abuf;
    1.80 +			channel[which].playing = chunk->alen;
    1.81 +			channel[which].looping = loops;
    1.82 +			channel[which].chunk = chunk;
    1.83 +			channel[which].paused = 0;
    1.84 +			channel[which].fading = MIX_FADING_IN;
    1.85 +			channel[which].fade_volume = channel[which].volume;
    1.86 +			channel[which].volume = 0;
    1.87 +			channel[which].fade_length = ms;
    1.88 +			channel[which].ticks_fade = SDL_GetTicks();
    1.89  		}
    1.90  	}
    1.91  	SDL_mutexV(mixer_lock);
    1.92 @@ -390,12 +458,13 @@
    1.93  		prev_volume /= MIX_CHANNELS;
    1.94  	} else {
    1.95  		prev_volume = channel[which].volume;
    1.96 -		if ( volume >= 0 ) {
    1.97 -			if ( volume > SDL_MIX_MAXVOLUME ) {
    1.98 -				volume = SDL_MIX_MAXVOLUME;
    1.99 -			}
   1.100 -			channel[which].volume = volume;
   1.101 +		if ( volume < 0 ) {
   1.102 +			volume = 0;
   1.103  		}
   1.104 +		if ( volume > SDL_MIX_MAXVOLUME ) {
   1.105 +			volume = SDL_MIX_MAXVOLUME;
   1.106 +		}
   1.107 +		channel[which].volume = volume;
   1.108  	}
   1.109  	return(prev_volume);
   1.110  }
   1.111 @@ -426,11 +495,47 @@
   1.112  	} else {
   1.113  		SDL_mutexP(mixer_lock);
   1.114  		channel[which].playing = 0;
   1.115 +		if(channel[which].fading != MIX_NO_FADING) /* Restore volume */
   1.116 +			channel[which].volume = channel[which].fade_volume;
   1.117 +		channel[which].fading = MIX_NO_FADING;
   1.118  		SDL_mutexV(mixer_lock);
   1.119  	}
   1.120  	return(0);
   1.121  }
   1.122  
   1.123 +/* Fade out a channel and then stop it automatically */
   1.124 +int Mix_FadeOutChannel(int which, int ms)
   1.125 +{
   1.126 +	int status;
   1.127 +
   1.128 +	status = 0;
   1.129 +	if ( which == -1 ) {
   1.130 +		int i;
   1.131 +
   1.132 +		for ( i=0; i<MIX_CHANNELS; ++i ) {
   1.133 +			status += Mix_FadeOutChannel(i,ms);
   1.134 +		}
   1.135 +	} else {
   1.136 +		SDL_mutexP(mixer_lock);
   1.137 +		if ( channel[which].playing && channel[which].volume>0 && 
   1.138 +			 channel[which].fading==MIX_NO_FADING ) {
   1.139 +
   1.140 +			channel[which].fading = MIX_FADING_OUT;
   1.141 +			channel[which].fade_volume = channel[which].volume;
   1.142 +			channel[which].fade_length = ms;
   1.143 +			channel[which].ticks_fade = SDL_GetTicks();
   1.144 +			++ status;
   1.145 +		}
   1.146 +		SDL_mutexV(mixer_lock);
   1.147 +	}
   1.148 +	return(status);
   1.149 +}
   1.150 +
   1.151 +Mix_Fading Mix_FadingChannel(int which)
   1.152 +{
   1.153 +	return channel[which].fading;
   1.154 +}
   1.155 +
   1.156  /* Check the status of a specific channel.
   1.157     If the specified channel is -1, check all channels.
   1.158  */
     2.1 --- a/mixer.h	Sat Oct 23 00:39:09 1999 +0000
     2.2 +++ b/mixer.h	Sat Oct 23 03:31:21 1999 +0000
     2.3 @@ -50,6 +50,13 @@
     2.4  	Uint8 volume;		/* Per-sample volume, 0-128 */
     2.5  } Mix_Chunk;
     2.6  
     2.7 +/* The different fading types supported */
     2.8 +typedef enum {
     2.9 +	MIX_NO_FADING,
    2.10 +	MIX_FADING_OUT,
    2.11 +	MIX_FADING_IN
    2.12 +} Mix_Fading;
    2.13 +
    2.14  /* The internal format for a music chunk interpreted via mikmod */
    2.15  typedef struct _Mix_Music Mix_Music;
    2.16  
    2.17 @@ -98,6 +105,10 @@
    2.18  extern int Mix_PlayChannel(int channel, Mix_Chunk *chunk, int loops);
    2.19  extern int Mix_PlayMusic(Mix_Music *music, int loops);
    2.20  
    2.21 +/* Fade in music or a channel over "ms" milliseconds, same semantics as the "Play" functions */
    2.22 +extern int Mix_FadeInMusic(Mix_Music *music, int loops, int ms);
    2.23 +extern int Mix_FadeInChannel(int channel, Mix_Chunk *chunk, int loops, int ms);
    2.24 +
    2.25  /* Set the volume in the range of 0-128 of a specific channel or chunk.
    2.26     If the specified channel is -1, set volume for all channels.
    2.27     Returns the original volume.
    2.28 @@ -111,6 +122,17 @@
    2.29  extern int Mix_HaltChannel(int channel);
    2.30  extern int Mix_HaltMusic(void);
    2.31  
    2.32 +/* Halt a channel, fading it out progressively till it's silent 
    2.33 +   The ms parameter indicates the number of milliseconds the fading
    2.34 +   will take.
    2.35 + */
    2.36 +extern int Mix_FadeOutChannel(int which, int ms);
    2.37 +extern int Mix_FadeOutMusic(int ms);
    2.38 +
    2.39 +/* Query the fading status of a channel */
    2.40 +extern Mix_Fading Mix_FadingMusic(void);
    2.41 +extern Mix_Fading Mix_FadingChannel(int which);
    2.42 +
    2.43  /* Pause/Resume a particular channel */
    2.44  extern void Mix_Pause(int channel);
    2.45  extern void Mix_Resume(int channel);
     3.1 --- a/music.c	Sat Oct 23 00:39:09 1999 +0000
     3.2 +++ b/music.c	Sat Oct 23 03:31:21 1999 +0000
     3.3 @@ -57,9 +57,11 @@
     3.4  static char *music_cmd = NULL;
     3.5  static int samplesize;
     3.6  static Mix_Music *music_playing = 0;
     3.7 +static SDL_mutex *music_lock;
     3.8  static int music_volume;
     3.9  static int music_swap8;
    3.10  static int music_swap16;
    3.11 +
    3.12  struct _Mix_Music {
    3.13  	enum {
    3.14  		MUS_CMD,
    3.15 @@ -85,6 +87,10 @@
    3.16  		SMPEG *mp3;
    3.17  #endif
    3.18  	} data;
    3.19 +	Mix_Fading fading;
    3.20 +	int fade_volume;
    3.21 +	int fade_length;
    3.22 +	Uint32 ticks_fade;
    3.23  	int error;
    3.24  };
    3.25  static int timidity_ok;
    3.26 @@ -95,6 +101,26 @@
    3.27  	int i;
    3.28  
    3.29  	if ( music_playing ) {
    3.30 +		if( music_playing->fading != MIX_NO_FADING ) {
    3.31 +			Uint32 ticks = SDL_GetTicks() - music_playing->ticks_fade;
    3.32 +			if( ticks > music_playing->fade_length ) {
    3.33 +				if ( music_playing->fading == MIX_FADING_OUT ) {
    3.34 +					music_volume = music_playing->fade_volume;
    3.35 +					music_playing->fading = MIX_NO_FADING;
    3.36 +					Mix_HaltMusic();
    3.37 +					return;
    3.38 +				}
    3.39 +				music_playing->fading = MIX_NO_FADING;
    3.40 +			} else {
    3.41 +				if ( music_playing->fading == MIX_FADING_OUT ) {
    3.42 +					Mix_VolumeMusic((music_playing->fade_volume * (music_playing->fade_length-ticks)) 
    3.43 +									/ music_playing->fade_length);
    3.44 +				} else { /* Fading in */
    3.45 +					Mix_VolumeMusic((music_playing->fade_volume * ticks) 
    3.46 +									/ music_playing->fade_length);
    3.47 +				}
    3.48 +			}
    3.49 +		}
    3.50  		switch (music_playing->type) {
    3.51  #ifdef CMD_MUSIC
    3.52  			case MUS_CMD:
    3.53 @@ -227,6 +253,9 @@
    3.54  	used_mixer = *mixer;
    3.55  #endif
    3.56  	music_playing = 0;
    3.57 +
    3.58 +	/* Initialize the music lock */
    3.59 +	music_lock = SDL_CreateMutex();
    3.60  	if ( music_error ) {
    3.61  		return(-1);
    3.62  	}
    3.63 @@ -340,7 +369,13 @@
    3.64  	if ( music ) {
    3.65  		/* Caution: If music is playing, mixer will crash */
    3.66  		if ( music == music_playing ) {
    3.67 -			Mix_HaltMusic();
    3.68 +			if ( music->fading == MIX_FADING_OUT ) {
    3.69 +				/* Wait for the fade out to finish */
    3.70 +				while(music->fading == MIX_FADING_OUT)
    3.71 +					SDL_Delay(100);
    3.72 +			} else {
    3.73 +				Mix_HaltMusic(); /* Stop it immediately */
    3.74 +			}
    3.75  		}
    3.76  		switch (music->type) {
    3.77  #ifdef CMD_MUSIC
    3.78 @@ -384,6 +419,10 @@
    3.79  	if ( music == NULL ) {
    3.80  		return(-1);
    3.81  	}
    3.82 +	/* If the current music is fading out, wait for the fade to complete */
    3.83 +	while ( music_playing && music_playing->fading==MIX_FADING_OUT ) {
    3.84 +		SDL_Delay(100);
    3.85 +	}
    3.86  	switch (music->type) {
    3.87  #ifdef CMD_MUSIC
    3.88  		case MUS_CMD:
    3.89 @@ -425,6 +464,22 @@
    3.90  	}
    3.91  	music_active = 1;
    3.92  	music_playing = music;
    3.93 +	music_playing->fading = MIX_NO_FADING;
    3.94 +	return(0);
    3.95 +}
    3.96 +
    3.97 +/* Fade in a music over "ms" milliseconds */
    3.98 +int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
    3.99 +{
   3.100 +	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   3.101 +		music->fade_volume = music_volume;
   3.102 +		music_volume = 0;
   3.103 +		if(Mix_PlayMusic(music,loops)<0)
   3.104 +			return(-1);
   3.105 +		music_playing->fading = MIX_FADING_IN;
   3.106 +		music_playing->fade_length = ms;
   3.107 +		music_playing->ticks_fade = SDL_GetTicks();
   3.108 +	}
   3.109  	return(0);
   3.110  }
   3.111  
   3.112 @@ -434,42 +489,43 @@
   3.113  	int prev_volume;
   3.114  
   3.115  	prev_volume = music_volume;
   3.116 -	if ( volume >= 0 ) {
   3.117 -		if ( volume > SDL_MIX_MAXVOLUME ) {
   3.118 -			volume = SDL_MIX_MAXVOLUME;
   3.119 -		}
   3.120 -		music_volume = volume;
   3.121 -		if ( music_playing ) {
   3.122 -			switch (music_playing->type) {
   3.123 +	if ( volume < 0 ) {
   3.124 +		volume = 0;
   3.125 +	}
   3.126 +	if ( volume > SDL_MIX_MAXVOLUME ) {
   3.127 +		volume = SDL_MIX_MAXVOLUME;
   3.128 +	}
   3.129 +	music_volume = volume;
   3.130 +	if ( music_playing ) {
   3.131 +		switch (music_playing->type) {
   3.132  #ifdef CMD_MUSIC
   3.133 -				case MUS_CMD:
   3.134 -					MusicCMD_SetVolume(music_volume);
   3.135 -					break;
   3.136 +		case MUS_CMD:
   3.137 +			MusicCMD_SetVolume(music_volume);
   3.138 +			break;
   3.139  #endif
   3.140  #ifdef WAV_MUSIC
   3.141 -				case MUS_WAV:
   3.142 -					WAVStream_SetVolume(music_volume);
   3.143 -					break;
   3.144 +		case MUS_WAV:
   3.145 +			WAVStream_SetVolume(music_volume);
   3.146 +			break;
   3.147  #endif
   3.148  #ifdef MOD_MUSIC
   3.149 -				case MUS_MOD:
   3.150 -					Player_SetVolume(music_volume);
   3.151 -					break;
   3.152 +		case MUS_MOD:
   3.153 +			Player_SetVolume(music_volume);
   3.154 +			break;
   3.155  #endif
   3.156  #ifdef MID_MUSIC
   3.157 -				case MUS_MID:
   3.158 -					Timidity_SetVolume(music_volume);
   3.159 -					break;
   3.160 +		case MUS_MID:
   3.161 +			Timidity_SetVolume(music_volume);
   3.162 +			break;
   3.163  #endif
   3.164  #ifdef MP3_MUSIC
   3.165 -			    case MUS_MP3:
   3.166 -					SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   3.167 -					break;
   3.168 +		case MUS_MP3:
   3.169 +			SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   3.170 +			break;
   3.171  #endif
   3.172 -				default:
   3.173 -					/* Unknown music type?? */
   3.174 -					break;
   3.175 -			}
   3.176 +		default:
   3.177 +			/* Unknown music type?? */
   3.178 +			break;
   3.179  		}
   3.180  	}
   3.181  	return(prev_volume);
   3.182 @@ -478,6 +534,10 @@
   3.183  /* Halt playing of music */
   3.184  int Mix_HaltMusic(void)
   3.185  {
   3.186 +	/* This function can be called both from the main program thread
   3.187 +	   and from the SDL audio thread (when fading), so we need to ensure 
   3.188 +	   that only one thread is running it at once */
   3.189 +	SDL_mutexP(music_lock);
   3.190  	if ( music_playing ) {
   3.191  		switch (music_playing->type) {
   3.192  #ifdef CMD_MUSIC
   3.193 @@ -507,13 +567,40 @@
   3.194  #endif
   3.195  			default:
   3.196  				/* Unknown music type?? */
   3.197 +				SDL_mutexV(music_lock);
   3.198  				return(-1);
   3.199  		}
   3.200 +		if(music_playing->fading != MIX_NO_FADING) /* Restore volume */
   3.201 +			music_volume = music_playing->fade_volume;
   3.202 +		music_playing->fading = MIX_NO_FADING;
   3.203  		music_playing = 0;
   3.204  	}
   3.205 +	SDL_mutexV(music_lock);
   3.206  	return(0);
   3.207  }
   3.208  
   3.209 +/* Progressively stop the music */
   3.210 +int Mix_FadeOutMusic(int ms)
   3.211 +{
   3.212 +	if ( music_playing && music_playing->fading==MIX_NO_FADING ) {
   3.213 +		if ( music_volume>0 ) {
   3.214 +			music_playing->fading = MIX_FADING_OUT;
   3.215 +			music_playing->fade_volume = music_volume;
   3.216 +			music_playing->fade_length = ms;
   3.217 +			music_playing->ticks_fade = SDL_GetTicks();
   3.218 +			return(1);
   3.219 +		}
   3.220 +	}
   3.221 +	return(0);
   3.222 +}
   3.223 +
   3.224 +Mix_Fading Mix_FadingMusic(void)
   3.225 +{
   3.226 +	if( music_playing )
   3.227 +		return music_playing->fading;
   3.228 +	return MIX_NO_FADING;
   3.229 +}
   3.230 +
   3.231  /* Pause/Resume the music stream */
   3.232  void Mix_PauseMusic(void)
   3.233  {
   3.234 @@ -533,6 +620,7 @@
   3.235  	}
   3.236  	music_active = 0;
   3.237  }
   3.238 +
   3.239  void Mix_ResumeMusic(void)
   3.240  {
   3.241  	if ( music_playing ) {
     4.1 --- a/playmus.c	Sat Oct 23 00:39:09 1999 +0000
     4.2 +++ b/playmus.c	Sat Oct 23 03:31:21 1999 +0000
     4.3 @@ -39,6 +39,10 @@
     4.4  
     4.5  void CleanUp(void)
     4.6  {
     4.7 +	if( Mix_PlayingMusic() ) {
     4.8 +		Mix_FadeOutMusic(1500);
     4.9 +		SDL_Delay(1500);
    4.10 +	}
    4.11  	if ( audio_open ) {
    4.12  		Mix_CloseAudio();
    4.13  		audio_open = 0;
    4.14 @@ -121,7 +125,7 @@
    4.15  	}
    4.16  
    4.17  	/* Play and then exit */
    4.18 -	Mix_PlayMusic(music,0);
    4.19 +	Mix_FadeInMusic(music,0,2000);
    4.20  	while ( Mix_PlayingMusic() ) {
    4.21  		SDL_Delay(100);
    4.22  	}