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