music.c
author Sam Lantinga <slouken@lokigames.com>
Mon, 03 Jul 2000 00:25:20 +0000
changeset 63 92b13db7d0a5
parent 58 7b2c2ed3399e
child 64 00b28153c609
permissions -rw-r--r--
Sam Lantinga - Sun Jul 2 14:16:44 PDT 2000
* Added support for the Ogg Vorbis music format: http://www.vorbis.org/
* Cleaned up the streaming wave code a bit
     1 /*
     2 	MIXERLIB:  An audio mixer library based on the SDL library
     3 	Copyright (C) 1997-1999  Sam Lantinga
     4 
     5 	This library is free software; you can redistribute it and/or
     6 	modify it under the terms of the GNU Library General Public
     7 	License as published by the Free Software Foundation; either
     8 	version 2 of the License, or (at your option) any later version.
     9 
    10 	This library is distributed in the hope that it will be useful,
    11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
    12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13 	Library General Public License for more details.
    14 
    15 	You should have received a copy of the GNU Library General Public
    16 	License along with this library; if not, write to the Free
    17 	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19 	Sam Lantinga
    20 	5635-34 Springhouse Dr.
    21 	Pleasanton, CA 94588 (USA)
    22 	slouken@devolution.com
    23 */
    24 
    25 #include <stdlib.h>
    26 #include <string.h>
    27 #include "SDL_endian.h"
    28 #include "SDL_audio.h"
    29 #include "SDL_timer.h"
    30 
    31 #include "SDL_mixer.h"
    32 
    33 /* The music command hack is UNIX specific */
    34 #ifndef unix
    35 #undef CMD_MUSIC
    36 #endif
    37 
    38 #ifdef CMD_MUSIC
    39 #include "music_cmd.h"
    40 #endif
    41 #ifdef WAV_MUSIC
    42 #include "wavestream.h"
    43 #endif
    44 #ifdef MOD_MUSIC
    45 #  include "mikmod.h"
    46 #  if defined(LIBMIKMOD_VERSION)                /* libmikmod 3.1.8 */
    47 #    define UNIMOD			MODULE
    48 #    define MikMod_Init()		MikMod_Init(NULL)
    49 #    define MikMod_LoadSong(a,b)	Player_Load(a,b,0)
    50 #    define MikMod_FreeSong		Player_Free
    51      extern int MikMod_errno;
    52 #  else                                        /* old MikMod 3.0.3 */
    53 #    define MikMod_strerror(x)		_mm_errmsg[x])
    54 #    define MikMod_errno		_mm_errno
    55 #  endif
    56 #endif
    57 #ifdef MID_MUSIC
    58 #include "timidity.h"
    59 #endif
    60 #ifdef OGG_MUSIC
    61 #include "music_ogg.h"
    62 #endif
    63 #ifdef MP3_MUSIC
    64 #include <smpeg/smpeg.h>
    65 
    66 static SDL_AudioSpec used_mixer;
    67 #endif
    68 
    69 int volatile music_active = 1;
    70 static int volatile music_stopped = 0;
    71 static int music_loops = 0;
    72 static char *music_cmd = NULL;
    73 static int samplesize;
    74 static Mix_Music * volatile music_playing = NULL;
    75 static int music_volume = MIX_MAX_VOLUME;
    76 static int music_swap8;
    77 static int music_swap16;
    78 
    79 struct _Mix_Music {
    80 	enum {
    81 		MUS_CMD,
    82 		MUS_WAV,
    83 		MUS_MOD,
    84 		MUS_MID,
    85 		MUS_OGG,
    86 		MUS_MP3
    87 	} type;
    88 	union {
    89 #ifdef CMD_MUSIC
    90 		MusicCMD *cmd;
    91 #endif
    92 #ifdef WAV_MUSIC
    93 		WAVStream *wave;
    94 #endif
    95 #ifdef MOD_MUSIC
    96 		UNIMOD *module;
    97 #endif
    98 #ifdef MID_MUSIC
    99 		MidiSong *midi;
   100 #endif
   101 #ifdef OGG_MUSIC
   102 		OGG_music *ogg;
   103 #endif
   104 #ifdef MP3_MUSIC
   105 		SMPEG *mp3;
   106 #endif
   107 	} data;
   108 	Mix_Fading fading;
   109 	int fade_volume;
   110 	int fade_step;
   111 	int fade_steps;
   112 	int error;
   113 };
   114 #ifdef MID_MUSIC
   115 static int timidity_ok;
   116 #endif
   117 
   118 /* Used to calculate fading steps */
   119 static int ms_per_step;
   120 
   121 /* Local low-level functions prototypes */
   122 static void lowlevel_halt(void);
   123 static int  lowlevel_play(Mix_Music *music);
   124 
   125 
   126 /* Support for hooking when the music has finished */
   127 static void (*music_finished_hook)(void) = NULL;
   128 
   129 void Mix_HookMusicFinished(void (*music_finished)(void))
   130 {
   131 	SDL_LockAudio();
   132 	music_finished_hook = music_finished;
   133 	SDL_UnlockAudio();
   134 }
   135 
   136 
   137 /* Mixing function */
   138 void music_mixer(void *udata, Uint8 *stream, int len)
   139 {
   140 	if ( music_playing ) {
   141 		if ( music_stopped ) {
   142 			/* To avoid concurrency problems and the use of mutexes,
   143 			   the music is always stopped from the sound thread */
   144 			lowlevel_halt(); /* This function sets music_playing to NULL */
   145 			return;
   146 		}
   147 		/* Handle fading */
   148 		if ( music_playing->fading != MIX_NO_FADING ) {
   149 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   150 				int fade_volume = music_playing->fade_volume;
   151 				int fade_step = music_playing->fade_step;
   152 				int fade_steps = music_playing->fade_steps;
   153 
   154 				if ( music_playing->fading == MIX_FADING_OUT ) {
   155 					Mix_VolumeMusic((fade_volume * (fade_steps-fade_step))
   156 									/ fade_steps);
   157 				} else { /* Fading in */
   158 					Mix_VolumeMusic((fade_volume * fade_step) / fade_steps);
   159 				}
   160 			} else {
   161 				if ( music_playing->fading == MIX_FADING_OUT ) {
   162 					lowlevel_halt();
   163 					return;
   164 				}
   165 				music_playing->fading = MIX_NO_FADING;
   166 			}
   167 		}
   168 		/* Restart music if it has to loop */
   169 		if ( !Mix_PlayingMusic() ) {
   170 			/* Restart music if it has to loop */
   171 			if ( music_loops && --music_loops ) {
   172 				Mix_RewindMusic();
   173 				if ( lowlevel_play(music_playing) < 0 ) {
   174 					fprintf(stderr,"Warning: Music restart failed.\n");
   175 					music_stopped = 1; /* Something went wrong */
   176 					music_playing->fading = MIX_NO_FADING;
   177 				}
   178 			}
   179 			else if (music_finished_hook) {
   180 			    lowlevel_halt();
   181 			    music_finished_hook();
   182 			    return;
   183 			}
   184 		}
   185 		if ( music_volume <= 0 ) { /* Don't mix if volume is null */
   186 			return;
   187 		}
   188 		switch (music_playing->type) {
   189 #ifdef CMD_MUSIC
   190 			case MUS_CMD:
   191 				/* The playing is done externally */
   192 				break;
   193 #endif
   194 #ifdef WAV_MUSIC
   195 			case MUS_WAV:
   196 				WAVStream_PlaySome(music_playing->data.wave, stream, len);
   197 				break;
   198 #endif
   199 #ifdef MOD_MUSIC
   200 			case MUS_MOD:
   201 				VC_WriteBytes((SBYTE *)stream, len);
   202 				if ( music_swap8 ) {
   203 					Uint8 *dst;
   204 					int i;
   205 
   206 					dst = stream;
   207 					for ( i=len; i; --i ) {
   208 						*dst++ ^= 0x80;
   209 					}
   210 				} else
   211 				if ( music_swap16 ) {
   212 					Uint8 *dst, tmp;
   213 					int i;
   214 
   215 					dst = stream;
   216 					for ( i=(len/2); i; --i ) {
   217 						tmp = dst[0];
   218 						dst[0] = dst[1];
   219 						dst[1] = tmp;
   220 						dst += 2;
   221 					}
   222 				}
   223 				break;
   224 #endif
   225 #ifdef MID_MUSIC
   226 			case MUS_MID:
   227 				Timidity_PlaySome(stream, len/samplesize);
   228 				break;
   229 #endif
   230 #ifdef OGG_MUSIC
   231 			case MUS_OGG:
   232 				OGG_playAudio(music_playing->data.ogg, stream, len);
   233 				break;
   234 #endif
   235 #ifdef MP3_MUSIC
   236 			case MUS_MP3:
   237 				SMPEG_playAudio(music_playing->data.mp3, stream, len);
   238 				break;
   239 #endif
   240 			default:
   241 				/* Unknown music type?? */
   242 				break;
   243 		}
   244 	}
   245 }
   246 
   247 /* Initialize the music players with a certain desired audio format */
   248 int open_music(SDL_AudioSpec *mixer)
   249 {
   250 	int music_error;
   251 
   252 	music_error = 0;
   253 #ifdef WAV_MUSIC
   254 	if ( WAVStream_Init(mixer) < 0 ) {
   255 		++music_error;
   256 	}
   257 #endif
   258 #ifdef MOD_MUSIC
   259 	/* Set the MikMod music format */
   260 	music_swap8 = 0;
   261 	music_swap16 = 0;
   262 	switch (mixer->format) {
   263 
   264 		case AUDIO_U8:
   265 		case AUDIO_S8: {
   266 			if ( mixer->format == AUDIO_S8 ) {
   267 				music_swap8 = 1;
   268 			}
   269 			md_mode = 0;
   270 		}
   271 		break;
   272 
   273 		case AUDIO_S16LSB:
   274 		case AUDIO_S16MSB: {
   275 			/* See if we need to correct MikMod mixing */
   276 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   277 			if ( mixer->format == AUDIO_S16MSB ) {
   278 #else
   279 			if ( mixer->format == AUDIO_S16LSB ) {
   280 #endif
   281 				music_swap16 = 1;
   282 			}
   283 			md_mode = DMODE_16BITS;
   284 		}
   285 		break;
   286 
   287 		default: {
   288 			Mix_SetError("Unknown hardware audio format");
   289 			++music_error;
   290 		}
   291 	}
   292 	if ( mixer->channels > 1 ) {
   293 		if ( mixer->channels > 2 ) {
   294 			Mix_SetError("Hardware uses more channels than mixer");
   295 			++music_error;
   296 		}
   297 		md_mode |= DMODE_STEREO;
   298 	}
   299 	samplesize	 = mixer->size/mixer->samples;
   300 	md_mixfreq	 = mixer->freq;
   301 	md_device	  = 0;
   302 	md_volume	  = 96;
   303 	md_musicvolume = 128;
   304 	md_sndfxvolume = 128;
   305 	md_pansep	  = 128;
   306 	md_reverb	  = 0;
   307 	MikMod_RegisterAllLoaders();
   308 	MikMod_RegisterAllDrivers();
   309 	if ( MikMod_Init() ) {
   310 		Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   311 		++music_error;
   312 	}
   313 #endif
   314 #ifdef MID_MUSIC
   315 	samplesize	 = mixer->size/mixer->samples;
   316 	if ( Timidity_Init(mixer->freq,
   317 			mixer->format, mixer->channels, mixer->samples) == 0 ) {
   318 		timidity_ok = 1;
   319 	} else {
   320 		timidity_ok = 0;
   321 	}
   322 #endif
   323 #ifdef OGG_MUSIC
   324 	if ( OGG_init(mixer) < 0 ) {
   325 		++music_error;
   326 	}
   327 #endif
   328 #ifdef MP3_MUSIC
   329 	/* Keep a copy of the mixer */
   330 	used_mixer = *mixer;
   331 #endif
   332 	music_playing = NULL;
   333 	music_stopped = 0;
   334 	if ( music_error ) {
   335 		return(-1);
   336 	}
   337 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   338 
   339 	/* Calculate the number of ms for each callback */
   340 	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   341 
   342 	return(0);
   343 }
   344 
   345 /* Load a music file */
   346 Mix_Music *Mix_LoadMUS(const char *file)
   347 {
   348 	FILE *fp;
   349 	Uint8 magic[5];
   350 	Mix_Music *music;
   351 
   352 	/* Figure out what kind of file this is */
   353 	fp = fopen(file, "rb");
   354 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   355 		if ( fp != NULL ) {
   356 			fclose(fp);
   357 		}
   358 		Mix_SetError("Couldn't read from '%s'", file);
   359 		return(NULL);
   360 	}
   361 	magic[4] = '\0';
   362 	fclose(fp);
   363 
   364 	/* Allocate memory for the music structure */
   365 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   366 	if ( music == NULL ) {
   367 		Mix_SetError("Out of memory");
   368 		return(NULL);
   369 	}
   370 	music->error = 0;
   371 
   372 #ifdef CMD_MUSIC
   373 	if ( music_cmd ) {
   374 		music->type = MUS_CMD;
   375 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   376 		if ( music->data.cmd == NULL ) {
   377 			music->error = 1;
   378 		}
   379 	} else
   380 #endif
   381 #ifdef WAV_MUSIC
   382 	/* WAVE files have the magic four bytes "RIFF"
   383 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   384 	 */
   385 	if ( (strcmp((char *)magic, "RIFF") == 0) ||
   386 	     (strcmp((char *)magic, "FORM") == 0) ) {
   387 		music->type = MUS_WAV;
   388 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   389 		if ( music->data.wave == NULL ) {
   390 			music->error = 1;
   391 		}
   392 	} else
   393 #endif
   394 #ifdef MID_MUSIC
   395 	/* MIDI files have the magic four bytes "MThd" */
   396 	if ( strcmp(magic, "MThd") == 0 ) {
   397 		music->type = MUS_MID;
   398 		if ( timidity_ok ) {
   399 			music->data.midi = Timidity_LoadSong((char *)file);
   400 			if ( music->data.midi == NULL ) {
   401 				Mix_SetError("%s", Timidity_Error());
   402 				music->error = 1;
   403 			}
   404 		}
   405 		else {
   406 			Mix_SetError("%s", Timidity_Error());
   407 			music->error = 1;
   408 		}
   409 	} else
   410 #endif
   411 #ifdef OGG_MUSIC
   412 	/* Ogg Vorbis files have the magic four bytes "OggS" */
   413 	if ( strcmp(magic, "OggS") == 0 ) {
   414 		music->type = MUS_OGG;
   415 		music->data.ogg = OGG_new(file);
   416 		if ( music->data.ogg == NULL ) {
   417 			music->error = 1;
   418 		}
   419 	} else
   420 #endif
   421 #ifdef MP3_MUSIC
   422 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   423 		SMPEG_Info info;
   424 		music->type = MUS_MP3;
   425 		music->data.mp3 = SMPEG_new(file, &info, 0);
   426 		if(!info.has_audio){
   427 			Mix_SetError("MPEG file does not have any audio stream.");
   428 			music->error = 1;
   429 		}else{
   430 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   431 		}
   432 	} else
   433 #endif
   434 #ifdef MOD_MUSIC
   435 	if ( 1 ) {
   436 		music->type = MUS_MOD;
   437 		music->data.module = MikMod_LoadSong((char *)file, 64);
   438 		if ( music->data.module == NULL ) {
   439 			Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   440 			music->error = 1;
   441 		}
   442 	} else
   443 #endif
   444 	{
   445 		Mix_SetError("Unrecognized music format");
   446 		music->error = 1;
   447 	}
   448 	if ( music->error ) {
   449 		free(music);
   450 		music = NULL;
   451 	}
   452 	return(music);
   453 }
   454 
   455 /* Free a music chunk previously loaded */
   456 void Mix_FreeMusic(Mix_Music *music)
   457 {
   458 	if ( music ) {
   459 		/* Caution: If music is playing, mixer will crash */
   460 		if ( music == music_playing && !music_stopped ) {
   461 			if ( music->fading == MIX_FADING_OUT ) {
   462 				/* Wait for the fade out to finish */
   463 				while ( music_playing && !music_stopped && (music_playing->fading == MIX_FADING_OUT) )
   464 					SDL_Delay(100);
   465 			} else {
   466 				Mix_HaltMusic(); /* Stop it immediately */
   467 			}
   468 		}
   469 		switch (music->type) {
   470 #ifdef CMD_MUSIC
   471 			case MUS_CMD:
   472 				MusicCMD_FreeSong(music->data.cmd);
   473 				break;
   474 #endif
   475 #ifdef WAV_MUSIC
   476 			case MUS_WAV:
   477 				WAVStream_FreeSong(music->data.wave);
   478 				break;
   479 #endif
   480 #ifdef MOD_MUSIC
   481 			case MUS_MOD:
   482 				MikMod_FreeSong(music->data.module);
   483 				break;
   484 #endif
   485 #ifdef MID_MUSIC
   486 			case MUS_MID:
   487 				Timidity_FreeSong(music->data.midi);
   488 				break;
   489 #endif
   490 #ifdef OGG_MUSIC
   491 			case MUS_OGG:
   492 				OGG_delete(music->data.ogg);
   493 				break;
   494 #endif
   495 #ifdef MP3_MUSIC
   496 			case MUS_MP3:
   497 				SMPEG_delete(music->data.mp3);
   498 				break;
   499 #endif
   500 			default:
   501 				/* Unknown music type?? */
   502 				break;
   503 		}
   504 		free(music);
   505 	}
   506 }
   507 
   508 static int lowlevel_play(Mix_Music *music)
   509 {
   510 	if(!music)
   511 		return(-1);
   512 
   513 	switch (music->type) {
   514 #ifdef CMD_MUSIC
   515 		case MUS_CMD:
   516 			MusicCMD_SetVolume(music_volume);
   517 			MusicCMD_Start(music->data.cmd);
   518 			break;
   519 #endif
   520 #ifdef WAV_MUSIC
   521 		case MUS_WAV:
   522 			WAVStream_SetVolume(music_volume);
   523 			WAVStream_Start(music->data.wave);
   524 			break;
   525 #endif
   526 #ifdef MOD_MUSIC
   527 		case MUS_MOD:
   528 			Player_SetVolume((SWORD)music_volume);
   529 			Player_Start(music->data.module);
   530 			Player_SetPosition(0);
   531 			break;
   532 #endif
   533 #ifdef MID_MUSIC
   534 		case MUS_MID:
   535 			Timidity_SetVolume(music_volume);
   536 			Timidity_Start(music->data.midi);
   537 			break;
   538 #endif
   539 #ifdef OGG_MUSIC
   540 		case MUS_OGG:
   541 			OGG_setvolume(music->data.ogg, music_volume);
   542 			OGG_play(music->data.ogg);
   543 			break;
   544 #endif
   545 #ifdef MP3_MUSIC
   546 		case MUS_MP3:
   547 			SMPEG_enableaudio(music->data.mp3,1);
   548 			SMPEG_enablevideo(music->data.mp3,0);
   549 			SMPEG_setvolume(music->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   550 			SMPEG_play(music->data.mp3);
   551 			break;
   552 #endif
   553 		default:
   554 			/* Unknown music type?? */
   555 			return(-1);
   556 	}
   557 	return(0);
   558 }
   559 
   560 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   561 */
   562 int Mix_PlayMusic(Mix_Music *music, int loops)
   563 {
   564 	/* Don't play null pointers :-) */
   565 	if ( music == NULL ) {
   566 		return(-1);
   567 	}
   568 	/* If the current music is fading out, wait for the fade to complete */
   569 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   570 		SDL_Delay(100);
   571 	}
   572 
   573 	if ( lowlevel_play(music) < 0 ) {
   574 		return(-1);
   575 	}
   576 	music_active = 1;
   577 	music_stopped = 0;
   578 	music_loops = loops;
   579 	music_playing = music;
   580 	music_playing->fading = MIX_NO_FADING;
   581 	return(0);
   582 }
   583 
   584 /* Fade in a music over "ms" milliseconds */
   585 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   586 {
   587 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   588 		music->fade_volume = music_volume;
   589 		music_volume = 0;
   590 		if ( Mix_PlayMusic(music, loops) < 0 ) {
   591 			return(-1);
   592 		}
   593 		music_playing->fade_step = 0;
   594 		music_playing->fade_steps = ms/ms_per_step;
   595 		music_playing->fading = MIX_FADING_IN;
   596 	}
   597 	return(0);
   598 }
   599 
   600 /* Set the music volume */
   601 int Mix_VolumeMusic(int volume)
   602 {
   603 	int prev_volume;
   604 
   605 	prev_volume = music_volume;
   606 	if ( volume < 0 ) {
   607 		volume = 0;
   608 	}
   609 	if ( volume > SDL_MIX_MAXVOLUME ) {
   610 		volume = SDL_MIX_MAXVOLUME;
   611 	}
   612 	music_volume = volume;
   613 	if ( music_playing && !music_stopped ) {
   614 		switch (music_playing->type) {
   615 #ifdef CMD_MUSIC
   616 		case MUS_CMD:
   617 			MusicCMD_SetVolume(music_volume);
   618 			break;
   619 #endif
   620 #ifdef WAV_MUSIC
   621 		case MUS_WAV:
   622 			WAVStream_SetVolume(music_volume);
   623 			break;
   624 #endif
   625 #ifdef MOD_MUSIC
   626 		case MUS_MOD:
   627 			Player_SetVolume((SWORD)music_volume);
   628 			break;
   629 #endif
   630 #ifdef MID_MUSIC
   631 		case MUS_MID:
   632 			Timidity_SetVolume(music_volume);
   633 			break;
   634 #endif
   635 #ifdef OGG_MUSIC
   636 		case MUS_OGG:
   637 			OGG_setvolume(music_playing->data.ogg, music_volume);
   638 			break;
   639 #endif
   640 #ifdef MP3_MUSIC
   641 		case MUS_MP3:
   642 			SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   643 			break;
   644 #endif
   645 		default:
   646 			/* Unknown music type?? */
   647 			break;
   648 		}
   649 	}
   650 	return(prev_volume);
   651 }
   652 
   653 static void lowlevel_halt(void)
   654 {
   655 	switch (music_playing->type) {
   656 #ifdef CMD_MUSIC
   657 	case MUS_CMD:
   658 		MusicCMD_Stop(music_playing->data.cmd);
   659 		break;
   660 #endif
   661 #ifdef WAV_MUSIC
   662 	case MUS_WAV:
   663 		WAVStream_Stop();
   664 		break;
   665 #endif
   666 #ifdef MOD_MUSIC
   667 	case MUS_MOD:
   668 		Player_Stop();
   669 		break;
   670 #endif
   671 #ifdef MID_MUSIC
   672 	case MUS_MID:
   673 		Timidity_Stop();
   674 		break;
   675 #endif
   676 #ifdef OGG_MUSIC
   677 	case MUS_OGG:
   678 		OGG_stop(music_playing->data.ogg);
   679 		break;
   680 #endif
   681 #ifdef MP3_MUSIC
   682 	case MUS_MP3:
   683 		SMPEG_stop(music_playing->data.mp3);
   684 		break;
   685 #endif
   686 	default:
   687 		/* Unknown music type?? */
   688 		return;
   689 	}
   690 	if ( music_playing->fading != MIX_NO_FADING ) /* Restore volume */
   691 		music_volume = music_playing->fade_volume;
   692 	music_playing->fading = MIX_NO_FADING;
   693 	music_playing = NULL;
   694 	music_active = 0;
   695 	music_loops = 0;
   696 	music_stopped = 0;
   697 }
   698 
   699 /* Halt playing of music */
   700 int Mix_HaltMusic(void)
   701 {
   702 	if ( music_playing && !music_stopped ) {
   703 		/* Mark the music to be stopped from the sound thread */
   704 		music_stopped = 1;
   705 		/* Wait for it to be actually stopped */
   706 		while ( music_playing && music_active )
   707 			SDL_Delay(10);
   708 	}
   709 	return(0);
   710 }
   711 
   712 /* Progressively stop the music */
   713 int Mix_FadeOutMusic(int ms)
   714 {
   715 	if ( music_playing && !music_stopped &&
   716 	     (music_playing->fading == MIX_NO_FADING) ) {
   717 		if ( music_volume > 0 ) {
   718 			music_playing->fading = MIX_FADING_OUT;
   719 			music_playing->fade_volume = music_volume;
   720 			music_playing->fade_step = 0;
   721 			music_playing->fade_steps = ms/ms_per_step;
   722 			return(1);
   723 		}
   724 	}
   725 	return(0);
   726 }
   727 
   728 Mix_Fading Mix_FadingMusic(void)
   729 {
   730 	if( music_playing && !music_stopped )
   731 		return music_playing->fading;
   732 	return MIX_NO_FADING;
   733 }
   734 
   735 /* Pause/Resume the music stream */
   736 void Mix_PauseMusic(void)
   737 {
   738 	if ( music_playing && !music_stopped ) {
   739 		music_active = 0;
   740 	}
   741 }
   742 
   743 void Mix_ResumeMusic(void)
   744 {
   745 	if ( music_playing && !music_stopped ) {
   746 		music_active = 1;
   747 	}
   748 }
   749 
   750 void Mix_RewindMusic(void)
   751 {
   752 	if ( music_playing && !music_stopped ) {
   753 		switch ( music_playing->type ) {
   754 #ifdef MOD_MUSIC
   755 		case MUS_MOD:
   756 			Player_Start(music_playing->data.module);
   757 			Player_SetPosition(0);
   758 			break;
   759 #endif
   760 #ifdef MP3_MUSIC
   761 		case MUS_MP3:
   762 			SMPEG_rewind(music_playing->data.mp3);
   763 			break;
   764 #endif
   765 		default:
   766 			/* TODO: Implement this for other music backends */
   767 			break;
   768 		}
   769 	}
   770 }
   771 
   772 int Mix_PausedMusic(void)
   773 {
   774 	return (music_active == 0);
   775 }
   776 
   777 /* Check the status of the music */
   778 int Mix_PlayingMusic(void)
   779 {
   780 	if ( music_playing && ! music_stopped ) {
   781 		switch (music_playing->type) {
   782 #ifdef CMD_MUSIC
   783 			case MUS_CMD:
   784 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   785 					return(0);
   786 				}
   787 				break;
   788 #endif
   789 #ifdef WAV_MUSIC
   790 			case MUS_WAV:
   791 				if ( ! WAVStream_Active(music_playing->data.wave) ) {
   792 					return(0);
   793 				}
   794 				break;
   795 #endif
   796 #ifdef MOD_MUSIC
   797 			case MUS_MOD:
   798 				if ( ! Player_Active() ) {
   799 					return(0);
   800 				}
   801 				break;
   802 #endif
   803 #ifdef MID_MUSIC
   804 			case MUS_MID:
   805 				if ( ! Timidity_Active() ) {
   806 					return(0);
   807 				}
   808 				break;
   809 #endif
   810 #ifdef OGG_MUSIC
   811 			case MUS_OGG:
   812 				if ( ! OGG_playing(music_playing->data.ogg) ) {
   813 					return(0);
   814 				}
   815 				break;
   816 #endif
   817 #ifdef MP3_MUSIC
   818 			case MUS_MP3:
   819 				if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING)
   820 					return(0);
   821 				break;
   822 #endif
   823 			default:
   824 				break;
   825 		}
   826 		return(1);
   827 	}
   828 	return(0);
   829 }
   830 
   831 /* Set the external music playback command */
   832 int Mix_SetMusicCMD(const char *command)
   833 {
   834 	Mix_HaltMusic();
   835 	if ( music_cmd ) {
   836 		free(music_cmd);
   837 		music_cmd = NULL;
   838 	}
   839 	if ( command ) {
   840 		music_cmd = (char *)malloc(strlen(command)+1);
   841 		if ( music_cmd == NULL ) {
   842 			return(-1);
   843 		}
   844 		strcpy(music_cmd, command);
   845 	}
   846 	return(0);
   847 }
   848 
   849 /* Uninitialize the music players */
   850 void close_music(void)
   851 {
   852 	Mix_HaltMusic();
   853 #ifdef CMD_MUSIC
   854 	Mix_SetMusicCMD(NULL);
   855 #endif
   856 #ifdef MOD_MUSIC
   857 	MikMod_Exit();
   858 #endif
   859 }
   860