music.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 29 Jan 2006 06:47:14 +0000
changeset 285 9274a084491d
parent 281 33730d0864d8
child 310 77e72cff08e7
permissions -rw-r--r--
Date: Fri, 24 Dec 2004 16:11:30 +0100
From: Gaetan de Menten
Subject: Re: [SDL] SDL_mixer and implicit looping of module music files

Maybe it will be clearer with this information copy-pasted from
Mikmod's documentation:

BOOL wrap
If nonzero, module wraps to its restart position when it is
finished, to play continuously. Default value is zero (play only
once).

BOOL loop
If nonzero, all in-module loops are processed; otherwise, backward
loops which decrease the current position are not processed (i.e. only
forward loops, and backward loops in the same pattern, are processed).
This ensures that the module never loops endlessly. The default value
is 1 (all loops are processed).

and this is from SDL_mixer's code:

music->data.module->wrap = 0;
music->data.module->loop = 0;

What I don't like is the loop = 0 (note it is not the default value in
mikmod) and that there is no way to change it, the wrap = 0 is fine
with me.

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