music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 08 Nov 2009 18:40:07 +0000
changeset 474 a2c238c0c4b2
parent 473 60b7e1c4f6b2
child 479 3d8a5a7b1249
permissions -rw-r--r--
Don't break binary compatibility!
     1 /*
     2     SDL_mixer:  An audio mixer library based on the SDL library
     3     Copyright (C) 1997-2009 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 <assert.h>
    29 #include "SDL_endian.h"
    30 #include "SDL_audio.h"
    31 #include "SDL_timer.h"
    32 
    33 #include "SDL_mixer.h"
    34 
    35 #ifdef CMD_MUSIC
    36 #include "music_cmd.h"
    37 #endif
    38 #ifdef WAV_MUSIC
    39 #include "wavestream.h"
    40 #endif
    41 #ifdef MOD_MUSIC
    42 #include "music_mod.h"
    43 #endif
    44 #ifdef MID_MUSIC
    45 #  ifdef USE_TIMIDITY_MIDI
    46 #    include "timidity.h"
    47 #  endif
    48 #  ifdef USE_NATIVE_MIDI
    49 #    include "native_midi.h"
    50 #  endif
    51 #  if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
    52 #    define MIDI_ELSE	else
    53 #  else
    54 #    define MIDI_ELSE
    55 #  endif
    56 #endif
    57 #ifdef OGG_MUSIC
    58 #include "music_ogg.h"
    59 #endif
    60 #ifdef MP3_MUSIC
    61 #include "dynamic_mp3.h"
    62 #endif
    63 #ifdef MP3_MAD_MUSIC
    64 #include "music_mad.h"
    65 #endif
    66 #ifdef FLAC_MUSIC
    67 #include "music_flac.h"
    68 #endif
    69 
    70 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
    71 static SDL_AudioSpec used_mixer;
    72 #endif
    73 
    74 
    75 int volatile music_active = 1;
    76 static int volatile music_stopped = 0;
    77 static int music_loops = 0;
    78 static char *music_cmd = NULL;
    79 static Mix_Music * volatile music_playing = NULL;
    80 static int music_volume = MIX_MAX_VOLUME;
    81 
    82 struct _Mix_Music {
    83 	Mix_MusicType type;
    84 	union {
    85 #ifdef CMD_MUSIC
    86 		MusicCMD *cmd;
    87 #endif
    88 #ifdef WAV_MUSIC
    89 		WAVStream *wave;
    90 #endif
    91 #ifdef MOD_MUSIC
    92 		struct MODULE *module;
    93 #endif
    94 #ifdef MID_MUSIC
    95 #ifdef USE_TIMIDITY_MIDI
    96 		MidiSong *midi;
    97 #endif
    98 #ifdef USE_NATIVE_MIDI
    99 		NativeMidiSong *nativemidi;
   100 #endif
   101 #endif
   102 #ifdef OGG_MUSIC
   103 		OGG_music *ogg;
   104 #endif
   105 #ifdef MP3_MUSIC
   106 		SMPEG *mp3;
   107 #endif
   108 #ifdef MP3_MAD_MUSIC
   109 		mad_data *mp3_mad;
   110 #endif
   111 #ifdef FLAC_MUSIC
   112 		FLAC_music *flac;
   113 #endif
   114 	} data;
   115 	Mix_Fading fading;
   116 	int fade_step;
   117 	int fade_steps;
   118 	int error;
   119 };
   120 #ifdef MID_MUSIC
   121 #ifdef USE_TIMIDITY_MIDI
   122 static int timidity_ok;
   123 static int samplesize;
   124 #endif
   125 #ifdef USE_NATIVE_MIDI
   126 static int native_midi_ok;
   127 #endif
   128 #endif
   129 
   130 /* Used to calculate fading steps */
   131 static int ms_per_step;
   132 
   133 /* rcg06042009 report available decoders at runtime. */
   134 static const char **music_decoders = NULL;
   135 static int num_decoders = 0;
   136 
   137 int Mix_GetNumMusicDecoders(void)
   138 {
   139 	return(num_decoders);
   140 }
   141 
   142 const char *Mix_GetMusicDecoder(int index)
   143 {
   144 	if ((index < 0) || (index >= num_decoders)) {
   145 		return NULL;
   146 	}
   147 	return(music_decoders[index]);
   148 }
   149 
   150 static void add_music_decoder(const char *decoder)
   151 {
   152 	void *ptr = realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
   153 	if (ptr == NULL) {
   154 		return;  /* oh well, go on without it. */
   155 	}
   156 	music_decoders = (const char **) ptr;
   157 	music_decoders[num_decoders++] = decoder;
   158 }
   159 
   160 /* Local low-level functions prototypes */
   161 static void music_internal_initialize_volume(void);
   162 static void music_internal_volume(int volume);
   163 static int  music_internal_play(Mix_Music *music, double position);
   164 static int  music_internal_position(double position);
   165 static int  music_internal_playing();
   166 static void music_internal_halt(void);
   167 
   168 
   169 /* Support for hooking when the music has finished */
   170 static void (*music_finished_hook)(void) = NULL;
   171 
   172 void Mix_HookMusicFinished(void (*music_finished)(void))
   173 {
   174 	SDL_LockAudio();
   175 	music_finished_hook = music_finished;
   176 	SDL_UnlockAudio();
   177 }
   178 
   179 
   180 /* If music isn't playing, halt it if no looping is required, restart it */
   181 /* otherwhise. NOP if the music is playing */
   182 static int music_halt_or_loop (void)
   183 {
   184 	/* Restart music if it has to loop */
   185 	
   186 	if (!music_internal_playing()) 
   187 	{
   188 		/* Restart music if it has to loop at a high level */
   189 		if (music_loops && --music_loops)
   190 		{
   191 			Mix_Fading current_fade = music_playing->fading;
   192 			music_internal_play(music_playing, 0.0);
   193 			music_playing->fading = current_fade;
   194 		} 
   195 		else 
   196 		{
   197 			music_internal_halt();
   198 			if (music_finished_hook)
   199 				music_finished_hook();
   200 			
   201 			return 0;
   202 		}
   203 	}
   204 	
   205 	return 1;
   206 }
   207 
   208 
   209 
   210 /* Mixing function */
   211 void music_mixer(void *udata, Uint8 *stream, int len)
   212 {
   213 	int left = 0;
   214 
   215 	if ( music_playing && music_active ) {
   216 		/* Handle fading */
   217 		if ( music_playing->fading != MIX_NO_FADING ) {
   218 			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   219 				int volume;
   220 				int fade_step = music_playing->fade_step;
   221 				int fade_steps = music_playing->fade_steps;
   222 
   223 				if ( music_playing->fading == MIX_FADING_OUT ) {
   224 					volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
   225 				} else { /* Fading in */
   226 					volume = (music_volume * fade_step) / fade_steps;
   227 				}
   228 				music_internal_volume(volume);
   229 			} else {
   230 				if ( music_playing->fading == MIX_FADING_OUT ) {
   231 					music_internal_halt();
   232 					if ( music_finished_hook ) {
   233 						music_finished_hook();
   234 					}
   235 					return;
   236 				}
   237 				music_playing->fading = MIX_NO_FADING;
   238 			}
   239 		}
   240 		
   241 		if (music_halt_or_loop() == 0)
   242 			return;
   243 		
   244 		
   245 		switch (music_playing->type) {
   246 #ifdef CMD_MUSIC
   247 			case MUS_CMD:
   248 				/* The playing is done externally */
   249 				break;
   250 #endif
   251 #ifdef WAV_MUSIC
   252 			case MUS_WAV:
   253 				left = WAVStream_PlaySome(stream, len);
   254 				break;
   255 #endif
   256 #ifdef MOD_MUSIC
   257 			case MUS_MOD:
   258 				left = MOD_playAudio(music_playing->data.module, stream, len);
   259 				break;
   260 #endif
   261 #ifdef MID_MUSIC
   262 #ifdef USE_TIMIDITY_MIDI
   263 			case MUS_MID:
   264 				if ( timidity_ok ) {
   265 					int samples = len / samplesize;
   266   					Timidity_PlaySome(stream, samples);
   267 				}
   268 				break;
   269 #endif
   270 #endif
   271 #ifdef OGG_MUSIC
   272 			case MUS_OGG:
   273 				
   274 				left = OGG_playAudio(music_playing->data.ogg, stream, len);
   275 				break;
   276 #endif
   277 #ifdef FLAC_MUSIC
   278 			case MUS_FLAC:
   279 				left = FLAC_playAudio(music_playing->data.flac, stream, len);
   280 				break;
   281 #endif
   282 #ifdef MP3_MUSIC
   283 			case MUS_MP3:
   284 				left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
   285 				break;
   286 #endif
   287 #ifdef MP3_MAD_MUSIC
   288 			case MUS_MP3_MAD:
   289 				left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
   290 				break;
   291 #endif
   292 			default:
   293 				/* Unknown music type?? */
   294 				break;
   295 		}
   296 	}
   297 
   298 	/* Handle seamless music looping */
   299 	if (left > 0 && left < len && music_halt_or_loop()) {
   300 		music_mixer(udata, stream+(len-left), left);
   301 	}
   302 }
   303 
   304 /* Initialize the music players with a certain desired audio format */
   305 int open_music(SDL_AudioSpec *mixer)
   306 {
   307 	int music_error = 0;
   308 
   309 #ifdef WAV_MUSIC
   310 	if ( WAVStream_Init(mixer) < 0 ) {
   311 		++music_error;
   312 	} else {
   313 		add_music_decoder("WAVE");
   314 	}
   315 #endif
   316 #ifdef MOD_MUSIC
   317 	if ( MOD_init(mixer) < 0 ) {
   318 		++music_error;
   319 	} else {
   320 		add_music_decoder("MIKMOD");
   321 	}
   322 #endif
   323 #ifdef MID_MUSIC
   324 #ifdef USE_TIMIDITY_MIDI
   325 	samplesize = mixer->size / mixer->samples;
   326 	if ( Timidity_Init(mixer->freq, mixer->format,
   327 	                    mixer->channels, mixer->samples) == 0 ) {
   328 		timidity_ok = 1;
   329 		add_music_decoder("TIMIDITY");
   330 	} else {
   331 		timidity_ok = 0;
   332 	}
   333 #endif
   334 #ifdef USE_NATIVE_MIDI
   335 #ifdef USE_TIMIDITY_MIDI
   336 	native_midi_ok = !timidity_ok;
   337 	if ( !native_midi_ok ) {
   338 		native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
   339 	}
   340 	if ( native_midi_ok )
   341 #endif
   342 		native_midi_ok = native_midi_detect();
   343 	if ( native_midi_ok )
   344 		add_music_decoder("NATIVEMIDI");
   345 #endif
   346 #endif
   347 #ifdef OGG_MUSIC
   348 	if ( OGG_init(mixer) < 0 ) {
   349 		++music_error;
   350 	} else {
   351 		add_music_decoder("OGG");
   352 	}
   353 #endif
   354 #ifdef FLAC_MUSIC
   355 	if ( FLAC_init(mixer) < 0 ) {
   356 		++music_error;
   357 	} else {
   358 		add_music_decoder("FLAC");
   359 	}
   360 #endif
   361 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
   362 	/* Keep a copy of the mixer */
   363 	used_mixer = *mixer;
   364 	add_music_decoder("MP3");
   365 #endif
   366 
   367 	music_playing = NULL;
   368 	music_stopped = 0;
   369 	if ( music_error ) {
   370 		return(-1);
   371 	}
   372 	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   373 
   374 	/* Calculate the number of ms for each callback */
   375 	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   376 
   377 	return(0);
   378 }
   379 
   380 /* Portable case-insensitive string compare function */
   381 int MIX_string_equals(const char *str1, const char *str2)
   382 {
   383 	while ( *str1 && *str2 ) {
   384 		if ( toupper((unsigned char)*str1) !=
   385 		     toupper((unsigned char)*str2) )
   386 			break;
   387 		++str1;
   388 		++str2;
   389 	}
   390 	return (!*str1 && !*str2);
   391 }
   392 
   393 /* Load a music file */
   394 Mix_Music *Mix_LoadMUS(const char *file)
   395 {
   396 	FILE *fp;
   397 	char *ext;
   398 	Uint8 magic[5], moremagic[9];
   399 	Mix_Music *music;
   400 
   401 	/* Figure out what kind of file this is */
   402 	fp = fopen(file, "rb");
   403 	if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
   404 		if ( fp != NULL ) {
   405 			fclose(fp);
   406 		}
   407 		Mix_SetError("Couldn't read from '%s'", file);
   408 		return(NULL);
   409 	}
   410 	if (!fread(moremagic, 8, 1, fp)) {
   411 		Mix_SetError("Couldn't read from '%s'", file);
   412 		return(NULL);
   413 	}
   414 	magic[4] = '\0';
   415 	moremagic[8] = '\0';
   416 	fclose(fp);
   417 
   418 	/* Figure out the file extension, so we can determine the type */
   419 	ext = strrchr(file, '.');
   420 	if ( ext ) ++ext; /* skip the dot in the extension */
   421 
   422 	/* Allocate memory for the music structure */
   423 	music = (Mix_Music *)malloc(sizeof(Mix_Music));
   424 	if ( music == NULL ) {
   425 		Mix_SetError("Out of memory");
   426 		return(NULL);
   427 	}
   428 	music->error = 0;
   429 
   430 #ifdef CMD_MUSIC
   431 	if ( music_cmd ) {
   432 		music->type = MUS_CMD;
   433 		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   434 		if ( music->data.cmd == NULL ) {
   435 			music->error = 1;
   436 		}
   437 	} else
   438 #endif
   439 #ifdef WAV_MUSIC
   440 	/* WAVE files have the magic four bytes "RIFF"
   441 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
   442 	 */
   443 	if ( (ext && MIX_string_equals(ext, "WAV")) ||
   444 	     ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
   445 	     (strcmp((char *)magic, "FORM") == 0) ) {
   446 		music->type = MUS_WAV;
   447 		music->data.wave = WAVStream_LoadSong(file, (char *)magic);
   448 		if ( music->data.wave == NULL ) {
   449 		  	Mix_SetError("Unable to load WAV file");
   450 			music->error = 1;
   451 		}
   452 	} else
   453 #endif
   454 #ifdef MID_MUSIC
   455 	/* MIDI files have the magic four bytes "MThd" */
   456 	if ( (ext && MIX_string_equals(ext, "MID")) ||
   457 	     (ext && MIX_string_equals(ext, "MIDI")) ||
   458 	     strcmp((char *)magic, "MThd") == 0  ||
   459 	     ( strcmp((char *)magic, "RIFF") == 0  &&
   460 	  	strcmp((char *)(moremagic+4), "RMID") == 0 ) ) {
   461 		music->type = MUS_MID;
   462 #ifdef USE_NATIVE_MIDI
   463   		if ( native_midi_ok ) {
   464   			music->data.nativemidi = native_midi_loadsong(file);
   465 	  		if ( music->data.nativemidi == NULL ) {
   466 		  		Mix_SetError("%s", native_midi_error());
   467 			  	music->error = 1;
   468 			}
   469 	  	} MIDI_ELSE
   470 #endif
   471 #ifdef USE_TIMIDITY_MIDI
   472 		if ( timidity_ok ) {
   473 			music->data.midi = Timidity_LoadSong(file);
   474 			if ( music->data.midi == NULL ) {
   475 				Mix_SetError("%s", Timidity_Error());
   476 				music->error = 1;
   477 			}
   478 		} else {
   479 			Mix_SetError("%s", Timidity_Error());
   480 			music->error = 1;
   481 		}
   482 #endif
   483 	} else
   484 #endif
   485 #ifdef OGG_MUSIC
   486 	/* Ogg Vorbis files have the magic four bytes "OggS" */
   487 	if ( (ext && MIX_string_equals(ext, "OGG")) ||
   488 	     strcmp((char *)magic, "OggS") == 0 ) {
   489 		music->type = MUS_OGG;
   490 		music->data.ogg = OGG_new(file);
   491 		if ( music->data.ogg == NULL ) {
   492 			music->error = 1;
   493 		}
   494 	} else
   495 #endif
   496 #ifdef FLAC_MUSIC
   497 	/* FLAC files have the magic four bytes "fLaC" */
   498 	if ( (ext && MIX_string_equals(ext, "FLAC")) ||
   499 		 strcmp((char *)magic, "fLaC") == 0 ) {
   500 		music->type = MUS_FLAC;
   501 		music->data.flac = FLAC_new(file);
   502 		if ( music->data.flac == NULL ) {
   503 			music->error = 1;
   504 		}
   505 	} else
   506 #endif
   507 #ifdef MP3_MUSIC
   508 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   509 	     (ext && MIX_string_equals(ext, "MP3")) ||
   510 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   511 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   512 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   513 		if ( Mix_Init(MIX_INIT_MP3) ) {
   514 			SMPEG_Info info;
   515 			music->type = MUS_MP3;
   516 			music->data.mp3 = smpeg.SMPEG_new(file, &info, 0);
   517 			if ( !info.has_audio ) {
   518 				Mix_SetError("MPEG file does not have any audio stream.");
   519 				music->error = 1;
   520 			} else {
   521 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   522 			}
   523 		} else {
   524 			music->error = 1;
   525 		}
   526 	} else
   527 #endif
   528 #ifdef MP3_MAD_MUSIC
   529 	if ( (ext && MIX_string_equals(ext, "MPG")) ||
   530 	     (ext && MIX_string_equals(ext, "MP3")) ||
   531 	     (ext && MIX_string_equals(ext, "MPEG")) ||
   532 	     (ext && MIX_string_equals(ext, "MAD")) ||
   533 	     (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
   534 	     (strncmp((char *)magic, "ID3", 3) == 0) ) {
   535 		music->type = MUS_MP3_MAD;
   536 		music->data.mp3_mad = mad_openFile(file, &used_mixer);
   537 		if (music->data.mp3_mad == 0) {
   538 		    Mix_SetError("Could not initialize MPEG stream.");
   539 			music->error = 1;
   540 		}
   541 	} else
   542 #endif
   543 #ifdef MOD_MUSIC
   544 	if ( 1 ) {
   545 		music->type = MUS_MOD;
   546 		music->data.module = MOD_new(file);
   547 		if ( music->data.module == NULL ) {
   548 			music->error = 1;
   549 		}
   550 	} else
   551 #endif
   552 	{
   553 		Mix_SetError("Unrecognized music format");
   554 		music->error = 1;
   555 	}
   556 	if ( music->error ) {
   557 		free(music);
   558 		music = NULL;
   559 	}
   560 	return(music);
   561 }
   562 
   563 /* Free a music chunk previously loaded */
   564 void Mix_FreeMusic(Mix_Music *music)
   565 {
   566 	if ( music ) {
   567 		/* Stop the music if it's currently playing */
   568 		SDL_LockAudio();
   569 		if ( music == music_playing ) {
   570 			/* Wait for any fade out to finish */
   571 			while ( music->fading == MIX_FADING_OUT ) {
   572 				SDL_UnlockAudio();
   573 				SDL_Delay(100);
   574 				SDL_LockAudio();
   575 			}
   576 			if ( music == music_playing ) {
   577 				music_internal_halt();
   578 			}
   579 		}
   580 		SDL_UnlockAudio();
   581 		switch (music->type) {
   582 #ifdef CMD_MUSIC
   583 			case MUS_CMD:
   584 				MusicCMD_FreeSong(music->data.cmd);
   585 				break;
   586 #endif
   587 #ifdef WAV_MUSIC
   588 			case MUS_WAV:
   589 				WAVStream_FreeSong(music->data.wave);
   590 				break;
   591 #endif
   592 #ifdef MOD_MUSIC
   593 			case MUS_MOD:
   594 				MOD_delete(music->data.module);
   595 				break;
   596 #endif
   597 #ifdef MID_MUSIC
   598 			case MUS_MID:
   599 #ifdef USE_NATIVE_MIDI
   600   				if ( native_midi_ok ) {
   601 					native_midi_freesong(music->data.nativemidi);
   602 				} MIDI_ELSE
   603 #endif
   604 #ifdef USE_TIMIDITY_MIDI
   605 				if ( timidity_ok ) {
   606 					Timidity_FreeSong(music->data.midi);
   607 				}
   608 #endif
   609 				break;
   610 #endif
   611 #ifdef OGG_MUSIC
   612 			case MUS_OGG:
   613 				OGG_delete(music->data.ogg);
   614 				break;
   615 #endif
   616 #ifdef FLAC_MUSIC
   617 			case MUS_FLAC:
   618 				FLAC_delete(music->data.flac);
   619 				break;
   620 #endif
   621 #ifdef MP3_MUSIC
   622 			case MUS_MP3:
   623 				smpeg.SMPEG_delete(music->data.mp3);
   624 				break;
   625 #endif
   626 #ifdef MP3_MAD_MUSIC
   627 			case MUS_MP3_MAD:
   628 				mad_closeFile(music->data.mp3_mad);
   629 				break;
   630 #endif
   631 			default:
   632 				/* Unknown music type?? */
   633 				break;
   634 		}
   635 		free(music);
   636 	}
   637 }
   638 
   639 /* Find out the music format of a mixer music, or the currently playing
   640    music, if 'music' is NULL.
   641 */
   642 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
   643 {
   644 	Mix_MusicType type = MUS_NONE;
   645 
   646 	if ( music ) {
   647 		type = music->type;
   648 	} else {
   649 		SDL_LockAudio();
   650 		if ( music_playing ) {
   651 			type = music_playing->type;
   652 		}
   653 		SDL_UnlockAudio();
   654 	}
   655 	return(type);
   656 }
   657 
   658 /* Play a music chunk.  Returns 0, or -1 if there was an error.
   659  */
   660 static int music_internal_play(Mix_Music *music, double position)
   661 {
   662 	int retval = 0;
   663 
   664 	/* Note the music we're playing */
   665 	if ( music_playing ) {
   666 		music_internal_halt();
   667 	}
   668 	music_playing = music;
   669 
   670 	/* Set the initial volume */
   671 	if ( music->type != MUS_MOD ) {
   672 		music_internal_initialize_volume();
   673 	}
   674 
   675 	/* Set up for playback */
   676 	switch (music->type) {
   677 #ifdef CMD_MUSIC
   678 	    case MUS_CMD:
   679 		MusicCMD_Start(music->data.cmd);
   680 		break;
   681 #endif
   682 #ifdef WAV_MUSIC
   683 	    case MUS_WAV:
   684 		WAVStream_Start(music->data.wave);
   685 		break;
   686 #endif
   687 #ifdef MOD_MUSIC
   688 	    case MUS_MOD:
   689 		MOD_play(music->data.module);
   690 		/* Player_SetVolume() does nothing before Player_Start() */
   691 		music_internal_initialize_volume();
   692 		break;
   693 #endif
   694 #ifdef MID_MUSIC
   695 	    case MUS_MID:
   696 #ifdef USE_NATIVE_MIDI
   697 		if ( native_midi_ok ) {
   698 			native_midi_start(music->data.nativemidi);
   699 		} MIDI_ELSE
   700 #endif
   701 #ifdef USE_TIMIDITY_MIDI
   702 		if ( timidity_ok ) {
   703 			Timidity_Start(music->data.midi);
   704 		}
   705 #endif
   706 		break;
   707 #endif
   708 #ifdef OGG_MUSIC
   709 	    case MUS_OGG:
   710 		OGG_play(music->data.ogg);
   711 		break;
   712 #endif
   713 #ifdef FLAC_MUSIC
   714 	    case MUS_FLAC:
   715 		FLAC_play(music->data.flac);
   716 		break;
   717 #endif
   718 #ifdef MP3_MUSIC
   719 	    case MUS_MP3:
   720 		smpeg.SMPEG_enableaudio(music->data.mp3,1);
   721 		smpeg.SMPEG_enablevideo(music->data.mp3,0);
   722 		smpeg.SMPEG_play(music_playing->data.mp3);
   723 		break;
   724 #endif
   725 #ifdef MP3_MAD_MUSIC
   726 	    case MUS_MP3_MAD:
   727 		mad_start(music->data.mp3_mad);
   728 		break;
   729 #endif
   730 	    default:
   731 		Mix_SetError("Can't play unknown music type");
   732 		retval = -1;
   733 		break;
   734 	}
   735 
   736 	/* Set the playback position, note any errors if an offset is used */
   737 	if ( retval == 0 ) {
   738 		if ( position > 0.0 ) {
   739 			if ( music_internal_position(position) < 0 ) {
   740 				Mix_SetError("Position not implemented for music type");
   741 				retval = -1;
   742 			}
   743 		} else {
   744 			music_internal_position(0.0);
   745 		}
   746 	}
   747 
   748 	/* If the setup failed, we're not playing any music anymore */
   749 	if ( retval < 0 ) {
   750 		music_playing = NULL;
   751 	}
   752 	return(retval);
   753 }
   754 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
   755 {
   756 	int retval;
   757 
   758 	/* Don't play null pointers :-) */
   759 	if ( music == NULL ) {
   760 		Mix_SetError("music parameter was NULL");
   761 		return(-1);
   762 	}
   763 
   764 	/* Setup the data */
   765 	if ( ms ) {
   766 		music->fading = MIX_FADING_IN;
   767 	} else {
   768 		music->fading = MIX_NO_FADING;
   769 	}
   770 	music->fade_step = 0;
   771 	music->fade_steps = ms/ms_per_step;
   772 
   773 	/* Play the puppy */
   774 	SDL_LockAudio();
   775 	/* If the current music is fading out, wait for the fade to complete */
   776 	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
   777 		SDL_UnlockAudio();
   778 		SDL_Delay(100);
   779 		SDL_LockAudio();
   780 	}
   781 	music_active = 1;
   782 	music_loops = loops;
   783 	retval = music_internal_play(music, position);
   784 	SDL_UnlockAudio();
   785 
   786 	return(retval);
   787 }
   788 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
   789 {
   790 	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
   791 }
   792 int Mix_PlayMusic(Mix_Music *music, int loops)
   793 {
   794 	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
   795 }
   796 
   797 /* Set the playing music position */
   798 int music_internal_position(double position)
   799 {
   800 	int retval = 0;
   801 
   802 	switch (music_playing->type) {
   803 #ifdef MOD_MUSIC
   804 	    case MUS_MOD:
   805 		MOD_jump_to_time(music_playing->data.module, position);
   806 		break;
   807 #endif
   808 #ifdef OGG_MUSIC
   809 	    case MUS_OGG:
   810 		OGG_jump_to_time(music_playing->data.ogg, position);
   811 		break;
   812 #endif
   813 #ifdef FLAC_MUSIC
   814 	    case MUS_FLAC:
   815 		FLAC_jump_to_time(music_playing->data.flac, position);
   816 		break;
   817 #endif
   818 #ifdef MP3_MUSIC
   819 	    case MUS_MP3:
   820 		if ( position > 0.0 ) {
   821 			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
   822 		} else {
   823 			smpeg.SMPEG_rewind(music_playing->data.mp3);
   824 			smpeg.SMPEG_play(music_playing->data.mp3);
   825 		}
   826 		break;
   827 #endif
   828 #ifdef MP3_MAD_MUSIC
   829 	    case MUS_MP3_MAD:
   830 		mad_seek(music_playing->data.mp3_mad, position);
   831 		break;
   832 #endif
   833 	    default:
   834 		/* TODO: Implement this for other music backends */
   835 		retval = -1;
   836 		break;
   837 	}
   838 	return(retval);
   839 }
   840 int Mix_SetMusicPosition(double position)
   841 {
   842 	int retval;
   843 
   844 	SDL_LockAudio();
   845 	if ( music_playing ) {
   846 		retval = music_internal_position(position);
   847 		if ( retval < 0 ) {
   848 			Mix_SetError("Position not implemented for music type");
   849 		}
   850 	} else {
   851 		Mix_SetError("Music isn't playing");
   852 		retval = -1;
   853 	}
   854 	SDL_UnlockAudio();
   855 
   856 	return(retval);
   857 }
   858 
   859 /* Set the music's initial volume */
   860 static void music_internal_initialize_volume(void)
   861 {
   862 	if ( music_playing->fading == MIX_FADING_IN ) {
   863 		music_internal_volume(0);
   864 	} else {
   865 		music_internal_volume(music_volume);
   866 	}
   867 }
   868 
   869 /* Set the music volume */
   870 static void music_internal_volume(int volume)
   871 {
   872 	switch (music_playing->type) {
   873 #ifdef CMD_MUSIC
   874 	    case MUS_CMD:
   875 		MusicCMD_SetVolume(volume);
   876 		break;
   877 #endif
   878 #ifdef WAV_MUSIC
   879 	    case MUS_WAV:
   880 		WAVStream_SetVolume(volume);
   881 		break;
   882 #endif
   883 #ifdef MOD_MUSIC
   884 	    case MUS_MOD:
   885 		MOD_setvolume(music_playing->data.module, volume);
   886 		break;
   887 #endif
   888 #ifdef MID_MUSIC
   889 	    case MUS_MID:
   890 #ifdef USE_NATIVE_MIDI
   891 		if ( native_midi_ok ) {
   892 			native_midi_setvolume(volume);
   893 		} MIDI_ELSE
   894 #endif
   895 #ifdef USE_TIMIDITY_MIDI
   896 		if ( timidity_ok ) {
   897 			Timidity_SetVolume(volume);
   898 		}
   899 #endif
   900 		break;
   901 #endif
   902 #ifdef OGG_MUSIC
   903 	    case MUS_OGG:
   904 		OGG_setvolume(music_playing->data.ogg, volume);
   905 		break;
   906 #endif
   907 #ifdef FLAC_MUSIC
   908 	    case MUS_FLAC:
   909 		FLAC_setvolume(music_playing->data.flac, volume);
   910 		break;
   911 #endif
   912 #ifdef MP3_MUSIC
   913 	    case MUS_MP3:
   914 		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
   915 		break;
   916 #endif
   917 #ifdef MP3_MAD_MUSIC
   918 	    case MUS_MP3_MAD:
   919 		mad_setVolume(music_playing->data.mp3_mad, volume);
   920 		break;
   921 #endif
   922 	    default:
   923 		/* Unknown music type?? */
   924 		break;
   925 	}
   926 }
   927 int Mix_VolumeMusic(int volume)
   928 {
   929 	int prev_volume;
   930 
   931 	prev_volume = music_volume;
   932 	if ( volume < 0 ) {
   933 		return prev_volume;
   934 	}
   935 	if ( volume > SDL_MIX_MAXVOLUME ) {
   936 		volume = SDL_MIX_MAXVOLUME;
   937 	}
   938 	music_volume = volume;
   939 	SDL_LockAudio();
   940 	if ( music_playing ) {
   941 		music_internal_volume(music_volume);
   942 	}
   943 	SDL_UnlockAudio();
   944 	return(prev_volume);
   945 }
   946 
   947 /* Halt playing of music */
   948 static void music_internal_halt(void)
   949 {
   950 	switch (music_playing->type) {
   951 #ifdef CMD_MUSIC
   952 	    case MUS_CMD:
   953 		MusicCMD_Stop(music_playing->data.cmd);
   954 		break;
   955 #endif
   956 #ifdef WAV_MUSIC
   957 	    case MUS_WAV:
   958 		WAVStream_Stop();
   959 		break;
   960 #endif
   961 #ifdef MOD_MUSIC
   962 	    case MUS_MOD:
   963 		MOD_stop(music_playing->data.module);
   964 		break;
   965 #endif
   966 #ifdef MID_MUSIC
   967 	    case MUS_MID:
   968 #ifdef USE_NATIVE_MIDI
   969 		if ( native_midi_ok ) {
   970 			native_midi_stop();
   971 		} MIDI_ELSE
   972 #endif
   973 #ifdef USE_TIMIDITY_MIDI
   974 		if ( timidity_ok ) {
   975 			Timidity_Stop();
   976 		}
   977 #endif
   978 		break;
   979 #endif
   980 #ifdef OGG_MUSIC
   981 	    case MUS_OGG:
   982 		OGG_stop(music_playing->data.ogg);
   983 		break;
   984 #endif
   985 #ifdef FLAC_MUSIC
   986 	    case MUS_FLAC:
   987 		FLAC_stop(music_playing->data.flac);
   988 		break;
   989 #endif
   990 #ifdef MP3_MUSIC
   991 	    case MUS_MP3:
   992 		smpeg.SMPEG_stop(music_playing->data.mp3);
   993 		break;
   994 #endif
   995 #ifdef MP3_MAD_MUSIC
   996 	    case MUS_MP3_MAD:
   997 		mad_stop(music_playing->data.mp3_mad);
   998 		break;
   999 #endif
  1000 	    default:
  1001 		/* Unknown music type?? */
  1002 		return;
  1003 	}
  1004 	music_playing->fading = MIX_NO_FADING;
  1005 	music_playing = NULL;
  1006 }
  1007 int Mix_HaltMusic(void)
  1008 {
  1009 	SDL_LockAudio();
  1010 	if ( music_playing ) {
  1011 		music_internal_halt();
  1012 	}
  1013 	SDL_UnlockAudio();
  1014 
  1015 	return(0);
  1016 }
  1017 
  1018 /* Progressively stop the music */
  1019 int Mix_FadeOutMusic(int ms)
  1020 {
  1021 	int retval = 0;
  1022 
  1023 	if (ms <= 0) {  /* just halt immediately. */
  1024 		Mix_HaltMusic();
  1025 		return 1;
  1026 	}
  1027 
  1028 	SDL_LockAudio();
  1029 	if ( music_playing) {
  1030                 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1031                 if ( music_playing->fading == MIX_NO_FADING ) {
  1032 	        	music_playing->fade_step = 0;
  1033                 } else {
  1034                         int step;
  1035                         int old_fade_steps = music_playing->fade_steps;
  1036                         if ( music_playing->fading == MIX_FADING_OUT ) {
  1037                                 step = music_playing->fade_step;
  1038                         } else {
  1039                                 step = old_fade_steps
  1040                                         - music_playing->fade_step + 1;
  1041                         }
  1042                         music_playing->fade_step = (step * fade_steps)
  1043                                 / old_fade_steps;
  1044                 }
  1045 		music_playing->fading = MIX_FADING_OUT;
  1046 		music_playing->fade_steps = fade_steps;
  1047 		retval = 1;
  1048 	}
  1049 	SDL_UnlockAudio();
  1050 
  1051 	return(retval);
  1052 }
  1053 
  1054 Mix_Fading Mix_FadingMusic(void)
  1055 {
  1056 	Mix_Fading fading = MIX_NO_FADING;
  1057 
  1058 	SDL_LockAudio();
  1059 	if ( music_playing ) {
  1060 		fading = music_playing->fading;
  1061 	}
  1062 	SDL_UnlockAudio();
  1063 
  1064 	return(fading);
  1065 }
  1066 
  1067 /* Pause/Resume the music stream */
  1068 void Mix_PauseMusic(void)
  1069 {
  1070 	music_active = 0;
  1071 }
  1072 
  1073 void Mix_ResumeMusic(void)
  1074 {
  1075 	music_active = 1;
  1076 }
  1077 
  1078 void Mix_RewindMusic(void)
  1079 {
  1080 	Mix_SetMusicPosition(0.0);
  1081 }
  1082 
  1083 int Mix_PausedMusic(void)
  1084 {
  1085 	return (music_active == 0);
  1086 }
  1087 
  1088 /* Check the status of the music */
  1089 static int music_internal_playing()
  1090 {
  1091 	int playing = 1;
  1092 	switch (music_playing->type) {
  1093 #ifdef CMD_MUSIC
  1094 	    case MUS_CMD:
  1095 		if (!MusicCMD_Active(music_playing->data.cmd)) {
  1096 			playing = 0;
  1097 		}
  1098 		break;
  1099 #endif
  1100 #ifdef WAV_MUSIC
  1101 	    case MUS_WAV:
  1102 		if ( ! WAVStream_Active() ) {
  1103 			playing = 0;
  1104 		}
  1105 		break;
  1106 #endif
  1107 #ifdef MOD_MUSIC
  1108 	    case MUS_MOD:
  1109 		if ( ! MOD_playing(music_playing->data.module) ) {
  1110 			playing = 0;
  1111 		}
  1112 		break;
  1113 #endif
  1114 #ifdef MID_MUSIC
  1115 	    case MUS_MID:
  1116 #ifdef USE_NATIVE_MIDI
  1117 		if ( native_midi_ok ) {
  1118 			if ( ! native_midi_active() )
  1119 				playing = 0;
  1120 		} MIDI_ELSE
  1121 #endif
  1122 #ifdef USE_TIMIDITY_MIDI
  1123 		if ( timidity_ok ) {
  1124 			if ( ! Timidity_Active() )
  1125 				playing = 0;
  1126 		}
  1127 #endif
  1128 		break;
  1129 #endif
  1130 #ifdef OGG_MUSIC
  1131 	    case MUS_OGG:
  1132 		if ( ! OGG_playing(music_playing->data.ogg) ) {
  1133 			playing = 0;
  1134 		}
  1135 		break;
  1136 #endif
  1137 #ifdef FLAC_MUSIC
  1138 	    case MUS_FLAC:
  1139 		if ( ! FLAC_playing(music_playing->data.flac) ) {
  1140 			playing = 0;
  1141 		}
  1142 		break;
  1143 #endif
  1144 #ifdef MP3_MUSIC
  1145 	    case MUS_MP3:
  1146 		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1147 			playing = 0;
  1148 		break;
  1149 #endif
  1150 #ifdef MP3_MAD_MUSIC
  1151 	    case MUS_MP3_MAD:
  1152 		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1153 			playing = 0;
  1154 		}
  1155 		break;
  1156 #endif
  1157 	    default:
  1158 		playing = 0;
  1159 		break;
  1160 	}
  1161 	return(playing);
  1162 }
  1163 int Mix_PlayingMusic(void)
  1164 {
  1165 	int playing = 0;
  1166 
  1167 	SDL_LockAudio();
  1168 	if ( music_playing ) {
  1169 		playing = music_internal_playing();
  1170 	}
  1171 	SDL_UnlockAudio();
  1172 
  1173 	return(playing);
  1174 }
  1175 
  1176 /* Set the external music playback command */
  1177 int Mix_SetMusicCMD(const char *command)
  1178 {
  1179 	Mix_HaltMusic();
  1180 	if ( music_cmd ) {
  1181 		free(music_cmd);
  1182 		music_cmd = NULL;
  1183 	}
  1184 	if ( command ) {
  1185 		music_cmd = (char *)malloc(strlen(command)+1);
  1186 		if ( music_cmd == NULL ) {
  1187 			return(-1);
  1188 		}
  1189 		strcpy(music_cmd, command);
  1190 	}
  1191 	return(0);
  1192 }
  1193 
  1194 int Mix_SetSynchroValue(int i)
  1195 {
  1196 	/* Not supported by any players at this time */
  1197 	return(-1);
  1198 }
  1199 
  1200 int Mix_GetSynchroValue(void)
  1201 {
  1202 	/* Not supported by any players at this time */
  1203 	return(-1);
  1204 }
  1205 
  1206 
  1207 /* Uninitialize the music players */
  1208 void close_music(void)
  1209 {
  1210 	Mix_HaltMusic();
  1211 #ifdef CMD_MUSIC
  1212 	Mix_SetMusicCMD(NULL);
  1213 #endif
  1214 #ifdef MOD_MUSIC
  1215 	MOD_exit();
  1216 #endif
  1217 #ifdef MID_MUSIC
  1218 # ifdef USE_TIMIDITY_MIDI
  1219 	Timidity_Close();
  1220 # endif
  1221 #endif
  1222 
  1223 	/* rcg06042009 report available decoders at runtime. */
  1224 	free(music_decoders);
  1225 	music_decoders = NULL;
  1226 	num_decoders = 0;
  1227 }
  1228 
  1229 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
  1230 {
  1231 	Uint8 magic[5];	  /*Apparently there is no way to check if the file is really a MOD,*/
  1232 	/*		    or there are too many formats supported by MikMod or MikMod does */
  1233 	/*		    this check by itself. If someone implements other formats (e.g. MP3) */
  1234 	/*		    the check can be uncommented */
  1235 	Uint8 moremagic[9];
  1236 	Mix_Music *music;
  1237 	int start;
  1238 
  1239 	if (!rw) {
  1240 		Mix_SetError("RWops pointer is NULL");
  1241 		return NULL;
  1242 	}
  1243 
  1244 	/* Figure out what kind of file this is */
  1245 	start = SDL_RWtell(rw);
  1246 	if ( SDL_RWread(rw,magic,1,4) != 4 ||
  1247 	     SDL_RWread(rw,moremagic,1,8) != 8 ) {
  1248 		Mix_SetError("Couldn't read from RWops");
  1249 		return NULL;
  1250 	}
  1251 	SDL_RWseek(rw, start, RW_SEEK_SET);
  1252 	magic[4]='\0';
  1253 	moremagic[8] = '\0';
  1254 
  1255 	/* Allocate memory for the music structure */
  1256 	music=(Mix_Music *)malloc(sizeof(Mix_Music));
  1257 	if (music==NULL ) {
  1258 		Mix_SetError("Out of memory");
  1259 		return(NULL);
  1260 	}
  1261 	music->error = 0;
  1262 
  1263 #ifdef WAV_MUSIC
  1264 	/* WAVE files have the magic four bytes "RIFF"
  1265 	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
  1266 	 */
  1267 	if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
  1268 	     (strcmp((char *)magic, "FORM") == 0) ) {
  1269 		music->type = MUS_WAV;
  1270 		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
  1271 		if ( music->data.wave == NULL ) {
  1272 			music->error = 1;
  1273 		}
  1274 
  1275 	} else
  1276 #endif
  1277 #ifdef OGG_MUSIC
  1278 	/* Ogg Vorbis files have the magic four bytes "OggS" */
  1279 	if ( strcmp((char *)magic, "OggS") == 0 ) {
  1280 		music->type = MUS_OGG;
  1281 		music->data.ogg = OGG_new_RW(rw);
  1282 		if ( music->data.ogg == NULL ) {
  1283 			music->error = 1;
  1284 		}
  1285 	} else
  1286 #endif
  1287 #ifdef FLAC_MUSIC
  1288 	/* FLAC files have the magic four bytes "fLaC" */
  1289 	if ( strcmp((char *)magic, "fLaC") == 0 ) {
  1290 		music->type = MUS_FLAC;
  1291 		music->data.flac = FLAC_new_RW(rw);
  1292 		if ( music->data.flac == NULL ) {
  1293 			music->error = 1;
  1294 		}
  1295 	} else
  1296 #endif
  1297 #ifdef MP3_MUSIC
  1298 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1299 		if ( Mix_Init(MIX_INIT_MP3) ) {
  1300 			SMPEG_Info info;
  1301 			music->type = MUS_MP3;
  1302 			music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
  1303 			if ( !info.has_audio ) {
  1304 				Mix_SetError("MPEG file does not have any audio stream.");
  1305 				music->error = 1;
  1306 			} else {
  1307 				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
  1308 			}
  1309 		} else {
  1310 			music->error = 1;
  1311 		}
  1312 	} else
  1313 #endif
  1314 #ifdef MP3_MAD_MUSIC
  1315 	if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
  1316 		music->type = MUS_MP3_MAD;
  1317 		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
  1318 		if (music->data.mp3_mad == 0) {
  1319 			Mix_SetError("Could not initialize MPEG stream.");
  1320 			music->error = 1;
  1321 		}
  1322 	} else
  1323 #endif
  1324 #ifdef MID_MUSIC
  1325 	/* MIDI files have the magic four bytes "MThd" */
  1326 	if ( strcmp((char *)magic, "MThd") == 0 ) {
  1327 		music->type = MUS_MID;
  1328 #ifdef USE_NATIVE_MIDI
  1329 		if ( native_midi_ok ) {
  1330 			music->data.nativemidi = native_midi_loadsong_RW(rw);
  1331 	  		if ( music->data.nativemidi == NULL ) {
  1332 		  		Mix_SetError("%s", native_midi_error());
  1333 			  	music->error = 1;
  1334 			}
  1335 		} MIDI_ELSE
  1336 #endif
  1337 #ifdef USE_TIMIDITY_MIDI
  1338 		if ( timidity_ok ) {
  1339 			music->data.midi = Timidity_LoadSong_RW(rw);
  1340 			if ( music->data.midi == NULL ) {
  1341 				Mix_SetError("%s", Timidity_Error());
  1342 				music->error = 1;
  1343 			}
  1344 		} else {
  1345 			Mix_SetError("%s", Timidity_Error());
  1346 			music->error = 1;
  1347 		}
  1348 #endif
  1349 	} else
  1350 #endif
  1351 #ifdef MOD_MUSIC
  1352 	if (1) {
  1353 		music->type=MUS_MOD;
  1354 		music->data.module = MOD_new_RW(rw);
  1355 		if ( music->data.module == NULL ) {
  1356 			music->error = 1;
  1357 		}
  1358 	} else
  1359 #endif
  1360 	{
  1361 		Mix_SetError("Unrecognized music format");
  1362 		music->error=1;
  1363 	}
  1364 	if (music->error) {
  1365 		free(music);
  1366 		music=NULL;
  1367 	}
  1368 	return(music);
  1369 }