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