From c0d0164a4d092d6b205421c8aa9f1926d304ea51 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 26 Feb 2008 11:46:22 +0000 Subject: [PATCH] Date: Sat, 16 Feb 2008 20:59:24 +0100 From: Tilman Sauerbeck Subject: [PATCH] Allow SDL_mixer to open wave streams via SDL_rwops the current version of SDL_mixer can only load WAVE streams directly from files. In my application I have the need to load them from an SDL_RWops structure. The attached patch adds that feature to SDL_mixer. --- CHANGES | 4 +++ music.c | 22 ++++++++++-- wavestream.c | 94 +++++++++++++++++++++------------------------------- wavestream.h | 6 +++- 4 files changed, 66 insertions(+), 60 deletions(-) diff --git a/CHANGES b/CHANGES index bafbfd6e..95e871c9 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,7 @@ +1.2.9: +Tilman Sauerbeck - Tue Feb 26 03:44:47 PST 2008 + * Added support for streaming WAV files with Mix_LoadMUS_RW() + 1.2.8: Sam Lantinga - Wed Jul 18 09:45:54 PDT 2007 * Improved detection of Ogg Vorbis and Tremor libraries diff --git a/music.c b/music.c index 3a37e104..e256c5b4 100644 --- a/music.c +++ b/music.c @@ -1416,11 +1416,13 @@ MODULE *MikMod_LoadSongRW(SDL_RWops *rw, int maxchan) } # endif -Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) { +Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) +{ Uint8 magic[5]; /*Apparently there is no way to check if the file is really a MOD,*/ /* or there are too many formats supported by MikMod or MikMod does */ /* this check by itself. If someone implements other formats (e.g. MP3) */ /* the check can be uncommented */ + Uint8 moremagic[9]; Mix_Music *music; int start; @@ -1431,12 +1433,14 @@ Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) { /* Figure out what kind of file this is */ start = SDL_RWtell(rw); - if (SDL_RWread(rw,magic,1,4)!=4) { + if ( SDL_RWread(rw,magic,1,4) != 4 || + SDL_RWread(rw,moremagic,1,8) != 8 ) { Mix_SetError("Couldn't read from RWops"); return NULL; } SDL_RWseek(rw, start, SEEK_SET); magic[4]='\0'; + moremagic[8] = '\0'; /* Allocate memory for the music structure */ music=(Mix_Music *)malloc(sizeof(Mix_Music)); @@ -1446,6 +1450,20 @@ Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) { } music->error = 0; +#ifdef WAV_MUSIC + /* WAVE files have the magic four bytes "RIFF" + AIFF files have the magic 12 bytes "FORM" XXXX "AIFF" + */ + if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) || + (strcmp((char *)magic, "FORM") == 0) ) { + music->type = MUS_WAV; + music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic); + if ( music->data.wave == NULL ) { + music->error = 1; + } + + } else +#endif #ifdef OGG_MUSIC /* Ogg Vorbis files have the magic four bytes "OggS" */ if ( strcmp((char *)magic, "OggS") == 0 ) { diff --git a/wavestream.c b/wavestream.c index 1f52cf73..f247ebf3 100644 --- a/wavestream.c +++ b/wavestream.c @@ -95,9 +95,9 @@ static SDL_AudioSpec mixer; static int wavestream_volume = MIX_MAX_VOLUME; /* Function to load the WAV/AIFF stream */ -static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec, +static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec, long *start, long *stop); -static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, +static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec, long *start, long *stop); /* Initialize the WAVStream player, with the given mixer settings @@ -114,8 +114,26 @@ void WAVStream_SetVolume(int volume) wavestream_volume = volume; } -/* Load a WAV stream from the given file */ WAVStream *WAVStream_LoadSong(const char *file, const char *magic) +{ + SDL_RWops *rw; + WAVStream *wave; + + rw = SDL_RWFromFile(file, "rb"); + if ( rw == NULL ) { + SDL_SetError("Couldn't open %s", file); + return NULL; + } + wave = WAVStream_LoadSong_RW(rw, magic); + if ( wave == NULL ) { + SDL_FreeRW(rw); + return NULL; + } + return wave; +} + +/* Load a WAV stream from the given file */ +WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic) { WAVStream *wave; SDL_AudioSpec wavespec; @@ -128,16 +146,16 @@ WAVStream *WAVStream_LoadSong(const char *file, const char *magic) if ( wave ) { memset(wave, 0, (sizeof *wave)); if ( strcmp(magic, "RIFF") == 0 ) { - wave->wavefp = LoadWAVStream(file, &wavespec, + wave->rw = LoadWAVStream(rw, &wavespec, &wave->start, &wave->stop); } else if ( strcmp(magic, "FORM") == 0 ) { - wave->wavefp = LoadAIFFStream(file, &wavespec, + wave->rw = LoadAIFFStream(rw, &wavespec, &wave->start, &wave->stop); } else { Mix_SetError("Unknown WAVE format"); } - if ( wave->wavefp == NULL ) { + if ( wave->rw == NULL ) { free(wave); return(NULL); } @@ -151,8 +169,7 @@ WAVStream *WAVStream_LoadSong(const char *file, const char *magic) /* Start playback of a given WAV stream */ void WAVStream_Start(WAVStream *wave) { - clearerr(wave->wavefp); - fseek(wave->wavefp, wave->start, SEEK_SET); + SDL_RWseek (wave->rw, wave->start, SEEK_SET); music = wave; } @@ -161,7 +178,7 @@ void WAVStream_PlaySome(Uint8 *stream, int len) { long pos; - if ( music && ((pos=ftell(music->wavefp)) < music->stop) ) { + if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) { if ( music->cvt.needed ) { int original_len; @@ -181,7 +198,7 @@ void WAVStream_PlaySome(Uint8 *stream, int len) if ( (music->stop - pos) < original_len ) { original_len = (music->stop - pos); } - original_len = fread(music->cvt.buf,1,original_len,music->wavefp); + original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len); /* At least at the time of writing, SDL_ConvertAudio() does byte-order swapping starting at the end of the buffer. Thus, if we are reading 16-bit samples, we @@ -202,7 +219,7 @@ void WAVStream_PlaySome(Uint8 *stream, int len) data = SDL_stack_alloc(Uint8, len); if (data) { - fread(data, len, 1, music->wavefp); + SDL_RWread(music->rw, data, len, 1); SDL_MixAudio(stream, data, len, wavestream_volume); SDL_stack_free(data); } @@ -221,8 +238,8 @@ void WAVStream_FreeSong(WAVStream *wave) { if ( wave ) { /* Clean up associated data */ - if ( wave->wavefp ) { - fclose(wave->wavefp); + if ( wave->freerw ) { + SDL_FreeRW(wave->rw); } if ( wave->cvt.buf ) { free(wave->cvt.buf); @@ -237,7 +254,7 @@ int WAVStream_Active(void) int active; active = 0; - if ( music && (ftell(music->wavefp) < music->stop) ) { + if ( music && (SDL_RWtell(music->rw) < music->stop) ) { active = 1; } return(active); @@ -264,12 +281,10 @@ static int ReadChunk(SDL_RWops *src, Chunk *chunk, int read_data) return(chunk->length); } -static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec, +static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec, long *start, long *stop) { int was_error; - FILE *wavefp; - SDL_RWops *src; Chunk chunk; int lenread; @@ -281,17 +296,7 @@ static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec, /* FMT chunk */ WaveFMT *format = NULL; - /* Make sure we are passed a valid data source */ was_error = 0; - wavefp = fopen(file, "rb"); - src = NULL; - if ( wavefp ) { - src = SDL_RWFromFP(wavefp, 0); - } - if ( src == NULL ) { - was_error = 1; - goto done; - } /* Check the magic header */ RIFFchunk = SDL_ReadLE32(src); @@ -367,16 +372,10 @@ static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec, if ( format != NULL ) { free(format); } - if ( src ) { - SDL_RWclose(src); - } if ( was_error ) { - if ( wavefp ) { - fclose(wavefp); - wavefp = NULL; - } + return NULL; } - return(wavefp); + return(src); } /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile. @@ -405,14 +404,12 @@ static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); } -static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, +static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec, long *start, long *stop) { int was_error; int found_SSND; int found_COMM; - FILE *wavefp; - SDL_RWops *src; Uint32 chunk_type; Uint32 chunk_length; @@ -431,18 +428,7 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, Uint8 sane_freq[10]; Uint32 frequency = 0; - - /* Make sure we are passed a valid data source */ was_error = 0; - wavefp = fopen(file, "rb"); - src = NULL; - if ( wavefp ) { - src = SDL_RWFromFP(wavefp, 0); - } - if ( src == NULL ) { - was_error = 1; - goto done; - } /* Check the magic header */ FORMchunk = SDL_ReadLE32(src); @@ -531,15 +517,9 @@ static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec, spec->samples = 4096; /* Good default buffer size */ done: - if ( src ) { - SDL_RWclose(src); - } if ( was_error ) { - if ( wavefp ) { - fclose(wavefp); - wavefp = NULL; - } + return NULL; } - return(wavefp); + return(src); } diff --git a/wavestream.h b/wavestream.h index 865abb37..0b4e8d19 100644 --- a/wavestream.h +++ b/wavestream.h @@ -27,7 +27,8 @@ #include typedef struct { - FILE *wavefp; + SDL_RWops *rw; + SDL_bool freerw; long start; long stop; SDL_AudioCVT cvt; @@ -44,6 +45,9 @@ extern void WAVStream_SetVolume(int volume); /* Load a WAV stream from the given file */ extern WAVStream *WAVStream_LoadSong(const char *file, const char *magic); +/* Load a WAV stream from an SDL_RWops object */ +extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic); + /* Start playback of a given WAV stream */ extern void WAVStream_Start(WAVStream *wave);