music.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 13 Jan 2012 03:15:19 -0500
changeset 561 87bdb4c81c0b
parent 547 a9a5f18ea123
child 565 64688955a7b2
permissions -rw-r--r--
Fixed memory crash loading Ogg Vorbis files on Windows
The pointer to the audio data could come from SDL_LoadWAV_RW() or from our other loaders, and we need to use the correct free() to release the memory. So we'll just use the SDL memory functions for consistency.
This pretty much only matters on Windows where we can't guarantee a certain C runtime so we provide our own malloc() and friends.
slouken@0
     1
/*
slouken@518
     2
  SDL_mixer:  An audio mixer library based on the SDL library
slouken@518
     3
  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
slouken@0
     4
slouken@518
     5
  This software is provided 'as-is', without any express or implied
slouken@518
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@518
     7
  arising from the use of this software.
slouken@0
     8
slouken@518
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@518
    10
  including commercial applications, and to alter it and redistribute it
slouken@518
    11
  freely, subject to the following restrictions:
slouken@0
    12
slouken@518
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@518
    14
     claim that you wrote the original software. If you use this software
slouken@518
    15
     in a product, an acknowledgment in the product documentation would be
slouken@518
    16
     appreciated but is not required.
slouken@518
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@518
    18
     misrepresented as being the original software.
slouken@518
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@0
    20
*/
slouken@0
    21
slouken@140
    22
/* $Id$ */
slouken@138
    23
slouken@3
    24
#include <stdlib.h>
slouken@3
    25
#include <string.h>
slouken@125
    26
#include <ctype.h>
icculus@280
    27
#include <assert.h>
slouken@24
    28
#include "SDL_endian.h"
slouken@24
    29
#include "SDL_audio.h"
slouken@29
    30
#include "SDL_timer.h"
slouken@0
    31
slouken@34
    32
#include "SDL_mixer.h"
slouken@0
    33
slouken@0
    34
#ifdef CMD_MUSIC
slouken@0
    35
#include "music_cmd.h"
slouken@0
    36
#endif
slouken@0
    37
#ifdef WAV_MUSIC
slouken@0
    38
#include "wavestream.h"
slouken@0
    39
#endif
slouken@481
    40
#ifdef MODPLUG_MUSIC
slouken@481
    41
#include "music_modplug.h"
slouken@481
    42
#endif
slouken@411
    43
#ifdef MOD_MUSIC
slouken@411
    44
#include "music_mod.h"
slouken@0
    45
#endif
slouken@0
    46
#ifdef MID_MUSIC
slouken@106
    47
#  ifdef USE_TIMIDITY_MIDI
slouken@106
    48
#    include "timidity.h"
slouken@106
    49
#  endif
chewi@506
    50
#  ifdef USE_FLUIDSYNTH_MIDI
chewi@506
    51
#    include "fluidsynth.h"
chewi@506
    52
#  endif
slouken@106
    53
#  ifdef USE_NATIVE_MIDI
slouken@106
    54
#    include "native_midi.h"
slouken@106
    55
#  endif
slouken@0
    56
#endif
slouken@63
    57
#ifdef OGG_MUSIC
slouken@63
    58
#include "music_ogg.h"
slouken@63
    59
#endif
slouken@0
    60
#ifdef MP3_MUSIC
slouken@314
    61
#include "dynamic_mp3.h"
slouken@357
    62
#endif
slouken@357
    63
#ifdef MP3_MAD_MUSIC
slouken@357
    64
#include "music_mad.h"
slouken@357
    65
#endif
slouken@382
    66
#ifdef FLAC_MUSIC
slouken@382
    67
#include "music_flac.h"
slouken@382
    68
#endif
slouken@0
    69
slouken@357
    70
#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
slouken@0
    71
static SDL_AudioSpec used_mixer;
slouken@0
    72
#endif
slouken@0
    73
slouken@357
    74
slouken@42
    75
int volatile music_active = 1;
slouken@42
    76
static int volatile music_stopped = 0;
slouken@0
    77
static int music_loops = 0;
slouken@0
    78
static char *music_cmd = NULL;
slouken@42
    79
static Mix_Music * volatile music_playing = NULL;
slouken@17
    80
static int music_volume = MIX_MAX_VOLUME;
megastep@4
    81
slouken@0
    82
struct _Mix_Music {
slouken@177
    83
	Mix_MusicType type;
slouken@0
    84
	union {
slouken@0
    85
#ifdef CMD_MUSIC
slouken@0
    86
		MusicCMD *cmd;
slouken@0
    87
#endif
slouken@0
    88
#ifdef WAV_MUSIC
slouken@0
    89
		WAVStream *wave;
slouken@0
    90
#endif
slouken@481
    91
#ifdef MODPLUG_MUSIC
slouken@481
    92
		modplug_data *modplug;
slouken@481
    93
#endif
slouken@411
    94
#ifdef MOD_MUSIC
slouken@411
    95
		struct MODULE *module;
slouken@0
    96
#endif
slouken@0
    97
#ifdef MID_MUSIC
slouken@106
    98
#ifdef USE_TIMIDITY_MIDI
slouken@0
    99
		MidiSong *midi;
slouken@106
   100
#endif
chewi@506
   101
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   102
		FluidSynthMidiSong *fluidsynthmidi;
chewi@506
   103
#endif
slouken@98
   104
#ifdef USE_NATIVE_MIDI
slouken@98
   105
		NativeMidiSong *nativemidi;
slouken@98
   106
#endif
slouken@0
   107
#endif
slouken@63
   108
#ifdef OGG_MUSIC
slouken@63
   109
		OGG_music *ogg;
slouken@63
   110
#endif
slouken@0
   111
#ifdef MP3_MUSIC
slouken@0
   112
		SMPEG *mp3;
slouken@0
   113
#endif
slouken@357
   114
#ifdef MP3_MAD_MUSIC
slouken@357
   115
		mad_data *mp3_mad;
slouken@357
   116
#endif
slouken@382
   117
#ifdef FLAC_MUSIC
slouken@382
   118
		FLAC_music *flac;
slouken@382
   119
#endif
slouken@0
   120
	} data;
megastep@4
   121
	Mix_Fading fading;
slouken@17
   122
	int fade_step;
slouken@17
   123
	int fade_steps;
slouken@0
   124
	int error;
slouken@0
   125
};
slouken@29
   126
#ifdef MID_MUSIC
slouken@106
   127
#ifdef USE_TIMIDITY_MIDI
slouken@0
   128
static int timidity_ok;
slouken@142
   129
static int samplesize;
slouken@106
   130
#endif
chewi@506
   131
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   132
static int fluidsynth_ok;
chewi@506
   133
#endif
slouken@98
   134
#ifdef USE_NATIVE_MIDI
slouken@98
   135
static int native_midi_ok;
slouken@98
   136
#endif
slouken@29
   137
#endif
slouken@0
   138
slouken@17
   139
/* Used to calculate fading steps */
slouken@17
   140
static int ms_per_step;
slouken@17
   141
icculus@390
   142
/* rcg06042009 report available decoders at runtime. */
icculus@390
   143
static const char **music_decoders = NULL;
icculus@390
   144
static int num_decoders = 0;
icculus@390
   145
chewi@506
   146
/* Semicolon-separated SoundFont paths */
chewi@506
   147
#ifdef MID_MUSIC
chewi@506
   148
char* soundfont_paths = NULL;
chewi@506
   149
#endif
chewi@506
   150
slouken@466
   151
int Mix_GetNumMusicDecoders(void)
icculus@390
   152
{
icculus@390
   153
	return(num_decoders);
icculus@390
   154
}
icculus@390
   155
icculus@390
   156
const char *Mix_GetMusicDecoder(int index)
icculus@390
   157
{
icculus@390
   158
	if ((index < 0) || (index >= num_decoders)) {
icculus@390
   159
		return NULL;
icculus@390
   160
	}
icculus@390
   161
	return(music_decoders[index]);
icculus@390
   162
}
icculus@390
   163
icculus@390
   164
static void add_music_decoder(const char *decoder)
icculus@390
   165
{
slouken@561
   166
	void *ptr = SDL_realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
icculus@390
   167
	if (ptr == NULL) {
icculus@390
   168
		return;  /* oh well, go on without it. */
icculus@390
   169
	}
slouken@411
   170
	music_decoders = (const char **) ptr;
icculus@390
   171
	music_decoders[num_decoders++] = decoder;
icculus@390
   172
}
icculus@390
   173
megastep@10
   174
/* Local low-level functions prototypes */
icculus@237
   175
static void music_internal_initialize_volume(void);
slouken@173
   176
static void music_internal_volume(int volume);
slouken@173
   177
static int  music_internal_play(Mix_Music *music, double position);
slouken@173
   178
static int  music_internal_position(double position);
slouken@173
   179
static int  music_internal_playing();
slouken@173
   180
static void music_internal_halt(void);
megastep@7
   181
slouken@29
   182
slouken@29
   183
/* Support for hooking when the music has finished */
slouken@29
   184
static void (*music_finished_hook)(void) = NULL;
slouken@29
   185
slouken@29
   186
void Mix_HookMusicFinished(void (*music_finished)(void))
slouken@29
   187
{
slouken@29
   188
	SDL_LockAudio();
slouken@29
   189
	music_finished_hook = music_finished;
slouken@29
   190
	SDL_UnlockAudio();
slouken@29
   191
}
slouken@29
   192
slouken@29
   193
icculus@281
   194
/* If music isn't playing, halt it if no looping is required, restart it */
icculus@281
   195
/* otherwhise. NOP if the music is playing */
icculus@281
   196
static int music_halt_or_loop (void)
icculus@281
   197
{
icculus@281
   198
	/* Restart music if it has to loop */
slouken@528
   199
	
icculus@281
   200
	if (!music_internal_playing()) 
icculus@281
   201
	{
slouken@541
   202
#ifdef USE_NATIVE_MIDI
slouken@533
   203
		/* Native MIDI handles looping internally */
slouken@533
   204
		if (music_playing->type == MUS_MID && native_midi_ok) {
slouken@533
   205
			music_loops = 0;
slouken@533
   206
		}
slouken@541
   207
#endif
slouken@533
   208
icculus@281
   209
		/* Restart music if it has to loop at a high level */
slouken@533
   210
		if (music_loops)
icculus@281
   211
		{
slouken@533
   212
			Mix_Fading current_fade;
slouken@533
   213
			--music_loops;
slouken@533
   214
			current_fade = music_playing->fading;
icculus@281
   215
			music_internal_play(music_playing, 0.0);
icculus@281
   216
			music_playing->fading = current_fade;
icculus@281
   217
		} 
icculus@281
   218
		else 
icculus@281
   219
		{
icculus@281
   220
			music_internal_halt();
icculus@281
   221
			if (music_finished_hook)
icculus@281
   222
				music_finished_hook();
icculus@281
   223
			
icculus@281
   224
			return 0;
icculus@281
   225
		}
icculus@281
   226
	}
icculus@281
   227
	
icculus@281
   228
	return 1;
icculus@281
   229
}
icculus@281
   230
icculus@281
   231
icculus@281
   232
slouken@0
   233
/* Mixing function */
slouken@0
   234
void music_mixer(void *udata, Uint8 *stream, int len)
slouken@0
   235
{
slouken@407
   236
	int left = 0;
slouken@407
   237
slouken@173
   238
	if ( music_playing && music_active ) {
megastep@13
   239
		/* Handle fading */
slouken@17
   240
		if ( music_playing->fading != MIX_NO_FADING ) {
slouken@17
   241
			if ( music_playing->fade_step++ < music_playing->fade_steps ) {
slouken@173
   242
				int volume;
slouken@26
   243
				int fade_step = music_playing->fade_step;
slouken@26
   244
				int fade_steps = music_playing->fade_steps;
slouken@17
   245
megastep@4
   246
				if ( music_playing->fading == MIX_FADING_OUT ) {
slouken@173
   247
					volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
slouken@17
   248
				} else { /* Fading in */
slouken@173
   249
					volume = (music_volume * fade_step) / fade_steps;
slouken@17
   250
				}
slouken@173
   251
				music_internal_volume(volume);
slouken@17
   252
			} else {
slouken@17
   253
				if ( music_playing->fading == MIX_FADING_OUT ) {
slouken@173
   254
					music_internal_halt();
slouken@173
   255
					if ( music_finished_hook ) {
slouken@173
   256
						music_finished_hook();
slouken@173
   257
					}
megastep@4
   258
					return;
megastep@4
   259
				}
megastep@4
   260
				music_playing->fading = MIX_NO_FADING;
megastep@4
   261
			}
megastep@4
   262
		}
icculus@281
   263
		
slouken@528
   264
		music_halt_or_loop();
slouken@528
   265
		if (!music_internal_playing())
slouken@528
   266
			return;
slouken@528
   267
slouken@0
   268
		switch (music_playing->type) {
slouken@0
   269
#ifdef CMD_MUSIC
slouken@0
   270
			case MUS_CMD:
slouken@0
   271
				/* The playing is done externally */
slouken@0
   272
				break;
slouken@0
   273
#endif
slouken@0
   274
#ifdef WAV_MUSIC
slouken@0
   275
			case MUS_WAV:
slouken@407
   276
				left = WAVStream_PlaySome(stream, len);
slouken@0
   277
				break;
slouken@0
   278
#endif
slouken@481
   279
#ifdef MODPLUG_MUSIC
slouken@481
   280
			case MUS_MODPLUG:
slouken@481
   281
				left = modplug_playAudio(music_playing->data.modplug, stream, len);
slouken@481
   282
				break;
slouken@481
   283
#endif
slouken@411
   284
#ifdef MOD_MUSIC
slouken@0
   285
			case MUS_MOD:
slouken@411
   286
				left = MOD_playAudio(music_playing->data.module, stream, len);
slouken@0
   287
				break;
slouken@0
   288
#endif
slouken@0
   289
#ifdef MID_MUSIC
chewi@506
   290
			case MUS_MID:
slouken@529
   291
#ifdef USE_NATIVE_MIDI
slouken@529
   292
  				if ( native_midi_ok ) {
slouken@529
   293
					/* Native midi is handled asynchronously */
slouken@529
   294
					goto skip;
slouken@529
   295
	  			}
slouken@529
   296
#endif
chewi@506
   297
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   298
				if ( fluidsynth_ok ) {
chewi@506
   299
					fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
slouken@528
   300
					goto skip;
chewi@506
   301
				}
chewi@506
   302
#endif
slouken@106
   303
#ifdef USE_TIMIDITY_MIDI
slouken@98
   304
				if ( timidity_ok ) {
slouken@98
   305
					int samples = len / samplesize;
slouken@98
   306
  					Timidity_PlaySome(stream, samples);
slouken@528
   307
					goto skip;
slouken@98
   308
				}
chewi@506
   309
#endif
slouken@0
   310
				break;
slouken@0
   311
#endif
slouken@63
   312
#ifdef OGG_MUSIC
slouken@63
   313
			case MUS_OGG:
icculus@281
   314
				
slouken@407
   315
				left = OGG_playAudio(music_playing->data.ogg, stream, len);
slouken@63
   316
				break;
slouken@63
   317
#endif
slouken@382
   318
#ifdef FLAC_MUSIC
slouken@382
   319
			case MUS_FLAC:
slouken@407
   320
				left = FLAC_playAudio(music_playing->data.flac, stream, len);
slouken@382
   321
				break;
slouken@382
   322
#endif
slouken@0
   323
#ifdef MP3_MUSIC
slouken@26
   324
			case MUS_MP3:
slouken@407
   325
				left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
slouken@0
   326
				break;
slouken@0
   327
#endif
slouken@357
   328
#ifdef MP3_MAD_MUSIC
slouken@357
   329
			case MUS_MP3_MAD:
slouken@407
   330
				left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
slouken@357
   331
				break;
slouken@357
   332
#endif
slouken@0
   333
			default:
slouken@0
   334
				/* Unknown music type?? */
slouken@0
   335
				break;
slouken@0
   336
		}
slouken@528
   337
	}
slouken@407
   338
slouken@528
   339
skip:
slouken@528
   340
	/* Handle seamless music looping */
slouken@528
   341
	if (left > 0 && left < len) {
icculus@509
   342
		music_halt_or_loop();
slouken@528
   343
		if (music_internal_playing())
icculus@509
   344
			music_mixer(udata, stream+(len-left), left);
slouken@407
   345
	}
slouken@0
   346
}
slouken@0
   347
slouken@0
   348
/* Initialize the music players with a certain desired audio format */
slouken@0
   349
int open_music(SDL_AudioSpec *mixer)
slouken@0
   350
{
slouken@0
   351
#ifdef WAV_MUSIC
slouken@479
   352
	if ( WAVStream_Init(mixer) == 0 ) {
icculus@390
   353
		add_music_decoder("WAVE");
slouken@0
   354
	}
slouken@0
   355
#endif
slouken@481
   356
#ifdef MODPLUG_MUSIC
icculus@484
   357
	if ( modplug_init(mixer) == 0 ) {
slouken@481
   358
		add_music_decoder("MODPLUG");
slouken@481
   359
	}
slouken@481
   360
#endif
slouken@411
   361
#ifdef MOD_MUSIC
slouken@479
   362
	if ( MOD_init(mixer) == 0 ) {
slouken@411
   363
		add_music_decoder("MIKMOD");
slouken@0
   364
	}
slouken@0
   365
#endif
slouken@0
   366
#ifdef MID_MUSIC
slouken@106
   367
#ifdef USE_TIMIDITY_MIDI
slouken@142
   368
	samplesize = mixer->size / mixer->samples;
slouken@100
   369
	if ( Timidity_Init(mixer->freq, mixer->format,
slouken@102
   370
	                    mixer->channels, mixer->samples) == 0 ) {
slouken@100
   371
		timidity_ok = 1;
icculus@390
   372
		add_music_decoder("TIMIDITY");
slouken@0
   373
	} else {
slouken@0
   374
		timidity_ok = 0;
slouken@0
   375
	}
slouken@106
   376
#endif
chewi@506
   377
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   378
	if ( fluidsynth_init(mixer) == 0 ) {
chewi@506
   379
		fluidsynth_ok = 1;
chewi@506
   380
		add_music_decoder("FLUIDSYNTH");
chewi@506
   381
	} else {
chewi@506
   382
		fluidsynth_ok = 0;
chewi@506
   383
	}
chewi@506
   384
#endif
slouken@100
   385
#ifdef USE_NATIVE_MIDI
chewi@506
   386
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   387
	native_midi_ok = !fluidsynth_ok;
chewi@506
   388
	if ( native_midi_ok )
chewi@506
   389
#endif
slouken@106
   390
#ifdef USE_TIMIDITY_MIDI
chewi@506
   391
		native_midi_ok = !timidity_ok;
slouken@415
   392
	if ( !native_midi_ok ) {
slouken@415
   393
		native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
slouken@415
   394
	}
slouken@106
   395
	if ( native_midi_ok )
slouken@106
   396
#endif
slouken@101
   397
		native_midi_ok = native_midi_detect();
icculus@390
   398
	if ( native_midi_ok )
icculus@390
   399
		add_music_decoder("NATIVEMIDI");
slouken@100
   400
#endif
slouken@0
   401
#endif
slouken@63
   402
#ifdef OGG_MUSIC
slouken@479
   403
	if ( OGG_init(mixer) == 0 ) {
icculus@390
   404
		add_music_decoder("OGG");
slouken@63
   405
	}
slouken@63
   406
#endif
slouken@382
   407
#ifdef FLAC_MUSIC
slouken@479
   408
	if ( FLAC_init(mixer) == 0 ) {
icculus@390
   409
		add_music_decoder("FLAC");
slouken@382
   410
	}
slouken@382
   411
#endif
slouken@357
   412
#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
slouken@0
   413
	/* Keep a copy of the mixer */
slouken@0
   414
	used_mixer = *mixer;
icculus@390
   415
	add_music_decoder("MP3");
slouken@0
   416
#endif
icculus@390
   417
slouken@42
   418
	music_playing = NULL;
megastep@7
   419
	music_stopped = 0;
slouken@0
   420
	Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
slouken@0
   421
slouken@26
   422
	/* Calculate the number of ms for each callback */
slouken@44
   423
	ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
slouken@17
   424
slouken@0
   425
	return(0);
slouken@0
   426
}
slouken@0
   427
slouken@125
   428
/* Portable case-insensitive string compare function */
slouken@125
   429
int MIX_string_equals(const char *str1, const char *str2)
slouken@125
   430
{
slouken@125
   431
	while ( *str1 && *str2 ) {
slouken@125
   432
		if ( toupper((unsigned char)*str1) !=
slouken@125
   433
		     toupper((unsigned char)*str2) )
slouken@125
   434
			break;
slouken@125
   435
		++str1;
slouken@125
   436
		++str2;
slouken@125
   437
	}
slouken@125
   438
	return (!*str1 && !*str2);
slouken@125
   439
}
slouken@125
   440
slouken@542
   441
static int detect_mp3(Uint8 *magic)
slouken@542
   442
{
slouken@542
   443
	if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
slouken@542
   444
		return 1;
slouken@542
   445
	}
slouken@542
   446
slouken@542
   447
	/* Detection code lifted from SMPEG */
slouken@542
   448
	if(((magic[0] & 0xff) != 0xff) || // No sync bits
slouken@542
   449
	   ((magic[1] & 0xf0) != 0xf0) || //
slouken@542
   450
	   ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
slouken@542
   451
	   ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
slouken@542
   452
	   ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
slouken@542
   453
	   ((magic[1] & 0x06) == 0x00)) { // Layer is 4
slouken@542
   454
		return(0);
slouken@542
   455
	}
slouken@542
   456
	return 1;
slouken@542
   457
}
slouken@542
   458
slouken@542
   459
/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
slouken@542
   460
 * assumed and MUS_MOD will be returned, meaning that the format might not
slouken@542
   461
 * actually be MOD-based.
slouken@542
   462
 *
slouken@542
   463
 * Returns MUS_NONE in case of errors. */
slouken@542
   464
static Mix_MusicType detect_music_type(SDL_RWops *rw)
slouken@542
   465
{
slouken@542
   466
	Uint8 magic[5];
slouken@542
   467
	Uint8 moremagic[9];
slouken@542
   468
slouken@542
   469
	int start = SDL_RWtell(rw);
slouken@542
   470
	if (SDL_RWread(rw, magic, 1, 4) != 4 || SDL_RWread(rw, moremagic, 1, 8) != 8 ) {
slouken@542
   471
		Mix_SetError("Couldn't read from RWops");
slouken@542
   472
		return MUS_NONE;
slouken@542
   473
	}
slouken@542
   474
	SDL_RWseek(rw, start, RW_SEEK_SET);
slouken@542
   475
	magic[4]='\0';
slouken@542
   476
	moremagic[8] = '\0';
slouken@542
   477
slouken@542
   478
	/* WAVE files have the magic four bytes "RIFF"
slouken@542
   479
	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
slouken@542
   480
	if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
slouken@542
   481
		(strcmp((char *)magic, "FORM") == 0)) {
slouken@542
   482
		return MUS_WAV;
slouken@542
   483
	}
slouken@542
   484
slouken@542
   485
	/* Ogg Vorbis files have the magic four bytes "OggS" */
slouken@542
   486
	if (strcmp((char *)magic, "OggS") == 0) {
slouken@542
   487
		return MUS_OGG;
slouken@542
   488
	}
slouken@542
   489
slouken@542
   490
	/* FLAC files have the magic four bytes "fLaC" */
slouken@542
   491
	if (strcmp((char *)magic, "fLaC") == 0) {
slouken@542
   492
		return MUS_FLAC;
slouken@542
   493
	}
slouken@542
   494
slouken@542
   495
	/* MIDI files have the magic four bytes "MThd" */
slouken@542
   496
	if (strcmp((char *)magic, "MThd") == 0) {
slouken@542
   497
		return MUS_MID;
slouken@542
   498
	}
slouken@542
   499
slouken@542
   500
	if (detect_mp3(magic)) {
slouken@542
   501
		return MUS_MP3;
slouken@542
   502
	}
slouken@542
   503
slouken@542
   504
	/* Assume MOD format.
slouken@542
   505
	 *
slouken@542
   506
	 * Apparently there is no way to check if the file is really a MOD,
slouken@542
   507
	 * or there are too many formats supported by MikMod/ModPlug, or
slouken@542
   508
	 * MikMod/ModPlug does this check by itself. */
slouken@542
   509
	return MUS_MOD;
slouken@542
   510
}
slouken@542
   511
slouken@0
   512
/* Load a music file */
slouken@0
   513
Mix_Music *Mix_LoadMUS(const char *file)
slouken@0
   514
{
slouken@542
   515
	SDL_RWops *rw;
slouken@542
   516
	Mix_Music *music;
slouken@542
   517
	Mix_MusicType type;
slouken@542
   518
	char *ext = strrchr(file, '.');
slouken@542
   519
slouken@542
   520
#ifdef CMD_MUSIC
slouken@542
   521
	if ( music_cmd ) {
slouken@542
   522
		/* Allocate memory for the music structure */
slouken@561
   523
		music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
slouken@542
   524
		if ( music == NULL ) {
slouken@542
   525
			Mix_SetError("Out of memory");
slouken@542
   526
			return(NULL);
slouken@542
   527
		}
slouken@542
   528
		music->error = 0;
slouken@542
   529
		music->type = MUS_CMD;
slouken@542
   530
		music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
slouken@542
   531
		if ( music->data.cmd == NULL ) {
slouken@561
   532
			SDL_free(music);
slouken@542
   533
			music == NULL;
slouken@542
   534
		}
slouken@542
   535
		return music;
slouken@542
   536
	}
slouken@542
   537
#endif
slouken@542
   538
slouken@542
   539
	rw = SDL_RWFromFile(file, "rb");
slouken@542
   540
	if ( rw == NULL ) {
slouken@542
   541
		Mix_SetError("Couldn't open '%s'", file);
slouken@542
   542
		return NULL;
slouken@542
   543
	}
slouken@542
   544
slouken@542
   545
	/* Use the extension as a first guess on the file type */
slouken@542
   546
	type = MUS_NONE;
slouken@542
   547
	ext = strrchr(file, '.');
slouken@542
   548
	/* No need to guard these with #ifdef *_MUSIC stuff,
slouken@542
   549
	 * since we simply call Mix_LoadMUSType_RW() later */
slouken@542
   550
	if ( ext ) {
slouken@542
   551
		++ext; /* skip the dot in the extension */
slouken@542
   552
		if ( MIX_string_equals(ext, "WAV") ) {
slouken@542
   553
			type = MUS_WAV;
slouken@542
   554
		} else if ( MIX_string_equals(ext, "MID") ||
slouken@542
   555
		            MIX_string_equals(ext, "MIDI") ||
slouken@542
   556
		            MIX_string_equals(ext, "KAR") ) {
slouken@542
   557
			type = MUS_MID;
slouken@542
   558
		} else if ( MIX_string_equals(ext, "OGG") ) {
slouken@542
   559
			type = MUS_OGG;
slouken@542
   560
		} else if ( MIX_string_equals(ext, "FLAC") ) {
slouken@542
   561
			type = MUS_FLAC;
slouken@542
   562
		} else 	if ( MIX_string_equals(ext, "MPG") ||
slouken@542
   563
		             MIX_string_equals(ext, "MPEG") ||
slouken@542
   564
		             MIX_string_equals(ext, "MP3") ||
slouken@542
   565
		             MIX_string_equals(ext, "MAD") ) {
slouken@542
   566
			type = MUS_MP3;
slouken@542
   567
		}
slouken@542
   568
	}
slouken@542
   569
	if ( type == MUS_NONE ) {
slouken@542
   570
		type = detect_music_type(rw);
slouken@542
   571
	}
slouken@542
   572
slouken@542
   573
	/* We need to know if a specific error occurs; if not, we'll set a
slouken@542
   574
	 * generic one, so we clear the current one. */
slouken@542
   575
	Mix_SetError("");
slouken@542
   576
	music = Mix_LoadMUSType_RW(rw, type, SDL_TRUE);
slouken@542
   577
	if ( music == NULL && Mix_GetError()[0] == '\0' ) {
slouken@542
   578
		SDL_FreeRW(rw);
slouken@542
   579
		Mix_SetError("Couldn't open '%s'", file);
slouken@542
   580
	}
slouken@542
   581
	return music;
slouken@542
   582
}
slouken@542
   583
slouken@542
   584
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
slouken@542
   585
{
slouken@542
   586
	return Mix_LoadMUSType_RW(rw, MUS_NONE, SDL_FALSE);
slouken@542
   587
}
slouken@542
   588
slouken@542
   589
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *rw, Mix_MusicType type, int freesrc)
slouken@542
   590
{
slouken@0
   591
	Mix_Music *music;
slouken@0
   592
slouken@542
   593
	if (!rw) {
slouken@542
   594
		Mix_SetError("RWops pointer is NULL");
slouken@542
   595
		return NULL;
slouken@542
   596
	}
slouken@542
   597
slouken@542
   598
	/* If the caller wants auto-detection, figure out what kind of file
slouken@542
   599
	 * this is. */
slouken@542
   600
	if (type == MUS_NONE) {
slouken@542
   601
		if ((type = detect_music_type(rw)) == MUS_NONE) {
slouken@542
   602
			/* Don't call Mix_SetError() here since detect_music_type()
slouken@542
   603
			 * does that. */
slouken@542
   604
			return NULL;
slouken@0
   605
		}
slouken@0
   606
	}
slouken@125
   607
slouken@0
   608
	/* Allocate memory for the music structure */
slouken@561
   609
	music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
slouken@542
   610
	if (music == NULL ) {
slouken@26
   611
		Mix_SetError("Out of memory");
slouken@542
   612
		return NULL;
slouken@0
   613
	}
slouken@0
   614
	music->error = 0;
slouken@0
   615
slouken@542
   616
	switch (type) {
slouken@542
   617
#ifdef WAV_MUSIC
slouken@542
   618
	case MUS_WAV:
slouken@542
   619
		/* The WAVE loader needs the first 4 bytes of the header */
slouken@542
   620
		{
slouken@542
   621
			Uint8 magic[5];
slouken@542
   622
			int start = SDL_RWtell(rw);
slouken@542
   623
			if (SDL_RWread(rw, magic, 1, 4) != 4) {
slouken@542
   624
				Mix_SetError("Couldn't read from RWops");
slouken@542
   625
				return MUS_NONE;
slouken@542
   626
			}
slouken@542
   627
			SDL_RWseek(rw, start, RW_SEEK_SET);
slouken@542
   628
			magic[4] = '\0';
slouken@542
   629
			music->type = MUS_WAV;
slouken@542
   630
			music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic, freesrc);
slouken@542
   631
		}
slouken@542
   632
		if (music->data.wave == NULL) {
slouken@0
   633
			music->error = 1;
slouken@0
   634
		}
slouken@542
   635
		break;
slouken@0
   636
#endif
slouken@542
   637
#ifdef OGG_MUSIC
slouken@542
   638
	case MUS_OGG:
slouken@542
   639
		music->type = MUS_OGG;
slouken@542
   640
		music->data.ogg = OGG_new_RW(rw, freesrc);
slouken@542
   641
		if ( music->data.ogg == NULL ) {
slouken@0
   642
			music->error = 1;
slouken@0
   643
		}
slouken@542
   644
		break;
slouken@542
   645
#endif
slouken@542
   646
#ifdef FLAC_MUSIC
slouken@542
   647
	case MUS_FLAC:
slouken@542
   648
		music->type = MUS_FLAC;
slouken@542
   649
		music->data.flac = FLAC_new_RW(rw, freesrc);
slouken@542
   650
		if ( music->data.flac == NULL ) {
slouken@542
   651
			music->error = 1;
slouken@542
   652
		}
slouken@542
   653
		break;
slouken@542
   654
#endif
slouken@542
   655
#ifdef MP3_MUSIC
slouken@542
   656
	case MUS_MP3:
slouken@542
   657
		if ( Mix_Init(MIX_INIT_MP3) ) {
slouken@542
   658
			SMPEG_Info info;
slouken@542
   659
			music->type = MUS_MP3;
slouken@542
   660
			music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
slouken@542
   661
			if ( !info.has_audio ) {
slouken@542
   662
				Mix_SetError("MPEG file does not have any audio stream.");
slouken@542
   663
				music->error = 1;
slouken@542
   664
			} else {
slouken@542
   665
				smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
slouken@542
   666
			}
slouken@542
   667
		} else {
slouken@542
   668
			music->error = 1;
slouken@542
   669
		}
slouken@542
   670
		break;
slouken@542
   671
#elif defined(MP3_MAD_MUSIC)
slouken@542
   672
	case MUS_MP3:
slouken@542
   673
		music->type = MUS_MP3_MAD;
slouken@542
   674
		music->data.mp3_mad = mad_openFileRW(rw, &used_mixer, freesrc);
slouken@542
   675
		if (music->data.mp3_mad == 0) {
slouken@542
   676
			Mix_SetError("Could not initialize MPEG stream.");
slouken@542
   677
			music->error = 1;
slouken@542
   678
		}
slouken@542
   679
		break;
slouken@0
   680
#endif
slouken@0
   681
#ifdef MID_MUSIC
slouken@542
   682
	case MUS_MID:
slouken@0
   683
		music->type = MUS_MID;
slouken@98
   684
#ifdef USE_NATIVE_MIDI
slouken@542
   685
		if ( native_midi_ok ) {
slouken@542
   686
			music->data.nativemidi = native_midi_loadsong_RW(rw, freesrc);
slouken@98
   687
	  		if ( music->data.nativemidi == NULL ) {
slouken@98
   688
		  		Mix_SetError("%s", native_midi_error());
slouken@98
   689
			  	music->error = 1;
slouken@98
   690
			}
slouken@542
   691
			break;
slouken@542
   692
		}
chewi@506
   693
#endif
chewi@506
   694
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   695
		if ( fluidsynth_ok ) {
slouken@542
   696
			music->data.fluidsynthmidi = fluidsynth_loadsong_RW(rw, freesrc);
chewi@506
   697
			if ( music->data.fluidsynthmidi == NULL ) {
chewi@506
   698
				music->error = 1;
chewi@506
   699
			}
slouken@542
   700
			break;
chewi@506
   701
		}
slouken@98
   702
#endif
slouken@106
   703
#ifdef USE_TIMIDITY_MIDI
slouken@0
   704
		if ( timidity_ok ) {
slouken@542
   705
			music->data.midi = Timidity_LoadSong_RW(rw, freesrc);
slouken@0
   706
			if ( music->data.midi == NULL ) {
slouken@26
   707
				Mix_SetError("%s", Timidity_Error());
slouken@0
   708
				music->error = 1;
slouken@0
   709
			}
slouken@98
   710
		} else {
slouken@26
   711
			Mix_SetError("%s", Timidity_Error());
slouken@0
   712
			music->error = 1;
slouken@0
   713
		}
slouken@106
   714
#endif
slouken@542
   715
		break;
slouken@0
   716
#endif
slouken@542
   717
#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
slouken@542
   718
	case MUS_MOD:
slouken@542
   719
		music->error = 1;
slouken@542
   720
#ifdef MODPLUG_MUSIC
slouken@542
   721
		if ( music->error ) {
slouken@542
   722
			music->type = MUS_MODPLUG;
slouken@542
   723
			music->data.modplug = modplug_new_RW(rw, freesrc);
slouken@542
   724
			if ( music->data.modplug ) {
slouken@542
   725
				music->error = 0;
slouken@542
   726
			}
slouken@63
   727
		}
slouken@481
   728
#endif
slouken@411
   729
#ifdef MOD_MUSIC
slouken@542
   730
		if ( music->error ) {
slouken@542
   731
			music->type = MUS_MOD;
slouken@542
   732
			music->data.module = MOD_new_RW(rw, freesrc);
slouken@542
   733
			if ( music->data.module ) {
slouken@542
   734
				music->error = 0;
slouken@542
   735
			}
slouken@0
   736
		}
slouken@0
   737
#endif
slouken@542
   738
		break;
slouken@542
   739
#endif
slouken@542
   740
slouken@542
   741
	default:
slouken@26
   742
		Mix_SetError("Unrecognized music format");
slouken@542
   743
		music->error=1;
slouken@542
   744
	} /* switch (want) */
chewi@506
   745
slouken@542
   746
slouken@542
   747
	if (music->error) {
slouken@561
   748
		SDL_free(music);
slouken@542
   749
		music=NULL;
slouken@0
   750
	}
slouken@0
   751
	return(music);
slouken@0
   752
}
slouken@0
   753
slouken@0
   754
/* Free a music chunk previously loaded */
slouken@0
   755
void Mix_FreeMusic(Mix_Music *music)
slouken@0
   756
{
slouken@0
   757
	if ( music ) {
slouken@173
   758
		/* Stop the music if it's currently playing */
slouken@173
   759
		SDL_LockAudio();
slouken@173
   760
		if ( music == music_playing ) {
slouken@173
   761
			/* Wait for any fade out to finish */
slouken@173
   762
			while ( music->fading == MIX_FADING_OUT ) {
slouken@173
   763
				SDL_UnlockAudio();
slouken@173
   764
				SDL_Delay(100);
slouken@173
   765
				SDL_LockAudio();
slouken@173
   766
			}
slouken@173
   767
			if ( music == music_playing ) {
slouken@173
   768
				music_internal_halt();
megastep@4
   769
			}
slouken@0
   770
		}
slouken@173
   771
		SDL_UnlockAudio();
slouken@0
   772
		switch (music->type) {
slouken@0
   773
#ifdef CMD_MUSIC
slouken@0
   774
			case MUS_CMD:
slouken@0
   775
				MusicCMD_FreeSong(music->data.cmd);
slouken@0
   776
				break;
slouken@0
   777
#endif
slouken@0
   778
#ifdef WAV_MUSIC
slouken@0
   779
			case MUS_WAV:
slouken@0
   780
				WAVStream_FreeSong(music->data.wave);
slouken@0
   781
				break;
slouken@0
   782
#endif
slouken@481
   783
#ifdef MODPLUG_MUSIC
slouken@481
   784
			case MUS_MODPLUG:
slouken@481
   785
				modplug_delete(music->data.modplug);
slouken@481
   786
				break;
slouken@481
   787
#endif
slouken@411
   788
#ifdef MOD_MUSIC
slouken@0
   789
			case MUS_MOD:
slouken@411
   790
				MOD_delete(music->data.module);
slouken@0
   791
				break;
slouken@0
   792
#endif
slouken@0
   793
#ifdef MID_MUSIC
slouken@0
   794
			case MUS_MID:
slouken@98
   795
#ifdef USE_NATIVE_MIDI
slouken@98
   796
  				if ( native_midi_ok ) {
slouken@98
   797
					native_midi_freesong(music->data.nativemidi);
chewi@506
   798
					goto skip;
chewi@506
   799
				}
chewi@506
   800
#endif
chewi@506
   801
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   802
				if ( fluidsynth_ok ) {
chewi@506
   803
					fluidsynth_freesong(music->data.fluidsynthmidi);
chewi@506
   804
					goto skip;
chewi@506
   805
				}
slouken@98
   806
#endif
slouken@106
   807
#ifdef USE_TIMIDITY_MIDI
slouken@98
   808
				if ( timidity_ok ) {
slouken@98
   809
					Timidity_FreeSong(music->data.midi);
chewi@506
   810
					goto skip;
slouken@98
   811
				}
slouken@106
   812
#endif
slouken@0
   813
				break;
slouken@0
   814
#endif
slouken@63
   815
#ifdef OGG_MUSIC
slouken@63
   816
			case MUS_OGG:
slouken@63
   817
				OGG_delete(music->data.ogg);
slouken@63
   818
				break;
slouken@63
   819
#endif
slouken@382
   820
#ifdef FLAC_MUSIC
slouken@382
   821
			case MUS_FLAC:
slouken@382
   822
				FLAC_delete(music->data.flac);
slouken@382
   823
				break;
slouken@382
   824
#endif
slouken@0
   825
#ifdef MP3_MUSIC
slouken@26
   826
			case MUS_MP3:
slouken@314
   827
				smpeg.SMPEG_delete(music->data.mp3);
slouken@0
   828
				break;
slouken@0
   829
#endif
slouken@357
   830
#ifdef MP3_MAD_MUSIC
slouken@357
   831
			case MUS_MP3_MAD:
slouken@357
   832
				mad_closeFile(music->data.mp3_mad);
slouken@357
   833
				break;
slouken@357
   834
#endif
slouken@0
   835
			default:
slouken@0
   836
				/* Unknown music type?? */
slouken@0
   837
				break;
slouken@0
   838
		}
chewi@506
   839
chewi@506
   840
    skip:
slouken@561
   841
		SDL_free(music);
slouken@0
   842
	}
slouken@0
   843
}
slouken@0
   844
slouken@177
   845
/* Find out the music format of a mixer music, or the currently playing
slouken@177
   846
   music, if 'music' is NULL.
slouken@177
   847
*/
slouken@177
   848
Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
slouken@177
   849
{
slouken@177
   850
	Mix_MusicType type = MUS_NONE;
slouken@177
   851
slouken@177
   852
	if ( music ) {
slouken@177
   853
		type = music->type;
slouken@177
   854
	} else {
slouken@177
   855
		SDL_LockAudio();
slouken@177
   856
		if ( music_playing ) {
slouken@177
   857
			type = music_playing->type;
slouken@177
   858
		}
slouken@177
   859
		SDL_UnlockAudio();
slouken@177
   860
	}
slouken@177
   861
	return(type);
slouken@177
   862
}
slouken@177
   863
slouken@173
   864
/* Play a music chunk.  Returns 0, or -1 if there was an error.
slouken@173
   865
 */
slouken@173
   866
static int music_internal_play(Mix_Music *music, double position)
slouken@0
   867
{
slouken@173
   868
	int retval = 0;
megastep@10
   869
slouken@547
   870
#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
slouken@531
   871
	/* This fixes a bug with native MIDI on Mac OS X, where you
slouken@531
   872
	   can't really stop and restart MIDI from the audio callback.
slouken@529
   873
	*/
slouken@531
   874
	if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
slouken@531
   875
		/* Just a seek suffices to restart playing */
slouken@531
   876
		music_internal_position(position);
slouken@531
   877
		return 0;
slouken@529
   878
	}
slouken@531
   879
#endif
slouken@529
   880
slouken@173
   881
	/* Note the music we're playing */
slouken@173
   882
	if ( music_playing ) {
slouken@173
   883
		music_internal_halt();
slouken@173
   884
	}
slouken@173
   885
	music_playing = music;
slouken@173
   886
slouken@173
   887
	/* Set the initial volume */
icculus@237
   888
	if ( music->type != MUS_MOD ) {
icculus@237
   889
		music_internal_initialize_volume();
slouken@173
   890
	}
slouken@173
   891
slouken@173
   892
	/* Set up for playback */
slouken@0
   893
	switch (music->type) {
slouken@0
   894
#ifdef CMD_MUSIC
slouken@173
   895
	    case MUS_CMD:
slouken@173
   896
		MusicCMD_Start(music->data.cmd);
slouken@173
   897
		break;
slouken@0
   898
#endif
slouken@0
   899
#ifdef WAV_MUSIC
slouken@173
   900
	    case MUS_WAV:
slouken@173
   901
		WAVStream_Start(music->data.wave);
slouken@173
   902
		break;
slouken@0
   903
#endif
slouken@481
   904
#ifdef MODPLUG_MUSIC
slouken@481
   905
	    case MUS_MODPLUG:
slouken@481
   906
		/* can't set volume until file is loaded, so finally set it now */
slouken@481
   907
		music_internal_initialize_volume();
slouken@481
   908
		modplug_play(music->data.modplug);
slouken@481
   909
		break;
slouken@481
   910
#endif
slouken@411
   911
#ifdef MOD_MUSIC
slouken@173
   912
	    case MUS_MOD:
slouken@411
   913
		MOD_play(music->data.module);
icculus@237
   914
		/* Player_SetVolume() does nothing before Player_Start() */
icculus@237
   915
		music_internal_initialize_volume();
slouken@173
   916
		break;
slouken@0
   917
#endif
slouken@0
   918
#ifdef MID_MUSIC
slouken@173
   919
	    case MUS_MID:
slouken@98
   920
#ifdef USE_NATIVE_MIDI
slouken@173
   921
		if ( native_midi_ok ) {
slouken@533
   922
			native_midi_start(music->data.nativemidi, music_loops);
chewi@506
   923
			goto skip;
chewi@506
   924
		}
chewi@506
   925
#endif
chewi@506
   926
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
   927
		if (fluidsynth_ok ) {
chewi@506
   928
			fluidsynth_start(music->data.fluidsynthmidi);
chewi@506
   929
			goto skip;
chewi@506
   930
		}
slouken@98
   931
#endif
slouken@106
   932
#ifdef USE_TIMIDITY_MIDI
slouken@173
   933
		if ( timidity_ok ) {
slouken@173
   934
			Timidity_Start(music->data.midi);
chewi@506
   935
			goto skip;
slouken@173
   936
		}
slouken@106
   937
#endif
slouken@173
   938
		break;
slouken@0
   939
#endif
slouken@63
   940
#ifdef OGG_MUSIC
slouken@173
   941
	    case MUS_OGG:
slouken@173
   942
		OGG_play(music->data.ogg);
slouken@173
   943
		break;
slouken@63
   944
#endif
slouken@382
   945
#ifdef FLAC_MUSIC
slouken@382
   946
	    case MUS_FLAC:
slouken@382
   947
		FLAC_play(music->data.flac);
slouken@382
   948
		break;
slouken@382
   949
#endif
slouken@0
   950
#ifdef MP3_MUSIC
slouken@173
   951
	    case MUS_MP3:
slouken@314
   952
		smpeg.SMPEG_enableaudio(music->data.mp3,1);
slouken@314
   953
		smpeg.SMPEG_enablevideo(music->data.mp3,0);
slouken@314
   954
		smpeg.SMPEG_play(music_playing->data.mp3);
slouken@173
   955
		break;
slouken@0
   956
#endif
slouken@357
   957
#ifdef MP3_MAD_MUSIC
slouken@357
   958
	    case MUS_MP3_MAD:
slouken@357
   959
		mad_start(music->data.mp3_mad);
slouken@357
   960
		break;
slouken@357
   961
#endif
slouken@173
   962
	    default:
slouken@173
   963
		Mix_SetError("Can't play unknown music type");
slouken@173
   964
		retval = -1;
slouken@173
   965
		break;
slouken@0
   966
	}
slouken@173
   967
chewi@506
   968
skip:
slouken@173
   969
	/* Set the playback position, note any errors if an offset is used */
slouken@173
   970
	if ( retval == 0 ) {
slouken@173
   971
		if ( position > 0.0 ) {
slouken@173
   972
			if ( music_internal_position(position) < 0 ) {
slouken@173
   973
				Mix_SetError("Position not implemented for music type");
slouken@173
   974
				retval = -1;
slouken@173
   975
			}
slouken@173
   976
		} else {
slouken@173
   977
			music_internal_position(0.0);
slouken@173
   978
		}
slouken@173
   979
	}
slouken@173
   980
slouken@173
   981
	/* If the setup failed, we're not playing any music anymore */
slouken@173
   982
	if ( retval < 0 ) {
slouken@173
   983
		music_playing = NULL;
slouken@173
   984
	}
slouken@173
   985
	return(retval);
slouken@173
   986
}
slouken@173
   987
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
slouken@173
   988
{
slouken@173
   989
	int retval;
slouken@173
   990
slouken@499
   991
	if ( ms_per_step == 0 ) {
slouken@499
   992
		SDL_SetError("Audio device hasn't been opened");
slouken@499
   993
		return(-1);
slouken@499
   994
	}
slouken@499
   995
slouken@173
   996
	/* Don't play null pointers :-) */
slouken@173
   997
	if ( music == NULL ) {
slouken@173
   998
		Mix_SetError("music parameter was NULL");
slouken@173
   999
		return(-1);
slouken@173
  1000
	}
slouken@173
  1001
slouken@173
  1002
	/* Setup the data */
slouken@173
  1003
	if ( ms ) {
slouken@173
  1004
		music->fading = MIX_FADING_IN;
slouken@173
  1005
	} else {
slouken@173
  1006
		music->fading = MIX_NO_FADING;
slouken@173
  1007
	}
slouken@173
  1008
	music->fade_step = 0;
slouken@173
  1009
	music->fade_steps = ms/ms_per_step;
slouken@173
  1010
slouken@173
  1011
	/* Play the puppy */
slouken@173
  1012
	SDL_LockAudio();
slouken@173
  1013
	/* If the current music is fading out, wait for the fade to complete */
slouken@173
  1014
	while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
slouken@173
  1015
		SDL_UnlockAudio();
slouken@173
  1016
		SDL_Delay(100);
slouken@173
  1017
		SDL_LockAudio();
slouken@173
  1018
	}
slouken@173
  1019
	music_active = 1;
slouken@533
  1020
	if (loops == 1) {
slouken@533
  1021
		/* Loop is the number of times to play the audio */
slouken@533
  1022
		loops = 0;
slouken@533
  1023
	}
slouken@173
  1024
	music_loops = loops;
slouken@173
  1025
	retval = music_internal_play(music, position);
slouken@173
  1026
	SDL_UnlockAudio();
slouken@173
  1027
slouken@173
  1028
	return(retval);
slouken@173
  1029
}
slouken@173
  1030
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
slouken@173
  1031
{
slouken@173
  1032
	return Mix_FadeInMusicPos(music, loops, ms, 0.0);
slouken@173
  1033
}
slouken@173
  1034
int Mix_PlayMusic(Mix_Music *music, int loops)
slouken@173
  1035
{
slouken@173
  1036
	return Mix_FadeInMusicPos(music, loops, 0, 0.0);
megastep@10
  1037
}
megastep@10
  1038
slouken@173
  1039
/* Set the playing music position */
slouken@173
  1040
int music_internal_position(double position)
megastep@10
  1041
{
slouken@173
  1042
	int retval = 0;
slouken@173
  1043
slouken@173
  1044
	switch (music_playing->type) {
slouken@481
  1045
#ifdef MODPLUG_MUSIC
slouken@481
  1046
	    case MUS_MODPLUG:
slouken@481
  1047
		modplug_jump_to_time(music_playing->data.modplug, position);
slouken@481
  1048
		break;
slouken@481
  1049
#endif
slouken@411
  1050
#ifdef MOD_MUSIC
slouken@173
  1051
	    case MUS_MOD:
slouken@411
  1052
		MOD_jump_to_time(music_playing->data.module, position);
slouken@173
  1053
		break;
slouken@173
  1054
#endif
slouken@173
  1055
#ifdef OGG_MUSIC
slouken@173
  1056
	    case MUS_OGG:
slouken@173
  1057
		OGG_jump_to_time(music_playing->data.ogg, position);
slouken@173
  1058
		break;
slouken@173
  1059
#endif
slouken@382
  1060
#ifdef FLAC_MUSIC
slouken@382
  1061
	    case MUS_FLAC:
slouken@382
  1062
		FLAC_jump_to_time(music_playing->data.flac, position);
slouken@382
  1063
		break;
slouken@382
  1064
#endif
slouken@173
  1065
#ifdef MP3_MUSIC
slouken@173
  1066
	    case MUS_MP3:
slouken@176
  1067
		if ( position > 0.0 ) {
slouken@314
  1068
			smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
slouken@179
  1069
		} else {
slouken@314
  1070
			smpeg.SMPEG_rewind(music_playing->data.mp3);
slouken@314
  1071
			smpeg.SMPEG_play(music_playing->data.mp3);
slouken@173
  1072
		}
slouken@173
  1073
		break;
slouken@173
  1074
#endif
slouken@357
  1075
#ifdef MP3_MAD_MUSIC
slouken@357
  1076
	    case MUS_MP3_MAD:
slouken@357
  1077
		mad_seek(music_playing->data.mp3_mad, position);
slouken@357
  1078
		break;
slouken@357
  1079
#endif
slouken@173
  1080
	    default:
slouken@173
  1081
		/* TODO: Implement this for other music backends */
slouken@173
  1082
		retval = -1;
slouken@173
  1083
		break;
megastep@10
  1084
	}
slouken@173
  1085
	return(retval);
megastep@4
  1086
}
slouken@155
  1087
int Mix_SetMusicPosition(double position)
slouken@154
  1088
{
slouken@173
  1089
	int retval;
slouken@173
  1090
slouken@173
  1091
	SDL_LockAudio();
slouken@173
  1092
	if ( music_playing ) {
slouken@173
  1093
		retval = music_internal_position(position);
slouken@173
  1094
		if ( retval < 0 ) {
slouken@173
  1095
			Mix_SetError("Position not implemented for music type");
slouken@154
  1096
		}
slouken@173
  1097
	} else {
slouken@173
  1098
		Mix_SetError("Music isn't playing");
slouken@173
  1099
		retval = -1;
slouken@154
  1100
	}
slouken@173
  1101
	SDL_UnlockAudio();
slouken@154
  1102
slouken@173
  1103
	return(retval);
slouken@154
  1104
}
slouken@154
  1105
icculus@237
  1106
/* Set the music's initial volume */
icculus@237
  1107
static void music_internal_initialize_volume(void)
icculus@237
  1108
{
icculus@237
  1109
	if ( music_playing->fading == MIX_FADING_IN ) {
icculus@237
  1110
		music_internal_volume(0);
icculus@237
  1111
	} else {
icculus@237
  1112
		music_internal_volume(music_volume);
icculus@237
  1113
	}
icculus@237
  1114
}
icculus@237
  1115
slouken@0
  1116
/* Set the music volume */
slouken@173
  1117
static void music_internal_volume(int volume)
slouken@173
  1118
{
slouken@173
  1119
	switch (music_playing->type) {
slouken@173
  1120
#ifdef CMD_MUSIC
slouken@173
  1121
	    case MUS_CMD:
slouken@173
  1122
		MusicCMD_SetVolume(volume);
slouken@173
  1123
		break;
slouken@173
  1124
#endif
slouken@173
  1125
#ifdef WAV_MUSIC
slouken@173
  1126
	    case MUS_WAV:
slouken@173
  1127
		WAVStream_SetVolume(volume);
slouken@173
  1128
		break;
slouken@173
  1129
#endif
slouken@481
  1130
#ifdef MODPLUG_MUSIC
slouken@481
  1131
	    case MUS_MODPLUG:
slouken@481
  1132
		modplug_setvolume(music_playing->data.modplug, volume);
slouken@481
  1133
		break;
slouken@481
  1134
#endif
slouken@411
  1135
#ifdef MOD_MUSIC
slouken@173
  1136
	    case MUS_MOD:
slouken@411
  1137
		MOD_setvolume(music_playing->data.module, volume);
slouken@173
  1138
		break;
slouken@173
  1139
#endif
slouken@173
  1140
#ifdef MID_MUSIC
slouken@173
  1141
	    case MUS_MID:
slouken@173
  1142
#ifdef USE_NATIVE_MIDI
slouken@173
  1143
		if ( native_midi_ok ) {
slouken@173
  1144
			native_midi_setvolume(volume);
chewi@506
  1145
			return;
chewi@506
  1146
		}
chewi@506
  1147
#endif
chewi@506
  1148
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
  1149
		if ( fluidsynth_ok ) {
chewi@506
  1150
			fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
chewi@506
  1151
			return;
chewi@506
  1152
		}
slouken@173
  1153
#endif
slouken@173
  1154
#ifdef USE_TIMIDITY_MIDI
slouken@173
  1155
		if ( timidity_ok ) {
slouken@173
  1156
			Timidity_SetVolume(volume);
chewi@506
  1157
			return;
slouken@173
  1158
		}
slouken@173
  1159
#endif
slouken@173
  1160
		break;
slouken@173
  1161
#endif
slouken@173
  1162
#ifdef OGG_MUSIC
slouken@173
  1163
	    case MUS_OGG:
slouken@173
  1164
		OGG_setvolume(music_playing->data.ogg, volume);
slouken@173
  1165
		break;
slouken@173
  1166
#endif
slouken@382
  1167
#ifdef FLAC_MUSIC
slouken@382
  1168
	    case MUS_FLAC:
slouken@382
  1169
		FLAC_setvolume(music_playing->data.flac, volume);
slouken@382
  1170
		break;
slouken@382
  1171
#endif
slouken@173
  1172
#ifdef MP3_MUSIC
slouken@173
  1173
	    case MUS_MP3:
slouken@314
  1174
		smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
slouken@173
  1175
		break;
slouken@173
  1176
#endif
slouken@357
  1177
#ifdef MP3_MAD_MUSIC
slouken@357
  1178
	    case MUS_MP3_MAD:
slouken@357
  1179
		mad_setVolume(music_playing->data.mp3_mad, volume);
slouken@357
  1180
		break;
slouken@357
  1181
#endif
slouken@173
  1182
	    default:
slouken@173
  1183
		/* Unknown music type?? */
slouken@173
  1184
		break;
slouken@173
  1185
	}
slouken@173
  1186
}
slouken@0
  1187
int Mix_VolumeMusic(int volume)
slouken@0
  1188
{
slouken@0
  1189
	int prev_volume;
slouken@0
  1190
slouken@0
  1191
	prev_volume = music_volume;
megastep@4
  1192
	if ( volume < 0 ) {
slouken@163
  1193
		return prev_volume;
megastep@4
  1194
	}
megastep@4
  1195
	if ( volume > SDL_MIX_MAXVOLUME ) {
megastep@4
  1196
		volume = SDL_MIX_MAXVOLUME;
megastep@4
  1197
	}
megastep@4
  1198
	music_volume = volume;
slouken@173
  1199
	SDL_LockAudio();
slouken@173
  1200
	if ( music_playing ) {
slouken@173
  1201
		music_internal_volume(music_volume);
slouken@0
  1202
	}
slouken@173
  1203
	SDL_UnlockAudio();
slouken@0
  1204
	return(prev_volume);
slouken@0
  1205
}
slouken@0
  1206
slouken@173
  1207
/* Halt playing of music */
slouken@173
  1208
static void music_internal_halt(void)
megastep@7
  1209
{
megastep@7
  1210
	switch (music_playing->type) {
megastep@7
  1211
#ifdef CMD_MUSIC
slouken@173
  1212
	    case MUS_CMD:
megastep@7
  1213
		MusicCMD_Stop(music_playing->data.cmd);
megastep@7
  1214
		break;
megastep@7
  1215
#endif
megastep@7
  1216
#ifdef WAV_MUSIC
slouken@173
  1217
	    case MUS_WAV:
megastep@7
  1218
		WAVStream_Stop();
megastep@7
  1219
		break;
megastep@7
  1220
#endif
slouken@481
  1221
#ifdef MODPLUG_MUSIC
slouken@481
  1222
	    case MUS_MODPLUG:
slouken@481
  1223
		modplug_stop(music_playing->data.modplug);
slouken@481
  1224
		break;
slouken@481
  1225
#endif
slouken@411
  1226
#ifdef MOD_MUSIC
slouken@173
  1227
	    case MUS_MOD:
slouken@411
  1228
		MOD_stop(music_playing->data.module);
megastep@7
  1229
		break;
megastep@7
  1230
#endif
megastep@7
  1231
#ifdef MID_MUSIC
slouken@173
  1232
	    case MUS_MID:
slouken@98
  1233
#ifdef USE_NATIVE_MIDI
slouken@98
  1234
		if ( native_midi_ok ) {
slouken@98
  1235
			native_midi_stop();
chewi@506
  1236
			goto skip;
chewi@506
  1237
		}
chewi@506
  1238
#endif
chewi@506
  1239
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
  1240
		if ( fluidsynth_ok ) {
chewi@506
  1241
			fluidsynth_stop(music_playing->data.fluidsynthmidi);
chewi@506
  1242
			goto skip;
chewi@506
  1243
		}
slouken@98
  1244
#endif
slouken@106
  1245
#ifdef USE_TIMIDITY_MIDI
slouken@98
  1246
		if ( timidity_ok ) {
slouken@98
  1247
			Timidity_Stop();
chewi@506
  1248
			goto skip;
slouken@98
  1249
		}
slouken@106
  1250
#endif
megastep@7
  1251
		break;
megastep@7
  1252
#endif
slouken@63
  1253
#ifdef OGG_MUSIC
slouken@173
  1254
	    case MUS_OGG:
slouken@63
  1255
		OGG_stop(music_playing->data.ogg);
slouken@63
  1256
		break;
slouken@63
  1257
#endif
slouken@382
  1258
#ifdef FLAC_MUSIC
slouken@382
  1259
	    case MUS_FLAC:
slouken@382
  1260
		FLAC_stop(music_playing->data.flac);
slouken@382
  1261
		break;
slouken@382
  1262
#endif
megastep@7
  1263
#ifdef MP3_MUSIC
slouken@173
  1264
	    case MUS_MP3:
slouken@314
  1265
		smpeg.SMPEG_stop(music_playing->data.mp3);
megastep@7
  1266
		break;
megastep@7
  1267
#endif
slouken@357
  1268
#ifdef MP3_MAD_MUSIC
slouken@357
  1269
	    case MUS_MP3_MAD:
slouken@357
  1270
		mad_stop(music_playing->data.mp3_mad);
slouken@357
  1271
		break;
slouken@357
  1272
#endif
slouken@173
  1273
	    default:
megastep@7
  1274
		/* Unknown music type?? */
megastep@7
  1275
		return;
megastep@7
  1276
	}
chewi@506
  1277
chewi@506
  1278
skip:
megastep@7
  1279
	music_playing->fading = MIX_NO_FADING;
slouken@17
  1280
	music_playing = NULL;
megastep@7
  1281
}
slouken@0
  1282
int Mix_HaltMusic(void)
slouken@0
  1283
{
slouken@173
  1284
	SDL_LockAudio();
slouken@173
  1285
	if ( music_playing ) {
slouken@173
  1286
		music_internal_halt();
slouken@0
  1287
	}
slouken@173
  1288
	SDL_UnlockAudio();
slouken@173
  1289
slouken@0
  1290
	return(0);
slouken@0
  1291
}
slouken@0
  1292
megastep@4
  1293
/* Progressively stop the music */
megastep@4
  1294
int Mix_FadeOutMusic(int ms)
megastep@4
  1295
{
slouken@173
  1296
	int retval = 0;
slouken@173
  1297
slouken@499
  1298
	if ( ms_per_step == 0 ) {
slouken@499
  1299
		SDL_SetError("Audio device hasn't been opened");
slouken@499
  1300
		return 0;
slouken@499
  1301
	}
slouken@499
  1302
icculus@280
  1303
	if (ms <= 0) {  /* just halt immediately. */
icculus@280
  1304
		Mix_HaltMusic();
icculus@280
  1305
		return 1;
icculus@280
  1306
	}
icculus@280
  1307
slouken@173
  1308
	SDL_LockAudio();
icculus@280
  1309
	if ( music_playing) {
icculus@280
  1310
                int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
icculus@280
  1311
                if ( music_playing->fading == MIX_NO_FADING ) {
icculus@280
  1312
	        	music_playing->fade_step = 0;
icculus@280
  1313
                } else {
icculus@280
  1314
                        int step;
icculus@280
  1315
                        int old_fade_steps = music_playing->fade_steps;
icculus@280
  1316
                        if ( music_playing->fading == MIX_FADING_OUT ) {
icculus@280
  1317
                                step = music_playing->fade_step;
icculus@280
  1318
                        } else {
icculus@280
  1319
                                step = old_fade_steps
icculus@280
  1320
                                        - music_playing->fade_step + 1;
icculus@280
  1321
                        }
icculus@280
  1322
                        music_playing->fade_step = (step * fade_steps)
icculus@280
  1323
                                / old_fade_steps;
icculus@280
  1324
                }
slouken@173
  1325
		music_playing->fading = MIX_FADING_OUT;
icculus@280
  1326
		music_playing->fade_steps = fade_steps;
slouken@173
  1327
		retval = 1;
megastep@4
  1328
	}
slouken@173
  1329
	SDL_UnlockAudio();
slouken@173
  1330
slouken@173
  1331
	return(retval);
megastep@4
  1332
}
megastep@4
  1333
megastep@4
  1334
Mix_Fading Mix_FadingMusic(void)
megastep@4
  1335
{
slouken@173
  1336
	Mix_Fading fading = MIX_NO_FADING;
slouken@173
  1337
slouken@173
  1338
	SDL_LockAudio();
slouken@173
  1339
	if ( music_playing ) {
slouken@173
  1340
		fading = music_playing->fading;
slouken@173
  1341
	}
slouken@173
  1342
	SDL_UnlockAudio();
slouken@173
  1343
slouken@173
  1344
	return(fading);
megastep@4
  1345
}
megastep@4
  1346
slouken@0
  1347
/* Pause/Resume the music stream */
slouken@0
  1348
void Mix_PauseMusic(void)
slouken@0
  1349
{
slouken@173
  1350
	music_active = 0;
slouken@0
  1351
}
megastep@4
  1352
slouken@0
  1353
void Mix_ResumeMusic(void)
slouken@0
  1354
{
slouken@173
  1355
	music_active = 1;
slouken@0
  1356
}
slouken@0
  1357
slouken@0
  1358
void Mix_RewindMusic(void)
slouken@0
  1359
{
slouken@173
  1360
	Mix_SetMusicPosition(0.0);
slouken@0
  1361
}
slouken@0
  1362
megastep@13
  1363
int Mix_PausedMusic(void)
megastep@13
  1364
{
slouken@17
  1365
	return (music_active == 0);
megastep@13
  1366
}
megastep@13
  1367
slouken@0
  1368
/* Check the status of the music */
slouken@173
  1369
static int music_internal_playing()
slouken@173
  1370
{
slouken@173
  1371
	int playing = 1;
icculus@510
  1372
icculus@510
  1373
	if (music_playing == NULL) {
icculus@510
  1374
		return 0;
icculus@510
  1375
	}
icculus@510
  1376
slouken@173
  1377
	switch (music_playing->type) {
slouken@173
  1378
#ifdef CMD_MUSIC
slouken@173
  1379
	    case MUS_CMD:
slouken@173
  1380
		if (!MusicCMD_Active(music_playing->data.cmd)) {
slouken@173
  1381
			playing = 0;
slouken@173
  1382
		}
slouken@173
  1383
		break;
slouken@173
  1384
#endif
slouken@173
  1385
#ifdef WAV_MUSIC
slouken@173
  1386
	    case MUS_WAV:
slouken@173
  1387
		if ( ! WAVStream_Active() ) {
slouken@173
  1388
			playing = 0;
slouken@173
  1389
		}
slouken@173
  1390
		break;
slouken@173
  1391
#endif
slouken@481
  1392
#ifdef MODPLUG_MUSIC
slouken@481
  1393
	    case MUS_MODPLUG:
slouken@481
  1394
		if ( ! modplug_playing(music_playing->data.modplug) ) {
slouken@481
  1395
			playing = 0;
slouken@481
  1396
		}
slouken@481
  1397
		break;
slouken@481
  1398
#endif
slouken@411
  1399
#ifdef MOD_MUSIC
slouken@173
  1400
	    case MUS_MOD:
slouken@411
  1401
		if ( ! MOD_playing(music_playing->data.module) ) {
slouken@173
  1402
			playing = 0;
slouken@173
  1403
		}
slouken@173
  1404
		break;
slouken@173
  1405
#endif
slouken@173
  1406
#ifdef MID_MUSIC
slouken@173
  1407
	    case MUS_MID:
slouken@173
  1408
#ifdef USE_NATIVE_MIDI
slouken@173
  1409
		if ( native_midi_ok ) {
slouken@173
  1410
			if ( ! native_midi_active() )
slouken@173
  1411
				playing = 0;
chewi@506
  1412
			goto skip;
chewi@506
  1413
		}
chewi@506
  1414
#endif
chewi@506
  1415
#ifdef USE_FLUIDSYNTH_MIDI
chewi@506
  1416
		if ( fluidsynth_ok ) {
chewi@506
  1417
			if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
chewi@506
  1418
				playing = 0;
chewi@506
  1419
			goto skip;
chewi@506
  1420
		}
slouken@173
  1421
#endif
slouken@173
  1422
#ifdef USE_TIMIDITY_MIDI
slouken@173
  1423
		if ( timidity_ok ) {
slouken@173
  1424
			if ( ! Timidity_Active() )
slouken@173
  1425
				playing = 0;
chewi@506
  1426
			goto skip;
slouken@173
  1427
		}
slouken@173
  1428
#endif
slouken@173
  1429
		break;
slouken@173
  1430
#endif
slouken@173
  1431
#ifdef OGG_MUSIC
slouken@173
  1432
	    case MUS_OGG:
slouken@173
  1433
		if ( ! OGG_playing(music_playing->data.ogg) ) {
slouken@173
  1434
			playing = 0;
slouken@173
  1435
		}
slouken@173
  1436
		break;
slouken@173
  1437
#endif
slouken@382
  1438
#ifdef FLAC_MUSIC
slouken@382
  1439
	    case MUS_FLAC:
slouken@382
  1440
		if ( ! FLAC_playing(music_playing->data.flac) ) {
slouken@382
  1441
			playing = 0;
slouken@382
  1442
		}
slouken@382
  1443
		break;
slouken@382
  1444
#endif
slouken@173
  1445
#ifdef MP3_MUSIC
slouken@173
  1446
	    case MUS_MP3:
slouken@314
  1447
		if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
slouken@173
  1448
			playing = 0;
slouken@173
  1449
		break;
slouken@173
  1450
#endif
slouken@357
  1451
#ifdef MP3_MAD_MUSIC
slouken@357
  1452
	    case MUS_MP3_MAD:
slouken@357
  1453
		if (!mad_isPlaying(music_playing->data.mp3_mad)) {
slouken@357
  1454
			playing = 0;
slouken@357
  1455
		}
slouken@357
  1456
		break;
slouken@357
  1457
#endif
slouken@173
  1458
	    default:
slouken@173
  1459
		playing = 0;
slouken@173
  1460
		break;
slouken@173
  1461
	}
chewi@506
  1462
chewi@506
  1463
skip:
slouken@173
  1464
	return(playing);
slouken@173
  1465
}
megastep@13
  1466
int Mix_PlayingMusic(void)
slouken@0
  1467
{
slouken@173
  1468
	int playing = 0;
slouken@173
  1469
slouken@173
  1470
	SDL_LockAudio();
slouken@173
  1471
	if ( music_playing ) {
slouken@529
  1472
		playing = music_loops || music_internal_playing();
slouken@0
  1473
	}
slouken@173
  1474
	SDL_UnlockAudio();
slouken@173
  1475
slouken@173
  1476
	return(playing);
slouken@0
  1477
}
slouken@0
  1478
slouken@0
  1479
/* Set the external music playback command */
slouken@0
  1480
int Mix_SetMusicCMD(const char *command)
slouken@0
  1481
{
slouken@0
  1482
	Mix_HaltMusic();
slouken@0
  1483
	if ( music_cmd ) {
slouken@561
  1484
		SDL_free(music_cmd);
slouken@0
  1485
		music_cmd = NULL;
slouken@0
  1486
	}
slouken@0
  1487
	if ( command ) {
slouken@561
  1488
		music_cmd = (char *)SDL_malloc(strlen(command)+1);
slouken@0
  1489
		if ( music_cmd == NULL ) {
slouken@0
  1490
			return(-1);
slouken@0
  1491
		}
slouken@0
  1492
		strcpy(music_cmd, command);
slouken@0
  1493
	}
slouken@0
  1494
	return(0);
slouken@0
  1495
}
slouken@0
  1496
slouken@154
  1497
int Mix_SetSynchroValue(int i)
slouken@154
  1498
{
slouken@419
  1499
	/* Not supported by any players at this time */
slouken@154
  1500
	return(-1);
slouken@154
  1501
}
slouken@154
  1502
slouken@154
  1503
int Mix_GetSynchroValue(void)
slouken@154
  1504
{
slouken@419
  1505
	/* Not supported by any players at this time */
slouken@154
  1506
	return(-1);
slouken@154
  1507
}
slouken@154
  1508
slouken@154
  1509
slouken@0
  1510
/* Uninitialize the music players */
slouken@0
  1511
void close_music(void)
slouken@0
  1512
{
slouken@0
  1513
	Mix_HaltMusic();
slouken@0
  1514
#ifdef CMD_MUSIC
slouken@0
  1515
	Mix_SetMusicCMD(NULL);
slouken@0
  1516
#endif
slouken@481
  1517
#ifdef MODPLUG_MUSIC
slouken@481
  1518
	modplug_exit();
slouken@481
  1519
#endif
slouken@411
  1520
#ifdef MOD_MUSIC
slouken@411
  1521
	MOD_exit();
slouken@0
  1522
#endif
patmandin@264
  1523
#ifdef MID_MUSIC
patmandin@264
  1524
# ifdef USE_TIMIDITY_MIDI
patmandin@264
  1525
	Timidity_Close();
patmandin@264
  1526
# endif
patmandin@264
  1527
#endif
icculus@390
  1528
icculus@390
  1529
	/* rcg06042009 report available decoders at runtime. */
slouken@561
  1530
	SDL_free(music_decoders);
icculus@390
  1531
	music_decoders = NULL;
icculus@390
  1532
	num_decoders = 0;
slouken@499
  1533
slouken@499
  1534
	ms_per_step = 0;
slouken@0
  1535
}
slouken@0
  1536
chewi@506
  1537
int Mix_SetSoundFonts(const char *paths)
chewi@506
  1538
{
chewi@506
  1539
#ifdef MID_MUSIC
chewi@506
  1540
	if (soundfont_paths) {
slouken@561
  1541
		SDL_free(soundfont_paths);
chewi@506
  1542
		soundfont_paths = NULL;
chewi@506
  1543
	}
chewi@506
  1544
chewi@506
  1545
	if (paths) {
slouken@561
  1546
		if (!(soundfont_paths = SDL_strdup(paths))) {
chewi@506
  1547
			Mix_SetError("Insufficient memory to set SoundFonts");
chewi@506
  1548
			return 0;
chewi@506
  1549
		}
chewi@506
  1550
	}
chewi@506
  1551
#endif
chewi@506
  1552
	return 1;
chewi@506
  1553
}
chewi@506
  1554
chewi@506
  1555
#ifdef MID_MUSIC
dimitris@508
  1556
const char* Mix_GetSoundFonts(void)
chewi@506
  1557
{
chewi@506
  1558
	const char* force = getenv("SDL_FORCE_SOUNDFONTS");
chewi@506
  1559
chewi@506
  1560
	if (!soundfont_paths || (force && force[0] == '1')) {
chewi@506
  1561
		return getenv("SDL_SOUNDFONTS");
chewi@506
  1562
	} else {
chewi@506
  1563
		return soundfont_paths;
chewi@506
  1564
	}
chewi@506
  1565
}
chewi@506
  1566
chewi@506
  1567
int Mix_EachSoundFont(int (*function)(const char*, void*), void *data)
chewi@506
  1568
{
chewi@506
  1569
	char *context, *path, *paths;
chewi@506
  1570
	const char* cpaths = Mix_GetSoundFonts();
chewi@506
  1571
chewi@506
  1572
	if (!cpaths) {
chewi@506
  1573
		Mix_SetError("No SoundFonts have been requested");
chewi@506
  1574
		return 0;
chewi@506
  1575
	}
chewi@506
  1576
slouken@561
  1577
	if (!(paths = SDL_strdup(cpaths))) {
chewi@506
  1578
		Mix_SetError("Insufficient memory to iterate over SoundFonts");
chewi@506
  1579
		return 0;
chewi@506
  1580
	}
chewi@506
  1581
icculus@513
  1582
#if defined(__MINGW32__) || defined(__MINGW64__)
icculus@513
  1583
	for (path = strtok(paths, ";"); path; path = strtok(NULL, ";")) {
icculus@513
  1584
#elif defined(_WIN32)
chewi@506
  1585
	for (path = strtok_s(paths, ";", &context); path; path = strtok_s(NULL, ";", &context)) {
chewi@506
  1586
#else
chewi@506
  1587
	for (path = strtok_r(paths, ":;", &context); path; path = strtok_r(NULL, ":;", &context)) {
chewi@506
  1588
#endif
chewi@506
  1589
		if (!function(path, data)) {
slouken@561
  1590
			SDL_free(paths);
chewi@506
  1591
			return 0;
chewi@506
  1592
		}
chewi@506
  1593
	}
chewi@506
  1594
slouken@561
  1595
	SDL_free(paths);
chewi@506
  1596
	return 1;
chewi@506
  1597
}
chewi@506
  1598
#endif