music.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 09 Jul 2013 06:59:10 -0700
changeset 648 bd8389c6dd20
parent 644 030181ff9f59
child 682 6f2ff3d6e04d
permissions -rw-r--r--
Fixed looping behavior and Mix_Playing() result for looping channels

Lee Salzman

If you passed in a negative loop count, it is supposed to behave as if it loops forever. However, it blindly decrements the loop counter regardless of whether or not the loop count is actually positive. So first fix is just to put a > 0 guard before the loop counter decrement.

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