PageRenderTime 68ms CodeModel.GetById 13ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 1ms

/project/jni/sdl_mixer/music.c

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