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