music.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 16 May 2005 02:00:51 +0000
changeset 260 87f2a3d6e4e5
parent 256 6d7e102500c9
child 264 e62571f9bcbf
permissions -rw-r--r--
Date: Fri, 22 Apr 2005 21:07:49 -0600
From: Tyler Montbriand
Subject: [SDL] SDL_mixer mikmod patch

When SDL_mixer calls MikMod_RegisterAllDrivers using it's internally
compiled-in audio drivers, the only driver it registers is the nosound audio
driver. When it's using an external mikmod library, it initializes any and
all drivers it has available, such as OSS, ESD, and so forth. Because of the
way SDL_mixer uses mikmod directly, this will often work, but will do silly
things like open the audio device twice -- once by SDL, once by MikMod.
Worst case it will hang hard as MikMod attempts to open a busy audio device.

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