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