fix build.
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2019 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "SDL_hints.h"
23 #include "SDL_timer.h"
25 #include "SDL_mixer.h"
29 #include "music_cmd.h"
30 #include "music_wav.h"
31 #include "music_mikmod.h"
32 #include "music_modplug.h"
33 #include "music_nativemidi.h"
34 #include "music_fluidsynth.h"
35 #include "music_timidity.h"
36 #include "music_ogg.h"
37 #include "music_opus.h"
38 #include "music_mpg123.h"
39 #include "music_mad.h"
40 #include "music_flac.h"
41 #include "native_midi/native_midi.h"
45 /* Check to make sure we are building with a new enough SDL */
46 #if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 7)
47 #error You need SDL 2.0.7 or newer from http://www.libsdl.org
50 /* Set this hint to true if you want verbose logging of music interfaces */
51 #define SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES \
52 "SDL_MIXER_DEBUG_MUSIC_INTERFACES"
54 char *music_cmd = NULL;
55 static SDL_bool music_active = SDL_TRUE;
56 static int music_volume = MIX_MAX_VOLUME;
57 static Mix_Music * volatile music_playing = NULL;
58 SDL_AudioSpec music_spec;
61 Mix_MusicInterface *interface;
70 /* Used to calculate fading steps */
71 static int ms_per_step;
73 /* rcg06042009 report available decoders at runtime. */
74 static const char **music_decoders = NULL;
75 static int num_decoders = 0;
77 /* Semicolon-separated SoundFont paths */
78 static char* soundfont_paths = NULL;
80 /* full path of timidity config file */
81 static char* timidity_cfg = NULL;
83 /* Interfaces for the various music interfaces, ordered by priority */
84 static Mix_MusicInterface *s_music_interfaces[] =
87 &Mix_MusicInterface_CMD,
90 &Mix_MusicInterface_WAV,
93 &Mix_MusicInterface_FLAC,
96 &Mix_MusicInterface_OGG,
99 &Mix_MusicInterface_Opus,
101 #ifdef MUSIC_MP3_MPG123
102 &Mix_MusicInterface_MPG123,
105 &Mix_MusicInterface_MAD,
107 #ifdef MUSIC_MOD_MODPLUG
108 &Mix_MusicInterface_MODPLUG,
110 #ifdef MUSIC_MOD_MIKMOD
111 &Mix_MusicInterface_MIKMOD,
113 #ifdef MUSIC_MID_FLUIDSYNTH
114 &Mix_MusicInterface_FLUIDSYNTH,
116 #ifdef MUSIC_MID_TIMIDITY
117 &Mix_MusicInterface_TIMIDITY,
119 #ifdef MUSIC_MID_NATIVE
120 &Mix_MusicInterface_NATIVEMIDI,
124 int get_num_music_interfaces(void)
126 return SDL_arraysize(s_music_interfaces);
129 Mix_MusicInterface *get_music_interface(int index)
131 return s_music_interfaces[index];
134 int Mix_GetNumMusicDecoders(void)
136 return(num_decoders);
139 const char *Mix_GetMusicDecoder(int index)
141 if ((index < 0) || (index >= num_decoders)) {
144 return(music_decoders[index]);
147 static void add_music_decoder(const char *decoder)
152 /* Check to see if we already have this decoder */
153 for (i = 0; i < num_decoders; ++i) {
154 if (SDL_strcmp(music_decoders[i], decoder) == 0) {
159 ptr = SDL_realloc((void *)music_decoders, ((size_t)num_decoders + 1) * sizeof (const char *));
161 return; /* oh well, go on without it. */
163 music_decoders = (const char **) ptr;
164 music_decoders[num_decoders++] = decoder;
167 /* Local low-level functions prototypes */
168 static void music_internal_initialize_volume(void);
169 static void music_internal_volume(int volume);
170 static int music_internal_play(Mix_Music *music, int play_count, double position);
171 static int music_internal_position(double position);
172 static SDL_bool music_internal_playing(void);
173 static void music_internal_halt(void);
176 /* Support for hooking when the music has finished */
177 static void (SDLCALL *music_finished_hook)(void) = NULL;
179 void Mix_HookMusicFinished(void (SDLCALL *music_finished)(void))
182 music_finished_hook = music_finished;
186 /* Convenience function to fill audio and mix at the specified volume
187 This is called from many music player's GetAudio callback.
189 int music_pcm_getaudio(void *context, void *data, int bytes, int volume,
190 int (*GetSome)(void *context, void *data, int bytes, SDL_bool *done))
192 Uint8 *snd = (Uint8 *)data;
195 SDL_bool done = SDL_FALSE;
197 if (volume == MIX_MAX_VOLUME) {
200 dst = SDL_stack_alloc(Uint8, (size_t)bytes);
202 while (len > 0 && !done) {
203 int consumed = GetSome(context, dst, len, &done);
208 if (volume == MIX_MAX_VOLUME) {
211 SDL_MixAudioFormat(snd, dst, music_spec.format, (Uint32)consumed, volume);
216 if (volume != MIX_MAX_VOLUME) {
222 /* Mixing function */
223 void SDLCALL music_mixer(void *udata, Uint8 *stream, int len)
227 while (music_playing && music_active && len > 0) {
229 if (music_playing->fading != MIX_NO_FADING) {
230 if (music_playing->fade_step++ < music_playing->fade_steps) {
232 int fade_step = music_playing->fade_step;
233 int fade_steps = music_playing->fade_steps;
235 if (music_playing->fading == MIX_FADING_OUT) {
236 volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
237 } else { /* Fading in */
238 volume = (music_volume * fade_step) / fade_steps;
240 music_internal_volume(volume);
242 if (music_playing->fading == MIX_FADING_OUT) {
243 music_internal_halt();
244 if (music_finished_hook) {
245 music_finished_hook();
249 music_playing->fading = MIX_NO_FADING;
253 if (music_playing->interface->GetAudio) {
254 int left = music_playing->interface->GetAudio(music_playing->context, stream, len);
256 /* Either an error or finished playing with data left */
257 music_playing->playing = SDL_FALSE;
260 stream += (len - left);
269 if (!music_internal_playing()) {
270 music_internal_halt();
271 if (music_finished_hook) {
272 music_finished_hook();
278 /* Load the music interface libraries for a given music type */
279 SDL_bool load_music_type(Mix_MusicType type)
283 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
284 Mix_MusicInterface *interface = s_music_interfaces[i];
285 if (interface->type != type) {
288 if (!interface->loaded) {
290 SDL_snprintf(hint, sizeof(hint), "SDL_MIXER_DISABLE_%s", interface->tag);
291 if (SDL_GetHintBoolean(hint, SDL_FALSE)) {
295 if (interface->Load && interface->Load() < 0) {
296 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
297 SDL_Log("Couldn't load %s: %s\n", interface->tag, Mix_GetError());
301 interface->loaded = SDL_TRUE;
305 return (loaded > 0) ? SDL_TRUE : SDL_FALSE;
308 /* Open the music interfaces for a given music type */
309 SDL_bool open_music_type(Mix_MusicType type)
313 SDL_bool use_native_midi = SDL_FALSE;
315 if (!music_spec.format) {
316 /* Music isn't opened yet */
320 #ifdef MUSIC_MID_NATIVE
321 if (type == MUS_MID && SDL_GetHintBoolean("SDL_NATIVE_MUSIC", SDL_FALSE) && native_midi_detect()) {
322 use_native_midi = SDL_TRUE;
326 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
327 Mix_MusicInterface *interface = s_music_interfaces[i];
328 if (!interface->loaded) {
331 if (type != MUS_NONE && interface->type != type) {
335 if (interface->type == MUS_MID && use_native_midi && interface->api != MIX_MUSIC_NATIVEMIDI) {
339 if (!interface->opened) {
340 if (interface->Open && interface->Open(&music_spec) < 0) {
341 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
342 SDL_Log("Couldn't open %s: %s\n", interface->tag, Mix_GetError());
346 interface->opened = SDL_TRUE;
347 add_music_decoder(interface->tag);
352 if (has_music(MUS_MOD)) {
353 add_music_decoder("MOD");
354 add_chunk_decoder("MOD");
356 if (has_music(MUS_MID)) {
357 add_music_decoder("MIDI");
358 add_chunk_decoder("MID");
360 if (has_music(MUS_OGG)) {
361 add_music_decoder("OGG");
362 add_chunk_decoder("OGG");
364 if (has_music(MUS_OPUS)) {
365 add_music_decoder("OPUS");
366 add_chunk_decoder("OPUS");
368 if (has_music(MUS_MP3)) {
369 add_music_decoder("MP3");
370 add_chunk_decoder("MP3");
372 if (has_music(MUS_FLAC)) {
373 add_music_decoder("FLAC");
374 add_chunk_decoder("FLAC");
377 return (opened > 0) ? SDL_TRUE : SDL_FALSE;
380 /* Initialize the music interfaces with a certain desired audio format */
381 void open_music(const SDL_AudioSpec *spec)
383 #ifdef MIX_INIT_SOUNDFONT_PATHS
384 if (!soundfont_paths) {
385 soundfont_paths = SDL_strdup(MIX_INIT_SOUNDFONT_PATHS);
389 /* Load the music interfaces that don't have explicit initialization */
390 load_music_type(MUS_CMD);
391 load_music_type(MUS_WAV);
393 /* Open all the interfaces that are loaded */
395 open_music_type(MUS_NONE);
397 Mix_VolumeMusic(MIX_MAX_VOLUME);
399 /* Calculate the number of ms for each callback */
400 ms_per_step = (int) (((float)spec->samples * 1000.0f) / spec->freq);
403 /* Return SDL_TRUE if the music type is available */
404 SDL_bool has_music(Mix_MusicType type)
407 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
408 Mix_MusicInterface *interface = s_music_interfaces[i];
409 if (interface->type != type) {
412 if (interface->opened) {
419 Mix_MusicType detect_music_type(SDL_RWops *src)
423 if (SDL_RWread(src, magic, 1, 12) != 12) {
424 Mix_SetError("Couldn't read first 12 bytes of audio data");
427 SDL_RWseek(src, -12, RW_SEEK_CUR);
429 /* WAVE files have the magic four bytes "RIFF"
430 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" */
431 if (((SDL_memcmp(magic, "RIFF", 4) == 0) && (SDL_memcmp((magic+8), "WAVE", 4) == 0)) ||
432 (SDL_memcmp(magic, "FORM", 4) == 0)) {
436 /* Ogg Vorbis files have the magic four bytes "OggS" */
437 if (SDL_memcmp(magic, "OggS", 4) == 0) {
438 SDL_RWseek(src, 28, RW_SEEK_CUR);
439 SDL_RWread(src, magic, 1, 8);
440 SDL_RWseek(src,-36, RW_SEEK_CUR);
441 if (SDL_memcmp(magic, "OpusHead", 8) == 0) {
447 /* FLAC files have the magic four bytes "fLaC" */
448 if (SDL_memcmp(magic, "fLaC", 4) == 0) {
452 /* MIDI files have the magic four bytes "MThd" */
453 if (SDL_memcmp(magic, "MThd", 4) == 0) {
457 if (SDL_memcmp(magic, "ID3", 3) == 0 ||
458 (magic[0] == 0xFF && (magic[1] & 0xFE) == 0xFA)) {
462 /* Assume MOD format.
464 * Apparently there is no way to check if the file is really a MOD,
465 * or there are too many formats supported by MikMod/ModPlug, or
466 * MikMod/ModPlug does this check by itself. */
470 /* Load a music file */
471 Mix_Music *Mix_LoadMUS(const char *file)
479 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
480 Mix_MusicInterface *interface = s_music_interfaces[i];
481 if (!interface->opened || !interface->CreateFromFile) {
485 context = interface->CreateFromFile(file);
487 /* Allocate memory for the music structure */
488 Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
490 Mix_SetError("Out of memory");
493 music->interface = interface;
494 music->context = context;
499 src = SDL_RWFromFile(file, "rb");
501 Mix_SetError("Couldn't open '%s'", file);
505 /* Use the extension as a first guess on the file type */
507 ext = SDL_strrchr(file, '.');
509 ++ext; /* skip the dot in the extension */
510 if (SDL_strcasecmp(ext, "WAV") == 0) {
512 } else if (SDL_strcasecmp(ext, "MID") == 0 ||
513 SDL_strcasecmp(ext, "MIDI") == 0 ||
514 SDL_strcasecmp(ext, "KAR") == 0) {
516 } else if (SDL_strcasecmp(ext, "OGG") == 0) {
518 } else if (SDL_strcasecmp(ext, "OPUS") == 0) {
520 } else if (SDL_strcasecmp(ext, "FLAC") == 0) {
522 } else if (SDL_strcasecmp(ext, "MPG") == 0 ||
523 SDL_strcasecmp(ext, "MPEG") == 0 ||
524 SDL_strcasecmp(ext, "MP3") == 0 ||
525 SDL_strcasecmp(ext, "MAD") == 0) {
527 } else if (SDL_strcasecmp(ext, "669") == 0 ||
528 SDL_strcasecmp(ext, "AMF") == 0 ||
529 SDL_strcasecmp(ext, "AMS") == 0 ||
530 SDL_strcasecmp(ext, "DBM") == 0 ||
531 SDL_strcasecmp(ext, "DSM") == 0 ||
532 SDL_strcasecmp(ext, "FAR") == 0 ||
533 SDL_strcasecmp(ext, "IT") == 0 ||
534 SDL_strcasecmp(ext, "MED") == 0 ||
535 SDL_strcasecmp(ext, "MDL") == 0 ||
536 SDL_strcasecmp(ext, "MOD") == 0 ||
537 SDL_strcasecmp(ext, "MOL") == 0 ||
538 SDL_strcasecmp(ext, "MTM") == 0 ||
539 SDL_strcasecmp(ext, "NST") == 0 ||
540 SDL_strcasecmp(ext, "OKT") == 0 ||
541 SDL_strcasecmp(ext, "PTM") == 0 ||
542 SDL_strcasecmp(ext, "S3M") == 0 ||
543 SDL_strcasecmp(ext, "STM") == 0 ||
544 SDL_strcasecmp(ext, "ULT") == 0 ||
545 SDL_strcasecmp(ext, "UMX") == 0 ||
546 SDL_strcasecmp(ext, "WOW") == 0 ||
547 SDL_strcasecmp(ext, "XM") == 0) {
551 return Mix_LoadMUSType_RW(src, type, SDL_TRUE);
554 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *src, int freesrc)
556 return Mix_LoadMUSType_RW(src, MUS_NONE, freesrc);
559 Mix_Music *Mix_LoadMUSType_RW(SDL_RWops *src, Mix_MusicType type, int freesrc)
566 Mix_SetError("RWops pointer is NULL");
569 start = SDL_RWtell(src);
571 /* If the caller wants auto-detection, figure out what kind of file
573 if (type == MUS_NONE) {
574 if ((type = detect_music_type(src)) == MUS_NONE) {
575 /* Don't call Mix_SetError() since detect_music_type() does that. */
585 if (load_music_type(type) && open_music_type(type)) {
586 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
587 Mix_MusicInterface *interface = s_music_interfaces[i];
588 if (!interface->opened || type != interface->type || !interface->CreateFromRW) {
592 context = interface->CreateFromRW(src, freesrc);
594 /* Allocate memory for the music structure */
595 Mix_Music *music = (Mix_Music *)SDL_calloc(1, sizeof(Mix_Music));
597 interface->Delete(context);
598 Mix_SetError("Out of memory");
601 music->interface = interface;
602 music->context = context;
604 if (SDL_GetHintBoolean(SDL_MIXER_HINT_DEBUG_MUSIC_INTERFACES, SDL_FALSE)) {
605 SDL_Log("Loaded music with %s\n", interface->tag);
610 /* Reset the stream for the next decoder */
611 SDL_RWseek(src, start, RW_SEEK_SET);
615 if (!*Mix_GetError()) {
616 Mix_SetError("Unrecognized audio format");
621 SDL_RWseek(src, start, RW_SEEK_SET);
626 /* Free a music chunk previously loaded */
627 void Mix_FreeMusic(Mix_Music *music)
630 /* Stop the music if it's currently playing */
632 if (music == music_playing) {
633 /* Wait for any fade out to finish */
634 while (music->fading == MIX_FADING_OUT) {
639 if (music == music_playing) {
640 music_internal_halt();
645 music->interface->Delete(music->context);
650 /* Find out the music format of a mixer music, or the currently playing
651 music, if 'music' is NULL.
653 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
655 Mix_MusicType type = MUS_NONE;
658 type = music->interface->type;
662 type = music_playing->interface->type;
669 /* Play a music chunk. Returns 0, or -1 if there was an error.
671 static int music_internal_play(Mix_Music *music, int play_count, double position)
675 #if defined(__MACOSX__) && defined(MID_MUSIC_NATIVE)
676 /* This fixes a bug with native MIDI on Mac OS X, where you
677 can't really stop and restart MIDI from the audio callback.
679 if (music == music_playing && music->api == MIX_MUSIC_NATIVEMIDI) {
680 /* Just a seek suffices to restart playing */
681 music_internal_position(position);
686 /* Note the music we're playing */
688 music_internal_halt();
690 music_playing = music;
691 music_playing->playing = SDL_TRUE;
693 /* Set the initial volume */
694 music_internal_initialize_volume();
696 /* Set up for playback */
697 retval = music->interface->Play(music->context, play_count);
699 /* Set the playback position, note any errors if an offset is used */
701 if (position > 0.0) {
702 if (music_internal_position(position) < 0) {
703 Mix_SetError("Position not implemented for music type");
707 music_internal_position(0.0);
711 /* If the setup failed, we're not playing any music anymore */
713 music->playing = SDL_FALSE;
714 music_playing = NULL;
719 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
723 if (ms_per_step == 0) {
724 SDL_SetError("Audio device hasn't been opened");
728 /* Don't play null pointers :-) */
730 Mix_SetError("music parameter was NULL");
736 music->fading = MIX_FADING_IN;
738 music->fading = MIX_NO_FADING;
740 music->fade_step = 0;
741 music->fade_steps = ms/ms_per_step;
745 /* If the current music is fading out, wait for the fade to complete */
746 while (music_playing && (music_playing->fading == MIX_FADING_OUT)) {
752 /* Loop is the number of times to play the audio */
755 retval = music_internal_play(music, loops, position);
756 /* Set music as active */
757 music_active = (retval == 0);
762 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
764 return Mix_FadeInMusicPos(music, loops, ms, 0.0);
766 int Mix_PlayMusic(Mix_Music *music, int loops)
768 return Mix_FadeInMusicPos(music, loops, 0, 0.0);
771 /* Set the playing music position */
772 int music_internal_position(double position)
774 if (music_playing->interface->Seek) {
775 return music_playing->interface->Seek(music_playing->context, position);
779 int Mix_SetMusicPosition(double position)
785 retval = music_internal_position(position);
787 Mix_SetError("Position not implemented for music type");
790 Mix_SetError("Music isn't playing");
798 static double music_duration_int(Mix_Music *music)
800 if (music->interface->Duration) {
801 return music->interface->Duration(music->context);
803 Mix_SetError("Duration not implemented for music type");
808 double Mix_MusicDuration(Mix_Music *music)
815 retval = music_duration_int(music);
816 } else if (music_playing) {
817 retval = music_duration_int(music_playing);
819 Mix_SetError("music is NULL and no playing music");
827 /* Set the music's initial volume */
828 static void music_internal_initialize_volume(void)
830 if (music_playing->fading == MIX_FADING_IN) {
831 music_internal_volume(0);
833 music_internal_volume(music_volume);
837 /* Set the music volume */
838 static void music_internal_volume(int volume)
840 if (music_playing->interface->SetVolume) {
841 music_playing->interface->SetVolume(music_playing->context, volume);
844 int Mix_VolumeMusic(int volume)
848 prev_volume = music_volume;
852 if (volume > SDL_MIX_MAXVOLUME) {
853 volume = SDL_MIX_MAXVOLUME;
855 music_volume = volume;
858 music_internal_volume(music_volume);
864 /* Halt playing of music */
865 static void music_internal_halt(void)
867 if (music_playing->interface->Stop) {
868 music_playing->interface->Stop(music_playing->context);
871 music_playing->playing = SDL_FALSE;
872 music_playing->fading = MIX_NO_FADING;
873 music_playing = NULL;
875 int Mix_HaltMusic(void)
879 music_internal_halt();
880 if (music_finished_hook) {
881 music_finished_hook();
889 /* Progressively stop the music */
890 int Mix_FadeOutMusic(int ms)
894 if (ms_per_step == 0) {
895 SDL_SetError("Audio device hasn't been opened");
899 if (ms <= 0) { /* just halt immediately. */
906 int fade_steps = (ms + ms_per_step - 1) / ms_per_step;
907 if (music_playing->fading == MIX_NO_FADING) {
908 music_playing->fade_step = 0;
911 int old_fade_steps = music_playing->fade_steps;
912 if (music_playing->fading == MIX_FADING_OUT) {
913 step = music_playing->fade_step;
915 step = old_fade_steps - music_playing->fade_step + 1;
917 music_playing->fade_step = (step * fade_steps) / old_fade_steps;
919 music_playing->fading = MIX_FADING_OUT;
920 music_playing->fade_steps = fade_steps;
928 Mix_Fading Mix_FadingMusic(void)
930 Mix_Fading fading = MIX_NO_FADING;
934 fading = music_playing->fading;
941 /* Pause/Resume the music stream */
942 void Mix_PauseMusic(void)
946 if (music_playing->interface->Pause) {
947 music_playing->interface->Pause(music_playing->context);
950 music_active = SDL_FALSE;
954 void Mix_ResumeMusic(void)
958 if (music_playing->interface->Resume) {
959 music_playing->interface->Resume(music_playing->context);
962 music_active = SDL_TRUE;
966 void Mix_RewindMusic(void)
968 Mix_SetMusicPosition(0.0);
971 int Mix_PausedMusic(void)
973 return (music_active == SDL_FALSE);
976 /* Check the status of the music */
977 static SDL_bool music_internal_playing(void)
979 if (!music_playing) {
983 if (music_playing->interface->IsPlaying) {
984 music_playing->playing = music_playing->interface->IsPlaying(music_playing->context);
986 return music_playing->playing;
988 int Mix_PlayingMusic(void)
993 playing = music_internal_playing();
996 return playing ? 1 : 0;
999 /* Set the external music playback command */
1000 int Mix_SetMusicCMD(const char *command)
1004 SDL_free(music_cmd);
1008 size_t length = SDL_strlen(command) + 1;
1009 music_cmd = (char *)SDL_malloc(length);
1010 if (music_cmd == NULL) {
1011 return SDL_OutOfMemory();
1013 SDL_memcpy(music_cmd, command, length);
1018 int Mix_SetSynchroValue(int i)
1020 /* Not supported by any players at this time */
1024 int Mix_GetSynchroValue(void)
1026 /* Not supported by any players at this time */
1031 /* Uninitialize the music interfaces */
1032 void close_music(void)
1038 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
1039 Mix_MusicInterface *interface = s_music_interfaces[i];
1040 if (!interface || !interface->opened) {
1044 if (interface->Close) {
1047 interface->opened = SDL_FALSE;
1050 if (soundfont_paths) {
1051 SDL_free(soundfont_paths);
1052 soundfont_paths = NULL;
1055 /* rcg06042009 report available decoders at runtime. */
1056 if (music_decoders) {
1057 SDL_free((void *)music_decoders);
1058 music_decoders = NULL;
1065 /* Unload the music interface libraries */
1066 void unload_music(void)
1069 for (i = 0; i < SDL_arraysize(s_music_interfaces); ++i) {
1070 Mix_MusicInterface *interface = s_music_interfaces[i];
1071 if (!interface || !interface->loaded) {
1075 if (interface->Unload) {
1076 interface->Unload();
1078 interface->loaded = SDL_FALSE;
1082 int Mix_SetTimidityCfg(const char *path)
1085 SDL_free(timidity_cfg);
1086 timidity_cfg = NULL;
1089 if (path && *path) {
1090 if (!(timidity_cfg = SDL_strdup(path))) {
1091 Mix_SetError("Insufficient memory to set Timidity cfg file");
1099 const char* Mix_GetTimidityCfg(void)
1101 return timidity_cfg;
1104 int Mix_SetSoundFonts(const char *paths)
1106 if (soundfont_paths) {
1107 SDL_free(soundfont_paths);
1108 soundfont_paths = NULL;
1112 if (!(soundfont_paths = SDL_strdup(paths))) {
1113 Mix_SetError("Insufficient memory to set SoundFonts");
1120 const char* Mix_GetSoundFonts(void)
1122 const char *env_paths = SDL_getenv("SDL_SOUNDFONTS");
1123 SDL_bool force_env_paths = SDL_GetHintBoolean("SDL_FORCE_SOUNDFONTS", SDL_FALSE);
1124 if (force_env_paths && (!env_paths || !*env_paths)) {
1125 force_env_paths = SDL_FALSE;
1127 if (soundfont_paths && *soundfont_paths && !force_env_paths) {
1128 return soundfont_paths;
1134 /* We don't have any sound fonts set programmatically or in the environment
1135 Time to start guessing where they might be...
1138 static char *s_soundfont_paths[] = {
1139 "/usr/share/sounds/sf2/FluidR3_GM.sf2" /* Remember to add ',' here */
1143 for (i = 0; i < SDL_arraysize(s_soundfont_paths); ++i) {
1144 SDL_RWops *rwops = SDL_RWFromFile(s_soundfont_paths[i], "rb");
1147 return s_soundfont_paths[i];
1154 int Mix_EachSoundFont(int (SDLCALL *function)(const char*, void*), void *data)
1156 char *context, *path, *paths;
1157 const char* cpaths = Mix_GetSoundFonts();
1158 int soundfonts_found = 0;
1161 Mix_SetError("No SoundFonts have been requested");
1165 if (!(paths = SDL_strdup(cpaths))) {
1166 Mix_SetError("Insufficient memory to iterate over SoundFonts");
1170 #if defined(_WIN32)||defined(__OS2__)
1173 #define PATHSEP ":;"
1175 for (path = SDL_strtokr(paths, PATHSEP, &context); path;
1176 path = SDL_strtokr(NULL, PATHSEP, &context)) {
1177 if (!function(path, data)) {
1184 return (soundfonts_found > 0);
1187 /* vi: set ts=4 sw=4 expandtab: */