2 SDL_mixer: An audio mixer library based on the SDL library
3 Copyright (C) 1997-2004 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"
38 #define MAX_OUTPUT_CHANNELS 6
40 #define MAX_OUTPUT_CHANNELS 2
43 /* The music command hack is UNIX specific */
49 #include "music_cmd.h"
52 #include "wavestream.h"
54 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
56 # if defined(LIBMIKMOD_VERSION) /* libmikmod 3.1.8 */
57 # define UNIMOD MODULE
58 # define MikMod_Init() MikMod_Init(NULL)
59 # define MikMod_LoadSong(a,b) Player_Load(a,b,0)
60 # ifndef LIBMIKMOD_MUSIC
61 # define MikMod_LoadSongRW(a,b) Player_LoadRW(a,b,0)
63 # define MikMod_FreeSong Player_Free
64 extern int MikMod_errno;
65 # else /* old MikMod 3.0.3 */
66 # define MikMod_strerror(x) _mm_errmsg[x])
67 # define MikMod_errno _mm_errno
71 # ifdef USE_TIMIDITY_MIDI
72 # include "timidity.h"
74 # ifdef USE_NATIVE_MIDI
75 # include "native_midi.h"
77 # if defined(USE_TIMIDITY_MIDI) && defined(USE_NATIVE_MIDI)
78 # define MIDI_ELSE else
84 #include "music_ogg.h"
87 #include "dynamic_mp3.h"
90 #include "music_mad.h"
93 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
94 static SDL_AudioSpec used_mixer;
98 int volatile music_active = 1;
99 static int volatile music_stopped = 0;
100 static int music_loops = 0;
101 static char *music_cmd = NULL;
102 static Mix_Music * volatile music_playing = NULL;
103 static int music_volume = MIX_MAX_VOLUME;
104 static int music_swap8;
105 static int music_swap16;
116 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
120 #ifdef USE_TIMIDITY_MIDI
123 #ifdef USE_NATIVE_MIDI
124 NativeMidiSong *nativemidi;
143 #ifdef USE_TIMIDITY_MIDI
144 static int timidity_ok;
145 static int samplesize;
147 #ifdef USE_NATIVE_MIDI
148 static int native_midi_ok;
152 /* Reference for converting mikmod output to 4/6 channels */
153 static int current_output_channels;
154 static Uint16 current_output_format;
156 /* Used to calculate fading steps */
157 static int ms_per_step;
159 /* Local low-level functions prototypes */
160 static void music_internal_initialize_volume(void);
161 static void music_internal_volume(int volume);
162 static int music_internal_play(Mix_Music *music, double position);
163 static int music_internal_position(double position);
164 static int music_internal_playing();
165 static void music_internal_halt(void);
168 /* Support for hooking when the music has finished */
169 static void (*music_finished_hook)(void) = NULL;
171 void Mix_HookMusicFinished(void (*music_finished)(void))
174 music_finished_hook = music_finished;
179 /* If music isn't playing, halt it if no looping is required, restart it */
180 /* otherwhise. NOP if the music is playing */
181 static int music_halt_or_loop (void)
183 /* Restart music if it has to loop */
185 if (!music_internal_playing())
187 /* Restart music if it has to loop at a high level */
188 if (music_loops && --music_loops)
190 Mix_Fading current_fade = music_playing->fading;
191 music_internal_play(music_playing, 0.0);
192 music_playing->fading = current_fade;
196 music_internal_halt();
197 if (music_finished_hook)
198 music_finished_hook();
209 /* Mixing function */
210 void music_mixer(void *udata, Uint8 *stream, int len)
212 if ( music_playing && music_active ) {
214 if ( music_playing->fading != MIX_NO_FADING ) {
215 if ( music_playing->fade_step++ < music_playing->fade_steps ) {
217 int fade_step = music_playing->fade_step;
218 int fade_steps = music_playing->fade_steps;
220 if ( music_playing->fading == MIX_FADING_OUT ) {
221 volume = (music_volume * (fade_steps-fade_step)) / fade_steps;
222 } else { /* Fading in */
223 volume = (music_volume * fade_step) / fade_steps;
225 music_internal_volume(volume);
227 if ( music_playing->fading == MIX_FADING_OUT ) {
228 music_internal_halt();
229 if ( music_finished_hook ) {
230 music_finished_hook();
234 music_playing->fading = MIX_NO_FADING;
238 if (music_halt_or_loop() == 0)
242 switch (music_playing->type) {
245 /* The playing is done externally */
250 WAVStream_PlaySome(stream, len);
253 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
255 if (current_output_channels > 2) {
256 int small_len = 2 * len / current_output_channels;
260 VC_WriteBytes((SBYTE *)stream, small_len);
261 /* and extend to len by copying channels */
262 src = stream + small_len;
265 switch (current_output_format & 0xFF) {
267 for ( i=small_len/2; i; --i ) {
269 dst -= current_output_channels;
274 if (current_output_channels == 6) {
281 for ( i=small_len/4; i; --i ) {
283 dst -= 2 * current_output_channels;
292 if (current_output_channels == 6) {
305 else VC_WriteBytes((SBYTE *)stream, len);
311 for ( i=len; i; --i ) {
315 if ( music_swap16 ) {
320 for ( i=(len/2); i; --i ) {
330 #ifdef USE_TIMIDITY_MIDI
333 int samples = len / samplesize;
334 Timidity_PlaySome(stream, samples);
342 len = OGG_playAudio(music_playing->data.ogg, stream, len);
343 if (len > 0 && music_halt_or_loop())
344 OGG_playAudio(music_playing->data.ogg, stream, len);
350 smpeg.SMPEG_playAudio(music_playing->data.mp3, stream, len);
355 mad_getSamples(music_playing->data.mp3_mad, stream, len);
359 /* Unknown music type?? */
365 /* Initialize the music players with a certain desired audio format */
366 int open_music(SDL_AudioSpec *mixer)
369 #ifdef LIBMIKMOD_MUSIC
375 if ( WAVStream_Init(mixer) < 0 ) {
379 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
380 /* Set the MikMod music format */
383 switch (mixer->format) {
387 if ( mixer->format == AUDIO_S8 ) {
396 /* See if we need to correct MikMod mixing */
397 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
398 if ( mixer->format == AUDIO_S16MSB ) {
400 if ( mixer->format == AUDIO_S16LSB ) {
404 md_mode = DMODE_16BITS;
409 Mix_SetError("Unknown hardware audio format");
413 current_output_channels = mixer->channels;
414 current_output_format = mixer->format;
415 if ( mixer->channels > 1 ) {
416 if ( mixer->channels > MAX_OUTPUT_CHANNELS ) {
417 Mix_SetError("Hardware uses more channels than mixer");
420 md_mode |= DMODE_STEREO;
422 md_mixfreq = mixer->freq;
425 md_musicvolume = 128;
426 md_sndfxvolume = 128;
429 md_mode |= DMODE_HQMIXER|DMODE_SOFT_MUSIC|DMODE_SURROUND;
430 #ifdef LIBMIKMOD_MUSIC
431 list = MikMod_InfoDriver();
436 MikMod_RegisterDriver(&drv_nos);
437 #ifdef LIBMIKMOD_MUSIC
438 list = MikMod_InfoLoader();
443 MikMod_RegisterAllLoaders();
444 if ( MikMod_Init() ) {
445 Mix_SetError("%s", MikMod_strerror(MikMod_errno));
450 #ifdef USE_TIMIDITY_MIDI
451 samplesize = mixer->size / mixer->samples;
452 if ( Timidity_Init(mixer->freq, mixer->format,
453 mixer->channels, mixer->samples) == 0 ) {
459 #ifdef USE_NATIVE_MIDI
460 #ifdef USE_TIMIDITY_MIDI
461 native_midi_ok = !timidity_ok;
462 if ( native_midi_ok )
464 native_midi_ok = native_midi_detect();
468 if ( OGG_init(mixer) < 0 ) {
472 #if defined(MP3_MUSIC) || defined(MP3_MAD_MUSIC)
473 /* Keep a copy of the mixer */
476 music_playing = NULL;
481 Mix_VolumeMusic(SDL_MIX_MAXVOLUME);
483 /* Calculate the number of ms for each callback */
484 ms_per_step = (int) (((float)mixer->samples * 1000.0) / mixer->freq);
489 /* Portable case-insensitive string compare function */
490 int MIX_string_equals(const char *str1, const char *str2)
492 while ( *str1 && *str2 ) {
493 if ( toupper((unsigned char)*str1) !=
494 toupper((unsigned char)*str2) )
499 return (!*str1 && !*str2);
502 /* Load a music file */
503 Mix_Music *Mix_LoadMUS(const char *file)
507 Uint8 magic[5], moremagic[9];
510 /* Figure out what kind of file this is */
511 fp = fopen(file, "rb");
512 if ( (fp == NULL) || !fread(magic, 4, 1, fp) ) {
516 Mix_SetError("Couldn't read from '%s'", file);
519 if (!fread(moremagic, 8, 1, fp)) {
520 Mix_SetError("Couldn't read from '%s'", file);
527 /* Figure out the file extension, so we can determine the type */
528 ext = strrchr(file, '.');
529 if ( ext ) ++ext; /* skip the dot in the extension */
531 /* Allocate memory for the music structure */
532 music = (Mix_Music *)malloc(sizeof(Mix_Music));
533 if ( music == NULL ) {
534 Mix_SetError("Out of memory");
541 music->type = MUS_CMD;
542 music->data.cmd = MusicCMD_LoadSong(music_cmd, file);
543 if ( music->data.cmd == NULL ) {
549 /* WAVE files have the magic four bytes "RIFF"
550 AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
552 if ( (ext && MIX_string_equals(ext, "WAV")) ||
553 ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
554 (strcmp((char *)magic, "FORM") == 0) ) {
555 music->type = MUS_WAV;
556 music->data.wave = WAVStream_LoadSong(file, (char *)magic);
557 if ( music->data.wave == NULL ) {
558 Mix_SetError("Unable to load WAV file");
564 /* MIDI files have the magic four bytes "MThd" */
565 if ( (ext && MIX_string_equals(ext, "MID")) ||
566 (ext && MIX_string_equals(ext, "MIDI")) ||
567 strcmp((char *)magic, "MThd") == 0 ||
568 ( strcmp((char *)magic, "RIFF") == 0 &&
569 strcmp((char *)(moremagic+4), "RMID") == 0 ) ) {
570 music->type = MUS_MID;
571 #ifdef USE_NATIVE_MIDI
572 if ( native_midi_ok ) {
573 music->data.nativemidi = native_midi_loadsong((char *)file);
574 if ( music->data.nativemidi == NULL ) {
575 Mix_SetError("%s", native_midi_error());
580 #ifdef USE_TIMIDITY_MIDI
582 music->data.midi = Timidity_LoadSong((char *)file);
583 if ( music->data.midi == NULL ) {
584 Mix_SetError("%s", Timidity_Error());
588 Mix_SetError("%s", Timidity_Error());
595 /* Ogg Vorbis files have the magic four bytes "OggS" */
596 if ( (ext && MIX_string_equals(ext, "OGG")) ||
597 strcmp((char *)magic, "OggS") == 0 ) {
598 music->type = MUS_OGG;
599 music->data.ogg = OGG_new(file);
600 if ( music->data.ogg == NULL ) {
606 if ( (ext && MIX_string_equals(ext, "MPG")) ||
607 (ext && MIX_string_equals(ext, "MP3")) ||
608 (ext && MIX_string_equals(ext, "MPEG")) ||
609 (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ) {
610 if ( Mix_InitMP3() == 0 ) {
612 music->type = MUS_MP3;
613 music->data.mp3 = smpeg.SMPEG_new(file, &info, 0);
614 if ( !info.has_audio ) {
615 Mix_SetError("MPEG file does not have any audio stream.");
618 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
626 if ( (ext && MIX_string_equals(ext, "MPG")) ||
627 (ext && MIX_string_equals(ext, "MP3")) ||
628 (ext && MIX_string_equals(ext, "MPEG")) ||
629 (ext && MIX_string_equals(ext, "MAD")) ||
630 (magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0) ) {
631 music->type = MUS_MP3_MAD;
632 music->data.mp3_mad = mad_openFile(file, &used_mixer);
633 if (music->data.mp3_mad == 0) {
634 Mix_SetError("Could not initialize MPEG stream.");
639 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
641 music->type = MUS_MOD;
642 music->data.module = MikMod_LoadSong((char *)file, 64);
643 if ( music->data.module == NULL ) {
644 Mix_SetError("%s", MikMod_strerror(MikMod_errno));
647 /* Stop implicit looping, fade out and other flags. */
648 music->data.module->extspd = 1;
649 music->data.module->panflag = 1;
650 music->data.module->wrap = 0;
651 music->data.module->loop = 1;
652 #if 0 /* Don't set fade out by default - unfortunately there's no real way
653 to query the status of the song or set trigger actions. Hum. */
654 music->data.module->fadeout = 1;
660 Mix_SetError("Unrecognized music format");
663 if ( music->error ) {
670 /* Free a music chunk previously loaded */
671 void Mix_FreeMusic(Mix_Music *music)
674 /* Stop the music if it's currently playing */
676 if ( music == music_playing ) {
677 /* Wait for any fade out to finish */
678 while ( music->fading == MIX_FADING_OUT ) {
683 if ( music == music_playing ) {
684 music_internal_halt();
688 switch (music->type) {
691 MusicCMD_FreeSong(music->data.cmd);
696 WAVStream_FreeSong(music->data.wave);
699 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
701 MikMod_FreeSong(music->data.module);
706 #ifdef USE_NATIVE_MIDI
707 if ( native_midi_ok ) {
708 native_midi_freesong(music->data.nativemidi);
711 #ifdef USE_TIMIDITY_MIDI
713 Timidity_FreeSong(music->data.midi);
720 OGG_delete(music->data.ogg);
725 smpeg.SMPEG_delete(music->data.mp3);
731 mad_closeFile(music->data.mp3_mad);
735 /* Unknown music type?? */
742 /* Find out the music format of a mixer music, or the currently playing
743 music, if 'music' is NULL.
745 Mix_MusicType Mix_GetMusicType(const Mix_Music *music)
747 Mix_MusicType type = MUS_NONE;
753 if ( music_playing ) {
754 type = music_playing->type;
761 /* Play a music chunk. Returns 0, or -1 if there was an error.
763 static int music_internal_play(Mix_Music *music, double position)
767 /* Note the music we're playing */
768 if ( music_playing ) {
769 music_internal_halt();
771 music_playing = music;
773 /* Set the initial volume */
774 if ( music->type != MUS_MOD ) {
775 music_internal_initialize_volume();
778 /* Set up for playback */
779 switch (music->type) {
782 MusicCMD_Start(music->data.cmd);
787 WAVStream_Start(music->data.wave);
790 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
792 Player_Start(music->data.module);
793 /* Player_SetVolume() does nothing before Player_Start() */
794 music_internal_initialize_volume();
799 #ifdef USE_NATIVE_MIDI
800 if ( native_midi_ok ) {
801 native_midi_start(music->data.nativemidi);
804 #ifdef USE_TIMIDITY_MIDI
806 Timidity_Start(music->data.midi);
813 OGG_play(music->data.ogg);
818 smpeg.SMPEG_enableaudio(music->data.mp3,1);
819 smpeg.SMPEG_enablevideo(music->data.mp3,0);
820 smpeg.SMPEG_play(music_playing->data.mp3);
825 mad_start(music->data.mp3_mad);
829 Mix_SetError("Can't play unknown music type");
834 /* Set the playback position, note any errors if an offset is used */
836 if ( position > 0.0 ) {
837 if ( music_internal_position(position) < 0 ) {
838 Mix_SetError("Position not implemented for music type");
842 music_internal_position(0.0);
846 /* If the setup failed, we're not playing any music anymore */
848 music_playing = NULL;
852 int Mix_FadeInMusicPos(Mix_Music *music, int loops, int ms, double position)
856 /* Don't play null pointers :-) */
857 if ( music == NULL ) {
858 Mix_SetError("music parameter was NULL");
864 music->fading = MIX_FADING_IN;
866 music->fading = MIX_NO_FADING;
868 music->fade_step = 0;
869 music->fade_steps = ms/ms_per_step;
873 /* If the current music is fading out, wait for the fade to complete */
874 while ( music_playing && (music_playing->fading == MIX_FADING_OUT) ) {
881 retval = music_internal_play(music, position);
886 int Mix_FadeInMusic(Mix_Music *music, int loops, int ms)
888 return Mix_FadeInMusicPos(music, loops, ms, 0.0);
890 int Mix_PlayMusic(Mix_Music *music, int loops)
892 return Mix_FadeInMusicPos(music, loops, 0, 0.0);
895 /* Set the playing music position */
896 int music_internal_position(double position)
900 switch (music_playing->type) {
901 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
903 Player_SetPosition((UWORD)position);
908 OGG_jump_to_time(music_playing->data.ogg, position);
913 if ( position > 0.0 ) {
914 smpeg.SMPEG_skip(music_playing->data.mp3, (float)position);
916 smpeg.SMPEG_rewind(music_playing->data.mp3);
917 smpeg.SMPEG_play(music_playing->data.mp3);
923 mad_seek(music_playing->data.mp3_mad, position);
927 /* TODO: Implement this for other music backends */
933 int Mix_SetMusicPosition(double position)
938 if ( music_playing ) {
939 retval = music_internal_position(position);
941 Mix_SetError("Position not implemented for music type");
944 Mix_SetError("Music isn't playing");
952 /* Set the music's initial volume */
953 static void music_internal_initialize_volume(void)
955 if ( music_playing->fading == MIX_FADING_IN ) {
956 music_internal_volume(0);
958 music_internal_volume(music_volume);
962 /* Set the music volume */
963 static void music_internal_volume(int volume)
965 switch (music_playing->type) {
968 MusicCMD_SetVolume(volume);
973 WAVStream_SetVolume(volume);
976 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
978 Player_SetVolume((SWORD)volume);
983 #ifdef USE_NATIVE_MIDI
984 if ( native_midi_ok ) {
985 native_midi_setvolume(volume);
988 #ifdef USE_TIMIDITY_MIDI
990 Timidity_SetVolume(volume);
997 OGG_setvolume(music_playing->data.ogg, volume);
1002 smpeg.SMPEG_setvolume(music_playing->data.mp3,(int)(((float)volume/(float)MIX_MAX_VOLUME)*100.0));
1005 #ifdef MP3_MAD_MUSIC
1007 mad_setVolume(music_playing->data.mp3_mad, volume);
1011 /* Unknown music type?? */
1015 int Mix_VolumeMusic(int volume)
1019 prev_volume = music_volume;
1023 if ( volume > SDL_MIX_MAXVOLUME ) {
1024 volume = SDL_MIX_MAXVOLUME;
1026 music_volume = volume;
1028 if ( music_playing ) {
1029 music_internal_volume(music_volume);
1032 return(prev_volume);
1035 /* Halt playing of music */
1036 static void music_internal_halt(void)
1038 switch (music_playing->type) {
1041 MusicCMD_Stop(music_playing->data.cmd);
1049 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1056 #ifdef USE_NATIVE_MIDI
1057 if ( native_midi_ok ) {
1061 #ifdef USE_TIMIDITY_MIDI
1062 if ( timidity_ok ) {
1070 OGG_stop(music_playing->data.ogg);
1075 smpeg.SMPEG_stop(music_playing->data.mp3);
1078 #ifdef MP3_MAD_MUSIC
1080 mad_stop(music_playing->data.mp3_mad);
1084 /* Unknown music type?? */
1087 music_playing->fading = MIX_NO_FADING;
1088 music_playing = NULL;
1090 int Mix_HaltMusic(void)
1093 if ( music_playing ) {
1094 music_internal_halt();
1101 /* Progressively stop the music */
1102 int Mix_FadeOutMusic(int ms)
1106 if (ms <= 0) { /* just halt immediately. */
1112 if ( music_playing) {
1113 int fade_steps = (ms + ms_per_step - 1)/ms_per_step;
1114 if ( music_playing->fading == MIX_NO_FADING ) {
1115 music_playing->fade_step = 0;
1118 int old_fade_steps = music_playing->fade_steps;
1119 if ( music_playing->fading == MIX_FADING_OUT ) {
1120 step = music_playing->fade_step;
1122 step = old_fade_steps
1123 - music_playing->fade_step + 1;
1125 music_playing->fade_step = (step * fade_steps)
1128 music_playing->fading = MIX_FADING_OUT;
1129 music_playing->fade_steps = fade_steps;
1137 Mix_Fading Mix_FadingMusic(void)
1139 Mix_Fading fading = MIX_NO_FADING;
1142 if ( music_playing ) {
1143 fading = music_playing->fading;
1150 /* Pause/Resume the music stream */
1151 void Mix_PauseMusic(void)
1156 void Mix_ResumeMusic(void)
1161 void Mix_RewindMusic(void)
1163 Mix_SetMusicPosition(0.0);
1166 int Mix_PausedMusic(void)
1168 return (music_active == 0);
1171 /* Check the status of the music */
1172 static int music_internal_playing()
1175 switch (music_playing->type) {
1178 if (!MusicCMD_Active(music_playing->data.cmd)) {
1185 if ( ! WAVStream_Active() ) {
1190 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1192 if ( ! Player_Active() ) {
1199 #ifdef USE_NATIVE_MIDI
1200 if ( native_midi_ok ) {
1201 if ( ! native_midi_active() )
1205 #ifdef USE_TIMIDITY_MIDI
1206 if ( timidity_ok ) {
1207 if ( ! Timidity_Active() )
1215 if ( ! OGG_playing(music_playing->data.ogg) ) {
1222 if ( smpeg.SMPEG_status(music_playing->data.mp3) != SMPEG_PLAYING )
1226 #ifdef MP3_MAD_MUSIC
1228 if (!mad_isPlaying(music_playing->data.mp3_mad)) {
1239 int Mix_PlayingMusic(void)
1244 if ( music_playing ) {
1245 playing = music_internal_playing();
1252 /* Set the external music playback command */
1253 int Mix_SetMusicCMD(const char *command)
1261 music_cmd = (char *)malloc(strlen(command)+1);
1262 if ( music_cmd == NULL ) {
1265 strcpy(music_cmd, command);
1270 #ifdef LIBMIKMOD_MUSIC
1271 static int _pl_synchro_value;
1272 void Player_SetSynchroValue(int i)
1274 fprintf(stderr,"SDL_mixer: Player_SetSynchroValue is not supported.\n");
1275 _pl_synchro_value = i;
1278 int Player_GetSynchroValue(void)
1280 fprintf(stderr,"SDL_mixer: Player_GetSynchroValue is not supported.\n");
1281 return _pl_synchro_value;
1285 int Mix_SetSynchroValue(int i)
1287 if ( music_playing && ! music_stopped ) {
1288 switch (music_playing->type) {
1289 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1291 if ( ! Player_Active() ) {
1294 Player_SetSynchroValue(i);
1307 int Mix_GetSynchroValue(void)
1309 if ( music_playing && ! music_stopped ) {
1310 switch (music_playing->type) {
1311 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1313 if ( ! Player_Active() ) {
1316 return Player_GetSynchroValue();
1329 /* Uninitialize the music players */
1330 void close_music(void)
1334 Mix_SetMusicCMD(NULL);
1336 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1338 # ifndef LIBMIKMOD_MUSIC
1339 MikMod_UnregisterAllLoaders();
1340 MikMod_UnregisterAllDrivers();
1344 # ifdef USE_TIMIDITY_MIDI
1350 # ifdef LIBMIKMOD_MUSIC
1358 BOOL LMM_Seek(struct MREADER *mr,long to,int dir)
1361 LMM_MREADER* lmmmr=(LMM_MREADER*)mr;
1364 at=SDL_RWseek(lmmmr->rw, to, dir);
1365 return at<lmmmr->offset;
1367 long LMM_Tell(struct MREADER *mr)
1370 LMM_MREADER* lmmmr=(LMM_MREADER*)mr;
1371 at=SDL_RWtell(lmmmr->rw)-lmmmr->offset;
1374 BOOL LMM_Read(struct MREADER *mr,void *buf,size_t sz)
1377 LMM_MREADER* lmmmr=(LMM_MREADER*)mr;
1378 got=SDL_RWread(lmmmr->rw, buf, sz, 1);
1381 int LMM_Get(struct MREADER *mr)
1385 LMM_MREADER* lmmmr=(LMM_MREADER*)mr;
1386 if(SDL_RWread(lmmmr->rw,&c,1,1))
1390 BOOL LMM_Eof(struct MREADER *mr)
1393 LMM_MREADER* lmmmr=(LMM_MREADER*)mr;
1394 offset=LMM_Tell(mr);
1395 return offset>=lmmmr->eof;
1397 MODULE *MikMod_LoadSongRW(SDL_RWops *rw, int maxchan)
1410 lmmmr.offset=SDL_RWtell(rw);
1411 SDL_RWseek(rw,0,SEEK_END);
1412 lmmmr.eof=SDL_RWtell(rw);
1413 SDL_RWseek(rw,lmmmr.offset,SEEK_SET);
1414 m=Player_LoadGeneric((MREADER*)&lmmmr,maxchan,0);
1419 Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) {
1420 Uint8 magic[5]; /*Apparently there is no way to check if the file is really a MOD,*/
1421 /* or there are too many formats supported by MikMod or MikMod does */
1422 /* this check by itself. If someone implements other formats (e.g. MP3) */
1423 /* the check can be uncommented */
1428 Mix_SetError("RWops pointer is NULL");
1432 /* Figure out what kind of file this is */
1433 start = SDL_RWtell(rw);
1434 if (SDL_RWread(rw,magic,1,4)!=4) {
1435 Mix_SetError("Couldn't read from RWops");
1438 SDL_RWseek(rw, start, SEEK_SET);
1441 /* Allocate memory for the music structure */
1442 music=(Mix_Music *)malloc(sizeof(Mix_Music));
1444 Mix_SetError("Out of memory");
1450 /* Ogg Vorbis files have the magic four bytes "OggS" */
1451 if ( strcmp((char *)magic, "OggS") == 0 ) {
1452 music->type = MUS_OGG;
1453 music->data.ogg = OGG_new_RW(rw);
1454 if ( music->data.ogg == NULL ) {
1460 if ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0 ) {
1461 if ( Mix_InitMP3() == 0 ) {
1463 music->type = MUS_MP3;
1464 music->data.mp3 = smpeg.SMPEG_new_rwops(rw, &info, 0);
1465 if ( !info.has_audio ) {
1466 Mix_SetError("MPEG file does not have any audio stream.");
1469 smpeg.SMPEG_actualSpec(music->data.mp3, &used_mixer);
1476 #ifdef MP3_MAD_MUSIC
1477 if ( magic[0] == 0xFF && (magic[1] & 0xF0) == 0xF0 ) {
1478 music->type = MUS_MP3_MAD;
1479 music->data.mp3_mad = mad_openFileRW(rw, &used_mixer);
1480 if (music->data.mp3_mad == 0) {
1481 Mix_SetError("Could not initialize MPEG stream.");
1487 /* MIDI files have the magic four bytes "MThd" */
1488 if ( strcmp((char *)magic, "MThd") == 0 ) {
1489 music->type = MUS_MID;
1490 #ifdef USE_NATIVE_MIDI
1491 if ( native_midi_ok ) {
1492 music->data.nativemidi = native_midi_loadsong_RW(rw);
1493 if ( music->data.nativemidi == NULL ) {
1494 Mix_SetError("%s", native_midi_error());
1499 #ifdef USE_TIMIDITY_MIDI
1500 if ( timidity_ok ) {
1501 music->data.midi = Timidity_LoadSong_RW(rw);
1502 if ( music->data.midi == NULL ) {
1503 Mix_SetError("%s", Timidity_Error());
1507 Mix_SetError("%s", Timidity_Error());
1513 #if defined(MOD_MUSIC) || defined(LIBMIKMOD_MUSIC)
1515 music->type=MUS_MOD;
1516 music->data.module=MikMod_LoadSongRW(rw,64);
1517 if (music->data.module==NULL) {
1518 Mix_SetError("%s",MikMod_strerror(MikMod_errno));
1521 /* Stop implicit looping, fade out and other flags. */
1522 music->data.module->extspd = 1;
1523 music->data.module->panflag = 1;
1524 music->data.module->wrap = 0;
1525 music->data.module->loop = 0;
1526 #if 0 /* Don't set fade out by default - unfortunately there's no real way
1527 to query the status of the song or set trigger actions. Hum. */
1528 music->data.module->fadeout = 1;
1534 Mix_SetError("Unrecognized music format");