music.c
author Sam Lantinga <slouken@lokigames.com>
Sat, 04 Mar 2000 04:39:12 +0000
changeset 57 68b1508afa73
parent 52 45d39b2e8dba
child 58 7b2c2ed3399e
permissions -rw-r--r--
Compile fix for MacOS
     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 	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 = NULL;
   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 = (int) (((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 	Uint8 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((char *)magic, "RIFF") == 0) ||
   368 	     (strcmp((char *)magic, "FORM") == 0) ) {
   369 		music->type = MUS_WAV;
   370 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   371 		if ( music->data.wave == NULL ) {
   372 			music->error = 1;
   373 		}
   374 	} else
   375 #endif
   376 #ifdef MID_MUSIC
   377 	/* MIDI files have the magic four bytes "MThd" */
   378 	if ( strcmp(magic, "MThd") == 0 ) {
   379 		music->type = MUS_MID;
   380 		if ( timidity_ok ) {
   381 			music->data.midi = Timidity_LoadSong((char *)file);
   382 			if ( music->data.midi == NULL ) {
   383 				Mix_SetError("%s", Timidity_Error());
   384 				music->error = 1;
   385 			}
   386 		}
   387 		else {
   388 			Mix_SetError("%s", Timidity_Error());
   389 			music->error = 1;
   390 		}
   391 	} else
   392 #endif
   393 #ifdef MP3_MUSIC
   394 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   395 		SMPEG_Info info;
   396 		music->type = MUS_MP3;
   397 		music->data.mp3 = SMPEG_new(file, &info, 0);
   398 		if(!info.has_audio){
   399 			Mix_SetError("MPEG file does not have any audio stream.");
   400 			music->error = 1;
   401 		}else{
   402 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   403 		}
   404 	} else
   405 #endif
   406 #ifdef MOD_MUSIC
   407 	if ( 1 ) {
   408 		music->type = MUS_MOD;
   409 		music->data.module = MikMod_LoadSong((char *)file, 64);
   410 		if ( music->data.module == NULL ) {
   411 			Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   412 			music->error = 1;
   413 		}
   414 	} else
   415 #endif
   416 	{
   417 		Mix_SetError("Unrecognized music format");
   418 		music->error = 1;
   419 	}
   420 	if ( music->error ) {
   421 		free(music);
   422 		music = NULL;
   423 	}
   424 	return(music);
   425 }
   426 
   427 /* Free a music chunk previously loaded */
   428 void Mix_FreeMusic(Mix_Music *music)
   429 {
   430 	if ( music ) {
   431 		/* Caution: If music is playing, mixer will crash */
   432 		if ( music == music_playing && !music_stopped ) {
   433 			if ( music->fading == MIX_FADING_OUT ) {
   434 				/* Wait for the fade out to finish */
   435 				while ( music_playing && !music_stopped && (music_playing->fading == MIX_FADING_OUT) )
   436 					SDL_Delay(100);
   437 			} else {
   438 				Mix_HaltMusic(); /* Stop it immediately */
   439 			}
   440 		}
   441 		switch (music->type) {
   442 #ifdef CMD_MUSIC
   443 			case MUS_CMD:
   444 				MusicCMD_FreeSong(music->data.cmd);
   445 				break;
   446 #endif
   447 #ifdef WAV_MUSIC
   448 			case MUS_WAV:
   449 				WAVStream_FreeSong(music->data.wave);
   450 				break;
   451 #endif
   452 #ifdef MOD_MUSIC
   453 			case MUS_MOD:
   454 				MikMod_FreeSong(music->data.module);
   455 				break;
   456 #endif
   457 #ifdef MID_MUSIC
   458 			case MUS_MID:
   459 				Timidity_FreeSong(music->data.midi);
   460 				break;
   461 #endif
   462 #ifdef MP3_MUSIC
   463 			case MUS_MP3:
   464 				SMPEG_delete(music->data.mp3);
   465 				break;
   466 #endif
   467 			default:
   468 				/* Unknown music type?? */
   469 				break;
   470 		}
   471 		free(music);
   472 	}
   473 }
   474 
   475 static int lowlevel_play(Mix_Music *music)
   476 {
   477 	if(!music)
   478 		return(-1);
   479 
   480 	switch (music->type) {
   481 #ifdef CMD_MUSIC
   482 		case MUS_CMD:
   483 			MusicCMD_SetVolume(music_volume);
   484 			MusicCMD_Start(music->data.cmd);
   485 			break;
   486 #endif
   487 #ifdef WAV_MUSIC
   488 		case MUS_WAV:
   489 			WAVStream_SetVolume(music_volume);
   490 			WAVStream_Start(music->data.wave);
   491 			break;
   492 #endif
   493 #ifdef MOD_MUSIC
   494 		case MUS_MOD:
   495 			Player_SetVolume((SWORD)music_volume);
   496 			Player_Start(music->data.module);
   497 			Player_SetPosition(0);
   498 			break;
   499 #endif
   500 #ifdef MID_MUSIC
   501 		case MUS_MID:
   502 			Timidity_SetVolume(music_volume);
   503 			Timidity_Start(music->data.midi);
   504 			break;
   505 #endif
   506 #ifdef MP3_MUSIC
   507 		case MUS_MP3:
   508 			SMPEG_enableaudio(music->data.mp3,1);
   509 			SMPEG_enablevideo(music->data.mp3,0);
   510 			SMPEG_setvolume(music->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   511 			SMPEG_play(music->data.mp3);
   512 			break;
   513 #endif
   514 		default:
   515 			/* Unknown music type?? */
   516 			return(-1);
   517 	}
   518 	return(0);
   519 }
   520 
   521 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   522 */
   523 int Mix_PlayMusic(Mix_Music *music, int loops)
   524 {
   525 	/* Don't play null pointers :-) */
   526 	if ( music == NULL ) {
   527 		return(-1);
   528 	}
   529 	/* If the current music is fading out, wait for the fade to complete */
   530 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   531 		SDL_Delay(100);
   532 	}
   533 
   534 	if ( lowlevel_play(music) < 0 ) {
   535 		return(-1);
   536 	}
   537 	music_active = 1;
   538 	music_stopped = 0;
   539 	music_loops = loops;
   540 	music_playing = music;
   541 	music_playing->fading = MIX_NO_FADING;
   542 	return(0);
   543 }
   544 
   545 /* Fade in a music over "ms" milliseconds */
   546 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   547 {
   548 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   549 		music->fade_volume = music_volume;
   550 		music_volume = 0;
   551 		if ( Mix_PlayMusic(music, loops) < 0 ) {
   552 			return(-1);
   553 		}
   554 		music_playing->fade_step = 0;
   555 		music_playing->fade_steps = ms/ms_per_step;
   556 		music_playing->fading = MIX_FADING_IN;
   557 	}
   558 	return(0);
   559 }
   560 
   561 /* Set the music volume */
   562 int Mix_VolumeMusic(int volume)
   563 {
   564 	int prev_volume;
   565 
   566 	prev_volume = music_volume;
   567 	if ( volume < 0 ) {
   568 		volume = 0;
   569 	}
   570 	if ( volume > SDL_MIX_MAXVOLUME ) {
   571 		volume = SDL_MIX_MAXVOLUME;
   572 	}
   573 	music_volume = volume;
   574 	if ( music_playing && !music_stopped ) {
   575 		switch (music_playing->type) {
   576 #ifdef CMD_MUSIC
   577 		case MUS_CMD:
   578 			MusicCMD_SetVolume(music_volume);
   579 			break;
   580 #endif
   581 #ifdef WAV_MUSIC
   582 		case MUS_WAV:
   583 			WAVStream_SetVolume(music_volume);
   584 			break;
   585 #endif
   586 #ifdef MOD_MUSIC
   587 		case MUS_MOD:
   588 			Player_SetVolume((SWORD)music_volume);
   589 			break;
   590 #endif
   591 #ifdef MID_MUSIC
   592 		case MUS_MID:
   593 			Timidity_SetVolume(music_volume);
   594 			break;
   595 #endif
   596 #ifdef MP3_MUSIC
   597 		case MUS_MP3:
   598 			SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0);
   599 			break;
   600 #endif
   601 		default:
   602 			/* Unknown music type?? */
   603 			break;
   604 		}
   605 	}
   606 	return(prev_volume);
   607 }
   608 
   609 static void lowlevel_halt(void)
   610 {
   611 	switch (music_playing->type) {
   612 #ifdef CMD_MUSIC
   613 	case MUS_CMD:
   614 		MusicCMD_Stop(music_playing->data.cmd);
   615 		break;
   616 #endif
   617 #ifdef WAV_MUSIC
   618 	case MUS_WAV:
   619 		WAVStream_Stop();
   620 		break;
   621 #endif
   622 #ifdef MOD_MUSIC
   623 	case MUS_MOD:
   624 		Player_Stop();
   625 		break;
   626 #endif
   627 #ifdef MID_MUSIC
   628 	case MUS_MID:
   629 		Timidity_Stop();
   630 		break;
   631 #endif
   632 #ifdef MP3_MUSIC
   633 	case MUS_MP3:
   634 		SMPEG_stop(music_playing->data.mp3);
   635 		break;
   636 #endif
   637 	default:
   638 		/* Unknown music type?? */
   639 		return;
   640 	}
   641 	if ( music_playing->fading != MIX_NO_FADING ) /* Restore volume */
   642 		music_volume = music_playing->fade_volume;
   643 	music_playing->fading = MIX_NO_FADING;
   644 	music_playing = NULL;
   645 	music_active = 0;
   646 	music_loops = 0;
   647 	music_stopped = 0;
   648 }
   649 
   650 /* Halt playing of music */
   651 int Mix_HaltMusic(void)
   652 {
   653 	if ( music_playing && !music_stopped ) {
   654 		/* Mark the music to be stopped from the sound thread */
   655 		music_stopped = 1;
   656 		/* Wait for it to be actually stopped */
   657 		while ( music_playing && music_active )
   658 			SDL_Delay(10);
   659 	}
   660 	return(0);
   661 }
   662 
   663 /* Progressively stop the music */
   664 int Mix_FadeOutMusic(int ms)
   665 {
   666 	if ( music_playing && !music_stopped &&
   667 	     (music_playing->fading == MIX_NO_FADING) ) {
   668 		if ( music_volume > 0 ) {
   669 			music_playing->fading = MIX_FADING_OUT;
   670 			music_playing->fade_volume = music_volume;
   671 			music_playing->fade_step = 0;
   672 			music_playing->fade_steps = ms/ms_per_step;
   673 			return(1);
   674 		}
   675 	}
   676 	return(0);
   677 }
   678 
   679 Mix_Fading Mix_FadingMusic(void)
   680 {
   681 	if( music_playing && !music_stopped )
   682 		return music_playing->fading;
   683 	return MIX_NO_FADING;
   684 }
   685 
   686 /* Pause/Resume the music stream */
   687 void Mix_PauseMusic(void)
   688 {
   689 	if ( music_playing && !music_stopped ) {
   690 		music_active = 0;
   691 	}
   692 }
   693 
   694 void Mix_ResumeMusic(void)
   695 {
   696 	if ( music_playing && !music_stopped ) {
   697 		music_active = 1;
   698 	}
   699 }
   700 
   701 void Mix_RewindMusic(void)
   702 {
   703 	if ( music_playing && !music_stopped ) {
   704 		switch ( music_playing->type ) {
   705 #ifdef MOD_MUSIC
   706 		case MUS_MOD:
   707 			Player_Start(music_playing->data.module);
   708 			Player_SetPosition(0);
   709 			break;
   710 #endif
   711 #ifdef MP3_MUSIC
   712 		case MUS_MP3:
   713 			SMPEG_rewind(music_playing->data.mp3);
   714 			break;
   715 #endif
   716 		default:
   717 			/* TODO: Implement this for other music backends */
   718 			break;
   719 		}
   720 	}
   721 }
   722 
   723 int Mix_PausedMusic(void)
   724 {
   725 	return (music_active == 0);
   726 }
   727 
   728 /* Check the status of the music */
   729 int Mix_PlayingMusic(void)
   730 {
   731 	if ( music_playing && ! music_stopped ) {
   732 		switch (music_playing->type) {
   733 #ifdef CMD_MUSIC
   734 			case MUS_CMD:
   735 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   736 					return(0);
   737 				}
   738 				break;
   739 #endif
   740 #ifdef WAV_MUSIC
   741 			case MUS_WAV:
   742 				if ( ! WAVStream_Active() ) {
   743 					return(0);
   744 				}
   745 				break;
   746 #endif
   747 #ifdef MOD_MUSIC
   748 			case MUS_MOD:
   749 				if ( ! Player_Active() ) {
   750 					return(0);
   751 				}
   752 				break;
   753 #endif
   754 #ifdef MID_MUSIC
   755 			case MUS_MID:
   756 				if ( ! Timidity_Active() ) {
   757 					return(0);
   758 				}
   759 				break;
   760 #endif
   761 #ifdef MP3_MUSIC
   762 			case MUS_MP3:
   763 				if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING)
   764 					return(0);
   765 				break;
   766 #endif
   767 			default:
   768 				break;
   769 		}
   770 		return(1);
   771 	}
   772 	return(0);
   773 }
   774 
   775 /* Set the external music playback command */
   776 int Mix_SetMusicCMD(const char *command)
   777 {
   778 	Mix_HaltMusic();
   779 	if ( music_cmd ) {
   780 		free(music_cmd);
   781 		music_cmd = NULL;
   782 	}
   783 	if ( command ) {
   784 		music_cmd = (char *)malloc(strlen(command)+1);
   785 		if ( music_cmd == NULL ) {
   786 			return(-1);
   787 		}
   788 		strcpy(music_cmd, command);
   789 	}
   790 	return(0);
   791 }
   792 
   793 /* Uninitialize the music players */
   794 void close_music(void)
   795 {
   796 	Mix_HaltMusic();
   797 #ifdef CMD_MUSIC
   798 	Mix_SetMusicCMD(NULL);
   799 #endif
   800 #ifdef MOD_MUSIC
   801 	MikMod_Exit();
   802 #endif
   803 }
   804