From 9c21f8e47ef58e80548769e98d95ea986cae769f Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 3 Jul 2000 00:25:20 +0000 Subject: [PATCH] Sam Lantinga - Sun Jul 2 14:16:44 PDT 2000 * Added support for the Ogg Vorbis music format: http://www.vorbis.org/ * Cleaned up the streaming wave code a bit --- CHANGES | 2 + Makefile.am | 2 + autogen.sh | 3 +- configure.in | 18 +++++ music.c | 59 +++++++++++++++- music_ogg.c | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++ music_ogg.h | 67 +++++++++++++++++++ wavestream.c | 78 +++++++--------------- wavestream.h | 4 +- 9 files changed, 359 insertions(+), 59 deletions(-) create mode 100644 music_ogg.c create mode 100644 music_ogg.h diff --git a/CHANGES b/CHANGES index 79269a89..273a1595 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,7 @@ 1.0.6: +Sam Lantinga - Sun Jul 2 14:16:44 PDT 2000 + * Added support for the Ogg Vorbis music format: http://www.vorbis.org/ Darrell Walisser - Wed Jun 28 11:59:40 PDT 2000 * Added Codewarrior projects for MacOS Sam Lantinga - Mon Jun 26 12:01:11 PDT 2000 diff --git a/Makefile.am b/Makefile.am index f2d58dad..2bd27416 100644 --- a/Makefile.am +++ b/Makefile.am @@ -14,6 +14,8 @@ libSDL_mixer_la_SOURCES = \ music.c \ music_cmd.c \ music_cmd.h \ + music_ogg.c \ + music_ogg.h \ wave.h \ wavestream.c \ wavestream.h diff --git a/autogen.sh b/autogen.sh index 88ec030c..b686b4df 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,4 +4,5 @@ aclocal automake --foreign autoconf -./configure $* +#./configure $* +echo "Now you are ready to run ./configure" diff --git a/configure.in b/configure.in index 7aa6a0b6..5887ebe5 100644 --- a/configure.in +++ b/configure.in @@ -95,6 +95,24 @@ if test x$enable_music_midi = xyes; then CFLAGS="$CFLAGS -DMID_MUSIC -I\$(top_srcdir)/timidity" MUSIC_SUBDIRS="$MUSIC_SUBDIRS timidity" fi +AC_ARG_ENABLE(music-ogg, +[ --enable-music-ogg enable Ogg Vorbis music [default=yes]], + , enable_music_ogg=yes) +if test x$enable_music_ogg = xyes; then + AC_MSG_CHECKING(for Ogg Vorbis headers and libraries) + have_vorbis=no + AC_TRY_COMPILE([ + #include + ],[ + ],[ + have_vorbis=yes + ]) + AC_MSG_RESULT($have_vorbis) + if test x$have_vorbis = xyes; then + CFLAGS="$CFLAGS -DOGG_MUSIC" + LIBS="$LIBS -lvorbisfile -lvorbis" + fi +fi AC_ARG_ENABLE(music-mp3, [ --enable-music-mp3 enable MP3 music via smpeg [default=yes]], , enable_music_mp3=yes) diff --git a/music.c b/music.c index 764ff506..dd313e84 100644 --- a/music.c +++ b/music.c @@ -57,6 +57,9 @@ #ifdef MID_MUSIC #include "timidity.h" #endif +#ifdef OGG_MUSIC +#include "music_ogg.h" +#endif #ifdef MP3_MUSIC #include @@ -79,6 +82,7 @@ struct _Mix_Music { MUS_WAV, MUS_MOD, MUS_MID, + MUS_OGG, MUS_MP3 } type; union { @@ -94,6 +98,9 @@ struct _Mix_Music { #ifdef MID_MUSIC MidiSong *midi; #endif +#ifdef OGG_MUSIC + OGG_music *ogg; +#endif #ifdef MP3_MUSIC SMPEG *mp3; #endif @@ -186,7 +193,7 @@ void music_mixer(void *udata, Uint8 *stream, int len) #endif #ifdef WAV_MUSIC case MUS_WAV: - WAVStream_PlaySome(stream, len); + WAVStream_PlaySome(music_playing->data.wave, stream, len); break; #endif #ifdef MOD_MUSIC @@ -220,6 +227,11 @@ void music_mixer(void *udata, Uint8 *stream, int len) Timidity_PlaySome(stream, len/samplesize); break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_playAudio(music_playing->data.ogg, stream, len); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_playAudio(music_playing->data.mp3, stream, len); @@ -308,6 +320,11 @@ int open_music(SDL_AudioSpec *mixer) timidity_ok = 0; } #endif +#ifdef OGG_MUSIC + if ( OGG_init(mixer) < 0 ) { + ++music_error; + } +#endif #ifdef MP3_MUSIC /* Keep a copy of the mixer */ used_mixer = *mixer; @@ -391,6 +408,16 @@ Mix_Music *Mix_LoadMUS(const char *file) } } else #endif +#ifdef OGG_MUSIC + /* Ogg Vorbis files have the magic four bytes "OggS" */ + if ( strcmp(magic, "OggS") == 0 ) { + music->type = MUS_OGG; + music->data.ogg = OGG_new(file); + if ( music->data.ogg == NULL ) { + music->error = 1; + } + } else +#endif #ifdef MP3_MUSIC if ( magic[0]==0xFF && (magic[1]&0xF0)==0xF0) { SMPEG_Info info; @@ -460,6 +487,11 @@ void Mix_FreeMusic(Mix_Music *music) Timidity_FreeSong(music->data.midi); break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_delete(music->data.ogg); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_delete(music->data.mp3); @@ -504,6 +536,12 @@ static int lowlevel_play(Mix_Music *music) Timidity_Start(music->data.midi); break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_setvolume(music->data.ogg, music_volume); + OGG_play(music->data.ogg); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_enableaudio(music->data.mp3,1); @@ -594,6 +632,11 @@ int Mix_VolumeMusic(int volume) Timidity_SetVolume(music_volume); break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_setvolume(music_playing->data.ogg, music_volume); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_setvolume(music_playing->data.mp3,((float)music_volume/(float)MIX_MAX_VOLUME)*100.0); @@ -630,6 +673,11 @@ static void lowlevel_halt(void) Timidity_Stop(); break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + OGG_stop(music_playing->data.ogg); + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: SMPEG_stop(music_playing->data.mp3); @@ -740,7 +788,7 @@ int Mix_PlayingMusic(void) #endif #ifdef WAV_MUSIC case MUS_WAV: - if ( ! WAVStream_Active() ) { + if ( ! WAVStream_Active(music_playing->data.wave) ) { return(0); } break; @@ -759,6 +807,13 @@ int Mix_PlayingMusic(void) } break; #endif +#ifdef OGG_MUSIC + case MUS_OGG: + if ( ! OGG_playing(music_playing->data.ogg) ) { + return(0); + } + break; +#endif #ifdef MP3_MUSIC case MUS_MP3: if(SMPEG_status(music_playing->data.mp3)!=SMPEG_PLAYING) diff --git a/music_ogg.c b/music_ogg.c new file mode 100644 index 00000000..cd296d16 --- /dev/null +++ b/music_ogg.c @@ -0,0 +1,185 @@ +/* + MIXERLIB: An audio mixer library based on the SDL library + Copyright (C) 1997-1999 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + 5635-34 Springhouse Dr. + Pleasanton, CA 94588 (USA) + slouken@devolution.com +*/ + +#ifdef OGG_MUSIC + +/* This file supports Ogg Vorbis music streams */ + +#include +#include + +#include "SDL_mixer.h" +#include "music_ogg.h" + +/* This is the format of the audio mixer data */ +static SDL_AudioSpec mixer; + +/* Initialize the Ogg Vorbis player, with the given mixer settings + This function returns 0, or -1 if there was an error. + */ +int OGG_init(SDL_AudioSpec *mixerfmt) +{ + mixer = *mixerfmt; + return(0); +} + +/* Set the volume for an OGG stream */ +void OGG_setvolume(OGG_music *music, int volume) +{ + music->volume = volume; +} + +/* Load an OGG stream from the given file */ +OGG_music *OGG_new(const char *file) +{ + OGG_music *music; + FILE *fp; + + music = (OGG_music *)malloc(sizeof *music); + if ( music ) { + /* Initialize the music structure */ + memset(music, 0, (sizeof *music)); + OGG_stop(music); + OGG_setvolume(music, MIX_MAX_VOLUME); + music->section = -1; + + fp = fopen(file, "rb"); + if ( fp == NULL ) { + SDL_SetError("Couldn't open %s", file); + free(music); + return(NULL); + } + if ( ov_open(fp, &music->vf, NULL, 0) < 0 ) { + SDL_SetError("Not an Ogg Vorbis audio stream"); + free(music); + fclose(fp); + return(NULL); + } + } else { + SDL_OutOfMemory(); + } + return(music); +} + +/* Start playback of a given OGG stream */ +void OGG_play(OGG_music *music) +{ + music->playing = 1; +} + +/* Return non-zero if a stream is currently playing */ +int OGG_playing(OGG_music *music) +{ + return(music->playing); +} + +/* Read some Ogg stream data and convert it for output */ +static void OGG_getsome(OGG_music *music) +{ + int section; + int len; + char data[4096]; + SDL_AudioCVT *cvt; + + len = ov_read(&music->vf, data, sizeof(data), 0, 2, 1, §ion); + if ( len <= 0 ) { + if ( len == 0 ) { + music->playing = 0; + } + return; + } + cvt = &music->cvt; + if ( section != music->section ) { + vorbis_info *vi; + + vi = ov_info(&music->vf, -1); + SDL_BuildAudioCVT(cvt, AUDIO_S16, vi->channels, vi->rate, + mixer.format,mixer.channels,mixer.freq); + if ( cvt->buf ) { + free(cvt->buf); + } + cvt->buf = (Uint8 *)malloc(sizeof(data)*cvt->len_mult); + music->section = section; + } + if ( cvt->buf ) { + memcpy(cvt->buf, data, len); + if ( cvt->needed ) { + cvt->len = len; + SDL_ConvertAudio(cvt); + } else { + cvt->len_cvt = len; + } + music->len_available = music->cvt.len_cvt; + music->snd_available = music->cvt.buf; + } else { + SDL_OutOfMemory(); + music->playing = 0; + } +} + +/* Play some of a stream previously started with OGG_play() */ +void OGG_playAudio(OGG_music *music, Uint8 *snd, int len) +{ + int mixable; + + while ( (len > 0) && music->playing ) { + if ( ! music->len_available ) { + OGG_getsome(music); + } + mixable = len; + if ( mixable > music->len_available ) { + mixable = music->len_available; + } + if ( music->volume == MIX_MAX_VOLUME ) { + memcpy(snd, music->snd_available, mixable); + } else { + SDL_MixAudio(snd, music->snd_available, mixable, + music->volume); + } + music->len_available -= mixable; + music->snd_available += mixable; + len -= mixable; + snd += mixable; + } +} + +/* Stop playback of a stream previously started with OGG_play() */ +void OGG_stop(OGG_music *music) +{ + music->playing = 0; +} + +/* Close the given OGG stream */ +void OGG_delete(OGG_music *music) +{ + if ( music ) { + if ( music->cvt.buf ) { + free(music->cvt.buf); + } + ov_clear(&music->vf); + free(music); + } +} + +#endif /* OGG_MUSIC */ diff --git a/music_ogg.h b/music_ogg.h new file mode 100644 index 00000000..295610e0 --- /dev/null +++ b/music_ogg.h @@ -0,0 +1,67 @@ +/* + MIXERLIB: An audio mixer library based on the SDL library + Copyright (C) 1997-1999 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + Sam Lantinga + 5635-34 Springhouse Dr. + Pleasanton, CA 94588 (USA) + slouken@devolution.com +*/ + +#ifdef OGG_MUSIC + +/* This file supports Ogg Vorbis music streams */ + +#include + +typedef struct { + int playing; + int volume; + OggVorbis_File vf; + int section; + SDL_AudioCVT cvt; + int len_available; + Uint8 *snd_available; +} OGG_music; + +/* Initialize the Ogg Vorbis player, with the given mixer settings + This function returns 0, or -1 if there was an error. + */ +extern int OGG_init(SDL_AudioSpec *mixer); + +/* Set the volume for an OGG stream */ +extern void OGG_setvolume(OGG_music *music, int volume); + +/* Load an OGG stream from the given file */ +extern OGG_music *OGG_new(const char *file); + +/* Start playback of a given OGG stream */ +extern void OGG_play(OGG_music *music); + +/* Return non-zero if a stream is currently playing */ +extern int OGG_playing(OGG_music *music); + +/* Play some of a stream previously started with OGG_play() */ +extern void OGG_playAudio(OGG_music *music, Uint8 *stream, int len); + +/* Stop playback of a stream previously started with OGG_play() */ +extern void OGG_stop(OGG_music *music); + +/* Close the given OGG stream */ +extern void OGG_delete(OGG_music *music); + +#endif /* OGG_MUSIC */ diff --git a/wavestream.c b/wavestream.c index 2d608e84..6ab3185a 100644 --- a/wavestream.c +++ b/wavestream.c @@ -35,12 +35,6 @@ #include "wave.h" #include "wavestream.h" -/* Currently we only support a single stream at a time */ -static WAVStream *theWave = NULL; - -/* This is initialized by the music mixer */ -static SDL_mutex *music_lock = NULL; - /* This is the format of the audio mixer data */ static SDL_AudioSpec mixer; @@ -55,13 +49,6 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, */ int WAVStream_Init(SDL_AudioSpec *mixerfmt) { - /* FIXME: clean up the mutex, or move it into music.c */ - music_lock = SDL_CreateMutex(); -#ifndef macintosh /* Hmm.. */ - if ( music_lock == NULL ) { - return(-1); - } -#endif mixer = *mixerfmt; return(0); } @@ -106,75 +93,58 @@ extern WAVStream *WAVStream_LoadSong(const char *file, const char *magic) /* Start playback of a given WAV stream */ extern void WAVStream_Start(WAVStream *wave) { - SDL_mutexP(music_lock); clearerr(wave->wavefp); fseek(wave->wavefp, wave->start, SEEK_SET); - theWave = wave; - SDL_mutexV(music_lock); } /* Play some of a stream previously started with WAVStream_Start() - The music_lock is held while this function is called. */ -extern void WAVStream_PlaySome(Uint8 *stream, int len) +extern void WAVStream_PlaySome(WAVStream *wave, Uint8 *stream, int len) { long pos; - SDL_mutexP(music_lock); - if ( theWave && ((pos=ftell(theWave->wavefp)) < theWave->stop) ) { - if ( theWave->cvt.needed ) { + if ( (pos=ftell(wave->wavefp)) < wave->stop ) { + if ( wave->cvt.needed ) { int original_len; - original_len=(int)((double)len/theWave->cvt.len_ratio); - if ( theWave->cvt.len != original_len ) { + original_len=(int)((double)len/wave->cvt.len_ratio); + if ( wave->cvt.len != original_len ) { int worksize; - if ( theWave->cvt.buf != NULL ) { - free(theWave->cvt.buf); + if ( wave->cvt.buf != NULL ) { + free(wave->cvt.buf); } - worksize = original_len*theWave->cvt.len_mult; - theWave->cvt.buf=(Uint8 *)malloc(worksize); - if ( theWave->cvt.buf == NULL ) { - SDL_mutexV(music_lock); + worksize = original_len*wave->cvt.len_mult; + wave->cvt.buf=(Uint8 *)malloc(worksize); + if ( wave->cvt.buf == NULL ) { return; } - theWave->cvt.len = original_len; + wave->cvt.len = original_len; } - if ( (theWave->stop - pos) < original_len ) { - original_len = (theWave->stop - pos); + if ( (wave->stop - pos) < original_len ) { + original_len = (wave->stop - pos); } - theWave->cvt.len = original_len; - fread(theWave->cvt.buf,original_len,1,theWave->wavefp); - SDL_ConvertAudio(&theWave->cvt); - memcpy(stream, theWave->cvt.buf, theWave->cvt.len_cvt); + wave->cvt.len = original_len; + fread(wave->cvt.buf,original_len,1,wave->wavefp); + SDL_ConvertAudio(&wave->cvt); + memcpy(stream, wave->cvt.buf, wave->cvt.len_cvt); } else { - if ( (theWave->stop - pos) < len ) { - len = (theWave->stop - pos); + if ( (wave->stop - pos) < len ) { + len = (wave->stop - pos); } - fread(stream, len, 1, theWave->wavefp); + fread(stream, len, 1, wave->wavefp); } } - SDL_mutexV(music_lock); } /* Stop playback of a stream previously started with WAVStream_Start() */ extern void WAVStream_Stop(void) { - SDL_mutexP(music_lock); - theWave = NULL; - SDL_mutexV(music_lock); } /* Close the given WAV stream */ extern void WAVStream_FreeSong(WAVStream *wave) { if ( wave ) { - /* Remove song from the currently playing list */ - SDL_mutexP(music_lock); - if ( wave == theWave ) { - theWave = NULL; - } - SDL_mutexV(music_lock); - /* Clean up associated data */ if ( wave->wavefp ) { fclose(wave->wavefp); @@ -187,16 +157,16 @@ extern void WAVStream_FreeSong(WAVStream *wave) } /* Return non-zero if a stream is currently playing */ -extern int WAVStream_Active(void) +extern int WAVStream_Active(WAVStream *wave) { int active; - SDL_mutexP(music_lock); + SDL_LockAudio(); active = 0; - if ( theWave && (ftell(theWave->wavefp) < theWave->stop) ) { + if ( ftell(wave->wavefp) < wave->stop ) { active = 1; } - SDL_mutexV(music_lock); + SDL_UnlockAudio(); return(active); } diff --git a/wavestream.h b/wavestream.h index a827feb1..220864f3 100644 --- a/wavestream.h +++ b/wavestream.h @@ -48,7 +48,7 @@ extern WAVStream *WAVStream_LoadSong(const char *file, const char *magic); extern void WAVStream_Start(WAVStream *wave); /* Play some of a stream previously started with WAVStream_Start() */ -extern void WAVStream_PlaySome(Uint8 *stream, int len); +extern void WAVStream_PlaySome(WAVStream *wave, Uint8 *stream, int len); /* Stop playback of a stream previously started with WAVStream_Start() */ extern void WAVStream_Stop(void); @@ -57,4 +57,4 @@ extern void WAVStream_Stop(void); extern void WAVStream_FreeSong(WAVStream *wave); /* Return non-zero if a stream is currently playing */ -extern int WAVStream_Active(void); +extern int WAVStream_Active(WAVStream *wave);