src/music.c
author Ozkan Sezer
Wed, 18 Dec 2019 18:55:56 +0300
changeset 1098 3be892f72aa7
parent 1090 543b77a3c0eb
child 1100 ba8b8227a7bd
permissions -rw-r--r--
fix build.
admin@999
     1
/*
admin@999
     2
  SDL_mixer:  An audio mixer library based on the SDL library
admin@999
     3
  Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
admin@999
     4
admin@999
     5
  This software is provided 'as-is', without any express or implied
admin@999
     6
  warranty.  In no event will the authors be held liable for any damages
admin@999
     7
  arising from the use of this software.
admin@999
     8
admin@999
     9
  Permission is granted to anyone to use this software for any purpose,
admin@999
    10
  including commercial applications, and to alter it and redistribute it
admin@999
    11
  freely, subject to the following restrictions:
admin@999
    12
admin@999
    13
  1. The origin of this software must not be misrepresented; you must not
admin@999
    14
     claim that you wrote the original software. If you use this software
admin@999
    15
     in a product, an acknowledgment in the product documentation would be
admin@999
    16
     appreciated but is not required.
admin@999
    17
  2. Altered source versions must be plainly marked as such, and must not be
admin@999
    18
     misrepresented as being the original software.
admin@999
    19
  3. This notice may not be removed or altered from any source distribution.
admin@999
    20
*/
admin@999
    21
#include "SDL_hints.h"
admin@999
    22
#include "SDL_log.h"
admin@999
    23
#include "SDL_timer.h"
admin@999
    24
admin@999
    25
#include "SDL_mixer.h"
admin@999
    26
#include "mixer.h"
admin@999
    27
#include "music.h"
admin@999
    28
admin@999
    29
#include "music_cmd.h"
admin@999
    30
#include "music_wav.h"
admin@999
    31
#include "music_mikmod.h"
admin@999
    32
#include "music_modplug.h"
admin@999
    33
#include "music_nativemidi.h"
admin@999
    34
#include "music_fluidsynth.h"
admin@999
    35
#include "music_timidity.h"
admin@999
    36
#include "music_ogg.h"
admin@999
    37
#include "music_opus.h"
admin@999
    38
#include "music_mpg123.h"
admin@999
    39
#include "music_mad.h"
admin@999
    40
#include "music_flac.h"
admin@999
    41
#include "native_midi/native_midi.h"
admin@999
    42
sezeroz@1012
    43
#include "compat.h"
sezeroz@1012
    44
admin@999
    45
/* Check to make sure we are building with a new enough SDL */
admin@999
    46
#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 7)
admin@999
    47
#error You need SDL 2.0.7 or newer from http://www.libsdl.org
admin@999
    48
#endif
admin@999
    49
admin@999
    50
/* Set this hint to true if you want verbose logging of music interfaces */
admin@999
    51
#define SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES \
admin@999
    52
    "SDL_MIXER_DEBUG_MUSIC_INTERFACES"
admin@999
    53
admin@999
    54
char *music_cmd = NULL;
admin@999
    55
static SDL_bool music_active = SDL_TRUE;
admin@999
    56
static int music_volume = MIX_MAX_VOLUME;
admin@999
    57
static Mix_Music * volatile music_playing = NULL;
admin@999
    58
SDL_AudioSpec music_spec;
admin@999
    59
admin@999
    60
struct _Mix_Music {
admin@999
    61
    Mix_MusicInterface *interface;
admin@999
    62
    void *context;
admin@999
    63
admin@999
    64
    SDL_bool playing;
admin@999
    65
    Mix_Fading fading;
admin@999
    66
    int fade_step;
admin@999
    67
    int fade_steps;
admin@999
    68
};
admin@999
    69
admin@999
    70
/* Used to calculate fading steps */
admin@999
    71
static int ms_per_step;
admin@999
    72
admin@999
    73
/* rcg06042009 report available decoders at runtime. */
admin@999
    74
static const char **music_decoders = NULL;
admin@999
    75
static int num_decoders = 0;
admin@999
    76
admin@999
    77
/* Semicolon-separated SoundFont paths */
admin@999
    78
static char* soundfont_paths = NULL;
admin@999
    79
sezeroz@1086
    80
/* full path of timidity config file */
sezeroz@1086
    81
static char* timidity_cfg = NULL;
sezeroz@1086
    82
admin@999
    83
/* Interfaces for the various music interfaces, ordered by priority */
admin@999
    84
static Mix_MusicInterface *s_music_interfaces[] =
admin@999
    85
{
admin@999
    86
#ifdef MUSIC_CMD
admin@999
    87
    &Mix_MusicInterface_CMD,
admin@999
    88
#endif
admin@999
    89
#ifdef MUSIC_WAV
admin@999
    90
    &Mix_MusicInterface_WAV,
admin@999
    91
#endif
admin@999
    92
#ifdef MUSIC_FLAC
admin@999
    93
    &Mix_MusicInterface_FLAC,
admin@999
    94
#endif
admin@999
    95
#ifdef MUSIC_OGG
admin@999
    96
    &Mix_MusicInterface_OGG,
admin@999
    97
#endif
admin@999
    98
#ifdef MUSIC_OPUS
admin@999
    99
    &Mix_MusicInterface_Opus,
admin@999
   100
#endif
admin@999
   101
#ifdef MUSIC_MP3_MPG123
admin@999
   102
    &Mix_MusicInterface_MPG123,
admin@999
   103
#endif
admin@999
   104
#ifdef MUSIC_MP3_MAD
admin@999
   105
    &Mix_MusicInterface_MAD,
admin@999
   106
#endif
admin@999
   107
#ifdef MUSIC_MOD_MODPLUG
admin@999
   108
    &Mix_MusicInterface_MODPLUG,
admin@999
   109
#endif
admin@999
   110
#ifdef MUSIC_MOD_MIKMOD
admin@999
   111
    &Mix_MusicInterface_MIKMOD,
admin@999
   112
#endif
admin@999
   113
#ifdef MUSIC_MID_FLUIDSYNTH
admin@999
   114
    &Mix_MusicInterface_FLUIDSYNTH,
admin@999
   115
#endif
admin@999
   116
#ifdef MUSIC_MID_TIMIDITY
admin@999
   117
    &Mix_MusicInterface_TIMIDITY,
admin@999
   118
#endif
admin@999
   119
#ifdef MUSIC_MID_NATIVE
admin@999
   120
    &Mix_MusicInterface_NATIVEMIDI,
admin@999
   121
#endif
admin@999
   122
};
admin@999
   123
admin@999
   124
int get_num_music_interfaces(void)
admin@999
   125
{
admin@999
   126
    return SDL_arraysize(s_music_interfaces);
admin@999
   127
}
admin@999
   128
admin@999
   129
Mix_MusicInterface *get_music_interface(int index)
admin@999
   130
{
admin@999
   131
    return s_music_interfaces[index];
admin@999
   132
}
admin@999
   133
admin@999
   134
int Mix_GetNumMusicDecoders(void)
admin@999
   135
{
admin@999
   136
    return(num_decoders);
admin@999
   137
}
admin@999
   138
admin@999
   139
const char *Mix_GetMusicDecoder(int index)
admin@999
   140
{
admin@999
   141
    if ((index < 0) || (index >= num_decoders)) {
admin@999
   142
        return NULL;
admin@999
   143
    }
admin@999
   144
    return(music_decoders[index]);
admin@999
   145
}
admin@999
   146
admin@999
   147
static void add_music_decoder(const char *decoder)
admin@999
   148
{
admin@999
   149
    void *ptr;
admin@999
   150
    int i;
admin@999
   151
admin@999
   152
    /* Check to see if we already have this decoder */
admin@999
   153
    for (i = 0; i < num_decoders; ++i) {
admin@999
   154
        if (SDL_strcmp(music_decoders[i], decoder) == 0) {
admin@999
   155
            return;
admin@999
   156
        }
admin@999
   157
    }
admin@999
   158
admin@1047
   159
    ptr = SDL_realloc((void *)music_decoders, ((size_t)num_decoders + 1) * sizeof (const char *));
admin@999
   160
    if (ptr == NULL) {
admin@999
   161
        return;  /* oh well, go on without it. */
admin@999
   162
    }
admin@999
   163
    music_decoders = (const char **) ptr;
admin@999
   164
    music_decoders[num_decoders++] = decoder;
admin@999
   165
}
admin@999
   166
admin@999
   167
/* Local low-level functions prototypes */
admin@999
   168
static void music_internal_initialize_volume(void);
admin@999
   169
static void music_internal_volume(int volume);
admin@999
   170
static int  music_internal_play(Mix_Music *music, int play_count, double position);
admin@999
   171
static int  music_internal_position(double position);
admin@999
   172
static SDL_bool music_internal_playing(void);
admin@999
   173
static void music_internal_halt(void);
admin@999
   174
admin@999
   175
admin@999
   176
/* Support for hooking when the music has finished */
admin@999
   177
static void (SDLCALL *music_finished_hook)(void) = NULL;
admin@999
   178
admin@999
   179
void Mix_HookMusicFinished(void (SDLCALL *music_finished)(void))
admin@999
   180
{
admin@999
   181
    Mix_LockAudio();
admin@999
   182
    music_finished_hook = music_finished;
admin@999
   183
    Mix_UnlockAudio();
admin@999
   184
}
admin@999
   185
admin@999
   186
/* Convenience function to fill audio and mix at the specified volume
admin@999
   187
   This is called from many music player's GetAudio callback.
admin@999
   188
 */
admin@999
   189
int music_pcm_getaudio(void *context, void *data, int bytes, int volume,
admin@999
   190
                       int (*GetSome)(void *context, void *data, int bytes, SDL_bool *done))
admin@999
   191
{
admin@999
   192
    Uint8 *snd = (Uint8 *)data;
admin@999
   193
    Uint8 *dst;
admin@999
   194
    int len = bytes;
admin@999
   195
    SDL_bool done = SDL_FALSE;
admin@999
   196
admin@999
   197
    if (volume == MIX_MAX_VOLUME) {
admin@999
   198
        dst = snd;
admin@999
   199
    } else {
admin@1047
   200
        dst = SDL_stack_alloc(Uint8, (size_t)bytes);
admin@999
   201
    }
admin@999
   202
    while (len > 0 && !done) {
admin@999
   203
        int consumed = GetSome(context, dst, len, &done);
admin@999
   204
        if (consumed < 0) {
admin@999
   205
            break;
admin@999
   206
        }
admin@999
   207
admin@999
   208
        if (volume == MIX_MAX_VOLUME) {
admin@999
   209
            dst += consumed;
admin@999
   210
        } else {
admin@999
   211
            SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
admin@999
   212
            snd += consumed;
admin@999
   213
        }
admin@999
   214
        len -= consumed;
admin@999
   215
    }
admin@999
   216
    if (volume != MIX_MAX_VOLUME) {
admin@999
   217
        SDL_stack_free(dst);
admin@999
   218
    }
admin@999
   219
    return len;
admin@999
   220
}
admin@999
   221
admin@999
   222
/* Mixing function */
admin@999
   223
void SDLCALL music_mixer(void *udata, Uint8 *stream, int len)
admin@999
   224
{
admin@999
   225
    (void)udata;
admin@999
   226
admin@999
   227
    while (music_playing && music_active && len > 0) {
admin@999
   228
        /* Handle fading */
admin@999
   229
        if (music_playing->fading != MIX_NO_FADING) {
admin@999
   230
            if (music_playing->fade_step++ < music_playing->fade_steps) {
admin@999
   231
                int volume;
admin@999
   232
                int fade_step = music_playing->fade_step;
admin@999
   233
                int fade_steps = music_playing->fade_steps;
admin@999
   234
admin@999
   235
                if (music_playing->fading == MIX_FADING_OUT) {
admin@999
   236
                    volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
admin@999
   237
                } else { /* Fading in */
admin@999
   238
                    volume = (music_volume * fade_step) / fade_steps;
admin@999
   239
                }
admin@999
   240
                music_internal_volume(volume);
admin@999
   241
            } else {
admin@999
   242
                if (music_playing->fading == MIX_FADING_OUT) {
admin@999
   243
                    music_internal_halt();
admin@999
   244
                    if (music_finished_hook) {
admin@999
   245
                        music_finished_hook();
admin@999
   246
                    }
admin@999
   247
                    return;
admin@999
   248
                }
admin@999
   249
                music_playing->fading = MIX_NO_FADING;
admin@999
   250
            }
admin@999
   251
        }
admin@999
   252
admin@999
   253
        if (music_playing->interface->GetAudio) {
admin@999
   254
            int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
admin@999
   255
            if (left != 0) {
admin@999
   256
                /* Either an error or finished playing with data left */
admin@999
   257
                music_playing->playing = SDL_FALSE;
admin@999
   258
            }
admin@999
   259
            if (left > 0) {
admin@999
   260
                stream += (len - left);
admin@999
   261
                len = left;
admin@999
   262
            } else {
admin@999
   263
                len = 0;
admin@999
   264
            }
admin@999
   265
        } else {
admin@999
   266
            len = 0;
admin@999
   267
        }
admin@999
   268
admin@999
   269
        if (!music_internal_playing()) {
admin@999
   270
            music_internal_halt();
admin@999
   271
            if (music_finished_hook) {
admin@999
   272
                music_finished_hook();
admin@999
   273
            }
admin@999
   274
        }
admin@999
   275
    }
admin@999
   276
}
admin@999
   277
admin@999
   278
/* Load the music interface libraries for a given music type */
admin@999
   279
SDL_bool load_music_type(Mix_MusicType type)
admin@999
   280
{
admin@999
   281
    size_t i;
admin@999
   282
    int loaded = 0;
admin@999
   283
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
   284
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
   285
        if (interface->type != type) {
admin@999
   286
            continue;
admin@999
   287
        }
admin@999
   288
        if (!interface->loaded) {
admin@999
   289
            char hint[64];
admin@999
   290
            SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
admin@999
   291
            if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
admin@999
   292
                continue;
admin@999
   293
            }
admin@999
   294
admin@999
   295
            if (interface->Load && interface->Load() < 0) {
admin@999
   296
                if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
admin@999
   297
                    SDL_Log("Couldn't load %s: %s\n", interface->tag, Mix_GetError());
admin@999
   298
                }
admin@999
   299
                continue;
admin@999
   300
            }
admin@999
   301
            interface->loaded = SDL_TRUE;
admin@999
   302
        }
admin@999
   303
        ++loaded;
admin@999
   304
    }
admin@999
   305
    return (loaded > 0) ? SDL_TRUE : SDL_FALSE;
admin@999
   306
}
admin@999
   307
admin@999
   308
/* Open the music interfaces for a given music type */
admin@999
   309
SDL_bool open_music_type(Mix_MusicType type)
admin@999
   310
{
admin@999
   311
    size_t i;
admin@999
   312
    int opened = 0;
admin@999
   313
    SDL_bool use_native_midi = SDL_FALSE;
admin@999
   314
admin@999
   315
    if (!music_spec.format) {
admin@999
   316
        /* Music isn't opened yet */
admin@999
   317
        return SDL_FALSE;
admin@999
   318
    }
admin@999
   319
admin@999
   320
#ifdef MUSIC_MID_NATIVE
admin@999
   321
    if (type == MUS_MID && SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
admin@999
   322
        use_native_midi = SDL_TRUE;
admin@999
   323
    }
admin@999
   324
#endif
admin@999
   325
admin@999
   326
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
   327
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
   328
        if (!interface->loaded) {
admin@999
   329
            continue;
admin@999
   330
        }
admin@999
   331
        if (type != MUS_NONE && interface->type != type) {
admin@999
   332
            continue;
admin@999
   333
        }
admin@999
   334
admin@999
   335
        if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
admin@999
   336
            continue;
admin@999
   337
        }
admin@999
   338
admin@999
   339
        if (!interface->opened) {
admin@999
   340
            if (interface->Open && interface->Open(&music_spec) < 0) {
admin@999
   341
                if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
admin@999
   342
                    SDL_Log("Couldn't open %s: %s\n", interface->tag, Mix_GetError());
admin@999
   343
                }
admin@999
   344
                continue;
admin@999
   345
            }
admin@999
   346
            interface->opened = SDL_TRUE;
admin@999
   347
            add_music_decoder(interface->tag);
admin@999
   348
        }
admin@999
   349
        ++opened;
admin@999
   350
    }
admin@999
   351
admin@999
   352
    if (has_music(MUS_MOD)) {
admin@999
   353
        add_music_decoder("MOD");
admin@999
   354
        add_chunk_decoder("MOD");
admin@999
   355
    }
admin@999
   356
    if (has_music(MUS_MID)) {
admin@999
   357
        add_music_decoder("MIDI");
admin@999
   358
        add_chunk_decoder("MID");
admin@999
   359
    }
admin@999
   360
    if (has_music(MUS_OGG)) {
admin@999
   361
        add_music_decoder("OGG");
admin@999
   362
        add_chunk_decoder("OGG");
admin@999
   363
    }
admin@999
   364
    if (has_music(MUS_OPUS)) {
admin@999
   365
        add_music_decoder("OPUS");
admin@999
   366
        add_chunk_decoder("OPUS");
admin@999
   367
    }
admin@999
   368
    if (has_music(MUS_MP3)) {
admin@999
   369
        add_music_decoder("MP3");
admin@999
   370
        add_chunk_decoder("MP3");
admin@999
   371
    }
admin@999
   372
    if (has_music(MUS_FLAC)) {
admin@999
   373
        add_music_decoder("FLAC");
admin@999
   374
        add_chunk_decoder("FLAC");
admin@999
   375
    }
admin@999
   376
admin@999
   377
    return (opened > 0) ? SDL_TRUE : SDL_FALSE;
admin@999
   378
}
admin@999
   379
admin@999
   380
/* Initialize the music interfaces with a certain desired audio format */
admin@999
   381
void open_music(const SDL_AudioSpec *spec)
admin@999
   382
{
admin@999
   383
#ifdef MIX_INIT_SOUNDFONT_PATHS
admin@999
   384
    if (!soundfont_paths) {
admin@999
   385
        soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
admin@999
   386
    }
admin@999
   387
#endif
admin@999
   388
admin@999
   389
    /* Load the music interfaces that don't have explicit initialization */
admin@999
   390
    load_music_type(MUS_CMD);
admin@999
   391
    load_music_type(MUS_WAV);
admin@999
   392
admin@999
   393
    /* Open all the interfaces that are loaded */
admin@999
   394
    music_spec = *spec;
admin@999
   395
    open_music_type(MUS_NONE);
admin@999
   396
admin@999
   397
    Mix_VolumeMusic(MIX_MAX_VOLUME);
admin@999
   398
admin@999
   399
    /* Calculate the number of ms for each callback */
admin@1047
   400
    ms_per_step = (int) (((float)spec->samples * 1000.0f) / spec->freq);
admin@999
   401
}
admin@999
   402
admin@999
   403
/* Return SDL_TRUE if the music type is available */
admin@999
   404
SDL_bool has_music(Mix_MusicType type)
admin@999
   405
{
admin@999
   406
    size_t i;
admin@999
   407
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
   408
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
   409
        if (interface->type != type) {
admin@999
   410
            continue;
admin@999
   411
        }
admin@999
   412
        if (interface->opened) {
admin@999
   413
            return SDL_TRUE;
admin@999
   414
        }
admin@999
   415
    }
admin@999
   416
    return SDL_FALSE;
admin@999
   417
}
admin@999
   418
admin@999
   419
Mix_MusicType detect_music_type(SDL_RWops *src)
admin@999
   420
{
admin@999
   421
    Uint8 magic[12];
admin@999
   422
admin@999
   423
    if (SDL_RWread(src, magic, 1, 12) != 12) {
admin@999
   424
        Mix_SetError("Couldn't read first 12 bytes of audio data");
admin@999
   425
        return MUS_NONE;
admin@999
   426
    }
admin@999
   427
    SDL_RWseek(src, -12, RW_SEEK_CUR);
admin@999
   428
admin@999
   429
    /* WAVE files have the magic four bytes "RIFF"
admin@999
   430
       AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
admin@999
   431
    if (((SDL_memcmp(magic, "RIFF", 4) == 0) && (SDL_memcmp((magic+8), "WAVE", 4) == 0)) ||
admin@999
   432
        (SDL_memcmp(magic, "FORM", 4) == 0)) {
admin@999
   433
        return MUS_WAV;
admin@999
   434
    }
admin@999
   435
admin@999
   436
    /* Ogg Vorbis files have the magic four bytes "OggS" */
admin@999
   437
    if (SDL_memcmp(magic, "OggS", 4) == 0) {
admin@999
   438
        SDL_RWseek(src, 28, RW_SEEK_CUR);
admin@999
   439
        SDL_RWread(src, magic, 1, 8);
admin@999
   440
        SDL_RWseek(src,-36, RW_SEEK_CUR);
admin@999
   441
        if (SDL_memcmp(magic, "OpusHead", 8) == 0) {
admin@999
   442
            return MUS_OPUS;
admin@999
   443
        }
admin@999
   444
        return MUS_OGG;
admin@999
   445
    }
admin@999
   446
admin@999
   447
    /* FLAC files have the magic four bytes "fLaC" */
admin@999
   448
    if (SDL_memcmp(magic, "fLaC", 4) == 0) {
admin@999
   449
        return MUS_FLAC;
admin@999
   450
    }
admin@999
   451
admin@999
   452
    /* MIDI files have the magic four bytes "MThd" */
admin@999
   453
    if (SDL_memcmp(magic, "MThd", 4) == 0) {
admin@999
   454
        return MUS_MID;
admin@999
   455
    }
admin@999
   456
admin@999
   457
    if (SDL_memcmp(magic, "ID3", 3) == 0 ||
admin@999
   458
        (magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
admin@999
   459
        return MUS_MP3;
admin@999
   460
    }
admin@999
   461
admin@999
   462
    /* Assume MOD format.
admin@999
   463
     *
admin@999
   464
     * Apparently there is no way to check if the file is really a MOD,
admin@999
   465
     * or there are too many formats supported by MikMod/ModPlug, or
admin@999
   466
     * MikMod/ModPlug does this check by itself. */
admin@999
   467
    return MUS_MOD;
admin@999
   468
}
admin@999
   469
admin@999
   470
/* Load a music file */
admin@999
   471
Mix_Music *Mix_LoadMUS(const char *file)
admin@999
   472
{
admin@999
   473
    size_t i;
admin@999
   474
    void *context;
admin@999
   475
    char *ext;
admin@999
   476
    Mix_MusicType type;
admin@999
   477
    SDL_RWops *src;
admin@999
   478
admin@999
   479
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
   480
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
   481
        if (!interface->opened || !interface->CreateFromFile) {
admin@999
   482
            continue;
admin@999
   483
        }
admin@999
   484
admin@999
   485
        context = interface->CreateFromFile(file);
admin@999
   486
        if (context) {
admin@999
   487
            /* Allocate memory for the music structure */
admin@999
   488
            Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
admin@999
   489
            if (music == NULL) {
admin@999
   490
                Mix_SetError("Out of memory");
admin@999
   491
                return NULL;
admin@999
   492
            }
admin@999
   493
            music->interface = interface;
admin@999
   494
            music->context = context;
admin@999
   495
            return music;
admin@999
   496
        }
admin@999
   497
    }
admin@999
   498
admin@999
   499
    src = SDL_RWFromFile(file, "rb");
admin@999
   500
    if (src == NULL) {
admin@999
   501
        Mix_SetError("Couldn't open '%s'", file);
admin@999
   502
        return NULL;
admin@999
   503
    }
admin@999
   504
admin@999
   505
    /* Use the extension as a first guess on the file type */
admin@999
   506
    type = MUS_NONE;
sezeroz@1016
   507
    ext = SDL_strrchr(file, '.');
admin@999
   508
    if (ext) {
admin@999
   509
        ++ext; /* skip the dot in the extension */
admin@999
   510
        if (SDL_strcasecmp(ext, "WAV") == 0) {
admin@999
   511
            type = MUS_WAV;
admin@999
   512
        } else if (SDL_strcasecmp(ext, "MID") == 0 ||
admin@999
   513
                    SDL_strcasecmp(ext, "MIDI") == 0 ||
admin@999
   514
                    SDL_strcasecmp(ext, "KAR") == 0) {
admin@999
   515
            type = MUS_MID;
admin@999
   516
        } else if (SDL_strcasecmp(ext, "OGG") == 0) {
admin@999
   517
            type = MUS_OGG;
admin@999
   518
        } else if (SDL_strcasecmp(ext, "OPUS") == 0) {
admin@999
   519
            type = MUS_OPUS;
admin@999
   520
        } else if (SDL_strcasecmp(ext, "FLAC") == 0) {
admin@999
   521
            type = MUS_FLAC;
admin@999
   522
        } else  if (SDL_strcasecmp(ext, "MPG") == 0 ||
admin@999
   523
                     SDL_strcasecmp(ext, "MPEG") == 0 ||
admin@999
   524
                     SDL_strcasecmp(ext, "MP3") == 0 ||
admin@999
   525
                     SDL_strcasecmp(ext, "MAD") == 0) {
admin@999
   526
            type = MUS_MP3;
admin@999
   527
        } else if (SDL_strcasecmp(ext, "669") == 0 ||
admin@999
   528
                    SDL_strcasecmp(ext, "AMF") == 0 ||
admin@999
   529
                    SDL_strcasecmp(ext, "AMS") == 0 ||
admin@999
   530
                    SDL_strcasecmp(ext, "DBM") == 0 ||
admin@999
   531
                    SDL_strcasecmp(ext, "DSM") == 0 ||
admin@999
   532
                    SDL_strcasecmp(ext, "FAR") == 0 ||
admin@999
   533
                    SDL_strcasecmp(ext, "IT") == 0 ||
admin@999
   534
                    SDL_strcasecmp(ext, "MED") == 0 ||
admin@999
   535
                    SDL_strcasecmp(ext, "MDL") == 0 ||
admin@999
   536
                    SDL_strcasecmp(ext, "MOD") == 0 ||
admin@999
   537
                    SDL_strcasecmp(ext, "MOL") == 0 ||
admin@999
   538
                    SDL_strcasecmp(ext, "MTM") == 0 ||
admin@999
   539
                    SDL_strcasecmp(ext, "NST") == 0 ||
admin@999
   540
                    SDL_strcasecmp(ext, "OKT") == 0 ||
admin@999
   541
                    SDL_strcasecmp(ext, "PTM") == 0 ||
admin@999
   542
                    SDL_strcasecmp(ext, "S3M") == 0 ||
admin@999
   543
                    SDL_strcasecmp(ext, "STM") == 0 ||
admin@999
   544
                    SDL_strcasecmp(ext, "ULT") == 0 ||
admin@999
   545
                    SDL_strcasecmp(ext, "UMX") == 0 ||
admin@999
   546
                    SDL_strcasecmp(ext, "WOW") == 0 ||
admin@999
   547
                    SDL_strcasecmp(ext, "XM") == 0) {
admin@999
   548
            type = MUS_MOD;
admin@999
   549
        }
admin@999
   550
    }
admin@999
   551
    return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
admin@999
   552
}
admin@999
   553
admin@999
   554
Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
admin@999
   555
{
admin@999
   556
    return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
admin@999
   557
}
admin@999
   558
admin@999
   559
Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
admin@999
   560
{
admin@999
   561
    size_t i;
admin@999
   562
    void *context;
admin@999
   563
    Sint64 start;
admin@999
   564
admin@999
   565
    if (!src) {
admin@999
   566
        Mix_SetError("RWops pointer is NULL");
admin@999
   567
        return NULL;
admin@999
   568
    }
admin@999
   569
    start = SDL_RWtell(src);
admin@999
   570
admin@999
   571
    /* If the caller wants auto-detection, figure out what kind of file
admin@999
   572
     * this is. */
admin@999
   573
    if (type == MUS_NONE) {
admin@999
   574
        if ((type = detect_music_type(src)) == MUS_NONE) {
admin@999
   575
            /* Don't call Mix_SetError() since detect_music_type() does that. */
admin@999
   576
            if (freesrc) {
admin@999
   577
                SDL_RWclose(src);
admin@999
   578
            }
admin@999
   579
            return NULL;
admin@999
   580
        }
admin@999
   581
    }
admin@999
   582
admin@999
   583
    Mix_ClearError();
admin@999
   584
admin@999
   585
    if (load_music_type(type) && open_music_type(type)) {
admin@999
   586
        for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
   587
            Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
   588
            if (!interface->opened || type != interface->type || !interface->CreateFromRW) {
admin@999
   589
                continue;
admin@999
   590
            }
admin@999
   591
admin@999
   592
            context = interface->CreateFromRW(src, freesrc);
admin@999
   593
            if (context) {
admin@999
   594
                /* Allocate memory for the music structure */
admin@999
   595
                Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
admin@999
   596
                if (music == NULL) {
admin@999
   597
                    interface->Delete(context);
admin@999
   598
                    Mix_SetError("Out of memory");
admin@999
   599
                    return NULL;
admin@999
   600
                }
admin@999
   601
                music->interface = interface;
admin@999
   602
                music->context = context;
admin@999
   603
admin@999
   604
                if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
admin@999
   605
                    SDL_Log("Loaded music with %s\n", interface->tag);
admin@999
   606
                }
admin@999
   607
                return music;
admin@999
   608
            }
admin@999
   609
admin@999
   610
            /* Reset the stream for the next decoder */
admin@999
   611
            SDL_RWseek(src, start, RW_SEEK_SET);
admin@999
   612
        }
admin@999
   613
    }
admin@999
   614
admin@999
   615
    if (!*Mix_GetError()) {
admin@999
   616
        Mix_SetError("Unrecognized audio format");
admin@999
   617
    }
admin@999
   618
    if (freesrc) {
admin@999
   619
        SDL_RWclose(src);
admin@999
   620
    } else {
admin@999
   621
        SDL_RWseek(src, start, RW_SEEK_SET);
admin@999
   622
    }
admin@999
   623
    return NULL;
admin@999
   624
}
admin@999
   625
admin@999
   626
/* Free a music chunk previously loaded */
admin@999
   627
void Mix_FreeMusic(Mix_Music *music)
admin@999
   628
{
admin@999
   629
    if (music) {
admin@999
   630
        /* Stop the music if it's currently playing */
admin@999
   631
        Mix_LockAudio();
admin@999
   632
        if (music == music_playing) {
admin@999
   633
            /* Wait for any fade out to finish */
admin@999
   634
            while (music->fading == MIX_FADING_OUT) {
admin@999
   635
                Mix_UnlockAudio();
admin@999
   636
                SDL_Delay(100);
admin@999
   637
                Mix_LockAudio();
admin@999
   638
            }
admin@999
   639
            if (music == music_playing) {
admin@999
   640
                music_internal_halt();
admin@999
   641
            }
admin@999
   642
        }
admin@999
   643
        Mix_UnlockAudio();
admin@999
   644
admin@999
   645
        music->interface->Delete(music->context);
admin@999
   646
        SDL_free(music);
admin@999
   647
    }
admin@999
   648
}
admin@999
   649
admin@999
   650
/* Find out the music format of a mixer music, or the currently playing
admin@999
   651
   music, if 'music' is NULL.
admin@999
   652
*/
admin@999
   653
Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
admin@999
   654
{
admin@999
   655
    Mix_MusicType type = MUS_NONE;
admin@999
   656
admin@999
   657
    if (music) {
admin@999
   658
        type = music->interface->type;
admin@999
   659
    } else {
admin@999
   660
        Mix_LockAudio();
admin@999
   661
        if (music_playing) {
admin@999
   662
            type = music_playing->interface->type;
admin@999
   663
        }
admin@999
   664
        Mix_UnlockAudio();
admin@999
   665
    }
admin@999
   666
    return(type);
admin@999
   667
}
admin@999
   668
admin@999
   669
/* Play a music chunk.  Returns 0, or -1 if there was an error.
admin@999
   670
 */
admin@999
   671
static int music_internal_play(Mix_Music *music, int play_count, double position)
admin@999
   672
{
admin@999
   673
    int retval = 0;
admin@999
   674
admin@999
   675
#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
admin@999
   676
    /* This fixes a bug with native MIDI on Mac OS X, where you
admin@999
   677
       can't really stop and restart MIDI from the audio callback.
admin@999
   678
    */
admin@999
   679
    if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
admin@999
   680
        /* Just a seek suffices to restart playing */
admin@999
   681
        music_internal_position(position);
admin@999
   682
        return 0;
admin@999
   683
    }
admin@999
   684
#endif
admin@999
   685
admin@999
   686
    /* Note the music we're playing */
admin@999
   687
    if (music_playing) {
admin@999
   688
        music_internal_halt();
admin@999
   689
    }
admin@999
   690
    music_playing = music;
admin@999
   691
    music_playing->playing = SDL_TRUE;
admin@999
   692
admin@999
   693
    /* Set the initial volume */
admin@999
   694
    music_internal_initialize_volume();
admin@999
   695
admin@999
   696
    /* Set up for playback */
admin@999
   697
    retval = music->interface->Play(music->context, play_count);
admin@999
   698
admin@999
   699
    /* Set the playback position, note any errors if an offset is used */
admin@999
   700
    if (retval == 0) {
admin@999
   701
        if (position > 0.0) {
admin@999
   702
            if (music_internal_position(position) < 0) {
admin@999
   703
                Mix_SetError("Position not implemented for music type");
admin@999
   704
                retval = -1;
admin@999
   705
            }
admin@999
   706
        } else {
admin@999
   707
            music_internal_position(0.0);
admin@999
   708
        }
admin@999
   709
    }
admin@999
   710
admin@999
   711
    /* If the setup failed, we're not playing any music anymore */
admin@999
   712
    if (retval < 0) {
admin@999
   713
        music->playing = SDL_FALSE;
admin@999
   714
        music_playing = NULL;
admin@999
   715
    }
admin@999
   716
    return(retval);
admin@999
   717
}
admin@999
   718
admin@999
   719
int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
admin@999
   720
{
admin@999
   721
    int retval;
admin@999
   722
admin@999
   723
    if (ms_per_step == 0) {
admin@999
   724
        SDL_SetError("Audio device hasn't been opened");
admin@999
   725
        return(-1);
admin@999
   726
    }
admin@999
   727
admin@999
   728
    /* Don't play null pointers :-) */
admin@999
   729
    if (music == NULL) {
admin@999
   730
        Mix_SetError("music parameter was NULL");
admin@999
   731
        return(-1);
admin@999
   732
    }
admin@999
   733
admin@999
   734
    /* Setup the data */
admin@999
   735
    if (ms) {
admin@999
   736
        music->fading = MIX_FADING_IN;
admin@999
   737
    } else {
admin@999
   738
        music->fading = MIX_NO_FADING;
admin@999
   739
    }
admin@999
   740
    music->fade_step = 0;
admin@999
   741
    music->fade_steps = ms/ms_per_step;
admin@999
   742
admin@999
   743
    /* Play the puppy */
admin@999
   744
    Mix_LockAudio();
admin@999
   745
    /* If the current music is fading out, wait for the fade to complete */
admin@999
   746
    while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
admin@999
   747
        Mix_UnlockAudio();
admin@999
   748
        SDL_Delay(100);
admin@999
   749
        Mix_LockAudio();
admin@999
   750
    }
admin@999
   751
    if (loops == 0) {
admin@999
   752
        /* Loop is the number of times to play the audio */
admin@999
   753
        loops = 1;
admin@999
   754
    }
admin@999
   755
    retval = music_internal_play(music, loops, position);
admin@999
   756
    /* Set music as active */
admin@999
   757
    music_active = (retval == 0);
admin@999
   758
    Mix_UnlockAudio();
admin@999
   759
admin@999
   760
    return(retval);
admin@999
   761
}
admin@999
   762
int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
admin@999
   763
{
admin@999
   764
    return Mix_FadeInMusicPos(music, loops, ms, 0.0);
admin@999
   765
}
admin@999
   766
int Mix_PlayMusic(Mix_Music *music, int loops)
admin@999
   767
{
admin@999
   768
    return Mix_FadeInMusicPos(music, loops, 0, 0.0);
admin@999
   769
}
admin@999
   770
admin@999
   771
/* Set the playing music position */
admin@999
   772
int music_internal_position(double position)
admin@999
   773
{
admin@999
   774
    if (music_playing->interface->Seek) {
admin@999
   775
        return music_playing->interface->Seek(music_playing->context, position);
admin@999
   776
    }
admin@999
   777
    return -1;
admin@999
   778
}
admin@999
   779
int Mix_SetMusicPosition(double position)
admin@999
   780
{
admin@999
   781
    int retval;
admin@999
   782
admin@999
   783
    Mix_LockAudio();
admin@999
   784
    if (music_playing) {
admin@999
   785
        retval = music_internal_position(position);
admin@999
   786
        if (retval < 0) {
admin@999
   787
            Mix_SetError("Position not implemented for music type");
admin@999
   788
        }
admin@999
   789
    } else {
admin@999
   790
        Mix_SetError("Music isn't playing");
admin@999
   791
        retval = -1;
admin@999
   792
    }
admin@999
   793
    Mix_UnlockAudio();
admin@999
   794
admin@999
   795
    return(retval);
admin@999
   796
}
admin@999
   797
uso@1090
   798
static double music_duration_int(Mix_Music *music)
uso@1090
   799
{
uso@1090
   800
    if (music->interface->Duration) {
uso@1090
   801
        return music->interface->Duration(music->context);
uso@1090
   802
    } else {
uso@1090
   803
        Mix_SetError("Duration not implemented for music type");
uso@1090
   804
        return -1;
uso@1090
   805
    }
uso@1090
   806
}
uso@1090
   807
uso@1090
   808
double Mix_MusicDuration(Mix_Music *music)
uso@1090
   809
{
uso@1090
   810
    double retval;
uso@1090
   811
uso@1090
   812
    Mix_LockAudio();
uso@1090
   813
uso@1090
   814
    if (music) {
uso@1090
   815
        retval = music_duration_int(music);
uso@1090
   816
    } else if (music_playing) {
uso@1090
   817
        retval = music_duration_int(music_playing);
uso@1090
   818
    } else {
uso@1090
   819
        Mix_SetError("music is NULL and no playing music");
uso@1090
   820
        retval = -1;
uso@1090
   821
    }
uso@1090
   822
    Mix_UnlockAudio();
uso@1090
   823
uso@1090
   824
    return(retval);
uso@1090
   825
}
uso@1090
   826
admin@999
   827
/* Set the music's initial volume */
admin@999
   828
static void music_internal_initialize_volume(void)
admin@999
   829
{
admin@999
   830
    if (music_playing->fading == MIX_FADING_IN) {
admin@999
   831
        music_internal_volume(0);
admin@999
   832
    } else {
admin@999
   833
        music_internal_volume(music_volume);
admin@999
   834
    }
admin@999
   835
}
admin@999
   836
admin@999
   837
/* Set the music volume */
admin@999
   838
static void music_internal_volume(int volume)
admin@999
   839
{
admin@999
   840
    if (music_playing->interface->SetVolume) {
admin@999
   841
        music_playing->interface->SetVolume(music_playing->context, volume);
admin@999
   842
    }
admin@999
   843
}
admin@999
   844
int Mix_VolumeMusic(int volume)
admin@999
   845
{
admin@999
   846
    int prev_volume;
admin@999
   847
admin@999
   848
    prev_volume = music_volume;
admin@999
   849
    if (volume < 0) {
admin@999
   850
        return prev_volume;
admin@999
   851
    }
admin@999
   852
    if (volume > SDL_MIX_MAXVOLUME) {
admin@999
   853
        volume = SDL_MIX_MAXVOLUME;
admin@999
   854
    }
admin@999
   855
    music_volume = volume;
admin@999
   856
    Mix_LockAudio();
admin@999
   857
    if (music_playing) {
admin@999
   858
        music_internal_volume(music_volume);
admin@999
   859
    }
admin@999
   860
    Mix_UnlockAudio();
admin@999
   861
    return(prev_volume);
admin@999
   862
}
admin@999
   863
admin@999
   864
/* Halt playing of music */
admin@999
   865
static void music_internal_halt(void)
admin@999
   866
{
admin@999
   867
    if (music_playing->interface->Stop) {
admin@999
   868
        music_playing->interface->Stop(music_playing->context);
admin@999
   869
    }
admin@999
   870
admin@999
   871
    music_playing->playing = SDL_FALSE;
admin@999
   872
    music_playing->fading = MIX_NO_FADING;
admin@999
   873
    music_playing = NULL;
admin@999
   874
}
admin@999
   875
int Mix_HaltMusic(void)
admin@999
   876
{
admin@999
   877
    Mix_LockAudio();
admin@999
   878
    if (music_playing) {
admin@999
   879
        music_internal_halt();
admin@999
   880
        if (music_finished_hook) {
admin@999
   881
            music_finished_hook();
admin@999
   882
        }
admin@999
   883
    }
admin@999
   884
    Mix_UnlockAudio();
admin@999
   885
admin@999
   886
    return(0);
admin@999
   887
}
admin@999
   888
admin@999
   889
/* Progressively stop the music */
admin@999
   890
int Mix_FadeOutMusic(int ms)
admin@999
   891
{
admin@999
   892
    int retval = 0;
admin@999
   893
admin@999
   894
    if (ms_per_step == 0) {
admin@999
   895
        SDL_SetError("Audio device hasn't been opened");
admin@999
   896
        return 0;
admin@999
   897
    }
admin@999
   898
admin@999
   899
    if (ms <= 0) {  /* just halt immediately. */
admin@999
   900
        Mix_HaltMusic();
admin@999
   901
        return 1;
admin@999
   902
    }
admin@999
   903
admin@999
   904
    Mix_LockAudio();
admin@999
   905
    if (music_playing) {
admin@999
   906
        int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
admin@999
   907
        if (music_playing->fading == MIX_NO_FADING) {
admin@999
   908
            music_playing->fade_step = 0;
admin@999
   909
        } else {
admin@999
   910
            int step;
admin@999
   911
            int old_fade_steps = music_playing->fade_steps;
admin@999
   912
            if (music_playing->fading == MIX_FADING_OUT) {
admin@999
   913
                step = music_playing->fade_step;
admin@999
   914
            } else {
admin@999
   915
                step = old_fade_steps - music_playing->fade_step + 1;
admin@999
   916
            }
admin@999
   917
            music_playing->fade_step = (step * fade_steps) / old_fade_steps;
admin@999
   918
        }
admin@999
   919
        music_playing->fading = MIX_FADING_OUT;
admin@999
   920
        music_playing->fade_steps = fade_steps;
admin@999
   921
        retval = 1;
admin@999
   922
    }
admin@999
   923
    Mix_UnlockAudio();
admin@999
   924
admin@999
   925
    return(retval);
admin@999
   926
}
admin@999
   927
admin@999
   928
Mix_Fading Mix_FadingMusic(void)
admin@999
   929
{
admin@999
   930
    Mix_Fading fading = MIX_NO_FADING;
admin@999
   931
admin@999
   932
    Mix_LockAudio();
admin@999
   933
    if (music_playing) {
admin@999
   934
        fading = music_playing->fading;
admin@999
   935
    }
admin@999
   936
    Mix_UnlockAudio();
admin@999
   937
admin@999
   938
    return(fading);
admin@999
   939
}
admin@999
   940
admin@999
   941
/* Pause/Resume the music stream */
admin@999
   942
void Mix_PauseMusic(void)
admin@999
   943
{
admin@999
   944
    Mix_LockAudio();
admin@999
   945
    if (music_playing) {
admin@999
   946
        if (music_playing->interface->Pause) {
admin@999
   947
            music_playing->interface->Pause(music_playing->context);
admin@999
   948
        }
admin@999
   949
    }
admin@999
   950
    music_active = SDL_FALSE;
admin@999
   951
    Mix_UnlockAudio();
admin@999
   952
}
admin@999
   953
admin@999
   954
void Mix_ResumeMusic(void)
admin@999
   955
{
admin@999
   956
    Mix_LockAudio();
admin@999
   957
    if (music_playing) {
admin@999
   958
        if (music_playing->interface->Resume) {
admin@999
   959
            music_playing->interface->Resume(music_playing->context);
admin@999
   960
        }
admin@999
   961
    }
admin@999
   962
    music_active = SDL_TRUE;
admin@999
   963
    Mix_UnlockAudio();
admin@999
   964
}
admin@999
   965
admin@999
   966
void Mix_RewindMusic(void)
admin@999
   967
{
admin@999
   968
    Mix_SetMusicPosition(0.0);
admin@999
   969
}
admin@999
   970
admin@999
   971
int Mix_PausedMusic(void)
admin@999
   972
{
admin@999
   973
    return (music_active == SDL_FALSE);
admin@999
   974
}
admin@999
   975
admin@999
   976
/* Check the status of the music */
admin@999
   977
static SDL_bool music_internal_playing(void)
admin@999
   978
{
admin@999
   979
    if (!music_playing) {
admin@999
   980
        return SDL_FALSE;
admin@999
   981
    }
admin@999
   982
admin@999
   983
    if (music_playing->interface->IsPlaying) {
admin@999
   984
        music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
admin@999
   985
    }
admin@999
   986
    return music_playing->playing;
admin@999
   987
}
admin@999
   988
int Mix_PlayingMusic(void)
admin@999
   989
{
admin@999
   990
    SDL_bool playing;
admin@999
   991
admin@999
   992
    Mix_LockAudio();
admin@999
   993
    playing = music_internal_playing();
admin@999
   994
    Mix_UnlockAudio();
admin@999
   995
admin@999
   996
    return playing ? 1 : 0;
admin@999
   997
}
admin@999
   998
admin@999
   999
/* Set the external music playback command */
admin@999
  1000
int Mix_SetMusicCMD(const char *command)
admin@999
  1001
{
admin@999
  1002
    Mix_HaltMusic();
admin@999
  1003
    if (music_cmd) {
admin@999
  1004
        SDL_free(music_cmd);
admin@999
  1005
        music_cmd = NULL;
admin@999
  1006
    }
admin@999
  1007
    if (command) {
admin@999
  1008
        size_t length = SDL_strlen(command) + 1;
admin@999
  1009
        music_cmd = (char *)SDL_malloc(length);
admin@999
  1010
        if (music_cmd == NULL) {
admin@999
  1011
            return SDL_OutOfMemory();
admin@999
  1012
        }
admin@999
  1013
        SDL_memcpy(music_cmd, command, length);
admin@999
  1014
    }
admin@999
  1015
    return 0;
admin@999
  1016
}
admin@999
  1017
admin@999
  1018
int Mix_SetSynchroValue(int i)
admin@999
  1019
{
admin@999
  1020
    /* Not supported by any players at this time */
admin@999
  1021
    return(-1);
admin@999
  1022
}
admin@999
  1023
admin@999
  1024
int Mix_GetSynchroValue(void)
admin@999
  1025
{
admin@999
  1026
    /* Not supported by any players at this time */
admin@999
  1027
    return(-1);
admin@999
  1028
}
admin@999
  1029
admin@999
  1030
admin@999
  1031
/* Uninitialize the music interfaces */
admin@999
  1032
void close_music(void)
admin@999
  1033
{
admin@999
  1034
    size_t i;
admin@999
  1035
admin@999
  1036
    Mix_HaltMusic();
admin@999
  1037
admin@999
  1038
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
  1039
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
  1040
        if (!interface || !interface->opened) {
admin@999
  1041
            continue;
admin@999
  1042
        }
admin@999
  1043
admin@999
  1044
        if (interface->Close) {
admin@999
  1045
            interface->Close();
admin@999
  1046
        }
admin@999
  1047
        interface->opened = SDL_FALSE;
admin@999
  1048
    }
admin@999
  1049
admin@999
  1050
    if (soundfont_paths) {
admin@999
  1051
        SDL_free(soundfont_paths);
admin@999
  1052
        soundfont_paths = NULL;
admin@999
  1053
    }
admin@999
  1054
admin@999
  1055
    /* rcg06042009 report available decoders at runtime. */
admin@999
  1056
    if (music_decoders) {
admin@999
  1057
        SDL_free((void *)music_decoders);
admin@999
  1058
        music_decoders = NULL;
admin@999
  1059
    }
admin@999
  1060
    num_decoders = 0;
admin@999
  1061
admin@999
  1062
    ms_per_step = 0;
admin@999
  1063
}
admin@999
  1064
admin@999
  1065
/* Unload the music interface libraries */
admin@999
  1066
void unload_music(void)
admin@999
  1067
{
admin@999
  1068
    size_t i;
admin@999
  1069
    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
admin@999
  1070
        Mix_MusicInterface *interface = s_music_interfaces[i];
admin@999
  1071
        if (!interface || !interface->loaded) {
admin@999
  1072
            continue;
admin@999
  1073
        }
admin@999
  1074
admin@999
  1075
        if (interface->Unload) {
admin@999
  1076
            interface->Unload();
admin@999
  1077
        }
admin@999
  1078
        interface->loaded = SDL_FALSE;
admin@999
  1079
    }
admin@999
  1080
}
admin@999
  1081
sezeroz@1086
  1082
int Mix_SetTimidityCfg(const char *path)
sezeroz@1086
  1083
{
sezeroz@1086
  1084
    if (timidity_cfg) {
sezeroz@1086
  1085
        SDL_free(timidity_cfg);
sezeroz@1086
  1086
        timidity_cfg = NULL;
sezeroz@1086
  1087
    }
sezeroz@1086
  1088
sezeroz@1086
  1089
    if (path && *path) {
sezeroz@1086
  1090
        if (!(timidity_cfg = SDL_strdup(path))) {
sezeroz@1086
  1091
            Mix_SetError("Insufficient memory to set Timidity cfg file");
sezeroz@1086
  1092
            return 0;
sezeroz@1086
  1093
        }
sezeroz@1086
  1094
    }
sezeroz@1086
  1095
sezeroz@1086
  1096
    return 1;
sezeroz@1086
  1097
}
sezeroz@1086
  1098
sezeroz@1086
  1099
const char* Mix_GetTimidityCfg(void)
sezeroz@1086
  1100
{
sezeroz@1086
  1101
    return timidity_cfg;
sezeroz@1086
  1102
}
sezeroz@1086
  1103
admin@999
  1104
int Mix_SetSoundFonts(const char *paths)
admin@999
  1105
{
admin@999
  1106
    if (soundfont_paths) {
admin@999
  1107
        SDL_free(soundfont_paths);
admin@999
  1108
        soundfont_paths = NULL;
admin@999
  1109
    }
admin@999
  1110
admin@999
  1111
    if (paths) {
admin@999
  1112
        if (!(soundfont_paths = SDL_strdup(paths))) {
admin@999
  1113
            Mix_SetError("Insufficient memory to set SoundFonts");
admin@999
  1114
            return 0;
admin@999
  1115
        }
admin@999
  1116
    }
admin@999
  1117
    return 1;
admin@999
  1118
}
admin@999
  1119
admin@999
  1120
const char* Mix_GetSoundFonts(void)
admin@999
  1121
{
admin@999
  1122
    const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
admin@999
  1123
    SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
admin@999
  1124
    if (force_env_paths && (!env_paths || !*env_paths)) {
admin@999
  1125
        force_env_paths = SDL_FALSE;
admin@999
  1126
    }
admin@999
  1127
    if (soundfont_paths && *soundfont_paths && !force_env_paths) {
admin@999
  1128
        return soundfont_paths;
admin@999
  1129
    }
admin@999
  1130
    if (env_paths) {
admin@999
  1131
        return env_paths;
admin@999
  1132
    }
admin@999
  1133
admin@999
  1134
    /* We don't have any sound fonts set programmatically or in the environment
admin@999
  1135
       Time to start guessing where they might be...
admin@999
  1136
     */
admin@999
  1137
    {
admin@999
  1138
        static char *s_soundfont_paths[] = {
admin@999
  1139
            "/usr/share/sounds/sf2/FluidR3_GM.sf2"  /* Remember to add ',' here */
admin@999
  1140
        };
admin@999
  1141
        unsigned i;
admin@999
  1142
admin@999
  1143
        for (i = 0; i < SDL_arraysize(s_soundfont_paths); ++i) {
admin@999
  1144
            SDL_RWops *rwops = SDL_RWFromFile(s_soundfont_paths[i], "rb");
admin@999
  1145
            if (rwops) {
admin@999
  1146
                SDL_RWclose(rwops);
admin@999
  1147
                return s_soundfont_paths[i];
admin@999
  1148
            }
admin@999
  1149
        }
admin@999
  1150
    }
admin@999
  1151
    return NULL;
admin@999
  1152
}
admin@999
  1153
admin@999
  1154
int Mix_EachSoundFont(int (SDLCALL *function)(const char*, void*), void *data)
admin@999
  1155
{
admin@999
  1156
    char *context, *path, *paths;
admin@999
  1157
    const char* cpaths = Mix_GetSoundFonts();
admin@999
  1158
    int soundfonts_found = 0;
admin@999
  1159
admin@999
  1160
    if (!cpaths) {
admin@999
  1161
        Mix_SetError("No SoundFonts have been requested");
admin@999
  1162
        return 0;
admin@999
  1163
    }
admin@999
  1164
admin@999
  1165
    if (!(paths = SDL_strdup(cpaths))) {
admin@999
  1166
        Mix_SetError("Insufficient memory to iterate over SoundFonts");
admin@999
  1167
        return 0;
admin@999
  1168
    }
admin@999
  1169
admin@999
  1170
#if defined(_WIN32)||defined(__OS2__)
sezeroz@1012
  1171
#define PATHSEP ";"
admin@999
  1172
#else
sezeroz@1012
  1173
#define PATHSEP ":;"
admin@999
  1174
#endif
sezeroz@1012
  1175
    for (path = SDL_strtokr(paths, PATHSEP, &context); path;
sezeroz@1012
  1176
         path = SDL_strtokr(NULL,  PATHSEP, &context)) {
admin@999
  1177
        if (!function(path, data)) {
admin@999
  1178
            continue;
admin@999
  1179
        }
sezeroz@1012
  1180
        soundfonts_found++;
admin@999
  1181
    }
admin@999
  1182
admin@999
  1183
    SDL_free(paths);
sezeroz@1012
  1184
    return (soundfonts_found > 0);
admin@999
  1185
}
admin@999
  1186
admin@999
  1187
/* vi: set ts=4 sw=4 expandtab: */