music.c
changeset 777 92882ef2ab81
parent 770 74a0ac03a448
child 779 a2b494c054d5
     1.1 --- a/music.c	Mon Oct 16 02:16:47 2017 -0700
     1.2 +++ b/music.c	Tue Oct 17 02:33:47 2017 -0700
     1.3 @@ -18,130 +18,47 @@
     1.4       misrepresented as being the original software.
     1.5    3. This notice may not be removed or altered from any source distribution.
     1.6  */
     1.7 +#include <string.h> /* for strtok() and strtok_s() */
     1.8  
     1.9 -/* $Id$ */
    1.10 -
    1.11 -#include <stdlib.h>
    1.12 -#include <string.h>
    1.13 -#include <ctype.h>
    1.14 -#include <assert.h>
    1.15 -#include "SDL_endian.h"
    1.16 -#include "SDL_audio.h"
    1.17 +#include "SDL_hints.h"
    1.18  #include "SDL_timer.h"
    1.19  
    1.20  #include "SDL_mixer.h"
    1.21  #include "mixer.h"
    1.22 +#include "music.h"
    1.23  
    1.24 -#ifdef CMD_MUSIC
    1.25  #include "music_cmd.h"
    1.26 -#endif
    1.27 -#ifdef WAV_MUSIC
    1.28 -#include "wavestream.h"
    1.29 -#endif
    1.30 -#ifdef MODPLUG_MUSIC
    1.31 +#include "music_wav.h"
    1.32 +#include "music_mikmod.h"
    1.33  #include "music_modplug.h"
    1.34 -#endif
    1.35 -#ifdef MOD_MUSIC
    1.36 -#include "music_mod.h"
    1.37 -#endif
    1.38 -#ifdef MID_MUSIC
    1.39 -#  ifdef USE_TIMIDITY_MIDI
    1.40 -#    include "timidity.h"
    1.41 -#  endif
    1.42 -#  ifdef USE_FLUIDSYNTH_MIDI
    1.43 -#    include "fluidsynth.h"
    1.44 -#  endif
    1.45 -#  ifdef USE_NATIVE_MIDI
    1.46 -#    include "native_midi.h"
    1.47 -#  endif
    1.48 -#endif
    1.49 -#ifdef OGG_MUSIC
    1.50 +#include "music_nativemidi.h"
    1.51 +#include "music_fluidsynth.h"
    1.52 +#include "music_timidity.h"
    1.53  #include "music_ogg.h"
    1.54 -#endif
    1.55 -#ifdef MP3_MUSIC
    1.56 -#include "dynamic_mp3.h"
    1.57 -#endif
    1.58 -#ifdef MP3_MAD_MUSIC
    1.59 +#include "music_mpg123.h"
    1.60  #include "music_mad.h"
    1.61 -#endif
    1.62 -#ifdef MP3_MPG_MUSIC
    1.63 -#include "music_mpg.h"
    1.64 -#endif
    1.65 -#ifdef FLAC_MUSIC
    1.66 +#include "music_smpeg.h"
    1.67  #include "music_flac.h"
    1.68 -#endif
    1.69 +#include "native_midi/native_midi.h"
    1.70  
    1.71 -#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC) || defined(MP3_MPG_MUSIC)
    1.72 -static SDL_AudioSpec used_mixer;
    1.73 -#endif
    1.74  
    1.75 -
    1.76 +char *music_cmd = NULL;
    1.77  int volatile music_active = 1;
    1.78 -static int volatile music_stopped = 0;
    1.79 -static int music_loops = 0;
    1.80 -static char *music_cmd = NULL;
    1.81  static Mix_Music * volatile music_playing = NULL;
    1.82 -static int music_volume = MIX_MAX_VOLUME;
    1.83 +int music_loops = 0;
    1.84 +int music_volume = MIX_MAX_VOLUME;
    1.85 +SDL_AudioSpec music_spec;
    1.86  
    1.87  struct _Mix_Music {
    1.88 -    Mix_MusicType type;
    1.89 -    union {
    1.90 -#ifdef CMD_MUSIC
    1.91 -        MusicCMD *cmd;
    1.92 -#endif
    1.93 -#ifdef WAV_MUSIC
    1.94 -        WAVStream *wave;
    1.95 -#endif
    1.96 -#ifdef MODPLUG_MUSIC
    1.97 -        modplug_data *modplug;
    1.98 -#endif
    1.99 -#ifdef MOD_MUSIC
   1.100 -        struct MODULE *module;
   1.101 -#endif
   1.102 -#ifdef MID_MUSIC
   1.103 -#ifdef USE_TIMIDITY_MIDI
   1.104 -        MidiSong *midi;
   1.105 -#endif
   1.106 -#ifdef USE_FLUIDSYNTH_MIDI
   1.107 -        FluidSynthMidiSong *fluidsynthmidi;
   1.108 -#endif
   1.109 -#ifdef USE_NATIVE_MIDI
   1.110 -        NativeMidiSong *nativemidi;
   1.111 -#endif
   1.112 -#endif
   1.113 -#ifdef OGG_MUSIC
   1.114 -        OGG_music *ogg;
   1.115 -#endif
   1.116 -#ifdef MP3_MUSIC
   1.117 -        SMPEG *mp3;
   1.118 -#endif
   1.119 -#ifdef MP3_MAD_MUSIC
   1.120 -        mad_data *mp3_mad;
   1.121 -#endif
   1.122 -#ifdef MP3_MPG_MUSIC
   1.123 -        mpg_data *mp3_mpg;
   1.124 -#endif
   1.125 -#ifdef FLAC_MUSIC
   1.126 -        FLAC_music *flac;
   1.127 -#endif
   1.128 -    } data;
   1.129 +    Mix_MusicInterface *interface;
   1.130 +    void *context;
   1.131 +
   1.132 +    SDL_bool playing;
   1.133      Mix_Fading fading;
   1.134      int fade_step;
   1.135      int fade_steps;
   1.136      int error;
   1.137  };
   1.138 -#ifdef MID_MUSIC
   1.139 -#ifdef USE_TIMIDITY_MIDI
   1.140 -static int timidity_ok;
   1.141 -static int samplesize;
   1.142 -#endif
   1.143 -#ifdef USE_FLUIDSYNTH_MIDI
   1.144 -static int fluidsynth_ok;
   1.145 -#endif
   1.146 -#ifdef USE_NATIVE_MIDI
   1.147 -static int native_midi_ok;
   1.148 -#endif
   1.149 -#endif
   1.150  
   1.151  /* Used to calculate fading steps */
   1.152  static int ms_per_step;
   1.153 @@ -153,6 +70,57 @@
   1.154  /* Semicolon-separated SoundFont paths */
   1.155  char* soundfont_paths = NULL;
   1.156  
   1.157 +/* Interfaces for the various music interfaces, ordered by priority */
   1.158 +static Mix_MusicInterface *s_music_interfaces[] =
   1.159 +{
   1.160 +#ifdef MUSIC_CMD
   1.161 +    &Mix_MusicInterface_CMD,
   1.162 +#endif
   1.163 +#ifdef MUSIC_WAV
   1.164 +    &Mix_MusicInterface_WAV,
   1.165 +#endif
   1.166 +#ifdef MUSIC_MOD_MODPLUG
   1.167 +    &Mix_MusicInterface_MODPLUG,
   1.168 +#endif
   1.169 +#ifdef MUSIC_MOD_MIKMOD
   1.170 +    &Mix_MusicInterface_MIKMOD,
   1.171 +#endif
   1.172 +#ifdef MUSIC_MID_FLUIDSYNTH
   1.173 +    &Mix_MusicInterface_FLUIDSYNTH,
   1.174 +#endif
   1.175 +#ifdef MUSIC_MID_TIMIDITY
   1.176 +    &Mix_MusicInterface_TIMIDITY,
   1.177 +#endif
   1.178 +#ifdef MUSIC_MID_NATIVE
   1.179 +    &Mix_MusicInterface_NATIVEMIDI,
   1.180 +#endif
   1.181 +#ifdef MUSIC_OGG
   1.182 +    &Mix_MusicInterface_OGG,
   1.183 +#endif
   1.184 +#ifdef MUSIC_MP3_MPG123
   1.185 +    &Mix_MusicInterface_MPG123,
   1.186 +#endif
   1.187 +#ifdef MUSIC_MP3_MAD
   1.188 +    &Mix_MusicInterface_MAD,
   1.189 +#endif
   1.190 +#ifdef MUSIC_MP3_SMPEG
   1.191 +    &Mix_MusicInterface_SMPEG,
   1.192 +#endif
   1.193 +#ifdef MUSIC_FLAC
   1.194 +    &Mix_MusicInterface_FLAC,
   1.195 +#endif
   1.196 +};
   1.197 +
   1.198 +int get_num_music_interfaces(void)
   1.199 +{
   1.200 +    return SDL_arraysize(s_music_interfaces);
   1.201 +}
   1.202 +
   1.203 +Mix_MusicInterface *get_music_interface(int index)
   1.204 +{
   1.205 +    return s_music_interfaces[index];
   1.206 +}
   1.207 +
   1.208  int Mix_GetNumMusicDecoders(void)
   1.209  {
   1.210      return(num_decoders);
   1.211 @@ -181,7 +149,7 @@
   1.212  static void music_internal_volume(int volume);
   1.213  static int  music_internal_play(Mix_Music *music, double position);
   1.214  static int  music_internal_position(double position);
   1.215 -static int  music_internal_playing();
   1.216 +static SDL_bool music_internal_playing();
   1.217  static void music_internal_halt(void);
   1.218  
   1.219  
   1.220 @@ -197,19 +165,17 @@
   1.221  
   1.222  
   1.223  /* If music isn't playing, halt it if no looping is required, restart it */
   1.224 -/* othesrchise. NOP if the music is playing */
   1.225 -static int music_halt_or_loop (void)
   1.226 +/* otherwise. NOP if the music is playing */
   1.227 +static int music_halt_or_loop(void)
   1.228  {
   1.229      /* Restart music if it has to loop */
   1.230  
   1.231      if (!music_internal_playing())
   1.232      {
   1.233 -#ifdef USE_NATIVE_MIDI
   1.234          /* Native MIDI handles looping internally */
   1.235 -        if (music_playing->type == MUS_MID && native_midi_ok) {
   1.236 +        if (music_playing->interface->api == MIX_MUSIC_NATIVEMIDI) {
   1.237              music_loops = 0;
   1.238          }
   1.239 -#endif
   1.240  
   1.241          /* Restart music if it has to loop at a high level */
   1.242          if (music_loops)
   1.243 @@ -236,30 +202,27 @@
   1.244  }
   1.245  
   1.246  
   1.247 -
   1.248  /* Mixing function */
   1.249  void music_mixer(void *udata, Uint8 *stream, int len)
   1.250  {
   1.251 -    int left = 0;
   1.252 -
   1.253 -    if ( music_playing && music_active ) {
   1.254 +    if (music_playing && music_active) {
   1.255          /* Handle fading */
   1.256 -        if ( music_playing->fading != MIX_NO_FADING ) {
   1.257 -            if ( music_playing->fade_step++ < music_playing->fade_steps ) {
   1.258 +        if (music_playing->fading != MIX_NO_FADING) {
   1.259 +            if (music_playing->fade_step++ < music_playing->fade_steps) {
   1.260                  int volume;
   1.261                  int fade_step = music_playing->fade_step;
   1.262                  int fade_steps = music_playing->fade_steps;
   1.263  
   1.264 -                if ( music_playing->fading == MIX_FADING_OUT ) {
   1.265 +                if (music_playing->fading == MIX_FADING_OUT) {
   1.266                      volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
   1.267                  } else { /* Fading in */
   1.268                      volume = (music_volume * fade_step) / fade_steps;
   1.269                  }
   1.270                  music_internal_volume(volume);
   1.271              } else {
   1.272 -                if ( music_playing->fading == MIX_FADING_OUT ) {
   1.273 +                if (music_playing->fading == MIX_FADING_OUT) {
   1.274                      music_internal_halt();
   1.275 -                    if ( music_finished_hook ) {
   1.276 +                    if (music_finished_hook) {
   1.277                          music_finished_hook();
   1.278                      }
   1.279                      return;
   1.280 @@ -269,247 +232,131 @@
   1.281          }
   1.282  
   1.283          music_halt_or_loop();
   1.284 -        if (!music_internal_playing())
   1.285 +        if (!music_internal_playing()) {
   1.286              return;
   1.287 +        }
   1.288  
   1.289 -        switch (music_playing->type) {
   1.290 -#ifdef CMD_MUSIC
   1.291 -            case MUS_CMD:
   1.292 -                /* The playing is done externally */
   1.293 -                break;
   1.294 -#endif
   1.295 -#ifdef WAV_MUSIC
   1.296 -            case MUS_WAV:
   1.297 -                left = WAVStream_PlaySome(stream, len);
   1.298 -                break;
   1.299 -#endif
   1.300 -#ifdef MODPLUG_MUSIC
   1.301 -            case MUS_MODPLUG:
   1.302 -                left = modplug_playAudio(music_playing->data.modplug, stream, len);
   1.303 -                break;
   1.304 -#endif
   1.305 -#ifdef MOD_MUSIC
   1.306 -            case MUS_MOD:
   1.307 -                left = MOD_playAudio(music_playing->data.module, stream, len);
   1.308 -                break;
   1.309 -#endif
   1.310 -#ifdef MID_MUSIC
   1.311 -            case MUS_MID:
   1.312 -#ifdef USE_NATIVE_MIDI
   1.313 -                if ( native_midi_ok ) {
   1.314 -                    /* Native midi is handled asynchronously */
   1.315 -                    goto skip;
   1.316 +        if (music_playing->interface->GetAudio) {
   1.317 +            int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
   1.318 +            if (left > 0) {
   1.319 +                music_playing->playing = SDL_FALSE;
   1.320 +            }
   1.321 +
   1.322 +            /* Handle seamless music looping */
   1.323 +            if (left > 0 && left < len) {
   1.324 +                music_halt_or_loop();
   1.325 +                if (music_internal_playing()) {
   1.326 +                    music_mixer(udata, stream+(len-left), left);
   1.327                  }
   1.328 -#endif
   1.329 -#ifdef USE_FLUIDSYNTH_MIDI
   1.330 -                if ( fluidsynth_ok ) {
   1.331 -                    fluidsynth_playsome(music_playing->data.fluidsynthmidi, stream, len);
   1.332 -                    goto skip;
   1.333 -                }
   1.334 -#endif
   1.335 -#ifdef USE_TIMIDITY_MIDI
   1.336 -                if ( timidity_ok ) {
   1.337 -                    int samples = len / samplesize;
   1.338 -                    Timidity_PlaySome(stream, samples);
   1.339 -                    goto skip;
   1.340 -                }
   1.341 -#endif
   1.342 -                break;
   1.343 -#endif
   1.344 -#ifdef OGG_MUSIC
   1.345 -            case MUS_OGG:
   1.346 +            }
   1.347 +        }
   1.348 +    }
   1.349 +}
   1.350  
   1.351 -                left = OGG_playAudio(music_playing->data.ogg, stream, len);
   1.352 -                break;
   1.353 -#endif
   1.354 -#ifdef FLAC_MUSIC
   1.355 -            case MUS_FLAC:
   1.356 -                left = FLAC_playAudio(music_playing->data.flac, stream, len);
   1.357 -                break;
   1.358 -#endif
   1.359 -#ifdef MP3_MUSIC
   1.360 -            case MUS_MP3:
   1.361 -                left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
   1.362 -                break;
   1.363 -#endif
   1.364 -#ifdef MP3_MAD_MUSIC
   1.365 -            case MUS_MP3_MAD:
   1.366 -                left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
   1.367 -                break;
   1.368 -#endif
   1.369 -#ifdef MP3_MPG_MUSIC
   1.370 -            case MUS_MP3_MPG:
   1.371 -                left = mpg_get_samples(music_playing->data.mp3_mpg, stream, len);
   1.372 -                break;
   1.373 -#endif
   1.374 -            default:
   1.375 -                /* Unknown music type?? */
   1.376 -                break;
   1.377 +/* Load the music interface libraries */
   1.378 +int load_music(void)
   1.379 +{
   1.380 +    char hint[128];
   1.381 +
   1.382 +    int i;
   1.383 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   1.384 +        Mix_MusicInterface *interface = s_music_interfaces[i];
   1.385 +        if (interface->loaded) {
   1.386 +            continue;
   1.387 +        }
   1.388 +
   1.389 +        SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
   1.390 +        if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
   1.391 +            continue;
   1.392 +        }
   1.393 +
   1.394 +        if (!interface->Load || interface->Load() == 0) {
   1.395 +            interface->loaded = SDL_TRUE;
   1.396 +        }
   1.397 +    }
   1.398 +    return 0;
   1.399 +}
   1.400 +
   1.401 +/* Return SDL_TRUE if the music type is available */
   1.402 +SDL_bool has_music(Mix_MusicType type)
   1.403 +{
   1.404 +    int i;
   1.405 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   1.406 +        Mix_MusicInterface *interface = s_music_interfaces[i];
   1.407 +        if (interface->type != type) {
   1.408 +            continue;
   1.409 +        }
   1.410 +        if (interface->opened) {
   1.411 +            return SDL_TRUE;
   1.412 +        }
   1.413 +    }
   1.414 +    return SDL_FALSE;
   1.415 +}
   1.416 +
   1.417 +/* Initialize the music interfaces with a certain desired audio format */
   1.418 +int open_music(const SDL_AudioSpec *spec)
   1.419 +{
   1.420 +    int i;
   1.421 +    SDL_bool use_native_midi = SDL_FALSE;
   1.422 +
   1.423 +    if (SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
   1.424 +        use_native_midi = SDL_TRUE;
   1.425 +    }
   1.426 +
   1.427 +    music_spec = *spec;
   1.428 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   1.429 +        Mix_MusicInterface *interface = s_music_interfaces[i];
   1.430 +        if (!interface->loaded) {
   1.431 +            continue;
   1.432 +        }
   1.433 +
   1.434 +        if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
   1.435 +            continue;
   1.436 +        }
   1.437 +
   1.438 +        if (!interface->Open || interface->Open(spec) == 0) {
   1.439 +            interface->opened = SDL_TRUE;
   1.440 +            add_music_decoder(interface->tag);
   1.441          }
   1.442      }
   1.443  
   1.444 -skip:
   1.445 -    /* Handle seamless music looping */
   1.446 -    if (left > 0 && left < len) {
   1.447 -        music_halt_or_loop();
   1.448 -        if (music_internal_playing())
   1.449 -            music_mixer(udata, stream+(len-left), left);
   1.450 +    if (has_music(MUS_MOD)) {
   1.451 +        add_music_decoder("MOD");
   1.452      }
   1.453 +    if (has_music(MUS_MID)) {
   1.454 +        add_music_decoder("MIDI");
   1.455 +    }
   1.456 +    if (has_music(MUS_MP3)) {
   1.457 +        add_music_decoder("MP3");
   1.458 +    }
   1.459 +
   1.460 +    Mix_VolumeMusic(MIX_MAX_VOLUME);
   1.461 +
   1.462 +    /* Calculate the number of ms for each callback */
   1.463 +    ms_per_step = (int) (((float)spec->samples * 1000.0) / spec->freq);
   1.464 +
   1.465 +    return 0;
   1.466  }
   1.467  
   1.468 -/* Initialize the music players with a certain desired audio format */
   1.469 -int open_music(SDL_AudioSpec *mixer)
   1.470 +Mix_MusicType detect_music_type_from_magic(const Uint8 *magic)
   1.471  {
   1.472 -#ifdef WAV_MUSIC
   1.473 -    if ( WAVStream_Init(mixer) == 0 ) {
   1.474 -        add_music_decoder("WAVE");
   1.475 -    }
   1.476 -#endif
   1.477 -#ifdef MODPLUG_MUSIC
   1.478 -    if ( modplug_init(mixer) == 0 ) {
   1.479 -        add_music_decoder("MODPLUG");
   1.480 -    }
   1.481 -#endif
   1.482 -#ifdef MOD_MUSIC
   1.483 -    if ( MOD_init(mixer) == 0 ) {
   1.484 -        add_music_decoder("MIKMOD");
   1.485 -    }
   1.486 -#endif
   1.487 -#ifdef MID_MUSIC
   1.488 -#ifdef USE_TIMIDITY_MIDI
   1.489 -    samplesize = mixer->size / mixer->samples;
   1.490 -    if ( Timidity_Init(mixer->freq, mixer->format,
   1.491 -                        mixer->channels, mixer->samples) == 0 ) {
   1.492 -        timidity_ok = 1;
   1.493 -        add_music_decoder("TIMIDITY");
   1.494 -    } else {
   1.495 -        timidity_ok = 0;
   1.496 -    }
   1.497 -#endif
   1.498 -#ifdef USE_FLUIDSYNTH_MIDI
   1.499 -    if ( fluidsynth_init(mixer) == 0 ) {
   1.500 -        fluidsynth_ok = 1;
   1.501 -        add_music_decoder("FLUIDSYNTH");
   1.502 -    } else {
   1.503 -        fluidsynth_ok = 0;
   1.504 -    }
   1.505 -#endif
   1.506 -#ifdef USE_NATIVE_MIDI
   1.507 -#ifdef USE_FLUIDSYNTH_MIDI
   1.508 -    native_midi_ok = !fluidsynth_ok;
   1.509 -    if ( native_midi_ok )
   1.510 -#endif
   1.511 -#ifdef USE_TIMIDITY_MIDI
   1.512 -        native_midi_ok = !timidity_ok;
   1.513 -    if ( !native_midi_ok ) {
   1.514 -        native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
   1.515 -    }
   1.516 -    if ( native_midi_ok )
   1.517 -#endif
   1.518 -        native_midi_ok = native_midi_detect();
   1.519 -    if ( native_midi_ok )
   1.520 -        add_music_decoder("NATIVEMIDI");
   1.521 -#endif
   1.522 -#endif
   1.523 -#ifdef OGG_MUSIC
   1.524 -    if ( OGG_init(mixer) == 0 ) {
   1.525 -        add_music_decoder("OGG");
   1.526 -    }
   1.527 -#endif
   1.528 -#ifdef FLAC_MUSIC
   1.529 -    if ( FLAC_init(mixer) == 0 ) {
   1.530 -        add_music_decoder("FLAC");
   1.531 -    }
   1.532 -#endif
   1.533 -#if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC) || defined(MP3_MPG_MUSIC)
   1.534 -    /* Keep a copy of the mixer */
   1.535 -    used_mixer = *mixer;
   1.536 -    add_music_decoder("MP3");
   1.537 -#endif
   1.538 -
   1.539 -    music_playing = NULL;
   1.540 -    music_stopped = 0;
   1.541 -    Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
   1.542 -
   1.543 -    /* Calculate the number of ms for each callback */
   1.544 -    ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
   1.545 -
   1.546 -    return(0);
   1.547 -}
   1.548 -
   1.549 -/* Portable case-insensitive string compare function */
   1.550 -int MIX_string_equals(const char *str1, const char *str2)
   1.551 -{
   1.552 -    while ( *str1 && *str2 ) {
   1.553 -        if ( toupper((unsigned char)*str1) !=
   1.554 -             toupper((unsigned char)*str2) )
   1.555 -            break;
   1.556 -        ++str1;
   1.557 -        ++str2;
   1.558 -    }
   1.559 -    return (!*str1 && !*str2);
   1.560 -}
   1.561 -
   1.562 -static int detect_mp3(Uint8 *magic)
   1.563 -{
   1.564 -    if ( strncmp((char *)magic, "ID3", 3) == 0 ) {
   1.565 -        return 1;
   1.566 -    }
   1.567 -
   1.568 -    /* Detection code lifted from SMPEG */
   1.569 -    if(((magic[0] & 0xff) != 0xff) || // No sync bits
   1.570 -       ((magic[1] & 0xf0) != 0xf0) || //
   1.571 -       ((magic[2] & 0xf0) == 0x00) || // Bitrate is 0
   1.572 -       ((magic[2] & 0xf0) == 0xf0) || // Bitrate is 15
   1.573 -       ((magic[2] & 0x0c) == 0x0c) || // Frequency is 3
   1.574 -       ((magic[1] & 0x06) == 0x00)) { // Layer is 4
   1.575 -        return(0);
   1.576 -    }
   1.577 -    return 1;
   1.578 -}
   1.579 -
   1.580 -/* MUS_MOD can't be auto-detected. If no other format was detected, MOD is
   1.581 - * assumed and MUS_MOD will be returned, meaning that the format might not
   1.582 - * actually be MOD-based.
   1.583 - *
   1.584 - * Returns MUS_NONE in case of errors. */
   1.585 -static Mix_MusicType detect_music_type(SDL_RWops *src)
   1.586 -{
   1.587 -    Uint8 magic[5];
   1.588 -    Uint8 moremagic[9];
   1.589 -
   1.590 -    Sint64 start = SDL_RWtell(src);
   1.591 -    if (SDL_RWread(src, magic, 1, 4) != 4 || SDL_RWread(src, moremagic, 1, 8) != 8 ) {
   1.592 -        Mix_SetError("Couldn't read from RWops");
   1.593 -        return MUS_NONE;
   1.594 -    }
   1.595 -    SDL_RWseek(src, start, RW_SEEK_SET);
   1.596 -    magic[4]='\0';
   1.597 -    moremagic[8] = '\0';
   1.598 -
   1.599 -    /* WAVE files have the magic four bytes "RIFF"
   1.600 -       AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
   1.601 -    if (((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
   1.602 -        (strcmp((char *)magic, "FORM") == 0)) {
   1.603 -        return MUS_WAV;
   1.604 -    }
   1.605 -
   1.606      /* Ogg Vorbis files have the magic four bytes "OggS" */
   1.607 -    if (strcmp((char *)magic, "OggS") == 0) {
   1.608 +    if (SDL_memcmp(magic, "OggS", 4) == 0) {
   1.609          return MUS_OGG;
   1.610      }
   1.611  
   1.612      /* FLAC files have the magic four bytes "fLaC" */
   1.613 -    if (strcmp((char *)magic, "fLaC") == 0) {
   1.614 +    if (SDL_memcmp(magic, "fLaC", 4) == 0) {
   1.615          return MUS_FLAC;
   1.616      }
   1.617  
   1.618      /* MIDI files have the magic four bytes "MThd" */
   1.619 -    if (strcmp((char *)magic, "MThd") == 0) {
   1.620 +    if (SDL_memcmp(magic, "MThd", 4) == 0) {
   1.621          return MUS_MID;
   1.622      }
   1.623  
   1.624 -    if (detect_mp3(magic)) {
   1.625 +    if (SDL_memcmp(magic, "ID3", 3) == 0 ||
   1.626 +        (magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
   1.627          return MUS_MP3;
   1.628      }
   1.629  
   1.630 @@ -521,35 +368,57 @@
   1.631      return MUS_MOD;
   1.632  }
   1.633  
   1.634 +static Mix_MusicType detect_music_type(SDL_RWops *src)
   1.635 +{
   1.636 +    char magic[12];
   1.637 +
   1.638 +    if (SDL_RWread(src, magic, 1, 12) != 12) {
   1.639 +        Mix_SetError("Couldn't read first 12 bytes of audio data");
   1.640 +        return MUS_NONE;
   1.641 +    }
   1.642 +    SDL_RWseek(src, -12, RW_SEEK_CUR);
   1.643 +
   1.644 +    /* WAVE files have the magic four bytes "RIFF"
   1.645 +       AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
   1.646 +    if (((SDL_memcmp(magic, "RIFF", 4) == 0) && (SDL_memcmp((magic+8), "WAVE", 4) == 0)) ||
   1.647 +        (SDL_memcmp(magic, "FORM", 4) == 0)) {
   1.648 +        return MUS_WAV;
   1.649 +    }
   1.650 +
   1.651 +    return detect_music_type_from_magic(magic);
   1.652 +}
   1.653 +
   1.654  /* Load a music file */
   1.655  Mix_Music *Mix_LoadMUS(const char *file)
   1.656  {
   1.657 +    int i;
   1.658 +    void *context;
   1.659 +    char *ext;
   1.660 +    Mix_MusicType type;
   1.661      SDL_RWops *src;
   1.662 -    Mix_Music *music;
   1.663 -    Mix_MusicType type;
   1.664 -    char *ext = strrchr(file, '.');
   1.665  
   1.666 -#ifdef CMD_MUSIC
   1.667 -    if ( music_cmd ) {
   1.668 -        /* Allocate memory for the music structure */
   1.669 -        music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
   1.670 -        if ( music == NULL ) {
   1.671 -            Mix_SetError("Out of memory");
   1.672 -            return(NULL);
   1.673 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   1.674 +        Mix_MusicInterface *interface = s_music_interfaces[i];
   1.675 +        if (!interface->opened || !interface->CreateFromFile) {
   1.676 +            continue;
   1.677          }
   1.678 -        music->error = 0;
   1.679 -        music->type = MUS_CMD;
   1.680 -        music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
   1.681 -        if ( music->data.cmd == NULL ) {
   1.682 -            SDL_free(music);
   1.683 -            music = NULL;
   1.684 +
   1.685 +        context = interface->CreateFromFile(file);
   1.686 +        if (context) {
   1.687 +            /* Allocate memory for the music structure */
   1.688 +            Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
   1.689 +            if (music == NULL) {
   1.690 +                Mix_SetError("Out of memory");
   1.691 +                return NULL;
   1.692 +            }
   1.693 +            music->interface = interface;
   1.694 +            music->context = context;
   1.695 +            return music;
   1.696          }
   1.697 -        return music;
   1.698      }
   1.699 -#endif
   1.700  
   1.701      src = SDL_RWFromFile(file, "rb");
   1.702 -    if ( src == NULL ) {
   1.703 +    if (src == NULL) {
   1.704          Mix_SetError("Couldn't open '%s'", file);
   1.705          return NULL;
   1.706      }
   1.707 @@ -557,39 +426,48 @@
   1.708      /* Use the extension as a first guess on the file type */
   1.709      type = MUS_NONE;
   1.710      ext = strrchr(file, '.');
   1.711 -    /* No need to guard these with #ifdef *_MUSIC stuff,
   1.712 -     * since we simply call Mix_LoadMUSType_RW() later */
   1.713 -    if ( ext ) {
   1.714 +    if (ext) {
   1.715          ++ext; /* skip the dot in the extension */
   1.716 -        if ( MIX_string_equals(ext, "WAV") ) {
   1.717 +        if (SDL_strcasecmp(ext, "WAV") == 0) {
   1.718              type = MUS_WAV;
   1.719 -        } else if ( MIX_string_equals(ext, "MID") ||
   1.720 -                    MIX_string_equals(ext, "MIDI") ||
   1.721 -                    MIX_string_equals(ext, "KAR") ) {
   1.722 +        } else if (SDL_strcasecmp(ext, "MID") == 0 ||
   1.723 +                    SDL_strcasecmp(ext, "MIDI") == 0 ||
   1.724 +                    SDL_strcasecmp(ext, "KAR") == 0) {
   1.725              type = MUS_MID;
   1.726 -        } else if ( MIX_string_equals(ext, "OGG") ) {
   1.727 +        } else if (SDL_strcasecmp(ext, "OGG") == 0) {
   1.728              type = MUS_OGG;
   1.729 -        } else if ( MIX_string_equals(ext, "FLAC") ) {
   1.730 +        } else if (SDL_strcasecmp(ext, "FLAC") == 0) {
   1.731              type = MUS_FLAC;
   1.732 -        } else  if ( MIX_string_equals(ext, "MPG") ||
   1.733 -                     MIX_string_equals(ext, "MPEG") ||
   1.734 -                     MIX_string_equals(ext, "MP3") ||
   1.735 -                     MIX_string_equals(ext, "MAD") ) {
   1.736 +        } else  if (SDL_strcasecmp(ext, "MPG") == 0 ||
   1.737 +                     SDL_strcasecmp(ext, "MPEG") == 0 ||
   1.738 +                     SDL_strcasecmp(ext, "MP3") == 0 ||
   1.739 +                     SDL_strcasecmp(ext, "MAD") == 0) {
   1.740              type = MUS_MP3;
   1.741 +        } else if (SDL_strcasecmp(ext, "669") == 0 ||
   1.742 +                    SDL_strcasecmp(ext, "AMF") == 0 ||
   1.743 +                    SDL_strcasecmp(ext, "AMS") == 0 ||
   1.744 +                    SDL_strcasecmp(ext, "DBM") == 0 ||
   1.745 +                    SDL_strcasecmp(ext, "DSM") == 0 ||
   1.746 +                    SDL_strcasecmp(ext, "FAR") == 0 ||
   1.747 +                    SDL_strcasecmp(ext, "IT") == 0 ||
   1.748 +                    SDL_strcasecmp(ext, "MED") == 0 ||
   1.749 +                    SDL_strcasecmp(ext, "MDL") == 0 ||
   1.750 +                    SDL_strcasecmp(ext, "MOD") == 0 ||
   1.751 +                    SDL_strcasecmp(ext, "MOL") == 0 ||
   1.752 +                    SDL_strcasecmp(ext, "MTM") == 0 ||
   1.753 +                    SDL_strcasecmp(ext, "NST") == 0 ||
   1.754 +                    SDL_strcasecmp(ext, "OKT") == 0 ||
   1.755 +                    SDL_strcasecmp(ext, "PTM") == 0 ||
   1.756 +                    SDL_strcasecmp(ext, "S3M") == 0 ||
   1.757 +                    SDL_strcasecmp(ext, "STM") == 0 ||
   1.758 +                    SDL_strcasecmp(ext, "ULT") == 0 ||
   1.759 +                    SDL_strcasecmp(ext, "UMX") == 0 ||
   1.760 +                    SDL_strcasecmp(ext, "WOW") == 0 ||
   1.761 +                    SDL_strcasecmp(ext, "XM") == 0) {
   1.762 +            type = MUS_MOD;
   1.763          }
   1.764      }
   1.765 -    if ( type == MUS_NONE ) {
   1.766 -        type = detect_music_type(src);
   1.767 -    }
   1.768 -
   1.769 -    /* We need to know if a specific error occurs; if not, we'll set a
   1.770 -     * generic one, so we clear the current one. */
   1.771 -    SDL_ClearError();
   1.772 -    music = Mix_LoadMUSType_RW(src, type, SDL_TRUE);
   1.773 -    if ( music == NULL && Mix_GetError()[0] == '\0' ) {
   1.774 -        Mix_SetError("Unrecognized music format");
   1.775 -    }
   1.776 -    return music;
   1.777 +    return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
   1.778  }
   1.779  
   1.780  Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
   1.781 @@ -599,7 +477,8 @@
   1.782  
   1.783  Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
   1.784  {
   1.785 -    Mix_Music *music;
   1.786 +    int i;
   1.787 +    void *context;
   1.788      Sint64 start;
   1.789  
   1.790      if (!src) {
   1.791 @@ -612,8 +491,7 @@
   1.792       * this is. */
   1.793      if (type == MUS_NONE) {
   1.794          if ((type = detect_music_type(src)) == MUS_NONE) {
   1.795 -            /* Don't call Mix_SetError() here since detect_music_type()
   1.796 -             * does that. */
   1.797 +            /* Don't call Mix_SetError() since detect_music_type() does that. */
   1.798              if (freesrc) {
   1.799                  SDL_RWclose(src);
   1.800              }
   1.801 @@ -621,257 +499,69 @@
   1.802          }
   1.803      }
   1.804  
   1.805 -    /* Allocate memory for the music structure */
   1.806 -    music = (Mix_Music *)SDL_malloc(sizeof(Mix_Music));
   1.807 -    if (music == NULL ) {
   1.808 -        Mix_SetError("Out of memory");
   1.809 -        if (freesrc) {
   1.810 -            SDL_RWclose(src);
   1.811 +    Mix_ClearError();
   1.812 +
   1.813 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
   1.814 +        Mix_MusicInterface *interface = s_music_interfaces[i];
   1.815 +        if (!interface->opened || type != interface->type || !interface->CreateFromRW) {
   1.816 +            continue;
   1.817          }
   1.818 -        return NULL;
   1.819 -    }
   1.820 -    music->error = 1;
   1.821  
   1.822 -    switch (type) {
   1.823 -#ifdef WAV_MUSIC
   1.824 -    case MUS_WAV:
   1.825 -        music->type = MUS_WAV;
   1.826 -        music->data.wave = WAVStream_LoadSong_RW(src, freesrc);
   1.827 -        if (music->data.wave) {
   1.828 -            music->error = 0;
   1.829 +        context = interface->CreateFromRW(src, freesrc);
   1.830 +        if (context) {
   1.831 +            /* Allocate memory for the music structure */
   1.832 +            Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
   1.833 +            if (music == NULL) {
   1.834 +                interface->Delete(context);
   1.835 +                Mix_SetError("Out of memory");
   1.836 +                return NULL;
   1.837 +            }
   1.838 +            music->interface = interface;
   1.839 +            music->context = context;
   1.840 +            return music;
   1.841          }
   1.842 -        break;
   1.843 -#endif
   1.844 -#ifdef OGG_MUSIC
   1.845 -    case MUS_OGG:
   1.846 -        music->type = MUS_OGG;
   1.847 -        music->data.ogg = OGG_new_RW(src, freesrc);
   1.848 -        if (music->data.ogg) {
   1.849 -            music->error = 0;
   1.850 -        }
   1.851 -        break;
   1.852 -#endif
   1.853 -#ifdef FLAC_MUSIC
   1.854 -    case MUS_FLAC:
   1.855 -        music->type = MUS_FLAC;
   1.856 -        music->data.flac = FLAC_new_RW(src, freesrc);
   1.857 -        if (music->data.flac) {
   1.858 -            music->error = 0;
   1.859 -        }
   1.860 -        break;
   1.861 -#endif
   1.862 -#ifdef MP3_MUSIC
   1.863 -    case MUS_MP3:
   1.864 -        if (Mix_Init(MIX_INIT_MP3)) {
   1.865 -            SMPEG_Info info;
   1.866 -            music->type = MUS_MP3;
   1.867 -            music->data.mp3 = smpeg.SMPEG_new_rwops(src, &info, freesrc, 0);
   1.868 -            if (!info.has_audio) {
   1.869 -                Mix_SetError("MPEG file does not have any audio stream.");
   1.870 -                smpeg.SMPEG_delete(music->data.mp3);
   1.871 -                /* Deleting the MP3 closed the source if desired */
   1.872 -                freesrc = SDL_FALSE;
   1.873 -            } else {
   1.874 -                smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
   1.875 -                music->error = 0;
   1.876 -            }
   1.877 -        }
   1.878 -        break;
   1.879 -#elif defined(MP3_MAD_MUSIC)
   1.880 -    case MUS_MP3:
   1.881 -        music->type = MUS_MP3_MAD;
   1.882 -        music->data.mp3_mad = mad_openFileRW(src, &used_mixer, freesrc);
   1.883 -        if (music->data.mp3_mad) {
   1.884 -            music->error = 0;
   1.885 -        } else {
   1.886 -            Mix_SetError("Could not initialize MPEG stream.");
   1.887 -        }
   1.888 -        break;
   1.889 -#elif defined(MP3_MPG_MUSIC)
   1.890 -    case MUS_MP3:
   1.891 -        music->type = MUS_MP3_MPG;
   1.892 -        music->data.mp3_mpg = mpg_new_rw(src, &used_mixer, freesrc);
   1.893 -        if (music->data.mp3_mpg) {
   1.894 -            music->error = 0;
   1.895 -        } else {
   1.896 -            Mix_SetError("Could not initialize MPEG stream.");
   1.897 -        }
   1.898 -        break;
   1.899 -#endif
   1.900 -#ifdef MID_MUSIC
   1.901 -    case MUS_MID:
   1.902 -        music->type = MUS_MID;
   1.903 -#ifdef USE_NATIVE_MIDI
   1.904 -        if (native_midi_ok) {
   1.905 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.906 -            music->data.nativemidi = native_midi_loadsong_RW(src, freesrc);
   1.907 -            if (music->data.nativemidi) {
   1.908 -                music->error = 0;
   1.909 -            } else {
   1.910 -                Mix_SetError("%s", native_midi_error());
   1.911 -            }
   1.912 +
   1.913 +        if (interface->api == MIX_MUSIC_SMPEG) {
   1.914 +            /* Uh oh, if SMPEG couldn't create a context, it freed the src */
   1.915 +            freesrc = SDL_FALSE;
   1.916              break;
   1.917          }
   1.918 -#endif
   1.919 -#ifdef USE_FLUIDSYNTH_MIDI
   1.920 -        if (fluidsynth_ok) {
   1.921 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.922 -            music->data.fluidsynthmidi = fluidsynth_loadsong_RW(src, freesrc);
   1.923 -            if (music->data.fluidsynthmidi) {
   1.924 -                music->error = 0;
   1.925 -            }
   1.926 -            break;
   1.927 -        }
   1.928 -#endif
   1.929 -#ifdef USE_TIMIDITY_MIDI
   1.930 -        if (timidity_ok) {
   1.931 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.932 -            music->data.midi = Timidity_LoadSong_RW(src, freesrc);
   1.933 -            if (music->data.midi) {
   1.934 -                music->error = 0;
   1.935 -            } else {
   1.936 -                Mix_SetError("%s", Timidity_Error());
   1.937 -            }
   1.938 -        } else {
   1.939 -            Mix_SetError("%s", Timidity_Error());
   1.940 -        }
   1.941 -#endif
   1.942 -        break;
   1.943 -#endif
   1.944 -#if defined(MODPLUG_MUSIC) || defined(MOD_MUSIC)
   1.945 -    case MUS_MOD:
   1.946 -#ifdef MODPLUG_MUSIC
   1.947 -        if (music->error) {
   1.948 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.949 -            music->type = MUS_MODPLUG;
   1.950 -            music->data.modplug = modplug_new_RW(src, freesrc);
   1.951 -            if (music->data.modplug) {
   1.952 -                music->error = 0;
   1.953 -            }
   1.954 -        }
   1.955 -#endif
   1.956 -#ifdef MOD_MUSIC
   1.957 -        if (music->error) {
   1.958 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.959 -            music->type = MUS_MOD;
   1.960 -            music->data.module = MOD_new_RW(src, freesrc);
   1.961 -            if (music->data.module) {
   1.962 -                music->error = 0;
   1.963 -            }
   1.964 -        }
   1.965 -#endif
   1.966 -        break;
   1.967 -#endif
   1.968  
   1.969 -    default:
   1.970 -        Mix_SetError("Unrecognized music format");
   1.971 -        break;
   1.972 -    } /* switch (want) */
   1.973 +        /* Reset the stream for the next decoder */
   1.974 +        SDL_RWseek(src, start, RW_SEEK_SET);
   1.975 +    }
   1.976  
   1.977 -    if (music->error) {
   1.978 -        SDL_free(music);
   1.979 -        if (freesrc) {
   1.980 -            SDL_RWclose(src);
   1.981 -        } else {
   1.982 -            SDL_RWseek(src, start, RW_SEEK_SET);
   1.983 -        }
   1.984 -        music = NULL;
   1.985 +    if (!*Mix_GetError()) {
   1.986 +        Mix_SetError("Unrecognized audio format");
   1.987      }
   1.988 -    return music;
   1.989 +    if (freesrc) {
   1.990 +        SDL_RWclose(src);
   1.991 +    } else {
   1.992 +        SDL_RWseek(src, start, RW_SEEK_SET);
   1.993 +    }
   1.994 +    return NULL;
   1.995  }
   1.996  
   1.997  /* Free a music chunk previously loaded */
   1.998  void Mix_FreeMusic(Mix_Music *music)
   1.999  {
  1.1000 -    if ( music ) {
  1.1001 +    if (music) {
  1.1002          /* Stop the music if it's currently playing */
  1.1003          Mix_LockAudio();
  1.1004 -        if ( music == music_playing ) {
  1.1005 +        if (music == music_playing) {
  1.1006              /* Wait for any fade out to finish */
  1.1007 -            while ( music->fading == MIX_FADING_OUT ) {
  1.1008 +            while (music->fading == MIX_FADING_OUT) {
  1.1009                  Mix_UnlockAudio();
  1.1010                  SDL_Delay(100);
  1.1011                  Mix_LockAudio();
  1.1012              }
  1.1013 -            if ( music == music_playing ) {
  1.1014 +            if (music == music_playing) {
  1.1015                  music_internal_halt();
  1.1016              }
  1.1017          }
  1.1018          Mix_UnlockAudio();
  1.1019 -        switch (music->type) {
  1.1020 -#ifdef CMD_MUSIC
  1.1021 -            case MUS_CMD:
  1.1022 -                MusicCMD_FreeSong(music->data.cmd);
  1.1023 -                break;
  1.1024 -#endif
  1.1025 -#ifdef WAV_MUSIC
  1.1026 -            case MUS_WAV:
  1.1027 -                WAVStream_FreeSong(music->data.wave);
  1.1028 -                break;
  1.1029 -#endif
  1.1030 -#ifdef MODPLUG_MUSIC
  1.1031 -            case MUS_MODPLUG:
  1.1032 -                modplug_delete(music->data.modplug);
  1.1033 -                break;
  1.1034 -#endif
  1.1035 -#ifdef MOD_MUSIC
  1.1036 -            case MUS_MOD:
  1.1037 -                MOD_delete(music->data.module);
  1.1038 -                break;
  1.1039 -#endif
  1.1040 -#ifdef MID_MUSIC
  1.1041 -            case MUS_MID:
  1.1042 -#ifdef USE_NATIVE_MIDI
  1.1043 -                if ( native_midi_ok ) {
  1.1044 -                    native_midi_freesong(music->data.nativemidi);
  1.1045 -                    goto skip;
  1.1046 -                }
  1.1047 -#endif
  1.1048 -#ifdef USE_FLUIDSYNTH_MIDI
  1.1049 -                if ( fluidsynth_ok ) {
  1.1050 -                    fluidsynth_freesong(music->data.fluidsynthmidi);
  1.1051 -                    goto skip;
  1.1052 -                }
  1.1053 -#endif
  1.1054 -#ifdef USE_TIMIDITY_MIDI
  1.1055 -                if ( timidity_ok ) {
  1.1056 -                    Timidity_FreeSong(music->data.midi);
  1.1057 -                    goto skip;
  1.1058 -                }
  1.1059 -#endif
  1.1060 -                break;
  1.1061 -#endif
  1.1062 -#ifdef OGG_MUSIC
  1.1063 -            case MUS_OGG:
  1.1064 -                OGG_delete(music->data.ogg);
  1.1065 -                break;
  1.1066 -#endif
  1.1067 -#ifdef FLAC_MUSIC
  1.1068 -            case MUS_FLAC:
  1.1069 -                FLAC_delete(music->data.flac);
  1.1070 -                break;
  1.1071 -#endif
  1.1072 -#ifdef MP3_MUSIC
  1.1073 -            case MUS_MP3:
  1.1074 -                smpeg.SMPEG_delete(music->data.mp3);
  1.1075 -                break;
  1.1076 -#endif
  1.1077 -#ifdef MP3_MAD_MUSIC
  1.1078 -            case MUS_MP3_MAD:
  1.1079 -                mad_closeFile(music->data.mp3_mad);
  1.1080 -                break;
  1.1081 -#endif
  1.1082 -#ifdef MP3_MPG_MUSIC
  1.1083 -            case MUS_MP3_MPG:
  1.1084 -                mpg_delete(music->data.mp3_mpg);
  1.1085 -                break;
  1.1086 -#endif
  1.1087 -            default:
  1.1088 -                /* Unknown music type?? */
  1.1089 -                break;
  1.1090 -        }
  1.1091  
  1.1092 -    skip:
  1.1093 +        music->interface->Delete(music->context);
  1.1094          SDL_free(music);
  1.1095      }
  1.1096  }
  1.1097 @@ -883,12 +573,12 @@
  1.1098  {
  1.1099      Mix_MusicType type = MUS_NONE;
  1.1100  
  1.1101 -    if ( music ) {
  1.1102 -        type = music->type;
  1.1103 +    if (music) {
  1.1104 +        type = music->interface->type;
  1.1105      } else {
  1.1106          Mix_LockAudio();
  1.1107 -        if ( music_playing ) {
  1.1108 -            type = music_playing->type;
  1.1109 +        if (music_playing) {
  1.1110 +            type = music_playing->interface->type;
  1.1111          }
  1.1112          Mix_UnlockAudio();
  1.1113      }
  1.1114 @@ -901,11 +591,11 @@
  1.1115  {
  1.1116      int retval = 0;
  1.1117  
  1.1118 -#if defined(__MACOSX__) && defined(USE_NATIVE_MIDI)
  1.1119 +#if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
  1.1120      /* This fixes a bug with native MIDI on Mac OS X, where you
  1.1121         can't really stop and restart MIDI from the audio callback.
  1.1122      */
  1.1123 -    if ( music == music_playing && music->type == MUS_MID && native_midi_ok ) {
  1.1124 +    if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
  1.1125          /* Just a seek suffices to restart playing */
  1.1126          music_internal_position(position);
  1.1127          return 0;
  1.1128 @@ -913,102 +603,22 @@
  1.1129  #endif
  1.1130  
  1.1131      /* Note the music we're playing */
  1.1132 -    if ( music_playing ) {
  1.1133 +    if (music_playing) {
  1.1134          music_internal_halt();
  1.1135      }
  1.1136      music_playing = music;
  1.1137 +    music_playing->playing = SDL_TRUE;
  1.1138  
  1.1139      /* Set the initial volume */
  1.1140 -    if ( music->type != MUS_MOD ) {
  1.1141 -        music_internal_initialize_volume();
  1.1142 -    }
  1.1143 +    music_internal_initialize_volume();
  1.1144  
  1.1145      /* Set up for playback */
  1.1146 -    switch (music->type) {
  1.1147 -#ifdef CMD_MUSIC
  1.1148 -        case MUS_CMD:
  1.1149 -        MusicCMD_Start(music->data.cmd);
  1.1150 -        break;
  1.1151 -#endif
  1.1152 -#ifdef WAV_MUSIC
  1.1153 -        case MUS_WAV:
  1.1154 -        WAVStream_Start(music->data.wave);
  1.1155 -        break;
  1.1156 -#endif
  1.1157 -#ifdef MODPLUG_MUSIC
  1.1158 -        case MUS_MODPLUG:
  1.1159 -        /* can't set volume until file is loaded, so finally set it now */
  1.1160 -        music_internal_initialize_volume();
  1.1161 -        modplug_play(music->data.modplug);
  1.1162 -        break;
  1.1163 -#endif
  1.1164 -#ifdef MOD_MUSIC
  1.1165 -        case MUS_MOD:
  1.1166 -        MOD_play(music->data.module);
  1.1167 -        /* Player_SetVolume() does nothing before Player_Start() */
  1.1168 -        music_internal_initialize_volume();
  1.1169 -        break;
  1.1170 -#endif
  1.1171 -#ifdef MID_MUSIC
  1.1172 -        case MUS_MID:
  1.1173 -#ifdef USE_NATIVE_MIDI
  1.1174 -        if ( native_midi_ok ) {
  1.1175 -            native_midi_start(music->data.nativemidi, music_loops);
  1.1176 -            goto skip;
  1.1177 -        }
  1.1178 -#endif
  1.1179 -#ifdef USE_FLUIDSYNTH_MIDI
  1.1180 -        if (fluidsynth_ok ) {
  1.1181 -            fluidsynth_start(music->data.fluidsynthmidi);
  1.1182 -            goto skip;
  1.1183 -        }
  1.1184 -#endif
  1.1185 -#ifdef USE_TIMIDITY_MIDI
  1.1186 -        if ( timidity_ok ) {
  1.1187 -            Timidity_Start(music->data.midi);
  1.1188 -            goto skip;
  1.1189 -        }
  1.1190 -#endif
  1.1191 -        break;
  1.1192 -#endif
  1.1193 -#ifdef OGG_MUSIC
  1.1194 -        case MUS_OGG:
  1.1195 -        OGG_play(music->data.ogg);
  1.1196 -        break;
  1.1197 -#endif
  1.1198 -#ifdef FLAC_MUSIC
  1.1199 -        case MUS_FLAC:
  1.1200 -        FLAC_play(music->data.flac);
  1.1201 -        break;
  1.1202 -#endif
  1.1203 -#ifdef MP3_MUSIC
  1.1204 -        case MUS_MP3:
  1.1205 -        smpeg.SMPEG_enableaudio(music->data.mp3,1);
  1.1206 -        smpeg.SMPEG_enablevideo(music->data.mp3,0);
  1.1207 -        smpeg.SMPEG_play(music_playing->data.mp3);
  1.1208 -        break;
  1.1209 -#endif
  1.1210 -#ifdef MP3_MAD_MUSIC
  1.1211 -        case MUS_MP3_MAD:
  1.1212 -        mad_start(music->data.mp3_mad);
  1.1213 -        break;
  1.1214 -#endif
  1.1215 -#ifdef MP3_MPG_MUSIC
  1.1216 -        case MUS_MP3_MPG:
  1.1217 -        mpg_start(music->data.mp3_mpg);
  1.1218 -        break;
  1.1219 -#endif
  1.1220 -        default:
  1.1221 -        Mix_SetError("Can't play unknown music type");
  1.1222 -        retval = -1;
  1.1223 -        break;
  1.1224 -    }
  1.1225 +    retval = music->interface->Play(music->context);
  1.1226  
  1.1227 -skip:
  1.1228      /* Set the playback position, note any errors if an offset is used */
  1.1229 -    if ( retval == 0 ) {
  1.1230 -        if ( position > 0.0 ) {
  1.1231 -            if ( music_internal_position(position) < 0 ) {
  1.1232 +    if (retval == 0) {
  1.1233 +        if (position > 0.0) {
  1.1234 +            if (music_internal_position(position) < 0) {
  1.1235                  Mix_SetError("Position not implemented for music type");
  1.1236                  retval = -1;
  1.1237              }
  1.1238 @@ -1018,28 +628,29 @@
  1.1239      }
  1.1240  
  1.1241      /* If the setup failed, we're not playing any music anymore */
  1.1242 -    if ( retval < 0 ) {
  1.1243 +    if (retval < 0) {
  1.1244          music_playing = NULL;
  1.1245      }
  1.1246      return(retval);
  1.1247  }
  1.1248 +
  1.1249  int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
  1.1250  {
  1.1251      int retval;
  1.1252  
  1.1253 -    if ( ms_per_step == 0 ) {
  1.1254 +    if (ms_per_step == 0) {
  1.1255          SDL_SetError("Audio device hasn't been opened");
  1.1256          return(-1);
  1.1257      }
  1.1258  
  1.1259      /* Don't play null pointers :-) */
  1.1260 -    if ( music == NULL ) {
  1.1261 +    if (music == NULL) {
  1.1262          Mix_SetError("music parameter was NULL");
  1.1263          return(-1);
  1.1264      }
  1.1265  
  1.1266      /* Setup the data */
  1.1267 -    if ( ms ) {
  1.1268 +    if (ms) {
  1.1269          music->fading = MIX_FADING_IN;
  1.1270      } else {
  1.1271          music->fading = MIX_NO_FADING;
  1.1272 @@ -1050,7 +661,7 @@
  1.1273      /* Play the puppy */
  1.1274      Mix_LockAudio();
  1.1275      /* If the current music is fading out, wait for the fade to complete */
  1.1276 -    while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
  1.1277 +    while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
  1.1278          Mix_UnlockAudio();
  1.1279          SDL_Delay(100);
  1.1280          Mix_LockAudio();
  1.1281 @@ -1078,63 +689,19 @@
  1.1282  /* Set the playing music position */
  1.1283  int music_internal_position(double position)
  1.1284  {
  1.1285 -    int retval = 0;
  1.1286 -
  1.1287 -    switch (music_playing->type) {
  1.1288 -#ifdef MODPLUG_MUSIC
  1.1289 -        case MUS_MODPLUG:
  1.1290 -        modplug_jump_to_time(music_playing->data.modplug, position);
  1.1291 -        break;
  1.1292 -#endif
  1.1293 -#ifdef MOD_MUSIC
  1.1294 -        case MUS_MOD:
  1.1295 -        MOD_jump_to_time(music_playing->data.module, position);
  1.1296 -        break;
  1.1297 -#endif
  1.1298 -#ifdef OGG_MUSIC
  1.1299 -        case MUS_OGG:
  1.1300 -        OGG_jump_to_time(music_playing->data.ogg, position);
  1.1301 -        break;
  1.1302 -#endif
  1.1303 -#ifdef FLAC_MUSIC
  1.1304 -        case MUS_FLAC:
  1.1305 -        FLAC_jump_to_time(music_playing->data.flac, position);
  1.1306 -        break;
  1.1307 -#endif
  1.1308 -#ifdef MP3_MUSIC
  1.1309 -        case MUS_MP3:
  1.1310 -        smpeg.SMPEG_rewind(music_playing->data.mp3);
  1.1311 -        smpeg.SMPEG_play(music_playing->data.mp3);
  1.1312 -        if ( position > 0.0 ) {
  1.1313 -            smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
  1.1314 -        }
  1.1315 -        break;
  1.1316 -#endif
  1.1317 -#ifdef MP3_MAD_MUSIC
  1.1318 -        case MUS_MP3_MAD:
  1.1319 -        mad_seek(music_playing->data.mp3_mad, position);
  1.1320 -        break;
  1.1321 -#endif
  1.1322 -#ifdef MP3_MPG_MUSIC
  1.1323 -        case MUS_MP3_MPG:
  1.1324 -        mpg_seek(music_playing->data.mp3_mpg, position);
  1.1325 -        break;
  1.1326 -#endif
  1.1327 -        default:
  1.1328 -        /* TODO: Implement this for other music backends */
  1.1329 -        retval = -1;
  1.1330 -        break;
  1.1331 +    if (music_playing->interface->Seek) {
  1.1332 +        return music_playing->interface->Seek(music_playing->context, position);
  1.1333      }
  1.1334 -    return(retval);
  1.1335 +    return -1;
  1.1336  }
  1.1337  int Mix_SetMusicPosition(double position)
  1.1338  {
  1.1339      int retval;
  1.1340  
  1.1341      Mix_LockAudio();
  1.1342 -    if ( music_playing ) {
  1.1343 +    if (music_playing) {
  1.1344          retval = music_internal_position(position);
  1.1345 -        if ( retval < 0 ) {
  1.1346 +        if (retval < 0) {
  1.1347              Mix_SetError("Position not implemented for music type");
  1.1348          }
  1.1349      } else {
  1.1350 @@ -1149,7 +716,7 @@
  1.1351  /* Set the music's initial volume */
  1.1352  static void music_internal_initialize_volume(void)
  1.1353  {
  1.1354 -    if ( music_playing->fading == MIX_FADING_IN ) {
  1.1355 +    if (music_playing->fading == MIX_FADING_IN) {
  1.1356          music_internal_volume(0);
  1.1357      } else {
  1.1358          music_internal_volume(music_volume);
  1.1359 @@ -1159,77 +726,8 @@
  1.1360  /* Set the music volume */
  1.1361  static void music_internal_volume(int volume)
  1.1362  {
  1.1363 -    switch (music_playing->type) {
  1.1364 -#ifdef CMD_MUSIC
  1.1365 -        case MUS_CMD:
  1.1366 -        MusicCMD_SetVolume(volume);
  1.1367 -        break;
  1.1368 -#endif
  1.1369 -#ifdef WAV_MUSIC
  1.1370 -        case MUS_WAV:
  1.1371 -        WAVStream_SetVolume(volume);
  1.1372 -        break;
  1.1373 -#endif
  1.1374 -#ifdef MODPLUG_MUSIC
  1.1375 -        case MUS_MODPLUG:
  1.1376 -        modplug_setvolume(music_playing->data.modplug, volume);
  1.1377 -        break;
  1.1378 -#endif
  1.1379 -#ifdef MOD_MUSIC
  1.1380 -        case MUS_MOD:
  1.1381 -        MOD_setvolume(music_playing->data.module, volume);
  1.1382 -        break;
  1.1383 -#endif
  1.1384 -#ifdef MID_MUSIC
  1.1385 -        case MUS_MID:
  1.1386 -#ifdef USE_NATIVE_MIDI
  1.1387 -        if ( native_midi_ok ) {
  1.1388 -            native_midi_setvolume(volume);
  1.1389 -            return;
  1.1390 -        }
  1.1391 -#endif
  1.1392 -#ifdef USE_FLUIDSYNTH_MIDI
  1.1393 -        if ( fluidsynth_ok ) {
  1.1394 -            fluidsynth_setvolume(music_playing->data.fluidsynthmidi, volume);
  1.1395 -            return;
  1.1396 -        }
  1.1397 -#endif
  1.1398 -#ifdef USE_TIMIDITY_MIDI
  1.1399 -        if ( timidity_ok ) {
  1.1400 -            Timidity_SetVolume(volume);
  1.1401 -            return;
  1.1402 -        }
  1.1403 -#endif
  1.1404 -        break;
  1.1405 -#endif
  1.1406 -#ifdef OGG_MUSIC
  1.1407 -        case MUS_OGG:
  1.1408 -        OGG_setvolume(music_playing->data.ogg, volume);
  1.1409 -        break;
  1.1410 -#endif
  1.1411 -#ifdef FLAC_MUSIC
  1.1412 -        case MUS_FLAC:
  1.1413 -        FLAC_setvolume(music_playing->data.flac, volume);
  1.1414 -        break;
  1.1415 -#endif
  1.1416 -#ifdef MP3_MUSIC
  1.1417 -        case MUS_MP3:
  1.1418 -        smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
  1.1419 -        break;
  1.1420 -#endif
  1.1421 -#ifdef MP3_MAD_MUSIC
  1.1422 -        case MUS_MP3_MAD:
  1.1423 -        mad_setVolume(music_playing->data.mp3_mad, volume);
  1.1424 -        break;
  1.1425 -#endif
  1.1426 -#ifdef MP3_MPG_MUSIC
  1.1427 -        case MUS_MP3_MPG:
  1.1428 -        mpg_volume(music_playing->data.mp3_mpg, volume);
  1.1429 -        break;
  1.1430 -#endif
  1.1431 -        default:
  1.1432 -        /* Unknown music type?? */
  1.1433 -        break;
  1.1434 +    if (music_playing->interface->SetVolume) {
  1.1435 +        music_playing->interface->SetVolume(music_playing->context, volume);
  1.1436      }
  1.1437  }
  1.1438  int Mix_VolumeMusic(int volume)
  1.1439 @@ -1237,15 +735,15 @@
  1.1440      int prev_volume;
  1.1441  
  1.1442      prev_volume = music_volume;
  1.1443 -    if ( volume < 0 ) {
  1.1444 +    if (volume < 0) {
  1.1445          return prev_volume;
  1.1446      }
  1.1447 -    if ( volume > SDL_MIX_MAXVOLUME ) {
  1.1448 +    if (volume > SDL_MIX_MAXVOLUME) {
  1.1449          volume = SDL_MIX_MAXVOLUME;
  1.1450      }
  1.1451      music_volume = volume;
  1.1452      Mix_LockAudio();
  1.1453 -    if ( music_playing ) {
  1.1454 +    if (music_playing) {
  1.1455          music_internal_volume(music_volume);
  1.1456      }
  1.1457      Mix_UnlockAudio();
  1.1458 @@ -1255,89 +753,20 @@
  1.1459  /* Halt playing of music */
  1.1460  static void music_internal_halt(void)
  1.1461  {
  1.1462 -    switch (music_playing->type) {
  1.1463 -#ifdef CMD_MUSIC
  1.1464 -        case MUS_CMD:
  1.1465 -        MusicCMD_Stop(music_playing->data.cmd);
  1.1466 -        break;
  1.1467 -#endif
  1.1468 -#ifdef WAV_MUSIC
  1.1469 -        case MUS_WAV:
  1.1470 -        WAVStream_Stop();
  1.1471 -        break;
  1.1472 -#endif
  1.1473 -#ifdef MODPLUG_MUSIC
  1.1474 -        case MUS_MODPLUG:
  1.1475 -        modplug_stop(music_playing->data.modplug);
  1.1476 -        break;
  1.1477 -#endif
  1.1478 -#ifdef MOD_MUSIC
  1.1479 -        case MUS_MOD:
  1.1480 -        MOD_stop(music_playing->data.module);
  1.1481 -        break;
  1.1482 -#endif
  1.1483 -#ifdef MID_MUSIC
  1.1484 -        case MUS_MID:
  1.1485 -#ifdef USE_NATIVE_MIDI
  1.1486 -        if ( native_midi_ok ) {
  1.1487 -            native_midi_stop();
  1.1488 -            goto skip;
  1.1489 -        }
  1.1490 -#endif
  1.1491 -#ifdef USE_FLUIDSYNTH_MIDI
  1.1492 -        if ( fluidsynth_ok ) {
  1.1493 -            fluidsynth_stop(music_playing->data.fluidsynthmidi);
  1.1494 -            goto skip;
  1.1495 -        }
  1.1496 -#endif
  1.1497 -#ifdef USE_TIMIDITY_MIDI
  1.1498 -        if ( timidity_ok ) {
  1.1499 -            Timidity_Stop();
  1.1500 -            goto skip;
  1.1501 -        }
  1.1502 -#endif
  1.1503 -        break;
  1.1504 -#endif
  1.1505 -#ifdef OGG_MUSIC
  1.1506 -        case MUS_OGG:
  1.1507 -        OGG_stop(music_playing->data.ogg);
  1.1508 -        break;
  1.1509 -#endif
  1.1510 -#ifdef FLAC_MUSIC
  1.1511 -        case MUS_FLAC:
  1.1512 -        FLAC_stop(music_playing->data.flac);
  1.1513 -        break;
  1.1514 -#endif
  1.1515 -#ifdef MP3_MUSIC
  1.1516 -        case MUS_MP3:
  1.1517 -        smpeg.SMPEG_stop(music_playing->data.mp3);
  1.1518 -        break;
  1.1519 -#endif
  1.1520 -#ifdef MP3_MAD_MUSIC
  1.1521 -        case MUS_MP3_MAD:
  1.1522 -        mad_stop(music_playing->data.mp3_mad);
  1.1523 -        break;
  1.1524 -#endif
  1.1525 -#ifdef MP3_MPG_MUSIC
  1.1526 -        case MUS_MP3_MPG:
  1.1527 -        mpg_stop(music_playing->data.mp3_mpg);
  1.1528 -        break;
  1.1529 -#endif
  1.1530 -        default:
  1.1531 -        /* Unknown music type?? */
  1.1532 -        return;
  1.1533 +    if (music_playing->interface->Stop) {
  1.1534 +        music_playing->interface->Stop(music_playing->context);
  1.1535      }
  1.1536  
  1.1537 -skip:
  1.1538 +    music_playing->playing = SDL_FALSE;
  1.1539      music_playing->fading = MIX_NO_FADING;
  1.1540      music_playing = NULL;
  1.1541  }
  1.1542  int Mix_HaltMusic(void)
  1.1543  {
  1.1544      Mix_LockAudio();
  1.1545 -    if ( music_playing ) {
  1.1546 +    if (music_playing) {
  1.1547          music_internal_halt();
  1.1548 -        if ( music_finished_hook ) {
  1.1549 +        if (music_finished_hook) {
  1.1550              music_finished_hook();
  1.1551          }
  1.1552      }
  1.1553 @@ -1351,7 +780,7 @@
  1.1554  {
  1.1555      int retval = 0;
  1.1556  
  1.1557 -    if ( ms_per_step == 0 ) {
  1.1558 +    if (ms_per_step == 0) {
  1.1559          SDL_SetError("Audio device hasn't been opened");
  1.1560          return 0;
  1.1561      }
  1.1562 @@ -1362,22 +791,20 @@
  1.1563      }
  1.1564  
  1.1565      Mix_LockAudio();
  1.1566 -    if ( music_playing) {
  1.1567 -                int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
  1.1568 -                if ( music_playing->fading == MIX_NO_FADING ) {
  1.1569 -                music_playing->fade_step = 0;
  1.1570 -                } else {
  1.1571 -                        int step;
  1.1572 -                        int old_fade_steps = music_playing->fade_steps;
  1.1573 -                        if ( music_playing->fading == MIX_FADING_OUT ) {
  1.1574 -                                step = music_playing->fade_step;
  1.1575 -                        } else {
  1.1576 -                                step = old_fade_steps
  1.1577 -                                        - music_playing->fade_step + 1;
  1.1578 -                        }
  1.1579 -                        music_playing->fade_step = (step * fade_steps)
  1.1580 -                                / old_fade_steps;
  1.1581 -                }
  1.1582 +    if (music_playing) {
  1.1583 +        int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
  1.1584 +        if (music_playing->fading == MIX_NO_FADING) {
  1.1585 +            music_playing->fade_step = 0;
  1.1586 +        } else {
  1.1587 +            int step;
  1.1588 +            int old_fade_steps = music_playing->fade_steps;
  1.1589 +            if (music_playing->fading == MIX_FADING_OUT) {
  1.1590 +                step = music_playing->fade_step;
  1.1591 +            } else {
  1.1592 +                step = old_fade_steps - music_playing->fade_step + 1;
  1.1593 +            }
  1.1594 +            music_playing->fade_step = (step * fade_steps) / old_fade_steps;
  1.1595 +        }
  1.1596          music_playing->fading = MIX_FADING_OUT;
  1.1597          music_playing->fade_steps = fade_steps;
  1.1598          retval = 1;
  1.1599 @@ -1392,7 +819,7 @@
  1.1600      Mix_Fading fading = MIX_NO_FADING;
  1.1601  
  1.1602      Mix_LockAudio();
  1.1603 -    if ( music_playing ) {
  1.1604 +    if (music_playing) {
  1.1605          fading = music_playing->fading;
  1.1606      }
  1.1607      Mix_UnlockAudio();
  1.1608 @@ -1403,12 +830,22 @@
  1.1609  /* Pause/Resume the music stream */
  1.1610  void Mix_PauseMusic(void)
  1.1611  {
  1.1612 +    Mix_LockAudio();
  1.1613 +    if (music_playing && music_playing->interface->Pause) {
  1.1614 +        music_playing->interface->Pause(music_playing->context);
  1.1615 +    }
  1.1616      music_active = 0;
  1.1617 +    Mix_UnlockAudio();
  1.1618  }
  1.1619  
  1.1620  void Mix_ResumeMusic(void)
  1.1621  {
  1.1622 +    Mix_LockAudio();
  1.1623      music_active = 1;
  1.1624 +    if (music_playing && music_playing->interface->Resume) {
  1.1625 +        music_playing->interface->Resume(music_playing->context);
  1.1626 +    }
  1.1627 +    Mix_UnlockAudio();
  1.1628  }
  1.1629  
  1.1630  void Mix_RewindMusic(void)
  1.1631 @@ -1422,116 +859,23 @@
  1.1632  }
  1.1633  
  1.1634  /* Check the status of the music */
  1.1635 -static int music_internal_playing()
  1.1636 +static SDL_bool music_internal_playing()
  1.1637  {
  1.1638 -    int playing = 1;
  1.1639 -
  1.1640      if (music_playing == NULL) {
  1.1641 -        return 0;
  1.1642 +        return SDL_FALSE;
  1.1643      }
  1.1644  
  1.1645 -    switch (music_playing->type) {
  1.1646 -#ifdef CMD_MUSIC
  1.1647 -        case MUS_CMD:
  1.1648 -        if (!MusicCMD_Active(music_playing->data.cmd)) {
  1.1649 -            playing = 0;
  1.1650 -        }
  1.1651 -        break;
  1.1652 -#endif
  1.1653 -#ifdef WAV_MUSIC
  1.1654 -        case MUS_WAV:
  1.1655 -        if ( ! WAVStream_Active() ) {
  1.1656 -            playing = 0;
  1.1657 -        }
  1.1658 -        break;
  1.1659 -#endif
  1.1660 -#ifdef MODPLUG_MUSIC
  1.1661 -        case MUS_MODPLUG:
  1.1662 -        if ( ! modplug_playing(music_playing->data.modplug) ) {
  1.1663 -            playing = 0;
  1.1664 -        }
  1.1665 -        break;
  1.1666 -#endif
  1.1667 -#ifdef MOD_MUSIC
  1.1668 -        case MUS_MOD:
  1.1669 -        if ( ! MOD_playing(music_playing->data.module) ) {
  1.1670 -            playing = 0;
  1.1671 -        }
  1.1672 -        break;
  1.1673 -#endif
  1.1674 -#ifdef MID_MUSIC
  1.1675 -        case MUS_MID:
  1.1676 -#ifdef USE_NATIVE_MIDI
  1.1677 -        if ( native_midi_ok ) {
  1.1678 -            if ( ! native_midi_active() )
  1.1679 -                playing = 0;
  1.1680 -            goto skip;
  1.1681 -        }
  1.1682 -#endif
  1.1683 -#ifdef USE_FLUIDSYNTH_MIDI
  1.1684 -        if ( fluidsynth_ok ) {
  1.1685 -            if ( ! fluidsynth_active(music_playing->data.fluidsynthmidi) )
  1.1686 -                playing = 0;
  1.1687 -            goto skip;
  1.1688 -        }
  1.1689 -#endif
  1.1690 -#ifdef USE_TIMIDITY_MIDI
  1.1691 -        if ( timidity_ok ) {
  1.1692 -            if ( ! Timidity_Active() )
  1.1693 -                playing = 0;
  1.1694 -            goto skip;
  1.1695 -        }
  1.1696 -#endif
  1.1697 -        break;
  1.1698 -#endif
  1.1699 -#ifdef OGG_MUSIC
  1.1700 -        case MUS_OGG:
  1.1701 -        if ( ! OGG_playing(music_playing->data.ogg) ) {
  1.1702 -            playing = 0;
  1.1703 -        }
  1.1704 -        break;
  1.1705 -#endif
  1.1706 -#ifdef FLAC_MUSIC
  1.1707 -        case MUS_FLAC:
  1.1708 -        if ( ! FLAC_playing(music_playing->data.flac) ) {
  1.1709 -            playing = 0;
  1.1710 -        }
  1.1711 -        break;
  1.1712 -#endif
  1.1713 -#ifdef MP3_MUSIC
  1.1714 -        case MUS_MP3:
  1.1715 -        if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
  1.1716 -            playing = 0;
  1.1717 -        break;
  1.1718 -#endif
  1.1719 -#ifdef MP3_MAD_MUSIC
  1.1720 -        case MUS_MP3_MAD:
  1.1721 -        if (!mad_isPlaying(music_playing->data.mp3_mad)) {
  1.1722 -            playing = 0;
  1.1723 -        }
  1.1724 -        break;
  1.1725 -#endif
  1.1726 -#ifdef MP3_MPG_MUSIC
  1.1727 -        case MUS_MP3_MPG:
  1.1728 -        if (!mpg_playing(music_playing->data.mp3_mpg)) {
  1.1729 -            playing = 0;
  1.1730 -        }
  1.1731 -        break;
  1.1732 -#endif
  1.1733 -        default:
  1.1734 -        playing = 0;
  1.1735 -        break;
  1.1736 +    if (music_playing->interface->IsPlaying) {
  1.1737 +        return music_playing->interface->IsPlaying(music_playing->context);
  1.1738      }
  1.1739 -
  1.1740 -skip:
  1.1741 -    return(playing);
  1.1742 +    return music_playing->playing;
  1.1743  }
  1.1744  int Mix_PlayingMusic(void)
  1.1745  {
  1.1746      int playing = 0;
  1.1747  
  1.1748      Mix_LockAudio();
  1.1749 -    if ( music_playing ) {
  1.1750 +    if (music_playing) {
  1.1751          playing = music_loops || music_internal_playing();
  1.1752      }
  1.1753      Mix_UnlockAudio();
  1.1754 @@ -1543,18 +887,19 @@
  1.1755  int Mix_SetMusicCMD(const char *command)
  1.1756  {
  1.1757      Mix_HaltMusic();
  1.1758 -    if ( music_cmd ) {
  1.1759 +    if (music_cmd) {
  1.1760          SDL_free(music_cmd);
  1.1761          music_cmd = NULL;
  1.1762      }
  1.1763 -    if ( command ) {
  1.1764 -        music_cmd = (char *)SDL_malloc(strlen(command)+1);
  1.1765 -        if ( music_cmd == NULL ) {
  1.1766 -            return(-1);
  1.1767 +    if (command) {
  1.1768 +        size_t length = SDL_strlen(command) + 1;
  1.1769 +        music_cmd = (char *)SDL_malloc(length);
  1.1770 +        if (music_cmd == NULL) {
  1.1771 +            return SDL_OutOfMemory();
  1.1772          }
  1.1773 -        strcpy(music_cmd, command);
  1.1774 +        SDL_memcpy(music_cmd, command, length);
  1.1775      }
  1.1776 -    return(0);
  1.1777 +    return 0;
  1.1778  }
  1.1779  
  1.1780  int Mix_SetSynchroValue(int i)
  1.1781 @@ -1570,24 +915,24 @@
  1.1782  }
  1.1783  
  1.1784  
  1.1785 -/* Uninitialize the music players */
  1.1786 +/* Uninitialize the music interfaces */
  1.1787  void close_music(void)
  1.1788  {
  1.1789 +    int i;
  1.1790 +
  1.1791      Mix_HaltMusic();
  1.1792 -#ifdef CMD_MUSIC
  1.1793 -    Mix_SetMusicCMD(NULL);
  1.1794 -#endif
  1.1795 -#ifdef MODPLUG_MUSIC
  1.1796 -    modplug_exit();
  1.1797 -#endif
  1.1798 -#ifdef MOD_MUSIC
  1.1799 -    MOD_exit();
  1.1800 -#endif
  1.1801 -#ifdef MID_MUSIC
  1.1802 -# ifdef USE_TIMIDITY_MIDI
  1.1803 -    Timidity_Close();
  1.1804 -# endif
  1.1805 -#endif
  1.1806 +
  1.1807 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1.1808 +        Mix_MusicInterface *interface = s_music_interfaces[i];
  1.1809 +        if (!interface || !interface->opened) {
  1.1810 +            continue;
  1.1811 +        }
  1.1812 +
  1.1813 +        if (interface->Close) {
  1.1814 +            interface->Close();
  1.1815 +        }
  1.1816 +        interface->opened = SDL_FALSE;
  1.1817 +    }
  1.1818  
  1.1819      /* rcg06042009 report available decoders at runtime. */
  1.1820      SDL_free((void *)music_decoders);
  1.1821 @@ -1597,6 +942,23 @@
  1.1822      ms_per_step = 0;
  1.1823  }
  1.1824  
  1.1825 +/* Unload the music interface libraries */
  1.1826 +void unload_music(void)
  1.1827 +{
  1.1828 +    int i;
  1.1829 +    for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
  1.1830 +        Mix_MusicInterface *interface = s_music_interfaces[i];
  1.1831 +        if (!interface || !interface->loaded) {
  1.1832 +            continue;
  1.1833 +        }
  1.1834 +
  1.1835 +        if (interface->Unload) {
  1.1836 +            interface->Unload();
  1.1837 +        }
  1.1838 +        interface->loaded = SDL_FALSE;
  1.1839 +    }
  1.1840 +}
  1.1841 +
  1.1842  int Mix_SetSoundFonts(const char *paths)
  1.1843  {
  1.1844      if (soundfont_paths) {
  1.1845 @@ -1615,10 +977,8 @@
  1.1846  
  1.1847  const char* Mix_GetSoundFonts(void)
  1.1848  {
  1.1849 -    const char* force = getenv("SDL_FORCE_SOUNDFONTS");
  1.1850 -
  1.1851 -    if (!soundfont_paths || (force && force[0] == '1')) {
  1.1852 -        return getenv("SDL_SOUNDFONTS");
  1.1853 +    if (!soundfont_paths || SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE)) {
  1.1854 +        return SDL_getenv("SDL_SOUNDFONTS");
  1.1855      } else {
  1.1856          return soundfont_paths;
  1.1857      }
  1.1858 @@ -1660,3 +1020,5 @@
  1.1859      else
  1.1860          return 0;
  1.1861  }
  1.1862 +
  1.1863 +/* vi: set ts=4 sw=4 expandtab: */