music.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 14 Jan 2002 19:35:45 +0000
changeset 158 954c719d0359
parent 155 53f259dae79d
child 161 2a4946fc5a62
permissions -rw-r--r--
*** empty log message ***
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001  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     slouken@libsdl.org
    21 */
    22 
    23 /* $Id$ */
    24 
    25 #include <stdlib.h>
    26 #include <string.h>
    27 #include <ctype.h>
    28 #include "SDL_endian.h"
    29 #include "SDL_audio.h"
    30 #include "SDL_timer.h"
    31 
    32 #include "SDL_mixer.h"
    33 
    34 /* The music command hack is UNIX specific */
    35 #ifndef unix
    36 #undef CMD_MUSIC
    37 #endif
    38 
    39 #ifdef CMD_MUSIC
    40 #include "music_cmd.h"
    41 #endif
    42 #ifdef WAV_MUSIC
    43 #include "wavestream.h"
    44 #endif
    45 #ifdef MOD_MUSIC
    46 #  include "mikmod.h"
    47 #  if defined(LIBMIKMOD_VERSION)                /* libmikmod 3.1.8 */
    48 #    define UNIMOD			MODULE
    49 #    define MikMod_Init()		MikMod_Init(NULL)
    50 #    define MikMod_LoadSong(a,b)	Player_Load(a,b,0)
    51 #    define MikMod_FreeSong		Player_Free
    52      extern int MikMod_errno;
    53 #  else                                        /* old MikMod 3.0.3 */
    54 #    define MikMod_strerror(x)		_mm_errmsg[x])
    55 #    define MikMod_errno		_mm_errno
    56 #  endif
    57 #endif
    58 #ifdef MID_MUSIC
    59 #  ifdef USE_TIMIDITY_MIDI
    60 #    include "timidity.h"
    61 #  endif
    62 #  ifdef USE_NATIVE_MIDI
    63 #    include "native_midi.h"
    64 #  endif
    65 #  if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
    66 #    define MIDI_ELSE	else
    67 #  else
    68 #    define MIDI_ELSE
    69 #  endif
    70 #endif
    71 #ifdef OGG_MUSIC
    72 #include "music_ogg.h"
    73 #endif
    74 #ifdef MP3_MUSIC
    75 #include "smpeg.h"
    76 
    77 static SDL_AudioSpec used_mixer;
    78 #endif
    79 
    80 int volatile music_active = 1;
    81 static int volatile music_stopped = 0;
    82 static int music_loops = 0;
    83 static char *music_cmd = NULL;
    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 static int samplesize;
   133 #endif
   134 #ifdef USE_NATIVE_MIDI
   135 static int native_midi_ok;
   136 #endif
   137 #endif
   138 
   139 /* Used to calculate fading steps */
   140 static int ms_per_step;
   141 
   142 /* Local low-level functions prototypes */
   143 static void lowlevel_halt(void);
   144 static int  lowlevel_play(Mix_Music *music);
   145 
   146 
   147 /* Support for hooking when the music has finished */
   148 static void (*music_finished_hook)(void) = NULL;
   149 
   150 void Mix_HookMusicFinished(void (*music_finished)(void))
   151 {
   152 	SDL_LockAudio();
   153 	music_finished_hook = music_finished;
   154 	SDL_UnlockAudio();
   155 }
   156 
   157 
   158 /* Mixing function */
   159 void music_mixer(void *udata, Uint8 *stream, int len)
   160 {
   161 	if ( music_playing ) {
   162 		if ( music_stopped ) {
   163 			/* To avoid concurrency problems and the use of mutexes,
   164 			   the music is always stopped from the sound thread */
   165 			lowlevel_halt(); /* This function sets music_playing to NULL */
   166 			return;
   167 		}
   168 		/* Handle fading */
   169 		if ( music_playing->fading != MIX_NO_FADING ) {
   170 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   171 				int fade_volume = music_playing->fade_volume;
   172 				int fade_step = music_playing->fade_step;
   173 				int fade_steps = music_playing->fade_steps;
   174 
   175 				if ( music_playing->fading == MIX_FADING_OUT ) {
   176 					Mix_VolumeMusic((fade_volume * (fade_steps-fade_step))
   177 									/ fade_steps);
   178 				} else { /* Fading in */
   179 					Mix_VolumeMusic((fade_volume * fade_step) / fade_steps);
   180 				}
   181 			} else {
   182 				if ( music_playing->fading == MIX_FADING_OUT ) {
   183 					lowlevel_halt();
   184 					return;
   185 				}
   186 				music_playing->fading = MIX_NO_FADING;
   187 			}
   188 		}
   189 		/* Restart music if it has to loop */
   190 		if ( !Mix_PlayingMusic() ) {
   191 			/* Restart music if it has to loop */
   192 			if ( music_loops && --music_loops ) {
   193 				Mix_RewindMusic();
   194 				if ( lowlevel_play(music_playing) < 0 ) {
   195 					fprintf(stderr,"Warning: Music restart failed.\n");
   196 					music_stopped = 1; /* Something went wrong */
   197 					music_playing->fading = MIX_NO_FADING;
   198 				}
   199 			}
   200 			else if (music_finished_hook) {
   201 			    lowlevel_halt();
   202 			    music_finished_hook();
   203 			    return;
   204 			}
   205 		}
   206 		if ( music_volume <= 0 ) { /* Don't mix if volume is null */
   207 			return;
   208 		}
   209 		switch (music_playing->type) {
   210 #ifdef CMD_MUSIC
   211 			case MUS_CMD:
   212 				/* The playing is done externally */
   213 				break;
   214 #endif
   215 #ifdef WAV_MUSIC
   216 			case MUS_WAV:
   217 				WAVStream_PlaySome(stream, len);
   218 				break;
   219 #endif
   220 #ifdef MOD_MUSIC
   221 			case MUS_MOD:
   222 				VC_WriteBytes((SBYTE *)stream, len);
   223 				if ( music_swap8 ) {
   224 					Uint8 *dst;
   225 					int i;
   226 
   227 					dst = stream;
   228 					for ( i=len; i; --i ) {
   229 						*dst++ ^= 0x80;
   230 					}
   231 				} else
   232 				if ( music_swap16 ) {
   233 					Uint8 *dst, tmp;
   234 					int i;
   235 
   236 					dst = stream;
   237 					for ( i=(len/2); i; --i ) {
   238 						tmp = dst[0];
   239 						dst[0] = dst[1];
   240 						dst[1] = tmp;
   241 						dst += 2;
   242 					}
   243 				}
   244 				break;
   245 #endif
   246 #ifdef MID_MUSIC
   247 #ifdef USE_TIMIDITY_MIDI
   248 			case MUS_MID:
   249 				if ( timidity_ok ) {
   250 					int samples = len / samplesize;
   251   					Timidity_PlaySome(stream, samples);
   252 				}
   253 				break;
   254 #endif
   255 #endif
   256 #ifdef OGG_MUSIC
   257 			case MUS_OGG:
   258 				OGG_playAudio(music_playing->data.ogg, stream, len);
   259 				break;
   260 #endif
   261 #ifdef MP3_MUSIC
   262 			case MUS_MP3:
   263 				SMPEG_playAudio(music_playing->data.mp3, stream, len);
   264 				break;
   265 #endif
   266 			default:
   267 				/* Unknown music type?? */
   268 				break;
   269 		}
   270 	}
   271 }
   272 
   273 /* Initialize the music players with a certain desired audio format */
   274 int open_music(SDL_AudioSpec *mixer)
   275 {
   276 	int music_error;
   277 
   278 	music_error = 0;
   279 #ifdef WAV_MUSIC
   280 	if ( WAVStream_Init(mixer) < 0 ) {
   281 		++music_error;
   282 	}
   283 #endif
   284 #ifdef MOD_MUSIC
   285 	/* Set the MikMod music format */
   286 	music_swap8 = 0;
   287 	music_swap16 = 0;
   288 	switch (mixer->format) {
   289 
   290 		case AUDIO_U8:
   291 		case AUDIO_S8: {
   292 			if ( mixer->format == AUDIO_S8 ) {
   293 				music_swap8 = 1;
   294 			}
   295 			md_mode = 0;
   296 		}
   297 		break;
   298 
   299 		case AUDIO_S16LSB:
   300 		case AUDIO_S16MSB: {
   301 			/* See if we need to correct MikMod mixing */
   302 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
   303 			if ( mixer->format == AUDIO_S16MSB ) {
   304 #else
   305 			if ( mixer->format == AUDIO_S16LSB ) {
   306 #endif
   307 				music_swap16 = 1;
   308 			}
   309 			md_mode = DMODE_16BITS;
   310 		}
   311 		break;
   312 
   313 		default: {
   314 			Mix_SetError("Unknown hardware audio format");
   315 			++music_error;
   316 		}
   317 	}
   318 	if ( mixer->channels > 1 ) {
   319 		if ( mixer->channels > 2 ) {
   320 			Mix_SetError("Hardware uses more channels than mixer");
   321 			++music_error;
   322 		}
   323 		md_mode |= DMODE_STEREO;
   324 	}
   325 	md_mixfreq	 = mixer->freq;
   326 	md_device	  = 0;
   327 	md_volume	  = 96;
   328 	md_musicvolume = 128;
   329 	md_sndfxvolume = 128;
   330 	md_pansep	  = 128;
   331 	md_reverb	  = 0;
   332 	MikMod_RegisterAllLoaders();
   333 	MikMod_RegisterAllDrivers();
   334 	if ( MikMod_Init() ) {
   335 		Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   336 		++music_error;
   337 	}
   338 #endif
   339 #ifdef MID_MUSIC
   340 #ifdef USE_TIMIDITY_MIDI
   341 	samplesize = mixer->size / mixer->samples;
   342 	if ( Timidity_Init(mixer->freq, mixer->format,
   343 	                    mixer->channels, mixer->samples) == 0 ) {
   344 		timidity_ok = 1;
   345 	} else {
   346 		timidity_ok = 0;
   347 	}
   348 #endif
   349 #ifdef USE_NATIVE_MIDI
   350 #ifdef USE_TIMIDITY_MIDI
   351 	native_midi_ok = !timidity_ok;
   352 	if ( native_midi_ok )
   353 #endif
   354 		native_midi_ok = native_midi_detect();
   355 #endif
   356 #endif
   357 #ifdef OGG_MUSIC
   358 	if ( OGG_init(mixer) < 0 ) {
   359 		++music_error;
   360 	}
   361 #endif
   362 #ifdef MP3_MUSIC
   363 	/* Keep a copy of the mixer */
   364 	used_mixer = *mixer;
   365 #endif
   366 	music_playing = NULL;
   367 	music_stopped = 0;
   368 	if ( music_error ) {
   369 		return(-1);
   370 	}
   371 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   372 
   373 	/* Calculate the number of ms for each callback */
   374 	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   375 
   376 	return(0);
   377 }
   378 
   379 /* Portable case-insensitive string compare function */
   380 int MIX_string_equals(const char *str1, const char *str2)
   381 {
   382 	while ( *str1 && *str2 ) {
   383 		if ( toupper((unsigned char)*str1) !=
   384 		     toupper((unsigned char)*str2) )
   385 			break;
   386 		++str1;
   387 		++str2;
   388 	}
   389 	return (!*str1 && !*str2);
   390 }
   391 
   392 /* Load a music file */
   393 Mix_Music *Mix_LoadMUS(const char *file)
   394 {
   395 	FILE *fp;
   396 	char *ext;
   397 	Uint8 magic[5];
   398 	Mix_Music *music;
   399 
   400 	/* Figure out what kind of file this is */
   401 	fp = fopen(file, "rb");
   402 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   403 		if ( fp != NULL ) {
   404 			fclose(fp);
   405 		}
   406 		Mix_SetError("Couldn't read from '%s'", file);
   407 		return(NULL);
   408 	}
   409 	magic[4] = '\0';
   410 	fclose(fp);
   411 
   412 	/* Figure out the file extension, so we can determine the type */
   413 	ext = strrchr(file, '.');
   414 	if ( ext ) ++ext; /* skip the dot in the extension */
   415 
   416 	/* Allocate memory for the music structure */
   417 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   418 	if ( music == NULL ) {
   419 		Mix_SetError("Out of memory");
   420 		return(NULL);
   421 	}
   422 	music->error = 0;
   423 
   424 #ifdef CMD_MUSIC
   425 	if ( music_cmd ) {
   426 		music->type = MUS_CMD;
   427 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   428 		if ( music->data.cmd == NULL ) {
   429 			music->error = 1;
   430 		}
   431 	} else
   432 #endif
   433 #ifdef WAV_MUSIC
   434 	/* WAVE files have the magic four bytes "RIFF"
   435 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   436 	 */
   437 	if ( (ext && MIX_string_equals(ext, "WAV")) ||
   438 	     (strcmp((char *)magic, "RIFF") == 0) ||
   439 	     (strcmp((char *)magic, "FORM") == 0) ) {
   440 		music->type = MUS_WAV;
   441 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   442 		if ( music->data.wave == NULL ) {
   443 		  	Mix_SetError("Unable to load WAV file");
   444 			music->error = 1;
   445 		}
   446 	} else
   447 #endif
   448 #ifdef MID_MUSIC
   449 	/* MIDI files have the magic four bytes "MThd" */
   450 	if ( (ext && MIX_string_equals(ext, "MID")) ||
   451 	     (ext && MIX_string_equals(ext, "MIDI")) ||
   452 	     strcmp((char *)magic, "MThd") == 0 ) {
   453 		music->type = MUS_MID;
   454 #ifdef USE_NATIVE_MIDI
   455   		if ( native_midi_ok ) {
   456   			music->data.nativemidi = native_midi_loadsong((char *)file);
   457 	  		if ( music->data.nativemidi == NULL ) {
   458 		  		Mix_SetError("%s", native_midi_error());
   459 			  	music->error = 1;
   460 			}
   461 	  	} MIDI_ELSE
   462 #endif
   463 #ifdef USE_TIMIDITY_MIDI
   464 		if ( timidity_ok ) {
   465 			music->data.midi = Timidity_LoadSong((char *)file);
   466 			if ( music->data.midi == NULL ) {
   467 				Mix_SetError("%s", Timidity_Error());
   468 				music->error = 1;
   469 			}
   470 		} else {
   471 			Mix_SetError("%s", Timidity_Error());
   472 			music->error = 1;
   473 		}
   474 #endif
   475 	} else
   476 #endif
   477 #ifdef OGG_MUSIC
   478 	/* Ogg Vorbis files have the magic four bytes "OggS" */
   479 	if ( (ext && MIX_string_equals(ext, "OGG")) ||
   480 	     strcmp((char *)magic, "OggS") == 0 ) {
   481 		music->type = MUS_OGG;
   482 		music->data.ogg = OGG_new(file);
   483 		if ( music->data.ogg == NULL ) {
   484 			music->error = 1;
   485 		}
   486 	} else
   487 #endif
   488 #ifdef MP3_MUSIC
   489 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   490 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   491 	     magic[0]==0xFF && (magic[1]&0xF0)==0xF0) {
   492 		SMPEG_Info info;
   493 		music->type = MUS_MP3;
   494 		music->data.mp3 = SMPEG_new(file, &info, 0);
   495 		if(!info.has_audio){
   496 			Mix_SetError("MPEG file does not have any audio stream.");
   497 			music->error = 1;
   498 		}else{
   499 			SMPEG_actualSpec(music->data.mp3, &used_mixer);
   500 		}
   501 	} else
   502 #endif
   503 #ifdef MOD_MUSIC
   504 	if ( 1 ) {
   505 		music->type = MUS_MOD;
   506 		music->data.module = MikMod_LoadSong((char *)file, 64);
   507 		if ( music->data.module == NULL ) {
   508 			Mix_SetError("%s", MikMod_strerror(MikMod_errno));
   509 			music->error = 1;
   510 		} else {
   511 			/* Stop implicit looping, fade out and other flags. */
   512 			music->data.module->extspd  = 1;
   513 			music->data.module->panflag = 1;
   514 			music->data.module->wrap    = 0;
   515 			music->data.module->loop    = 0;
   516 #if 0 /* Don't set fade out by default - unfortunately there's no real way
   517          to query the status of the song or set trigger actions.  Hum. */
   518 			music->data.module->fadeout = 1;
   519 #endif
   520 		}
   521 	} else
   522 #endif
   523 	{
   524 		Mix_SetError("Unrecognized music format");
   525 		music->error = 1;
   526 	}
   527 	if ( music->error ) {
   528 		free(music);
   529 		music = NULL;
   530 	}
   531 	return(music);
   532 }
   533 
   534 /* Free a music chunk previously loaded */
   535 void Mix_FreeMusic(Mix_Music *music)
   536 {
   537 	if ( music ) {
   538 		/* Caution: If music is playing, mixer will crash */
   539 		if ( music == music_playing && !music_stopped ) {
   540 			if ( music->fading == MIX_FADING_OUT ) {
   541 				/* Wait for the fade out to finish */
   542 				while ( music_playing && !music_stopped && (music_playing->fading == MIX_FADING_OUT) )
   543 					SDL_Delay(100);
   544 			} else {
   545 				Mix_HaltMusic(); /* Stop it immediately */
   546 			}
   547 		}
   548 		switch (music->type) {
   549 #ifdef CMD_MUSIC
   550 			case MUS_CMD:
   551 				MusicCMD_FreeSong(music->data.cmd);
   552 				break;
   553 #endif
   554 #ifdef WAV_MUSIC
   555 			case MUS_WAV:
   556 				WAVStream_FreeSong(music->data.wave);
   557 				break;
   558 #endif
   559 #ifdef MOD_MUSIC
   560 			case MUS_MOD:
   561 				MikMod_FreeSong(music->data.module);
   562 				break;
   563 #endif
   564 #ifdef MID_MUSIC
   565 			case MUS_MID:
   566 #ifdef USE_NATIVE_MIDI
   567   				if ( native_midi_ok ) {
   568 					native_midi_freesong(music->data.nativemidi);
   569 				} MIDI_ELSE
   570 #endif
   571 #ifdef USE_TIMIDITY_MIDI
   572 				if ( timidity_ok ) {
   573 					Timidity_FreeSong(music->data.midi);
   574 				}
   575 #endif
   576 				break;
   577 #endif
   578 #ifdef OGG_MUSIC
   579 			case MUS_OGG:
   580 				OGG_delete(music->data.ogg);
   581 				break;
   582 #endif
   583 #ifdef MP3_MUSIC
   584 			case MUS_MP3:
   585 				SMPEG_delete(music->data.mp3);
   586 				break;
   587 #endif
   588 			default:
   589 				/* Unknown music type?? */
   590 				break;
   591 		}
   592 		free(music);
   593 	}
   594 }
   595 
   596 static int lowlevel_play(Mix_Music *music)
   597 {
   598 	if(!music)
   599 		return(-1);
   600 
   601 	switch (music->type) {
   602 #ifdef CMD_MUSIC
   603 		case MUS_CMD:
   604 			MusicCMD_SetVolume(music_volume);
   605 			MusicCMD_Start(music->data.cmd);
   606 			break;
   607 #endif
   608 #ifdef WAV_MUSIC
   609 		case MUS_WAV:
   610 			WAVStream_SetVolume(music_volume);
   611 			WAVStream_Start(music->data.wave);
   612 			break;
   613 #endif
   614 #ifdef MOD_MUSIC
   615 		case MUS_MOD:
   616 			Player_SetVolume((SWORD)music_volume);
   617 			Player_Start(music->data.module);
   618 			Player_SetPosition(0);
   619 			break;
   620 #endif
   621 #ifdef MID_MUSIC
   622 		case MUS_MID:
   623 #ifdef USE_NATIVE_MIDI
   624   			if ( native_midi_ok ) {
   625 				native_midi_setvolume(music_volume);
   626 				native_midi_start(music->data.nativemidi);
   627 			} MIDI_ELSE
   628 #endif
   629 #ifdef USE_TIMIDITY_MIDI
   630 			if ( timidity_ok ) {
   631 				Timidity_SetVolume(music_volume);
   632 				Timidity_Start(music->data.midi);
   633 			}
   634 #endif
   635 			break;
   636 #endif
   637 #ifdef OGG_MUSIC
   638 		case MUS_OGG:
   639 			OGG_setvolume(music->data.ogg, music_volume);
   640 			OGG_play(music->data.ogg);
   641 			break;
   642 #endif
   643 #ifdef MP3_MUSIC
   644 		case MUS_MP3:
   645 			SMPEG_enableaudio(music->data.mp3,1);
   646 			SMPEG_enablevideo(music->data.mp3,0);
   647 			SMPEG_setvolume(music->data.mp3,(int)(((float)music_volume/(float)MIX_MAX_VOLUME)*100.0));
   648 			SMPEG_play(music->data.mp3);
   649 			break;
   650 #endif
   651 		default:
   652 			/* Unknown music type?? */
   653 			return(-1);
   654 	}
   655 	return(0);
   656 }
   657 
   658 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   659 */
   660 int Mix_PlayMusic(Mix_Music *music, int loops)
   661 {
   662 	/* Don't play null pointers :-) */
   663 	if ( music == NULL ) {
   664 		return(-1);
   665 	}
   666 	/* If the current music is fading out, wait for the fade to complete */
   667 	while ( music_playing && !music_stopped && music_playing->fading==MIX_FADING_OUT ) {
   668 		SDL_Delay(100);
   669 	}
   670 
   671 	if ( lowlevel_play(music) < 0 ) {
   672 		return(-1);
   673 	}
   674 	music_active = 1;
   675 	music_stopped = 0;
   676 	music_loops = loops;
   677 	music_playing = music;
   678 	music_playing->fading = MIX_NO_FADING;
   679 	return(0);
   680 }
   681 
   682 int Mix_SetMusicPosition(double position)
   683 {
   684 	if ( music_playing && !music_stopped ) {
   685 		switch ( music_playing->type ) {
   686 #ifdef MOD_MUSIC
   687 		case MUS_MOD:
   688 			Player_SetPosition(position);
   689 			return(0);
   690 			break;
   691 #endif
   692 #ifdef OGG_MUSIC
   693 		case MUS_OGG:
   694 			OGG_jump_to_time(music_playing->data.ogg, position);
   695 			return(0);
   696 			break;
   697 #endif
   698 #ifdef MP3_MUSIC
   699 		case MUS_MP3:
   700 			SMPEG_skip(music_playing->data.mp3, position);
   701 			return(0);
   702 			break;
   703 #endif
   704 		default:
   705 			/* TODO: Implement this for other music backends */
   706 			break;
   707 		}
   708 	}
   709 	return(-1);
   710 }
   711 
   712 /* Fade in a music over "ms" milliseconds */
   713 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   714 {
   715 	if ( music && music_volume > 0 ) { /* No need to fade if we can't hear it */
   716 		music->fade_volume = music_volume;
   717 		music_volume = 0;
   718 		if ( Mix_PlayMusic(music, loops) < 0 ) {
   719 			return(-1);
   720 		}
   721 		if ( position ) {
   722 			if ( Mix_SetMusicPosition(position) < 0 ) {
   723 				Mix_HaltMusic();
   724 				return(-1);
   725 			}
   726 		}
   727 		music_playing->fade_step = 0;
   728 		music_playing->fade_steps = ms/ms_per_step;
   729 		music_playing->fading = MIX_FADING_IN;
   730 	}
   731 	return(0);
   732 }
   733 
   734 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   735 {
   736 	return Mix_FadeInMusicPos(music, loops, ms, 0);
   737 }
   738 
   739 /* Set the music volume */
   740 int Mix_VolumeMusic(int volume)
   741 {
   742 	int prev_volume;
   743 
   744 	prev_volume = music_volume;
   745 	if ( volume < 0 ) {
   746 		volume = 0;
   747 	}
   748 	if ( volume > SDL_MIX_MAXVOLUME ) {
   749 		volume = SDL_MIX_MAXVOLUME;
   750 	}
   751 	music_volume = volume;
   752 	if ( music_playing && !music_stopped ) {
   753 		switch (music_playing->type) {
   754 #ifdef CMD_MUSIC
   755 		case MUS_CMD:
   756 			MusicCMD_SetVolume(music_volume);
   757 			break;
   758 #endif
   759 #ifdef WAV_MUSIC
   760 		case MUS_WAV:
   761 			WAVStream_SetVolume(music_volume);
   762 			break;
   763 #endif
   764 #ifdef MOD_MUSIC
   765 		case MUS_MOD:
   766 			Player_SetVolume((SWORD)music_volume);
   767 			break;
   768 #endif
   769 #ifdef MID_MUSIC
   770 		case MUS_MID:
   771 #ifdef USE_NATIVE_MIDI
   772 			if ( native_midi_ok ) {
   773 				native_midi_setvolume(music_volume);
   774 			} MIDI_ELSE
   775 #endif
   776 #ifdef USE_TIMIDITY_MIDI
   777 			if ( timidity_ok ) {
   778 				Timidity_SetVolume(music_volume);
   779 			}
   780 #endif
   781 			break;
   782 #endif
   783 #ifdef OGG_MUSIC
   784 		case MUS_OGG:
   785 			OGG_setvolume(music_playing->data.ogg, music_volume);
   786 			break;
   787 #endif
   788 #ifdef MP3_MUSIC
   789 		case MUS_MP3:
   790 			SMPEG_setvolume(music_playing->data.mp3,(int)(((float)music_volume/(float)MIX_MAX_VOLUME)*100.0));
   791 			break;
   792 #endif
   793 		default:
   794 			/* Unknown music type?? */
   795 			break;
   796 		}
   797 	}
   798 	return(prev_volume);
   799 }
   800 
   801 static void lowlevel_halt(void)
   802 {
   803 	switch (music_playing->type) {
   804 #ifdef CMD_MUSIC
   805 	case MUS_CMD:
   806 		MusicCMD_Stop(music_playing->data.cmd);
   807 		break;
   808 #endif
   809 #ifdef WAV_MUSIC
   810 	case MUS_WAV:
   811 		WAVStream_Stop();
   812 		break;
   813 #endif
   814 #ifdef MOD_MUSIC
   815 	case MUS_MOD:
   816 		Player_Stop();
   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 		} MIDI_ELSE
   825 #endif
   826 #ifdef USE_TIMIDITY_MIDI
   827 		if ( timidity_ok ) {
   828 			Timidity_Stop();
   829 		}
   830 #endif
   831 		break;
   832 #endif
   833 #ifdef OGG_MUSIC
   834 	case MUS_OGG:
   835 		OGG_stop(music_playing->data.ogg);
   836 		break;
   837 #endif
   838 #ifdef MP3_MUSIC
   839 	case MUS_MP3:
   840 		SMPEG_stop(music_playing->data.mp3);
   841 		break;
   842 #endif
   843 	default:
   844 		/* Unknown music type?? */
   845 		return;
   846 	}
   847 	if ( music_playing->fading != MIX_NO_FADING ) /* Restore volume */
   848 		music_volume = music_playing->fade_volume;
   849 	music_playing->fading = MIX_NO_FADING;
   850 	music_playing = NULL;
   851 	music_active = 0;
   852 	music_loops = 0;
   853 	music_stopped = 0;
   854 }
   855 
   856 /* Halt playing of music */
   857 int Mix_HaltMusic(void)
   858 {
   859 	if ( music_playing && !music_stopped ) {
   860 		/* Mark the music to be stopped from the sound thread */
   861 		music_stopped = 1;
   862 		/* Wait for it to be actually stopped */
   863 		while ( music_playing && music_active )
   864 			SDL_Delay(10);
   865 	}
   866 	return(0);
   867 }
   868 
   869 /* Progressively stop the music */
   870 int Mix_FadeOutMusic(int ms)
   871 {
   872 	if ( music_playing && !music_stopped &&
   873 	     (music_playing->fading == MIX_NO_FADING) ) {
   874 		if ( music_volume > 0 ) {
   875 			music_playing->fading = MIX_FADING_OUT;
   876 			music_playing->fade_volume = music_volume;
   877 			music_playing->fade_step = 0;
   878 			music_playing->fade_steps = ms/ms_per_step;
   879 			return(1);
   880 		}
   881 	}
   882 	return(0);
   883 }
   884 
   885 Mix_Fading Mix_FadingMusic(void)
   886 {
   887 	if( music_playing && !music_stopped )
   888 		return music_playing->fading;
   889 	return MIX_NO_FADING;
   890 }
   891 
   892 /* Pause/Resume the music stream */
   893 void Mix_PauseMusic(void)
   894 {
   895 	if ( music_playing && !music_stopped ) {
   896 		music_active = 0;
   897 	}
   898 }
   899 
   900 void Mix_ResumeMusic(void)
   901 {
   902 	if ( music_playing && !music_stopped ) {
   903 		music_active = 1;
   904 	}
   905 }
   906 
   907 void Mix_RewindMusic(void)
   908 {
   909 	if ( music_playing && !music_stopped ) {
   910 		switch ( music_playing->type ) {
   911 #ifdef MOD_MUSIC
   912 		case MUS_MOD:
   913 			Player_Start(music_playing->data.module);
   914 			Player_SetPosition(0);
   915 			break;
   916 #endif
   917 #ifdef MP3_MUSIC
   918 		case MUS_MP3:
   919 			SMPEG_rewind(music_playing->data.mp3);
   920 			break;
   921 #endif
   922 #ifdef MID_MUSIC
   923 		case MUS_MID:
   924 #ifdef USE_NATIVE_MIDI
   925 			if ( native_midi_ok ) {
   926 				native_midi_stop();
   927 			}
   928 #endif
   929 			break;
   930 #endif
   931 		default:
   932 			/* TODO: Implement this for other music backends */
   933 			break;
   934 		}
   935 	}
   936 }
   937 
   938 int Mix_PausedMusic(void)
   939 {
   940 	return (music_active == 0);
   941 }
   942 
   943 /* Check the status of the music */
   944 int Mix_PlayingMusic(void)
   945 {
   946 	if ( music_playing && ! music_stopped ) {
   947 		switch (music_playing->type) {
   948 #ifdef CMD_MUSIC
   949 			case MUS_CMD:
   950 				if (!MusicCMD_Active(music_playing->data.cmd)) {
   951 					return(0);
   952 				}
   953 				break;
   954 #endif
   955 #ifdef WAV_MUSIC
   956 			case MUS_WAV:
   957 				if ( ! WAVStream_Active() ) {
   958 					return(0);
   959 				}
   960 				break;
   961 #endif
   962 #ifdef MOD_MUSIC
   963 			case MUS_MOD:
   964 				if ( ! Player_Active() ) {
   965 					return(0);
   966 				}
   967 				break;
   968 #endif
   969 #ifdef MID_MUSIC
   970 			case MUS_MID:
   971 #ifdef USE_NATIVE_MIDI
   972 				if ( native_midi_ok ) {
   973 					if ( ! native_midi_active() )
   974 						return(0);
   975 				} MIDI_ELSE
   976 #endif
   977 #ifdef USE_TIMIDITY_MIDI
   978 				if ( timidity_ok ) {
   979 					if ( ! Timidity_Active() )
   980 						return(0);
   981 				}
   982 #endif
   983 				break;
   984 #endif
   985 #ifdef OGG_MUSIC
   986 			case MUS_OGG:
   987 				if ( ! OGG_playing(music_playing->data.ogg) ) {
   988 					return(0);
   989 				}
   990 				break;
   991 #endif
   992 #ifdef MP3_MUSIC
   993 			case MUS_MP3:
   994 				if ( SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
   995 					return(0);
   996 				break;
   997 #endif
   998 			default:
   999 				break;
  1000 		}
  1001 		return(1);
  1002 	}
  1003 	return(0);
  1004 }
  1005 
  1006 /* Set the external music playback command */
  1007 int Mix_SetMusicCMD(const char *command)
  1008 {
  1009 	Mix_HaltMusic();
  1010 	if ( music_cmd ) {
  1011 		free(music_cmd);
  1012 		music_cmd = NULL;
  1013 	}
  1014 	if ( command ) {
  1015 		music_cmd = (char *)malloc(strlen(command)+1);
  1016 		if ( music_cmd == NULL ) {
  1017 			return(-1);
  1018 		}
  1019 		strcpy(music_cmd, command);
  1020 	}
  1021 	return(0);
  1022 }
  1023 
  1024 int Mix_SetSynchroValue(int i)
  1025 {
  1026 	if ( music_playing && ! music_stopped ) {
  1027 		switch (music_playing->type) {
  1028 #ifdef MOD_MUSIC
  1029 			case MUS_MOD:
  1030 				if ( ! Player_Active() ) {
  1031 					return(-1);
  1032 				}
  1033 				Player_SetSynchroValue(i);
  1034 				return 0;
  1035 				break;
  1036 #endif
  1037 			default:
  1038 				return(-1);
  1039 				break;
  1040 		}
  1041 		return(-1);
  1042 	}
  1043 	return(-1);
  1044 }
  1045 
  1046 int Mix_GetSynchroValue(void)
  1047 {
  1048 	if ( music_playing && ! music_stopped ) {
  1049 		switch (music_playing->type) {
  1050 #ifdef MOD_MUSIC
  1051 			case MUS_MOD:
  1052 				if ( ! Player_Active() ) {
  1053 					return(-1);
  1054 				}
  1055 				return Player_GetSynchroValue();
  1056 				break;
  1057 #endif
  1058 			default:
  1059 				return(-1);
  1060 				break;
  1061 		}
  1062 		return(-1);
  1063 	}
  1064 	return(-1);
  1065 }
  1066 
  1067 
  1068 /* Uninitialize the music players */
  1069 void close_music(void)
  1070 {
  1071 	Mix_HaltMusic();
  1072 #ifdef CMD_MUSIC
  1073 	Mix_SetMusicCMD(NULL);
  1074 #endif
  1075 #ifdef MOD_MUSIC
  1076 	MikMod_Exit();
  1077 	MikMod_UnregisterAllLoaders();
  1078 	MikMod_UnregisterAllDrivers();
  1079 #endif
  1080 }
  1081