music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 19 Aug 2001 21:52:48 +0000
changeset 98 f00eb57224a5
parent 83 c95d43cc6d38
child 100 110d1c8470fa
permissions -rw-r--r--
Florian Schulze - Sun Aug 19 14:55:37 PDT 2001
* Added native MIDI music support on Windows
     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 	samplesize	 = mixer->size/mixer->samples;
   312 	md_mixfreq	 = mixer->freq;
   313 	md_device	  = 0;
   314 	md_volume	  = 96;
   315 	md_musicvolume = 128;
   316 	md_sndfxvolume = 128;
   317 	md_pansep	  = 128;
   318 	md_reverb	  = 0;
   319 	MikMod_RegisterAllLoaders();
   320 	MikMod_RegisterAllDrivers();
   321 	if ( MikMod_Init() ) {
   322 		Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   323 		++music_error;
   324 	}
   325 #endif
   326 #ifdef MID_MUSIC
   327 	samplesize = mixer->size/mixer->samples;
   328 #ifdef USE_NATIVE_MIDI
   329 	if ( native_midi_init() ) {
   330 		native_midi_ok = 1;
   331 	} else {
   332 		native_midi_ok = 0;
   333 	}
   334 	timidity_ok = !native_midi_ok;
   335 #else
   336 	timidity_ok = 1;
   337 #endif
   338 	if ( timidity_ok &&
   339 	     (Timidity_Init(mixer->freq, mixer->format,
   340 	                    mixer->channels, mixer->samples) != 0) ) {
   341 		timidity_ok = 0;
   342 	}
   343 #endif
   344 #ifdef OGG_MUSIC
   345 	if ( OGG_init(mixer) < 0 ) {
   346 		++music_error;
   347 	}
   348 #endif
   349 #ifdef MP3_MUSIC
   350 	/* Keep a copy of the mixer */
   351 	used_mixer = *mixer;
   352 #endif
   353 	music_playing = NULL;
   354 	music_stopped = 0;
   355 	if ( music_error ) {
   356 		return(-1);
   357 	}
   358 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   359 
   360 	/* Calculate the number of ms for each callback */
   361 	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   362 
   363 	return(0);
   364 }
   365 
   366 /* Load a music file */
   367 Mix_Music *Mix_LoadMUS(const char *file)
   368 {
   369 	FILE *fp;
   370 	Uint8 magic[5];
   371 	Mix_Music *music;
   372 
   373 	/* Figure out what kind of file this is */
   374 	fp = fopen(file, "rb");
   375 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   376 		if ( fp != NULL ) {
   377 			fclose(fp);
   378 		}
   379 		Mix_SetError("Couldn't read from '%s'", file);
   380 		return(NULL);
   381 	}
   382 	magic[4] = '\0';
   383 	fclose(fp);
   384 
   385 	/* Allocate memory for the music structure */
   386 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   387 	if ( music == NULL ) {
   388 		Mix_SetError("Out of memory");
   389 		return(NULL);
   390 	}
   391 	music->error = 0;
   392 
   393 #ifdef CMD_MUSIC
   394 	if ( music_cmd ) {
   395 		music->type = MUS_CMD;
   396 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   397 		if ( music->data.cmd == NULL ) {
   398 			music->error = 1;
   399 		}
   400 	} else
   401 #endif
   402 #ifdef WAV_MUSIC
   403 	/* WAVE files have the magic four bytes "RIFF"
   404 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   405 	 */
   406 	if ( (strcmp((char *)magic, "RIFF") == 0) ||
   407 	     (strcmp((char *)magic, "FORM") == 0) ) {
   408 		music->type = MUS_WAV;
   409 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   410 		if ( music->data.wave == NULL ) {
   411 			music->error = 1;
   412 		}
   413 	} else
   414 #endif
   415 #ifdef MID_MUSIC
   416 	/* MIDI files have the magic four bytes "MThd" */
   417 	if ( strcmp(magic, "MThd") == 0 ) {
   418 		music->type = MUS_MID;
   419 #ifdef USE_NATIVE_MIDI
   420   		if ( native_midi_ok ) {
   421   			music->data.nativemidi = native_midi_loadsong((char *)file);
   422 	  		if ( music->data.nativemidi == NULL ) {
   423 		  		Mix_SetError("%s", native_midi_error());
   424 			  	music->error = 1;
   425 			}
   426       		} else
   427 #endif
   428 		if ( timidity_ok ) {
   429 			music->data.midi = Timidity_LoadSong((char *)file);
   430 			if ( music->data.midi == NULL ) {
   431 				Mix_SetError("%s", Timidity_Error());
   432 				music->error = 1;
   433 			}
   434 		} else {
   435 			Mix_SetError("%s", Timidity_Error());
   436 			music->error = 1;
   437 		}
   438 	} else
   439 #endif
   440 #ifdef OGG_MUSIC
   441 	/* Ogg Vorbis files have the magic four bytes "OggS" */
   442 	if ( strcmp(magic, "OggS") == 0 ) {
   443 		music->type = MUS_OGG;
   444 		music->data.ogg = OGG_new(file);
   445 		if ( music->data.ogg == NULL ) {
   446 			music->error = 1;
   447 		}
   448 	} else
   449 #endif
   450 #ifdef MP3_MUSIC
   451 	if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   452 		SMPEG_Info info;
   453 		music->type = MUS_MP3;
   454 		music->data.mp3 = SMPEG_new(file, &info, 0);
   455 		if(!info.has_audio){
   456 			Mix_SetError("MPEG file does not have any audio stream.");
   457 			music->error = 1;
   458 		}else{
   459 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   460 		}
   461 	} else
   462 #endif
   463 #ifdef MOD_MUSIC
   464 	if ( 1 ) {
   465 		music->type = MUS_MOD;
   466 		music->data.module = MikMod_LoadSong((char *)file, 64);
   467 		if ( music->data.module == NULL ) {
   468 			Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   469 			music->error = 1;
   470 		}
   471 	} else
   472 #endif
   473 	{
   474 		Mix_SetError("Unrecognized music format");
   475 		music->error = 1;
   476 	}
   477 	if ( music->error ) {
   478 		free(music);
   479 		music = NULL;
   480 	}
   481 	return(music);
   482 }
   483 
   484 /* Free a music chunk previously loaded */
   485 void Mix_FreeMusic(Mix_Music *music)
   486 {
   487 	if ( music ) {
   488 		/* Caution: If music is playing, mixer will crash */
   489 		if ( music == music_playing && !music_stopped ) {
   490 			if ( music->fading == MIX_FADING_OUT ) {
   491 				/* Wait for the fade out to finish */
   492 				while ( music_playing && !music_stopped && (music_playing->fading == MIX_FADING_OUT) )
   493 					SDL_Delay(100);
   494 			} else {
   495 				Mix_HaltMusic(); /* Stop it immediately */
   496 			}
   497 		}
   498 		switch (music->type) {
   499 #ifdef CMD_MUSIC
   500 			case MUS_CMD:
   501 				MusicCMD_FreeSong(music->data.cmd);
   502 				break;
   503 #endif
   504 #ifdef WAV_MUSIC
   505 			case MUS_WAV:
   506 				WAVStream_FreeSong(music->data.wave);
   507 				break;
   508 #endif
   509 #ifdef MOD_MUSIC
   510 			case MUS_MOD:
   511 				MikMod_FreeSong(music->data.module);
   512 				break;
   513 #endif
   514 #ifdef MID_MUSIC
   515 			case MUS_MID:
   516 #ifdef USE_NATIVE_MIDI
   517   				if ( native_midi_ok ) {
   518 					native_midi_freesong(music->data.nativemidi);
   519 				} else
   520 #endif
   521 				if ( timidity_ok ) {
   522 					Timidity_FreeSong(music->data.midi);
   523 				}
   524 				break;
   525 #endif
   526 #ifdef OGG_MUSIC
   527 			case MUS_OGG:
   528 				OGG_delete(music->data.ogg);
   529 				break;
   530 #endif
   531 #ifdef MP3_MUSIC
   532 			case MUS_MP3:
   533 				SMPEG_delete(music->data.mp3);
   534 				break;
   535 #endif
   536 			default:
   537 				/* Unknown music type?? */
   538 				break;
   539 		}
   540 		free(music);
   541 	}
   542 }
   543 
   544 static int lowlevel_play(Mix_Music *music)
   545 {
   546 	if(!music)
   547 		return(-1);
   548 
   549 	switch (music->type) {
   550 #ifdef CMD_MUSIC
   551 		case MUS_CMD:
   552 			MusicCMD_SetVolume(music_volume);
   553 			MusicCMD_Start(music->data.cmd);
   554 			break;
   555 #endif
   556 #ifdef WAV_MUSIC
   557 		case MUS_WAV:
   558 			WAVStream_SetVolume(music_volume);
   559 			WAVStream_Start(music->data.wave);
   560 			break;
   561 #endif
   562 #ifdef MOD_MUSIC
   563 		case MUS_MOD:
   564 			Player_SetVolume((SWORD)music_volume);
   565 			Player_Start(music->data.module);
   566 			Player_SetPosition(0);
   567 			break;
   568 #endif
   569 #ifdef MID_MUSIC
   570 		case MUS_MID:
   571 #ifdef USE_NATIVE_MIDI
   572   			if ( native_midi_ok ) {
   573 				native_midi_setvolume(music_volume);
   574 				native_midi_start(music->data.nativemidi);
   575 			} else
   576 #endif
   577 			if ( timidity_ok ) {
   578 				Timidity_SetVolume(music_volume);
   579 				Timidity_Start(music->data.midi);
   580 			}
   581 			break;
   582 #endif
   583 #ifdef OGG_MUSIC
   584 		case MUS_OGG:
   585 			OGG_setvolume(music->data.ogg, music_volume);
   586 			OGG_play(music->data.ogg);
   587 			break;
   588 #endif
   589 #ifdef MP3_MUSIC
   590 		case MUS_MP3:
   591 			SMPEG_enableaudio(music->data.mp3,1);
   592 			SMPEG_enablevideo(music->data.mp3,0);
   593 			SMPEG_setvolume(music->data.mp3,(int)(((float)music_volume/(float)MIX_MAX_VOLUME)*100.0));
   594 			SMPEG_play(music->data.mp3);
   595 			break;
   596 #endif
   597 		default:
   598 			/* Unknown music type?? */
   599 			return(-1);
   600 	}
   601 	return(0);
   602 }
   603 
   604 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   605 */
   606 int Mix_PlayMusic(Mix_Music *music, int loops)
   607 {
   608 	/* Don't play null pointers :-) */
   609 	if ( music == NULL ) {
   610 		return(-1);
   611 	}
   612 	/* If the current music is fading out, wait for the fade to complete */
   613 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   614 		SDL_Delay(100);
   615 	}
   616 
   617 	if ( lowlevel_play(music) < 0 ) {
   618 		return(-1);
   619 	}
   620 	music_active = 1;
   621 	music_stopped = 0;
   622 	music_loops = loops;
   623 	music_playing = music;
   624 	music_playing->fading = MIX_NO_FADING;
   625 	return(0);
   626 }
   627 
   628 /* Fade in a music over "ms" milliseconds */
   629 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   630 {
   631 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   632 		music->fade_volume = music_volume;
   633 		music_volume = 0;
   634 		if ( Mix_PlayMusic(music, loops) < 0 ) {
   635 			return(-1);
   636 		}
   637 		music_playing->fade_step = 0;
   638 		music_playing->fade_steps = ms/ms_per_step;
   639 		music_playing->fading = MIX_FADING_IN;
   640 	}
   641 	return(0);
   642 }
   643 
   644 /* Set the music volume */
   645 int Mix_VolumeMusic(int volume)
   646 {
   647 	int prev_volume;
   648 
   649 	prev_volume = music_volume;
   650 	if ( volume < 0 ) {
   651 		volume = 0;
   652 	}
   653 	if ( volume > SDL_MIX_MAXVOLUME ) {
   654 		volume = SDL_MIX_MAXVOLUME;
   655 	}
   656 	music_volume = volume;
   657 	if ( music_playing && !music_stopped ) {
   658 		switch (music_playing->type) {
   659 #ifdef CMD_MUSIC
   660 		case MUS_CMD:
   661 			MusicCMD_SetVolume(music_volume);
   662 			break;
   663 #endif
   664 #ifdef WAV_MUSIC
   665 		case MUS_WAV:
   666 			WAVStream_SetVolume(music_volume);
   667 			break;
   668 #endif
   669 #ifdef MOD_MUSIC
   670 		case MUS_MOD:
   671 			Player_SetVolume((SWORD)music_volume);
   672 			break;
   673 #endif
   674 #ifdef MID_MUSIC
   675 		case MUS_MID:
   676 #ifdef USE_NATIVE_MIDI
   677 			if ( native_midi_ok ) {
   678 				native_midi_setvolume(music_volume);
   679 			} else
   680 #endif
   681 			if ( timidity_ok ) {
   682 				Timidity_SetVolume(music_volume);
   683 			}
   684 			break;
   685 #endif
   686 #ifdef OGG_MUSIC
   687 		case MUS_OGG:
   688 			OGG_setvolume(music_playing->data.ogg, music_volume);
   689 			break;
   690 #endif
   691 #ifdef MP3_MUSIC
   692 		case MUS_MP3:
   693 			SMPEG_setvolume(music_playing->data.mp3,(int)(((float)music_volume/(float)MIX_MAX_VOLUME)*100.0));
   694 			break;
   695 #endif
   696 		default:
   697 			/* Unknown music type?? */
   698 			break;
   699 		}
   700 	}
   701 	return(prev_volume);
   702 }
   703 
   704 static void lowlevel_halt(void)
   705 {
   706 	switch (music_playing->type) {
   707 #ifdef CMD_MUSIC
   708 	case MUS_CMD:
   709 		MusicCMD_Stop(music_playing->data.cmd);
   710 		break;
   711 #endif
   712 #ifdef WAV_MUSIC
   713 	case MUS_WAV:
   714 		WAVStream_Stop();
   715 		break;
   716 #endif
   717 #ifdef MOD_MUSIC
   718 	case MUS_MOD:
   719 		Player_Stop();
   720 		break;
   721 #endif
   722 #ifdef MID_MUSIC
   723 	case MUS_MID:
   724 #ifdef USE_NATIVE_MIDI
   725 		if ( native_midi_ok ) {
   726 			native_midi_stop();
   727 		} else
   728 #endif
   729 		if ( timidity_ok ) {
   730 			Timidity_Stop();
   731 		}
   732 		break;
   733 #endif
   734 #ifdef OGG_MUSIC
   735 	case MUS_OGG:
   736 		OGG_stop(music_playing->data.ogg);
   737 		break;
   738 #endif
   739 #ifdef MP3_MUSIC
   740 	case MUS_MP3:
   741 		SMPEG_stop(music_playing->data.mp3);
   742 		break;
   743 #endif
   744 	default:
   745 		/* Unknown music type?? */
   746 		return;
   747 	}
   748 	if ( music_playing->fading != MIX_NO_FADING ) /* Restore volume */
   749 		music_volume = music_playing->fade_volume;
   750 	music_playing->fading = MIX_NO_FADING;
   751 	music_playing = NULL;
   752 	music_active = 0;
   753 	music_loops = 0;
   754 	music_stopped = 0;
   755 }
   756 
   757 /* Halt playing of music */
   758 int Mix_HaltMusic(void)
   759 {
   760 	if ( music_playing && !music_stopped ) {
   761 		/* Mark the music to be stopped from the sound thread */
   762 		music_stopped = 1;
   763 		/* Wait for it to be actually stopped */
   764 		while ( music_playing && music_active )
   765 			SDL_Delay(10);
   766 	}
   767 	return(0);
   768 }
   769 
   770 /* Progressively stop the music */
   771 int Mix_FadeOutMusic(int ms)
   772 {
   773 	if ( music_playing && !music_stopped &&
   774 	     (music_playing->fading == MIX_NO_FADING) ) {
   775 		if ( music_volume > 0 ) {
   776 			music_playing->fading = MIX_FADING_OUT;
   777 			music_playing->fade_volume = music_volume;
   778 			music_playing->fade_step = 0;
   779 			music_playing->fade_steps = ms/ms_per_step;
   780 			return(1);
   781 		}
   782 	}
   783 	return(0);
   784 }
   785 
   786 Mix_Fading Mix_FadingMusic(void)
   787 {
   788 	if( music_playing && !music_stopped )
   789 		return music_playing->fading;
   790 	return MIX_NO_FADING;
   791 }
   792 
   793 /* Pause/Resume the music stream */
   794 void Mix_PauseMusic(void)
   795 {
   796 	if ( music_playing && !music_stopped ) {
   797 		music_active = 0;
   798 	}
   799 }
   800 
   801 void Mix_ResumeMusic(void)
   802 {
   803 	if ( music_playing && !music_stopped ) {
   804 		music_active = 1;
   805 	}
   806 }
   807 
   808 void Mix_RewindMusic(void)
   809 {
   810 	if ( music_playing && !music_stopped ) {
   811 		switch ( music_playing->type ) {
   812 #ifdef MOD_MUSIC
   813 		case MUS_MOD:
   814 			Player_Start(music_playing->data.module);
   815 			Player_SetPosition(0);
   816 			break;
   817 #endif
   818 #ifdef MP3_MUSIC
   819 		case MUS_MP3:
   820 			SMPEG_rewind(music_playing->data.mp3);
   821 			break;
   822 #endif
   823 #ifdef MID_MUSIC
   824 		case MUS_MID:
   825 #ifdef USE_NATIVE_MIDI
   826 			if ( native_midi_ok ) {
   827 				native_midi_stop();
   828 			}
   829 #endif
   830 			break;
   831 #endif
   832 		default:
   833 			/* TODO: Implement this for other music backends */
   834 			break;
   835 		}
   836 	}
   837 }
   838 
   839 int Mix_PausedMusic(void)
   840 {
   841 	return (music_active == 0);
   842 }
   843 
   844 /* Check the status of the music */
   845 int Mix_PlayingMusic(void)
   846 {
   847 	if ( music_playing && ! music_stopped ) {
   848 		switch (music_playing->type) {
   849 #ifdef CMD_MUSIC
   850 			case MUS_CMD:
   851 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   852 					return(0);
   853 				}
   854 				break;
   855 #endif
   856 #ifdef WAV_MUSIC
   857 			case MUS_WAV:
   858 				if ( ! WAVStream_Active() ) {
   859 					return(0);
   860 				}
   861 				break;
   862 #endif
   863 #ifdef MOD_MUSIC
   864 			case MUS_MOD:
   865 				if ( ! Player_Active() ) {
   866 					return(0);
   867 				}
   868 				break;
   869 #endif
   870 #ifdef MID_MUSIC
   871 			case MUS_MID:
   872 #ifdef USE_NATIVE_MIDI
   873 				if ( native_midi_ok ) {
   874 					if ( ! native_midi_active() )
   875 						return(0);
   876 				} else
   877 #endif
   878 				if ( timidity_ok ) {
   879 					if ( ! Timidity_Active() )
   880 						return(0);
   881 				}
   882 				break;
   883 #endif
   884 #ifdef OGG_MUSIC
   885 			case MUS_OGG:
   886 				if ( ! OGG_playing(music_playing->data.ogg) ) {
   887 					return(0);
   888 				}
   889 				break;
   890 #endif
   891 #ifdef MP3_MUSIC
   892 			case MUS_MP3:
   893 				if ( SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
   894 					return(0);
   895 				break;
   896 #endif
   897 			default:
   898 				break;
   899 		}
   900 		return(1);
   901 	}
   902 	return(0);
   903 }
   904 
   905 /* Set the external music playback command */
   906 int Mix_SetMusicCMD(const char *command)
   907 {
   908 	Mix_HaltMusic();
   909 	if ( music_cmd ) {
   910 		free(music_cmd);
   911 		music_cmd = NULL;
   912 	}
   913 	if ( command ) {
   914 		music_cmd = (char *)malloc(strlen(command)+1);
   915 		if ( music_cmd == NULL ) {
   916 			return(-1);
   917 		}
   918 		strcpy(music_cmd, command);
   919 	}
   920 	return(0);
   921 }
   922 
   923 /* Uninitialize the music players */
   924 void close_music(void)
   925 {
   926 	Mix_HaltMusic();
   927 #ifdef CMD_MUSIC
   928 	Mix_SetMusicCMD(NULL);
   929 #endif
   930 #ifdef MOD_MUSIC
   931 	MikMod_Exit();
   932     MikMod_UnregisterAllLoaders();
   933     MikMod_UnregisterAllDrivers();
   934 #endif
   935 }
   936