1 /*
2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2009 Sam Lantinga
4
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.
9
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.
14
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
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22
23 /* $Id: music.c 5247 2009-11-14 20:44:30Z slouken $ */
24
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <assert.h>
29 #include "SDL_endian.h"
30 #include "SDL_audio.h"
31 #include "SDL_timer.h"
32
33 #include "SDL_mixer.h"
34
35 #ifdef CMD_MUSIC
36 #include "music_cmd.h"
37 #endif
38 #ifdef WAV_MUSIC
39 #include "wavestream.h"
40 #endif
41 #ifdef OGG_MUSIC
42 #include "music_ogg.h"
43 #endif
44
45 int volatile music_active = 1;
46 static int volatile music_stopped = 0;
47 static int music_loops = 0;
48 static char *music_cmd = NULL;
49 static Mix_Music * volatile music_playing = NULL;
50 static int music_volume = MIX_MAX_VOLUME;
51
52 struct _Mix_Music {
53 Mix_MusicType type;
54 union {
55 #ifdef CMD_MUSIC
56 MusicCMD *cmd;
57 #endif
58 #ifdef WAV_MUSIC
59 WAVStream *wave;
60 #endif
61 #ifdef OGG_MUSIC
62 OGG_music *ogg;
63 #endif
64 } data;
65 Mix_Fading fading;
66 int fade_step;
67 int fade_steps;
68 int error;
69 };
70
71 /* Used to calculate fading steps */
72 static int ms_per_step;
73
74 /* rcg06042009 report available decoders at runtime. */
75 static const char **music_decoders = NULL;
76 static int num_decoders = 0;
77
Mix_GetNumMusicDecoders(void)78 int Mix_GetNumMusicDecoders(void)
79 {
80 return(num_decoders);
81 }
82
Mix_GetMusicDecoder(int index)83 const char *Mix_GetMusicDecoder(int index)
84 {
85 if ((index < 0) || (index >= num_decoders)) {
86 return NULL;
87 }
88 return(music_decoders[index]);
89 }
90
add_music_decoder(const char * decoder)91 static void add_music_decoder(const char *decoder)
92 {
93 void *ptr = realloc(music_decoders, (num_decoders + 1) * sizeof (const char **));
94 if (ptr == NULL) {
95 return; /* oh well, go on without it. */
96 }
97 music_decoders = (const char **) ptr;
98 music_decoders[num_decoders++] = decoder;
99 }
100
101 /* Local low-level functions prototypes */
102 static void music_internal_initialize_volume(void);
103 static void music_internal_volume(int volume);
104 static int music_internal_play(Mix_Music *music, double position);
105 static int music_internal_position(double position);
106 static int music_internal_playing();
107 static void music_internal_halt(void);
108
109
110 /* Support for hooking when the music has finished */
111 static void (*music_finished_hook)(void) = NULL;
112
Mix_HookMusicFinished(void (* music_finished)(void))113 void Mix_HookMusicFinished(void (*music_finished)(void))
114 {
115 SDL_LockAudio();
116 music_finished_hook = music_finished;
117 SDL_UnlockAudio();
118 }
119
120
121 /* If music isn't playing, halt it if no looping is required, restart it */
122 /* otherwhise. NOP if the music is playing */
music_halt_or_loop(void)123 static int music_halt_or_loop (void)
124 {
125 /* Restart music if it has to loop */
126
127 if (!music_internal_playing())
128 {
129 /* Restart music if it has to loop at a high level */
130 if (music_loops && --music_loops)
131 {
132 Mix_Fading current_fade = music_playing->fading;
133 music_internal_play(music_playing, 0.0);
134 music_playing->fading = current_fade;
135 }
136 else
137 {
138 music_internal_halt();
139 if (music_finished_hook)
140 music_finished_hook();
141
142 return 0;
143 }
144 }
145
146 return 1;
147 }
148
149
150
151 /* Mixing function */
music_mixer(void * udata,Uint8 * stream,int len)152 void music_mixer(void *udata, Uint8 *stream, int len)
153 {
154 int left = 0;
155
156 if ( music_playing && music_active ) {
157 /* Handle fading */
158 if ( music_playing->fading != MIX_NO_FADING ) {
159 if ( music_playing->fade_step++ < music_playing->fade_steps ) {
160 int volume;
161 int fade_step = music_playing->fade_step;
162 int fade_steps = music_playing->fade_steps;
163
164 if ( music_playing->fading == MIX_FADING_OUT ) {
165 volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
166 } else { /* Fading in */
167 volume = (music_volume * fade_step) / fade_steps;
168 }
169 music_internal_volume(volume);
170 } else {
171 if ( music_playing->fading == MIX_FADING_OUT ) {
172 music_internal_halt();
173 if ( music_finished_hook ) {
174 music_finished_hook();
175 }
176 return;
177 }
178 music_playing->fading = MIX_NO_FADING;
179 }
180 }
181
182 if (music_halt_or_loop() == 0)
183 return;
184
185
186 switch (music_playing->type) {
187 #ifdef CMD_MUSIC
188 case MUS_CMD:
189 /* The playing is done externally */
190 break;
191 #endif
192 #ifdef WAV_MUSIC
193 case MUS_WAV:
194 left = WAVStream_PlaySome(stream, len);
195 break;
196 #endif
197 #ifdef OGG_MUSIC
198 case MUS_OGG:
199
200 left = OGG_playAudio(music_playing->data.ogg, stream, len);
201 break;
202 #endif
203 default:
204 /* Unknown music type?? */
205 break;
206 }
207 }
208
209 /* Handle seamless music looping */
210 if (left > 0 && left < len && music_halt_or_loop()) {
211 music_mixer(udata, stream+(len-left), left);
212 }
213 }
214
215 /* Initialize the music players with a certain desired audio format */
open_music(SDL_AudioSpec * mixer)216 int open_music(SDL_AudioSpec *mixer)
217 {
218 #ifdef WAV_MUSIC
219 if ( WAVStream_Init(mixer) == 0 ) {
220 add_music_decoder("WAVE");
221 }
222 #endif
223 #ifdef OGG_MUSIC
224 if ( OGG_init(mixer) == 0 ) {
225 add_music_decoder("OGG");
226 }
227 #endif
228
229 music_playing = NULL;
230 music_stopped = 0;
231 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
232
233 /* Calculate the number of ms for each callback */
234 ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
235
236 return(0);
237 }
238
239 /* Portable case-insensitive string compare function */
MIX_string_equals(const char * str1,const char * str2)240 int MIX_string_equals(const char *str1, const char *str2)
241 {
242 while ( *str1 && *str2 ) {
243 if ( toupper((unsigned char)*str1) !=
244 toupper((unsigned char)*str2) )
245 break;
246 ++str1;
247 ++str2;
248 }
249 return (!*str1 && !*str2);
250 }
251
252 /* Load a music file */
Mix_LoadMUS(const char * file)253 Mix_Music *Mix_LoadMUS(const char *file)
254 {
255 FILE *fp;
256 char *ext;
257 Uint8 magic[5], moremagic[9];
258 Mix_Music *music;
259
260 /* Figure out what kind of file this is */
261 fp = fopen(file, "rb");
262 if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
263 if ( fp != NULL ) {
264 fclose(fp);
265 }
266 Mix_SetError("Couldn't read from '%s'", file);
267 return(NULL);
268 }
269 if (!fread(moremagic, 8, 1, fp)) {
270 Mix_SetError("Couldn't read from '%s'", file);
271 return(NULL);
272 }
273 magic[4] = '\0';
274 moremagic[8] = '\0';
275 fclose(fp);
276
277 /* Figure out the file extension, so we can determine the type */
278 ext = strrchr(file, '.');
279 if ( ext ) ++ext; /* skip the dot in the extension */
280
281 /* Allocate memory for the music structure */
282 music = (Mix_Music *)malloc(sizeof(Mix_Music));
283 if ( music == NULL ) {
284 Mix_SetError("Out of memory");
285 return(NULL);
286 }
287 music->error = 0;
288
289 #ifdef CMD_MUSIC
290 if ( music_cmd ) {
291 music->type = MUS_CMD;
292 music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
293 if ( music->data.cmd == NULL ) {
294 music->error = 1;
295 }
296 } else
297 #endif
298 #ifdef WAV_MUSIC
299 /* WAVE files have the magic four bytes "RIFF"
300 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
301 */
302 if ( (ext && MIX_string_equals(ext, "WAV")) ||
303 ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
304 (strcmp((char *)magic, "FORM") == 0) ) {
305 music->type = MUS_WAV;
306 music->data.wave = WAVStream_LoadSong(file, (char *)magic);
307 if ( music->data.wave == NULL ) {
308 Mix_SetError("Unable to load WAV file");
309 music->error = 1;
310 }
311 } else
312 #endif
313 #ifdef OGG_MUSIC
314 /* Ogg Vorbis files have the magic four bytes "OggS" */
315 if ( (ext && MIX_string_equals(ext, "OGG")) ||
316 strcmp((char *)magic, "OggS") == 0 ) {
317 music->type = MUS_OGG;
318 music->data.ogg = OGG_new(file);
319 if ( music->data.ogg == NULL ) {
320 music->error = 1;
321 }
322 } else
323 #endif
324 {
325 Mix_SetError("Unrecognized music format");
326 music->error = 1;
327 }
328 if ( music->error ) {
329 free(music);
330 music = NULL;
331 }
332 return(music);
333 }
334
335 /* Free a music chunk previously loaded */
Mix_FreeMusic(Mix_Music * music)336 void Mix_FreeMusic(Mix_Music *music)
337 {
338 if ( music ) {
339 /* Stop the music if it's currently playing */
340 SDL_LockAudio();
341 if ( music == music_playing ) {
342 /* Wait for any fade out to finish */
343 while ( music->fading == MIX_FADING_OUT ) {
344 SDL_UnlockAudio();
345 SDL_Delay(100);
346 SDL_LockAudio();
347 }
348 if ( music == music_playing ) {
349 music_internal_halt();
350 }
351 }
352 SDL_UnlockAudio();
353 switch (music->type) {
354 #ifdef CMD_MUSIC
355 case MUS_CMD:
356 MusicCMD_FreeSong(music->data.cmd);
357 break;
358 #endif
359 #ifdef WAV_MUSIC
360 case MUS_WAV:
361 WAVStream_FreeSong(music->data.wave);
362 break;
363 #endif
364 #ifdef OGG_MUSIC
365 case MUS_OGG:
366 OGG_delete(music->data.ogg);
367 break;
368 #endif
369 default:
370 /* Unknown music type?? */
371 break;
372 }
373 free(music);
374 }
375 }
376
377 /* Find out the music format of a mixer music, or the currently playing
378 music, if 'music' is NULL.
379 */
Mix_GetMusicType(const Mix_Music * music)380 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
381 {
382 Mix_MusicType type = MUS_NONE;
383
384 if ( music ) {
385 type = music->type;
386 } else {
387 SDL_LockAudio();
388 if ( music_playing ) {
389 type = music_playing->type;
390 }
391 SDL_UnlockAudio();
392 }
393 return(type);
394 }
395
396 /* Play a music chunk. Returns 0, or -1 if there was an error.
397 */
music_internal_play(Mix_Music * music,double position)398 static int music_internal_play(Mix_Music *music, double position)
399 {
400 int retval = 0;
401
402 /* Note the music we're playing */
403 if ( music_playing ) {
404 music_internal_halt();
405 }
406 music_playing = music;
407
408 /* Set the initial volume */
409 music_internal_initialize_volume();
410
411 /* Set up for playback */
412 switch (music->type) {
413 #ifdef CMD_MUSIC
414 case MUS_CMD:
415 MusicCMD_Start(music->data.cmd);
416 break;
417 #endif
418 #ifdef WAV_MUSIC
419 case MUS_WAV:
420 WAVStream_Start(music->data.wave);
421 break;
422 #endif
423 #ifdef OGG_MUSIC
424 case MUS_OGG:
425 OGG_play(music->data.ogg);
426 break;
427 #endif
428 default:
429 Mix_SetError("Can't play unknown music type");
430 retval = -1;
431 break;
432 }
433
434 /* Set the playback position, note any errors if an offset is used */
435 if ( retval == 0 ) {
436 if ( position > 0.0 ) {
437 if ( music_internal_position(position) < 0 ) {
438 Mix_SetError("Position not implemented for music type");
439 retval = -1;
440 }
441 } else {
442 music_internal_position(0.0);
443 }
444 }
445
446 /* If the setup failed, we're not playing any music anymore */
447 if ( retval < 0 ) {
448 music_playing = NULL;
449 }
450 return(retval);
451 }
Mix_FadeInMusicPos(Mix_Music * music,int loops,int ms,double position)452 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
453 {
454 int retval;
455
456 /* Don't play null pointers :-) */
457 if ( music == NULL ) {
458 Mix_SetError("music parameter was NULL");
459 return(-1);
460 }
461
462 /* Setup the data */
463 if ( ms ) {
464 music->fading = MIX_FADING_IN;
465 } else {
466 music->fading = MIX_NO_FADING;
467 }
468 music->fade_step = 0;
469 music->fade_steps = ms/ms_per_step;
470
471 /* Play the puppy */
472 SDL_LockAudio();
473 /* If the current music is fading out, wait for the fade to complete */
474 while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
475 SDL_UnlockAudio();
476 SDL_Delay(100);
477 SDL_LockAudio();
478 }
479 music_active = 1;
480 music_loops = loops;
481 retval = music_internal_play(music, position);
482 SDL_UnlockAudio();
483
484 return(retval);
485 }
Mix_FadeInMusic(Mix_Music * music,int loops,int ms)486 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
487 {
488 return Mix_FadeInMusicPos(music, loops, ms, 0.0);
489 }
Mix_PlayMusic(Mix_Music * music,int loops)490 int Mix_PlayMusic(Mix_Music *music, int loops)
491 {
492 return Mix_FadeInMusicPos(music, loops, 0, 0.0);
493 }
494
495 /* Set the playing music position */
music_internal_position(double position)496 int music_internal_position(double position)
497 {
498 int retval = 0;
499
500 switch (music_playing->type) {
501 #ifdef OGG_MUSIC
502 case MUS_OGG:
503 OGG_jump_to_time(music_playing->data.ogg, position);
504 break;
505 #endif
506 default:
507 /* TODO: Implement this for other music backends */
508 retval = -1;
509 break;
510 }
511 return(retval);
512 }
Mix_SetMusicPosition(double position)513 int Mix_SetMusicPosition(double position)
514 {
515 int retval;
516
517 SDL_LockAudio();
518 if ( music_playing ) {
519 retval = music_internal_position(position);
520 if ( retval < 0 ) {
521 Mix_SetError("Position not implemented for music type");
522 }
523 } else {
524 Mix_SetError("Music isn't playing");
525 retval = -1;
526 }
527 SDL_UnlockAudio();
528
529 return(retval);
530 }
531
532 /* Set the music's initial volume */
music_internal_initialize_volume(void)533 static void music_internal_initialize_volume(void)
534 {
535 if ( music_playing->fading == MIX_FADING_IN ) {
536 music_internal_volume(0);
537 } else {
538 music_internal_volume(music_volume);
539 }
540 }
541
542 /* Set the music volume */
music_internal_volume(int volume)543 static void music_internal_volume(int volume)
544 {
545 switch (music_playing->type) {
546 #ifdef CMD_MUSIC
547 case MUS_CMD:
548 MusicCMD_SetVolume(volume);
549 break;
550 #endif
551 #ifdef WAV_MUSIC
552 case MUS_WAV:
553 WAVStream_SetVolume(volume);
554 break;
555 #endif
556 #ifdef OGG_MUSIC
557 case MUS_OGG:
558 OGG_setvolume(music_playing->data.ogg, volume);
559 break;
560 #endif
561 default:
562 /* Unknown music type?? */
563 break;
564 }
565 }
Mix_VolumeMusic(int volume)566 int Mix_VolumeMusic(int volume)
567 {
568 int prev_volume;
569
570 prev_volume = music_volume;
571 if ( volume < 0 ) {
572 return prev_volume;
573 }
574 if ( volume > SDL_MIX_MAXVOLUME ) {
575 volume = SDL_MIX_MAXVOLUME;
576 }
577 music_volume = volume;
578 SDL_LockAudio();
579 if ( music_playing ) {
580 music_internal_volume(music_volume);
581 }
582 SDL_UnlockAudio();
583 return(prev_volume);
584 }
585
586 /* Halt playing of music */
music_internal_halt(void)587 static void music_internal_halt(void)
588 {
589 switch (music_playing->type) {
590 #ifdef CMD_MUSIC
591 case MUS_CMD:
592 MusicCMD_Stop(music_playing->data.cmd);
593 break;
594 #endif
595 #ifdef WAV_MUSIC
596 case MUS_WAV:
597 WAVStream_Stop();
598 break;
599 #endif
600 #ifdef OGG_MUSIC
601 case MUS_OGG:
602 OGG_stop(music_playing->data.ogg);
603 break;
604 #endif
605 default:
606 /* Unknown music type?? */
607 return;
608 }
609 music_playing->fading = MIX_NO_FADING;
610 music_playing = NULL;
611 }
Mix_HaltMusic(void)612 int Mix_HaltMusic(void)
613 {
614 SDL_LockAudio();
615 if ( music_playing ) {
616 music_internal_halt();
617 }
618 SDL_UnlockAudio();
619
620 return(0);
621 }
622
623 /* Progressively stop the music */
Mix_FadeOutMusic(int ms)624 int Mix_FadeOutMusic(int ms)
625 {
626 int retval = 0;
627
628 if (ms <= 0) { /* just halt immediately. */
629 Mix_HaltMusic();
630 return 1;
631 }
632
633 SDL_LockAudio();
634 if ( music_playing) {
635 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
636 if ( music_playing->fading == MIX_NO_FADING ) {
637 music_playing->fade_step = 0;
638 } else {
639 int step;
640 int old_fade_steps = music_playing->fade_steps;
641 if ( music_playing->fading == MIX_FADING_OUT ) {
642 step = music_playing->fade_step;
643 } else {
644 step = old_fade_steps
645 - music_playing->fade_step + 1;
646 }
647 music_playing->fade_step = (step * fade_steps)
648 / old_fade_steps;
649 }
650 music_playing->fading = MIX_FADING_OUT;
651 music_playing->fade_steps = fade_steps;
652 retval = 1;
653 }
654 SDL_UnlockAudio();
655
656 return(retval);
657 }
658
Mix_FadingMusic(void)659 Mix_Fading Mix_FadingMusic(void)
660 {
661 Mix_Fading fading = MIX_NO_FADING;
662
663 SDL_LockAudio();
664 if ( music_playing ) {
665 fading = music_playing->fading;
666 }
667 SDL_UnlockAudio();
668
669 return(fading);
670 }
671
672 /* Pause/Resume the music stream */
Mix_PauseMusic(void)673 void Mix_PauseMusic(void)
674 {
675 music_active = 0;
676 }
677
Mix_ResumeMusic(void)678 void Mix_ResumeMusic(void)
679 {
680 music_active = 1;
681 }
682
Mix_RewindMusic(void)683 void Mix_RewindMusic(void)
684 {
685 Mix_SetMusicPosition(0.0);
686 }
687
Mix_PausedMusic(void)688 int Mix_PausedMusic(void)
689 {
690 return (music_active == 0);
691 }
692
693 /* Check the status of the music */
music_internal_playing()694 static int music_internal_playing()
695 {
696 int playing = 1;
697 switch (music_playing->type) {
698 #ifdef CMD_MUSIC
699 case MUS_CMD:
700 if (!MusicCMD_Active(music_playing->data.cmd)) {
701 playing = 0;
702 }
703 break;
704 #endif
705 #ifdef WAV_MUSIC
706 case MUS_WAV:
707 if ( ! WAVStream_Active() ) {
708 playing = 0;
709 }
710 break;
711 #endif
712 #ifdef OGG_MUSIC
713 case MUS_OGG:
714 if ( ! OGG_playing(music_playing->data.ogg) ) {
715 playing = 0;
716 }
717 break;
718 #endif
719 default:
720 playing = 0;
721 break;
722 }
723 return(playing);
724 }
Mix_PlayingMusic(void)725 int Mix_PlayingMusic(void)
726 {
727 int playing = 0;
728
729 SDL_LockAudio();
730 if ( music_playing ) {
731 playing = music_internal_playing();
732 }
733 SDL_UnlockAudio();
734
735 return(playing);
736 }
737
738 /* Set the external music playback command */
Mix_SetMusicCMD(const char * command)739 int Mix_SetMusicCMD(const char *command)
740 {
741 Mix_HaltMusic();
742 if ( music_cmd ) {
743 free(music_cmd);
744 music_cmd = NULL;
745 }
746 if ( command ) {
747 music_cmd = (char *)malloc(strlen(command)+1);
748 if ( music_cmd == NULL ) {
749 return(-1);
750 }
751 strcpy(music_cmd, command);
752 }
753 return(0);
754 }
755
Mix_SetSynchroValue(int i)756 int Mix_SetSynchroValue(int i)
757 {
758 /* Not supported by any players at this time */
759 return(-1);
760 }
761
Mix_GetSynchroValue(void)762 int Mix_GetSynchroValue(void)
763 {
764 /* Not supported by any players at this time */
765 return(-1);
766 }
767
768
769 /* Uninitialize the music players */
close_music(void)770 void close_music(void)
771 {
772 Mix_HaltMusic();
773 #ifdef CMD_MUSIC
774 Mix_SetMusicCMD(NULL);
775 #endif
776
777 /* rcg06042009 report available decoders at runtime. */
778 free(music_decoders);
779 music_decoders = NULL;
780 num_decoders = 0;
781 }
782
Mix_LoadMUS_RW(SDL_RWops * rw)783 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
784 {
785 Uint8 magic[5]; /*Apparently there is no way to check if the file is really a MOD,*/
786 /* or there are too many formats supported by MikMod or MikMod does */
787 /* this check by itself. If someone implements other formats (e.g. MP3) */
788 /* the check can be uncommented */
789 Uint8 moremagic[9];
790 Mix_Music *music;
791 int start;
792
793 if (!rw) {
794 Mix_SetError("RWops pointer is NULL");
795 return NULL;
796 }
797
798 /* Figure out what kind of file this is */
799 start = SDL_RWtell(rw);
800 if ( SDL_RWread(rw,magic,1,4) != 4 ||
801 SDL_RWread(rw,moremagic,1,8) != 8 ) {
802 Mix_SetError("Couldn't read from RWops");
803 return NULL;
804 }
805 SDL_RWseek(rw, start, RW_SEEK_SET);
806 magic[4]='\0';
807 moremagic[8] = '\0';
808
809 /* Allocate memory for the music structure */
810 music=(Mix_Music *)malloc(sizeof(Mix_Music));
811 if (music==NULL ) {
812 Mix_SetError("Out of memory");
813 return(NULL);
814 }
815 music->error = 0;
816
817 #ifdef WAV_MUSIC
818 /* WAVE files have the magic four bytes "RIFF"
819 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
820 */
821 if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
822 (strcmp((char *)magic, "FORM") == 0) ) {
823 music->type = MUS_WAV;
824 music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
825 if ( music->data.wave == NULL ) {
826 music->error = 1;
827 }
828
829 } else
830 #endif
831 #ifdef OGG_MUSIC
832 /* Ogg Vorbis files have the magic four bytes "OggS" */
833 if ( strcmp((char *)magic, "OggS") == 0 ) {
834 music->type = MUS_OGG;
835 music->data.ogg = OGG_new_RW(rw);
836 if ( music->data.ogg == NULL ) {
837 music->error = 1;
838 }
839 } else
840 #endif
841 {
842 Mix_SetError("Unrecognized music format");
843 music->error=1;
844 }
845 if (music->error) {
846 free(music);
847 music=NULL;
848 }
849 return(music);
850 }
851