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