2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "SDL_endian.h"
30 #include "SDL_audio.h"
31 #include "SDL_timer.h"
33 #include "SDL_mixer.h"
35 /* The music command hack is UNIX specific */
41 #include "music_cmd.h"
44 #include "wavestream.h"
47 #include "music_mod.h"
50 # ifdef USE_TIMIDITY_MIDI
51 # include "timidity.h"
53 # ifdef USE_NATIVE_MIDI
54 # include "native_midi.h"
56 # if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
57 # define MIDI_ELSE else
63 #include "music_ogg.h"
66 #include "dynamic_mp3.h"
69 #include "music_mad.h"
72 #include "music_flac.h"
75 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
76 static SDL_AudioSpec used_mixer;
80 int volatile music_active = 1;
81 static int volatile music_stopped = 0;
82 static int music_loops = 0;
83 static char *music_cmd = NULL;
84 static Mix_Music * volatile music_playing = NULL;
85 static int music_volume = MIX_MAX_VOLUME;
97 struct MODULE *module;
100 #ifdef USE_TIMIDITY_MIDI
103 #ifdef USE_NATIVE_MIDI
104 NativeMidiSong *nativemidi;
126 #ifdef USE_TIMIDITY_MIDI
127 static int timidity_ok;
128 static int samplesize;
130 #ifdef USE_NATIVE_MIDI
131 static int native_midi_ok;
135 /* Used to calculate fading steps */
136 static int ms_per_step;
138 /* rcg06042009 report available decoders at runtime. */
139 static const char **music_decoders = NULL;
140 static int num_decoders = 0;
142 int Mix_GetNumMusicDecoders(void)
144 return(num_decoders);
147 const char *Mix_GetMusicDecoder(int index)
149 if ((index < 0) || (index >= num_decoders)) {
152 return(music_decoders[index]);
155 static void add_music_decoder(const char *decoder)
157 void *ptr = realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
159 return; /* oh well, go on without it. */
161 music_decoders = (const char **) ptr;
162 music_decoders[num_decoders++] = decoder;
165 /* Local low-level functions prototypes */
166 static void music_internal_initialize_volume(void);
167 static void music_internal_volume(int volume);
168 static int music_internal_play(Mix_Music *music, double position);
169 static int music_internal_position(double position);
170 static int music_internal_playing();
171 static void music_internal_halt(void);
174 /* Support for hooking when the music has finished */
175 static void (*music_finished_hook)(void) = NULL;
177 void Mix_HookMusicFinished(void (*music_finished)(void))
180 music_finished_hook = music_finished;
185 /* If music isn't playing, halt it if no looping is required, restart it */
186 /* otherwhise. NOP if the music is playing */
187 static int music_halt_or_loop (void)
189 /* Restart music if it has to loop */
191 if (!music_internal_playing())
193 /* Restart music if it has to loop at a high level */
194 if (music_loops && --music_loops)
196 Mix_Fading current_fade = music_playing->fading;
197 music_internal_play(music_playing, 0.0);
198 music_playing->fading = current_fade;
202 music_internal_halt();
203 if (music_finished_hook)
204 music_finished_hook();
215 /* Mixing function */
216 void music_mixer(void *udata, Uint8 *stream, int len)
220 if ( music_playing && music_active ) {
222 if ( music_playing->fading != MIX_NO_FADING ) {
223 if ( music_playing->fade_step++ < music_playing->fade_steps ) {
225 int fade_step = music_playing->fade_step;
226 int fade_steps = music_playing->fade_steps;
228 if ( music_playing->fading == MIX_FADING_OUT ) {
229 volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
230 } else { /* Fading in */
231 volume = (music_volume * fade_step) / fade_steps;
233 music_internal_volume(volume);
235 if ( music_playing->fading == MIX_FADING_OUT ) {
236 music_internal_halt();
237 if ( music_finished_hook ) {
238 music_finished_hook();
242 music_playing->fading = MIX_NO_FADING;
246 if (music_halt_or_loop() == 0)
250 switch (music_playing->type) {
253 /* The playing is done externally */
258 left = WAVStream_PlaySome(stream, len);
263 left = MOD_playAudio(music_playing->data.module, stream, len);
267 #ifdef USE_TIMIDITY_MIDI
270 int samples = len / samplesize;
271 Timidity_PlaySome(stream, samples);
279 left = OGG_playAudio(music_playing->data.ogg, stream, len);
284 left = FLAC_playAudio(music_playing->data.flac, stream, len);
289 left = (len - smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len));
294 left = mad_getSamples(music_playing->data.mp3_mad, stream, len);
298 /* Unknown music type?? */
303 /* Handle seamless music looping */
304 if (left > 0 && left < len && music_halt_or_loop()) {
305 music_mixer(udata, stream+(len-left), left);
309 /* Initialize the music players with a certain desired audio format */
310 int open_music(SDL_AudioSpec *mixer)
315 if ( WAVStream_Init(mixer) < 0 ) {
318 add_music_decoder("WAVE");
322 if ( MOD_init(mixer) < 0 ) {
325 add_music_decoder("MIKMOD");
329 #ifdef USE_TIMIDITY_MIDI
330 samplesize = mixer->size / mixer->samples;
331 if ( Timidity_Init(mixer->freq, mixer->format,
332 mixer->channels, mixer->samples) == 0 ) {
334 add_music_decoder("TIMIDITY");
339 #ifdef USE_NATIVE_MIDI
340 #ifdef USE_TIMIDITY_MIDI
341 native_midi_ok = !timidity_ok;
342 if ( !native_midi_ok ) {
343 native_midi_ok = (getenv("SDL_NATIVE_MUSIC") != NULL);
345 if ( native_midi_ok )
347 native_midi_ok = native_midi_detect();
348 if ( native_midi_ok )
349 add_music_decoder("NATIVEMIDI");
353 if ( OGG_init(mixer) < 0 ) {
356 add_music_decoder("OGG");
360 if ( FLAC_init(mixer) < 0 ) {
363 add_music_decoder("FLAC");
366 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
367 /* Keep a copy of the mixer */
369 add_music_decoder("MP3");
372 music_playing = NULL;
377 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
379 /* Calculate the number of ms for each callback */
380 ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
385 /* Portable case-insensitive string compare function */
386 int MIX_string_equals(const char *str1, const char *str2)
388 while ( *str1 && *str2 ) {
389 if ( toupper((unsigned char)*str1) !=
390 toupper((unsigned char)*str2) )
395 return (!*str1 && !*str2);
398 /* Load a music file */
399 Mix_Music *Mix_LoadMUS(const char *file)
403 Uint8 magic[5], moremagic[9];
406 /* Figure out what kind of file this is */
407 fp = fopen(file, "rb");
408 if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
412 Mix_SetError("Couldn't read from '%s'", file);
415 if (!fread(moremagic, 8, 1, fp)) {
416 Mix_SetError("Couldn't read from '%s'", file);
423 /* Figure out the file extension, so we can determine the type */
424 ext = strrchr(file, '.');
425 if ( ext ) ++ext; /* skip the dot in the extension */
427 /* Allocate memory for the music structure */
428 music = (Mix_Music *)malloc(sizeof(Mix_Music));
429 if ( music == NULL ) {
430 Mix_SetError("Out of memory");
437 music->type = MUS_CMD;
438 music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
439 if ( music->data.cmd == NULL ) {
445 /* WAVE files have the magic four bytes "RIFF"
446 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
448 if ( (ext && MIX_string_equals(ext, "WAV")) ||
449 ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
450 (strcmp((char *)magic, "FORM") == 0) ) {
451 music->type = MUS_WAV;
452 music->data.wave = WAVStream_LoadSong(file, (char *)magic);
453 if ( music->data.wave == NULL ) {
454 Mix_SetError("Unable to load WAV file");
460 /* MIDI files have the magic four bytes "MThd" */
461 if ( (ext && MIX_string_equals(ext, "MID")) ||
462 (ext && MIX_string_equals(ext, "MIDI")) ||
463 strcmp((char *)magic, "MThd") == 0 ||
464 ( strcmp((char *)magic, "RIFF") == 0 &&
465 strcmp((char *)(moremagic+4), "RMID") == 0 ) ) {
466 music->type = MUS_MID;
467 #ifdef USE_NATIVE_MIDI
468 if ( native_midi_ok ) {
469 music->data.nativemidi = native_midi_loadsong(file);
470 if ( music->data.nativemidi == NULL ) {
471 Mix_SetError("%s", native_midi_error());
476 #ifdef USE_TIMIDITY_MIDI
478 music->data.midi = Timidity_LoadSong(file);
479 if ( music->data.midi == NULL ) {
480 Mix_SetError("%s", Timidity_Error());
484 Mix_SetError("%s", Timidity_Error());
491 /* Ogg Vorbis files have the magic four bytes "OggS" */
492 if ( (ext && MIX_string_equals(ext, "OGG")) ||
493 strcmp((char *)magic, "OggS") == 0 ) {
494 music->type = MUS_OGG;
495 music->data.ogg = OGG_new(file);
496 if ( music->data.ogg == NULL ) {
502 /* FLAC files have the magic four bytes "fLaC" */
503 if ( (ext && MIX_string_equals(ext, "FLAC")) ||
504 strcmp((char *)magic, "fLaC") == 0 ) {
505 music->type = MUS_FLAC;
506 music->data.flac = FLAC_new(file);
507 if ( music->data.flac == NULL ) {
513 if ( (ext && MIX_string_equals(ext, "MPG")) ||
514 (ext && MIX_string_equals(ext, "MP3")) ||
515 (ext && MIX_string_equals(ext, "MPEG")) ||
516 (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
517 (strncmp((char *)magic, "ID3", 3) == 0) ) {
518 if ( Mix_InitMP3() == 0 ) {
520 music->type = MUS_MP3;
521 music->data.mp3 = smpeg.SMPEG_new(file, &info, 0);
522 if ( !info.has_audio ) {
523 Mix_SetError("MPEG file does not have any audio stream.");
526 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
534 if ( (ext && MIX_string_equals(ext, "MPG")) ||
535 (ext && MIX_string_equals(ext, "MP3")) ||
536 (ext && MIX_string_equals(ext, "MPEG")) ||
537 (ext && MIX_string_equals(ext, "MAD")) ||
538 (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ||
539 (strncmp((char *)magic, "ID3", 3) == 0) ) {
540 music->type = MUS_MP3_MAD;
541 music->data.mp3_mad = mad_openFile(file, &used_mixer);
542 if (music->data.mp3_mad == 0) {
543 Mix_SetError("Could not initialize MPEG stream.");
550 music->type = MUS_MOD;
551 music->data.module = MOD_new(file);
552 if ( music->data.module == NULL ) {
558 Mix_SetError("Unrecognized music format");
561 if ( music->error ) {
568 /* Free a music chunk previously loaded */
569 void Mix_FreeMusic(Mix_Music *music)
572 /* Stop the music if it's currently playing */
574 if ( music == music_playing ) {
575 /* Wait for any fade out to finish */
576 while ( music->fading == MIX_FADING_OUT ) {
581 if ( music == music_playing ) {
582 music_internal_halt();
586 switch (music->type) {
589 MusicCMD_FreeSong(music->data.cmd);
594 WAVStream_FreeSong(music->data.wave);
599 MOD_delete(music->data.module);
604 #ifdef USE_NATIVE_MIDI
605 if ( native_midi_ok ) {
606 native_midi_freesong(music->data.nativemidi);
609 #ifdef USE_TIMIDITY_MIDI
611 Timidity_FreeSong(music->data.midi);
618 OGG_delete(music->data.ogg);
623 FLAC_delete(music->data.flac);
628 smpeg.SMPEG_delete(music->data.mp3);
634 mad_closeFile(music->data.mp3_mad);
638 /* Unknown music type?? */
645 /* Find out the music format of a mixer music, or the currently playing
646 music, if 'music' is NULL.
648 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
650 Mix_MusicType type = MUS_NONE;
656 if ( music_playing ) {
657 type = music_playing->type;
664 /* Play a music chunk. Returns 0, or -1 if there was an error.
666 static int music_internal_play(Mix_Music *music, double position)
670 /* Note the music we're playing */
671 if ( music_playing ) {
672 music_internal_halt();
674 music_playing = music;
676 /* Set the initial volume */
677 if ( music->type != MUS_MOD ) {
678 music_internal_initialize_volume();
681 /* Set up for playback */
682 switch (music->type) {
685 MusicCMD_Start(music->data.cmd);
690 WAVStream_Start(music->data.wave);
695 MOD_play(music->data.module);
696 /* Player_SetVolume() does nothing before Player_Start() */
697 music_internal_initialize_volume();
702 #ifdef USE_NATIVE_MIDI
703 if ( native_midi_ok ) {
704 native_midi_start(music->data.nativemidi);
707 #ifdef USE_TIMIDITY_MIDI
709 Timidity_Start(music->data.midi);
716 OGG_play(music->data.ogg);
721 FLAC_play(music->data.flac);
726 smpeg.SMPEG_enableaudio(music->data.mp3,1);
727 smpeg.SMPEG_enablevideo(music->data.mp3,0);
728 smpeg.SMPEG_play(music_playing->data.mp3);
733 mad_start(music->data.mp3_mad);
737 Mix_SetError("Can't play unknown music type");
742 /* Set the playback position, note any errors if an offset is used */
744 if ( position > 0.0 ) {
745 if ( music_internal_position(position) < 0 ) {
746 Mix_SetError("Position not implemented for music type");
750 music_internal_position(0.0);
754 /* If the setup failed, we're not playing any music anymore */
756 music_playing = NULL;
760 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
764 /* Don't play null pointers :-) */
765 if ( music == NULL ) {
766 Mix_SetError("music parameter was NULL");
772 music->fading = MIX_FADING_IN;
774 music->fading = MIX_NO_FADING;
776 music->fade_step = 0;
777 music->fade_steps = ms/ms_per_step;
781 /* If the current music is fading out, wait for the fade to complete */
782 while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
789 retval = music_internal_play(music, position);
794 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
796 return Mix_FadeInMusicPos(music, loops, ms, 0.0);
798 int Mix_PlayMusic(Mix_Music *music, int loops)
800 return Mix_FadeInMusicPos(music, loops, 0, 0.0);
803 /* Set the playing music position */
804 int music_internal_position(double position)
808 switch (music_playing->type) {
811 MOD_jump_to_time(music_playing->data.module, position);
816 OGG_jump_to_time(music_playing->data.ogg, position);
821 FLAC_jump_to_time(music_playing->data.flac, position);
826 if ( position > 0.0 ) {
827 smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
829 smpeg.SMPEG_rewind(music_playing->data.mp3);
830 smpeg.SMPEG_play(music_playing->data.mp3);
836 mad_seek(music_playing->data.mp3_mad, position);
840 /* TODO: Implement this for other music backends */
846 int Mix_SetMusicPosition(double position)
851 if ( music_playing ) {
852 retval = music_internal_position(position);
854 Mix_SetError("Position not implemented for music type");
857 Mix_SetError("Music isn't playing");
865 /* Set the music's initial volume */
866 static void music_internal_initialize_volume(void)
868 if ( music_playing->fading == MIX_FADING_IN ) {
869 music_internal_volume(0);
871 music_internal_volume(music_volume);
875 /* Set the music volume */
876 static void music_internal_volume(int volume)
878 switch (music_playing->type) {
881 MusicCMD_SetVolume(volume);
886 WAVStream_SetVolume(volume);
891 MOD_setvolume(music_playing->data.module, volume);
896 #ifdef USE_NATIVE_MIDI
897 if ( native_midi_ok ) {
898 native_midi_setvolume(volume);
901 #ifdef USE_TIMIDITY_MIDI
903 Timidity_SetVolume(volume);
910 OGG_setvolume(music_playing->data.ogg, volume);
915 FLAC_setvolume(music_playing->data.flac, volume);
920 smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
925 mad_setVolume(music_playing->data.mp3_mad, volume);
929 /* Unknown music type?? */
933 int Mix_VolumeMusic(int volume)
937 prev_volume = music_volume;
941 if ( volume > SDL_MIX_MAXVOLUME ) {
942 volume = SDL_MIX_MAXVOLUME;
944 music_volume = volume;
946 if ( music_playing ) {
947 music_internal_volume(music_volume);
953 /* Halt playing of music */
954 static void music_internal_halt(void)
956 switch (music_playing->type) {
959 MusicCMD_Stop(music_playing->data.cmd);
969 MOD_stop(music_playing->data.module);
974 #ifdef USE_NATIVE_MIDI
975 if ( native_midi_ok ) {
979 #ifdef USE_TIMIDITY_MIDI
988 OGG_stop(music_playing->data.ogg);
993 FLAC_stop(music_playing->data.flac);
998 smpeg.SMPEG_stop(music_playing->data.mp3);
1001 #ifdef MP3_MAD_MUSIC
1003 mad_stop(music_playing->data.mp3_mad);
1007 /* Unknown music type?? */
1010 music_playing->fading = MIX_NO_FADING;
1011 music_playing = NULL;
1013 int Mix_HaltMusic(void)
1016 if ( music_playing ) {
1017 music_internal_halt();
1024 /* Progressively stop the music */
1025 int Mix_FadeOutMusic(int ms)
1029 if (ms <= 0) { /* just halt immediately. */
1035 if ( music_playing) {
1036 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
1037 if ( music_playing->fading == MIX_NO_FADING ) {
1038 music_playing->fade_step = 0;
1041 int old_fade_steps = music_playing->fade_steps;
1042 if ( music_playing->fading == MIX_FADING_OUT ) {
1043 step = music_playing->fade_step;
1045 step = old_fade_steps
1046 - music_playing->fade_step + 1;
1048 music_playing->fade_step = (step * fade_steps)
1051 music_playing->fading = MIX_FADING_OUT;
1052 music_playing->fade_steps = fade_steps;
1060 Mix_Fading Mix_FadingMusic(void)
1062 Mix_Fading fading = MIX_NO_FADING;
1065 if ( music_playing ) {
1066 fading = music_playing->fading;
1073 /* Pause/Resume the music stream */
1074 void Mix_PauseMusic(void)
1079 void Mix_ResumeMusic(void)
1084 void Mix_RewindMusic(void)
1086 Mix_SetMusicPosition(0.0);
1089 int Mix_PausedMusic(void)
1091 return (music_active == 0);
1094 /* Check the status of the music */
1095 static int music_internal_playing()
1098 switch (music_playing->type) {
1101 if (!MusicCMD_Active(music_playing->data.cmd)) {
1108 if ( ! WAVStream_Active() ) {
1115 if ( ! MOD_playing(music_playing->data.module) ) {
1122 #ifdef USE_NATIVE_MIDI
1123 if ( native_midi_ok ) {
1124 if ( ! native_midi_active() )
1128 #ifdef USE_TIMIDITY_MIDI
1129 if ( timidity_ok ) {
1130 if ( ! Timidity_Active() )
1138 if ( ! OGG_playing(music_playing->data.ogg) ) {
1145 if ( ! FLAC_playing(music_playing->data.flac) ) {
1152 if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
1156 #ifdef MP3_MAD_MUSIC
1158 if (!mad_isPlaying(music_playing->data.mp3_mad)) {
1169 int Mix_PlayingMusic(void)
1174 if ( music_playing ) {
1175 playing = music_internal_playing();
1182 /* Set the external music playback command */
1183 int Mix_SetMusicCMD(const char *command)
1191 music_cmd = (char *)malloc(strlen(command)+1);
1192 if ( music_cmd == NULL ) {
1195 strcpy(music_cmd, command);
1200 int Mix_SetSynchroValue(int i)
1202 /* Not supported by any players at this time */
1206 int Mix_GetSynchroValue(void)
1208 /* Not supported by any players at this time */
1213 /* Uninitialize the music players */
1214 void close_music(void)
1218 Mix_SetMusicCMD(NULL);
1224 # ifdef USE_TIMIDITY_MIDI
1229 /* rcg06042009 report available decoders at runtime. */
1230 free(music_decoders);
1231 music_decoders = NULL;
1235 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
1237 Uint8 magic[5]; /*Apparently there is no way to check if the file is really a MOD,*/
1238 /* or there are too many formats supported by MikMod or MikMod does */
1239 /* this check by itself. If someone implements other formats (e.g. MP3) */
1240 /* the check can be uncommented */
1246 Mix_SetError("RWops pointer is NULL");
1250 /* Figure out what kind of file this is */
1251 start = SDL_RWtell(rw);
1252 if ( SDL_RWread(rw,magic,1,4) != 4 ||
1253 SDL_RWread(rw,moremagic,1,8) != 8 ) {
1254 Mix_SetError("Couldn't read from RWops");
1257 SDL_RWseek(rw, start, SEEK_SET);
1259 moremagic[8] = '\0';
1261 /* Allocate memory for the music structure */
1262 music=(Mix_Music *)malloc(sizeof(Mix_Music));
1264 Mix_SetError("Out of memory");
1270 /* WAVE files have the magic four bytes "RIFF"
1271 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
1273 if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
1274 (strcmp((char *)magic, "FORM") == 0) ) {
1275 music->type = MUS_WAV;
1276 music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
1277 if ( music->data.wave == NULL ) {
1284 /* Ogg Vorbis files have the magic four bytes "OggS" */
1285 if ( strcmp((char *)magic, "OggS") == 0 ) {
1286 music->type = MUS_OGG;
1287 music->data.ogg = OGG_new_RW(rw);
1288 if ( music->data.ogg == NULL ) {
1294 /* FLAC files have the magic four bytes "fLaC" */
1295 if ( strcmp((char *)magic, "fLaC") == 0 ) {
1296 music->type = MUS_FLAC;
1297 music->data.flac = FLAC_new_RW(rw);
1298 if ( music->data.flac == NULL ) {
1304 if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
1305 if ( Mix_InitMP3() == 0 ) {
1307 music->type = MUS_MP3;
1308 music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
1309 if ( !info.has_audio ) {
1310 Mix_SetError("MPEG file does not have any audio stream.");
1313 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
1320 #ifdef MP3_MAD_MUSIC
1321 if ( ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) || ( strncmp((char *)magic, "ID3", 3) == 0 ) ) {
1322 music->type = MUS_MP3_MAD;
1323 music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
1324 if (music->data.mp3_mad == 0) {
1325 Mix_SetError("Could not initialize MPEG stream.");
1331 /* MIDI files have the magic four bytes "MThd" */
1332 if ( strcmp((char *)magic, "MThd") == 0 ) {
1333 music->type = MUS_MID;
1334 #ifdef USE_NATIVE_MIDI
1335 if ( native_midi_ok ) {
1336 music->data.nativemidi = native_midi_loadsong_RW(rw);
1337 if ( music->data.nativemidi == NULL ) {
1338 Mix_SetError("%s", native_midi_error());
1343 #ifdef USE_TIMIDITY_MIDI
1344 if ( timidity_ok ) {
1345 music->data.midi = Timidity_LoadSong_RW(rw);
1346 if ( music->data.midi == NULL ) {
1347 Mix_SetError("%s", Timidity_Error());
1351 Mix_SetError("%s", Timidity_Error());
1359 music->type=MUS_MOD;
1360 music->data.module = MOD_new_RW(rw);
1361 if ( music->data.module == NULL ) {
1367 Mix_SetError("Unrecognized music format");