music.c
author Sam Lantinga <slouken@lokigames.com>
Fri, 14 Jan 2000 18:59:44 +0000
changeset 34 25e00090b15c
parent 29 44b09d6e1170
child 42 69145e9bda35
permissions -rw-r--r--
*** empty log message ***
     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 music_active = 1;
    67 static int music_stopped = 0;
    68 static int music_loops = 0;
    69 static char *music_cmd = NULL;
    70 static int samplesize;
    71 static Mix_Music *music_playing = 0;
    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 	int i;
   134 
   135 	if ( music_playing ) {
   136 		if ( music_stopped ) {
   137 			/* To avoid concurrency problems and the use of mutexes,
   138 			   the music is always stopped from the sound thread */
   139 			lowlevel_halt(); /* This function sets music_playing to NULL */
   140 			return;
   141 		}
   142 		/* Handle fading */
   143 		if ( music_playing->fading != MIX_NO_FADING ) {
   144 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   145 				int fade_volume = music_playing->fade_volume;
   146 				int fade_step = music_playing->fade_step;
   147 				int fade_steps = music_playing->fade_steps;
   148 
   149 				if ( music_playing->fading == MIX_FADING_OUT ) {
   150 					Mix_VolumeMusic((fade_volume * (fade_steps-fade_step))
   151 									/ fade_steps);
   152 				} else { /* Fading in */
   153 					Mix_VolumeMusic((fade_volume * fade_step) / fade_steps);
   154 				}
   155 			} else {
   156 				if ( music_playing->fading == MIX_FADING_OUT ) {
   157 					lowlevel_halt();
   158 					return;
   159 				}
   160 				music_playing->fading = MIX_NO_FADING;
   161 			}
   162 		}
   163 		/* Restart music if it has to loop */
   164 		if ( !Mix_PlayingMusic() ) {
   165 			/* Restart music if it has to loop */
   166 			if ( music_loops && --music_loops ) {
   167 				Mix_RewindMusic();
   168 				if ( lowlevel_play(music_playing) < 0 ) {
   169 					fprintf(stderr,"Warning: Music restart failed.\n");
   170 					music_stopped = 1; /* Something went wrong */
   171 					music_playing->fading = MIX_NO_FADING;
   172 				}
   173 			}
   174 			else if (music_finished_hook) {
   175 			    lowlevel_halt();
   176 			    music_finished_hook();
   177 			    return;
   178 			}
   179 		}
   180 		if ( music_volume <= 0 ) { /* Don't mix if volume is null */
   181 			return;
   182 		}
   183 		switch (music_playing->type) {
   184 #ifdef CMD_MUSIC
   185 			case MUS_CMD:
   186 				/* The playing is done externally */
   187 				break;
   188 #endif
   189 #ifdef WAV_MUSIC
   190 			case MUS_WAV:
   191 				WAVStream_PlaySome(stream, len);
   192 				break;
   193 #endif
   194 #ifdef MOD_MUSIC
   195 			case MUS_MOD:
   196 				VC_WriteBytes((SBYTE *)stream, len);
   197 				if ( music_swap8 ) {
   198 					Uint8 *dst;
   199 
   200 					dst = stream;
   201 					for ( i=len; i; --i ) {
   202 						*dst++ ^= 0x80;
   203 					}
   204 				} else
   205 				if ( music_swap16 ) {
   206 					Uint8 *dst, tmp;
   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 	if ( Timidity_Init(mixer->freq,
   304 			mixer->format, mixer->channels, mixer->samples) == 0 ) {
   305 		timidity_ok = 1;
   306 	} else {
   307 		timidity_ok = 0;
   308 	}
   309 #endif
   310 #ifdef MP3_MUSIC
   311 	/* Keep a copy of the mixer */
   312 	used_mixer = *mixer;
   313 #endif
   314 	music_playing = 0;
   315 	music_stopped = 0;
   316 	if ( music_error ) {
   317 		return(-1);
   318 	}
   319 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   320 
   321 	/* Calculate the number of ms for each callback */
   322 	ms_per_step = ((float)mixer->samples * 1000.0) / mixer->freq;
   323 
   324 	return(0);
   325 }
   326 
   327 /* Load a music file */
   328 Mix_Music *Mix_LoadMUS(const char *file)
   329 {
   330 	FILE *fp;
   331 	unsigned char magic[5];
   332 	Mix_Music *music;
   333 
   334 	/* Figure out what kind of file this is */
   335 	fp = fopen(file, "rb");
   336 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   337 		if ( fp != NULL ) {
   338 			fclose(fp);
   339 		}
   340 		Mix_SetError("Couldn't read from '%s'", file);
   341 		return(NULL);
   342 	}
   343 	magic[4] = '\0';
   344 	fclose(fp);
   345 
   346 	/* Allocate memory for the music structure */
   347 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   348 	if ( music == NULL ) {
   349 		Mix_SetError("Out of memory");
   350 		return(NULL);
   351 	}
   352 	music->error = 0;
   353 
   354 #ifdef CMD_MUSIC
   355 	if ( music_cmd ) {
   356 		music->type = MUS_CMD;
   357 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   358 		if ( music->data.cmd == NULL ) {
   359 			music->error = 1;
   360 		}
   361 	} else
   362 #endif
   363 #ifdef WAV_MUSIC
   364 	/* WAVE files have the magic four bytes "RIFF"
   365 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   366 	 */
   367 	if ( (strcmp(magic, "RIFF") == 0) || (strcmp(magic, "FORM") == 0) ) {
   368 		music->type = MUS_WAV;
   369 		music->data.wave = WAVStream_LoadSong(file, magic);
   370 		if ( music->data.wave == NULL ) {
   371 			music->error = 1;
   372 		}
   373 	} else
   374 #endif
   375 #ifdef MID_MUSIC
   376 	/* MIDI files have the magic four bytes "MThd" */
   377 	if ( strcmp(magic, "MThd") == 0 ) {
   378 		music->type = MUS_MID;
   379 		if ( timidity_ok ) {
   380 			music->data.midi = Timidity_LoadSong((char *)file);
   381 			if ( music->data.midi == NULL ) {
   382 				Mix_SetError("%s", Timidity_Error());
   383 				music->error = 1;
   384 			}
   385 		}
   386 		else {
   387 			Mix_SetError("%s", Timidity_Error());
   388 			music->error = 1;
   389 		}
   390 	} else
   391 #endif
   392 #ifdef MP3_MUSIC
   393 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   394 		SMPEG_Info info;
   395 		music->type = MUS_MP3;
   396 		music->data.mp3 = SMPEG_new(file, &info, 0);
   397 		if(!info.has_audio){
   398 			Mix_SetError("MPEG file does not have any audio stream.");
   399 			music->error = 1;
   400 		}else{
   401 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   402 		}
   403 	} else
   404 #endif
   405 #ifdef MOD_MUSIC
   406 	if ( 1 ) {
   407 		music->type = MUS_MOD;
   408 		music->data.module = MikMod_LoadSong((char *)file, 64);
   409 		if ( music->data.module == NULL ) {
   410 			Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   411 			music->error = 1;
   412 		}
   413 	} else
   414 #endif
   415 	{
   416 		Mix_SetError("Unrecognized music format");
   417 		music->error = 1;
   418 	}
   419 	if ( music->error ) {
   420 		free(music);
   421 		music = NULL;
   422 	}
   423 	return(music);
   424 }
   425 
   426 /* Free a music chunk previously loaded */
   427 void Mix_FreeMusic(Mix_Music *music)
   428 {
   429 	if ( music ) {
   430 		/* Caution: If music is playing, mixer will crash */
   431 		if ( music == music_playing && !music_stopped ) {
   432 			if ( music->fading == MIX_FADING_OUT ) {
   433 				/* Wait for the fade out to finish */
   434 				while ( music_playing && !music_stopped && (music_playing->fading == MIX_FADING_OUT) )
   435 					SDL_Delay(100);
   436 			} else {
   437 				Mix_HaltMusic(); /* Stop it immediately */
   438 			}
   439 		}
   440 		switch (music->type) {
   441 #ifdef CMD_MUSIC
   442 			case MUS_CMD:
   443 				MusicCMD_FreeSong(music->data.cmd);
   444 				break;
   445 #endif
   446 #ifdef WAV_MUSIC
   447 			case MUS_WAV:
   448 				WAVStream_FreeSong(music->data.wave);
   449 				break;
   450 #endif
   451 #ifdef MOD_MUSIC
   452 			case MUS_MOD:
   453 				MikMod_FreeSong(music->data.module);
   454 				break;
   455 #endif
   456 #ifdef MID_MUSIC
   457 			case MUS_MID:
   458 				Timidity_FreeSong(music->data.midi);
   459 				break;
   460 #endif
   461 #ifdef MP3_MUSIC
   462 			case MUS_MP3:
   463 				SMPEG_delete(music->data.mp3);
   464 				break;
   465 #endif
   466 			default:
   467 				/* Unknown music type?? */
   468 				break;
   469 		}
   470 		free(music);
   471 	}
   472 }
   473 
   474 static int lowlevel_play(Mix_Music *music)
   475 {
   476 	if(!music)
   477 		return(-1);
   478 
   479 	switch (music->type) {
   480 #ifdef CMD_MUSIC
   481 		case MUS_CMD:
   482 			MusicCMD_SetVolume(music_volume);
   483 			MusicCMD_Start(music->data.cmd);
   484 			break;
   485 #endif
   486 #ifdef WAV_MUSIC
   487 		case MUS_WAV:
   488 			WAVStream_SetVolume(music_volume);
   489 			WAVStream_Start(music->data.wave);
   490 			break;
   491 #endif
   492 #ifdef MOD_MUSIC
   493 		case MUS_MOD:
   494 			Player_SetVolume(music_volume);
   495 			Player_Start(music->data.module);
   496 			Player_SetPosition(0);
   497 			break;
   498 #endif
   499 #ifdef MID_MUSIC
   500 		case MUS_MID:
   501 			Timidity_SetVolume(music_volume);
   502 			Timidity_Start(music->data.midi);
   503 			break;
   504 #endif
   505 #ifdef MP3_MUSIC
   506 		case MUS_MP3:
   507 			SMPEG_enableaudio(music->data.mp3,1);
   508 			SMPEG_enablevideo(music->data.mp3,0);
   509 			SMPEG_setvolume(music->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   510 			SMPEG_play(music->data.mp3);
   511 			break;
   512 #endif
   513 		default:
   514 			/* Unknown music type?? */
   515 			return(-1);
   516 	}
   517 	return(0);
   518 }
   519 
   520 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   521 */
   522 int Mix_PlayMusic(Mix_Music *music, int loops)
   523 {
   524 	/* Don't play null pointers :-) */
   525 	if ( music == NULL ) {
   526 		return(-1);
   527 	}
   528 	/* If the current music is fading out, wait for the fade to complete */
   529 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   530 		SDL_Delay(100);
   531 	}
   532 
   533 	if ( lowlevel_play(music) < 0 ) {
   534 		return(-1);
   535 	}
   536 	music_active = 1;
   537 	music_stopped = 0;
   538 	music_loops = loops;
   539 	music_playing = music;
   540 	music_playing->fading = MIX_NO_FADING;
   541 	return(0);
   542 }
   543 
   544 /* Fade in a music over "ms" milliseconds */
   545 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   546 {
   547 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   548 		music->fade_volume = music_volume;
   549 		music_volume = 0;
   550 		if ( Mix_PlayMusic(music, loops) < 0 ) {
   551 			return(-1);
   552 		}
   553 		music_playing->fade_step = 0;
   554 		music_playing->fade_steps = ms/ms_per_step;
   555 		music_playing->fading = MIX_FADING_IN;
   556 	}
   557 	return(0);
   558 }
   559 
   560 /* Set the music volume */
   561 int Mix_VolumeMusic(int volume)
   562 {
   563 	int prev_volume;
   564 
   565 	prev_volume = music_volume;
   566 	if ( volume < 0 ) {
   567 		volume = 0;
   568 	}
   569 	if ( volume > SDL_MIX_MAXVOLUME ) {
   570 		volume = SDL_MIX_MAXVOLUME;
   571 	}
   572 	music_volume = volume;
   573 	if ( music_playing && !music_stopped ) {
   574 		switch (music_playing->type) {
   575 #ifdef CMD_MUSIC
   576 		case MUS_CMD:
   577 			MusicCMD_SetVolume(music_volume);
   578 			break;
   579 #endif
   580 #ifdef WAV_MUSIC
   581 		case MUS_WAV:
   582 			WAVStream_SetVolume(music_volume);
   583 			break;
   584 #endif
   585 #ifdef MOD_MUSIC
   586 		case MUS_MOD:
   587 			Player_SetVolume(music_volume);
   588 			break;
   589 #endif
   590 #ifdef MID_MUSIC
   591 		case MUS_MID:
   592 			Timidity_SetVolume(music_volume);
   593 			break;
   594 #endif
   595 #ifdef MP3_MUSIC
   596 		case MUS_MP3:
   597 			SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   598 			break;
   599 #endif
   600 		default:
   601 			/* Unknown music type?? */
   602 			break;
   603 		}
   604 	}
   605 	return(prev_volume);
   606 }
   607 
   608 static void lowlevel_halt(void)
   609 {
   610 	switch (music_playing->type) {
   611 #ifdef CMD_MUSIC
   612 	case MUS_CMD:
   613 		MusicCMD_Stop(music_playing->data.cmd);
   614 		break;
   615 #endif
   616 #ifdef WAV_MUSIC
   617 	case MUS_WAV:
   618 		WAVStream_Stop();
   619 		break;
   620 #endif
   621 #ifdef MOD_MUSIC
   622 	case MUS_MOD:
   623 		Player_Stop();
   624 		break;
   625 #endif
   626 #ifdef MID_MUSIC
   627 	case MUS_MID:
   628 		Timidity_Stop();
   629 		break;
   630 #endif
   631 #ifdef MP3_MUSIC
   632 	case MUS_MP3:
   633 		SMPEG_stop(music_playing->data.mp3);
   634 		break;
   635 #endif
   636 	default:
   637 		/* Unknown music type?? */
   638 		return;
   639 	}
   640 	if ( music_playing->fading != MIX_NO_FADING ) /* Restore volume */
   641 		music_volume = music_playing->fade_volume;
   642 	music_playing->fading = MIX_NO_FADING;
   643 	music_playing = NULL;
   644 	music_active = 0;
   645 	music_loops = 0;
   646 	music_stopped = 0;
   647 }
   648 
   649 /* Halt playing of music */
   650 int Mix_HaltMusic(void)
   651 {
   652 	if ( music_playing && !music_stopped ) {
   653 		/* Mark the music to be stopped from the sound thread */
   654 		music_stopped = 1;
   655 		/* Wait for it to be actually stopped */
   656 		while ( music_playing )
   657 			SDL_Delay(10);
   658 	}
   659 	return(0);
   660 }
   661 
   662 /* Progressively stop the music */
   663 int Mix_FadeOutMusic(int ms)
   664 {
   665 	if ( music_playing && !music_stopped &&
   666 	     (music_playing->fading == MIX_NO_FADING) ) {
   667 		if ( music_volume > 0 ) {
   668 			music_playing->fading = MIX_FADING_OUT;
   669 			music_playing->fade_volume = music_volume;
   670 			music_playing->fade_step = 0;
   671 			music_playing->fade_steps = ms/ms_per_step;
   672 			return(1);
   673 		}
   674 	}
   675 	return(0);
   676 }
   677 
   678 Mix_Fading Mix_FadingMusic(void)
   679 {
   680 	if( music_playing && !music_stopped )
   681 		return music_playing->fading;
   682 	return MIX_NO_FADING;
   683 }
   684 
   685 /* Pause/Resume the music stream */
   686 void Mix_PauseMusic(void)
   687 {
   688 	if ( music_playing && !music_stopped ) {
   689 		music_active = 0;
   690 	}
   691 }
   692 
   693 void Mix_ResumeMusic(void)
   694 {
   695 	if ( music_playing && !music_stopped ) {
   696 		music_active = 1;
   697 	}
   698 }
   699 
   700 void Mix_RewindMusic(void)
   701 {
   702 	if ( music_playing && !music_stopped ) {
   703 		switch ( music_playing->type ) {
   704 #ifdef MOD_MUSIC
   705 		case MUS_MOD:
   706 			Player_Start(music_playing->data.module);
   707 			Player_SetPosition(0);
   708 			break;
   709 #endif
   710 #ifdef MP3_MUSIC
   711 		case MUS_MP3:
   712 			SMPEG_rewind(music_playing->data.mp3);
   713 			break;
   714 #endif
   715 		default:
   716 			/* TODO: Implement this for other music backends */
   717 			break;
   718 		}
   719 	}
   720 }
   721 
   722 int Mix_PausedMusic(void)
   723 {
   724 	return (music_active == 0);
   725 }
   726 
   727 /* Check the status of the music */
   728 int Mix_PlayingMusic(void)
   729 {
   730 	if ( music_playing && ! music_stopped ) {
   731 		switch (music_playing->type) {
   732 #ifdef CMD_MUSIC
   733 			case MUS_CMD:
   734 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   735 					return(0);
   736 				}
   737 				break;
   738 #endif
   739 #ifdef WAV_MUSIC
   740 			case MUS_WAV:
   741 				if ( ! WAVStream_Active() ) {
   742 					return(0);
   743 				}
   744 				break;
   745 #endif
   746 #ifdef MOD_MUSIC
   747 			case MUS_MOD:
   748 				if ( ! Player_Active() ) {
   749 					return(0);
   750 				}
   751 				break;
   752 #endif
   753 #ifdef MID_MUSIC
   754 			case MUS_MID:
   755 				if ( ! Timidity_Active() ) {
   756 					return(0);
   757 				}
   758 				break;
   759 #endif
   760 #ifdef MP3_MUSIC
   761 			case MUS_MP3:
   762 				if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING)
   763 					return(0);
   764 				break;
   765 #endif
   766 			default:
   767 				break;
   768 		}
   769 		return(1);
   770 	}
   771 	return(0);
   772 }
   773 
   774 /* Set the external music playback command */
   775 int Mix_SetMusicCMD(const char *command)
   776 {
   777 	Mix_HaltMusic();
   778 	if ( music_cmd ) {
   779 		free(music_cmd);
   780 		music_cmd = NULL;
   781 	}
   782 	if ( command ) {
   783 		music_cmd = (char *)malloc(strlen(command)+1);
   784 		if ( music_cmd == NULL ) {
   785 			return(-1);
   786 		}
   787 		strcpy(music_cmd, command);
   788 	}
   789 	return(0);
   790 }
   791 
   792 /* Uninitialize the music players */
   793 void close_music(void)
   794 {
   795 	Mix_HaltMusic();
   796 #ifdef CMD_MUSIC
   797 	Mix_SetMusicCMD(NULL);
   798 #endif
   799 #ifdef MOD_MUSIC
   800 	MikMod_Exit();
   801 #endif
   802 }
   803