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