Date: Sat, 16 Feb 2008 20:59:24 +0100
authorSam Lantinga <slouken@libsdl.org>
Tue, 26 Feb 2008 11:46:22 +0000
changeset 3812064088ea781
parent 380 161aa45d00c2
child 382 50501e45c57b
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
music.c
wavestream.c
wavestream.h
     1.1 --- a/CHANGES	Tue Feb 26 11:44:20 2008 +0000
     1.2 +++ b/CHANGES	Tue Feb 26 11:46:22 2008 +0000
     1.3 @@ -1,3 +1,7 @@
     1.4 +1.2.9:
     1.5 +Tilman Sauerbeck - Tue Feb 26 03:44:47 PST 2008
     1.6 + * Added support for streaming WAV files with Mix_LoadMUS_RW()
     1.7 +
     1.8  1.2.8:
     1.9  Sam Lantinga - Wed Jul 18 09:45:54 PDT 2007
    1.10   * Improved detection of Ogg Vorbis and Tremor libraries
     2.1 --- a/music.c	Tue Feb 26 11:44:20 2008 +0000
     2.2 +++ b/music.c	Tue Feb 26 11:46:22 2008 +0000
     2.3 @@ -1416,11 +1416,13 @@
     2.4  }
     2.5  # endif
     2.6  
     2.7 -Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw) {
     2.8 +Mix_Music *Mix_LoadMUS_RW(SDL_RWops *rw)
     2.9 +{
    2.10  	Uint8 magic[5];	  /*Apparently there is no way to check if the file is really a MOD,*/
    2.11  	/*		    or there are too many formats supported by MikMod or MikMod does */
    2.12  	/*		    this check by itself. If someone implements other formats (e.g. MP3) */
    2.13  	/*		    the check can be uncommented */
    2.14 +	Uint8 moremagic[9];
    2.15  	Mix_Music *music;
    2.16  	int start;
    2.17  
    2.18 @@ -1431,12 +1433,14 @@
    2.19  
    2.20  	/* Figure out what kind of file this is */
    2.21  	start = SDL_RWtell(rw);
    2.22 -	if (SDL_RWread(rw,magic,1,4)!=4) {
    2.23 +	if ( SDL_RWread(rw,magic,1,4) != 4 ||
    2.24 +	     SDL_RWread(rw,moremagic,1,8) != 8 ) {
    2.25  		Mix_SetError("Couldn't read from RWops");
    2.26  		return NULL;
    2.27  	}
    2.28  	SDL_RWseek(rw, start, SEEK_SET);
    2.29  	magic[4]='\0';
    2.30 +	moremagic[8] = '\0';
    2.31  
    2.32  	/* Allocate memory for the music structure */
    2.33  	music=(Mix_Music *)malloc(sizeof(Mix_Music));
    2.34 @@ -1446,6 +1450,20 @@
    2.35  	}
    2.36  	music->error = 0;
    2.37  
    2.38 +#ifdef WAV_MUSIC
    2.39 +	/* WAVE files have the magic four bytes "RIFF"
    2.40 +	   AIFF files have the magic 12 bytes "FORM" XXXX "AIFF"
    2.41 +	 */
    2.42 +	if ( ((strcmp((char *)magic, "RIFF") == 0) && (strcmp((char *)(moremagic+4), "WAVE") == 0)) ||
    2.43 +	     (strcmp((char *)magic, "FORM") == 0) ) {
    2.44 +		music->type = MUS_WAV;
    2.45 +		music->data.wave = WAVStream_LoadSong_RW(rw, (char *)magic);
    2.46 +		if ( music->data.wave == NULL ) {
    2.47 +			music->error = 1;
    2.48 +		}
    2.49 +
    2.50 +	} else
    2.51 +#endif
    2.52  #ifdef OGG_MUSIC
    2.53  	/* Ogg Vorbis files have the magic four bytes "OggS" */
    2.54  	if ( strcmp((char *)magic, "OggS") == 0 ) {
     3.1 --- a/wavestream.c	Tue Feb 26 11:44:20 2008 +0000
     3.2 +++ b/wavestream.c	Tue Feb 26 11:46:22 2008 +0000
     3.3 @@ -95,9 +95,9 @@
     3.4  static int wavestream_volume = MIX_MAX_VOLUME;
     3.5  
     3.6  /* Function to load the WAV/AIFF stream */
     3.7 -static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec,
     3.8 +static SDL_RWops *LoadWAVStream (SDL_RWops *rw, SDL_AudioSpec *spec,
     3.9  					long *start, long *stop);
    3.10 -static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec,
    3.11 +static SDL_RWops *LoadAIFFStream (SDL_RWops *rw, SDL_AudioSpec *spec,
    3.12  					long *start, long *stop);
    3.13  
    3.14  /* Initialize the WAVStream player, with the given mixer settings
    3.15 @@ -114,8 +114,26 @@
    3.16  	wavestream_volume = volume;
    3.17  }
    3.18  
    3.19 +WAVStream *WAVStream_LoadSong(const char *file, const char *magic)
    3.20 +{
    3.21 +	SDL_RWops *rw;
    3.22 +	WAVStream *wave;
    3.23 +
    3.24 +	rw = SDL_RWFromFile(file, "rb");
    3.25 +	if ( rw == NULL ) {
    3.26 +		SDL_SetError("Couldn't open %s", file);
    3.27 +		return NULL;
    3.28 +	}
    3.29 +	wave = WAVStream_LoadSong_RW(rw, magic);
    3.30 +	if ( wave == NULL ) {
    3.31 +		SDL_FreeRW(rw);
    3.32 +		return NULL;
    3.33 +	}
    3.34 +	return wave;
    3.35 +}
    3.36 +
    3.37  /* Load a WAV stream from the given file */
    3.38 -WAVStream *WAVStream_LoadSong(const char *file, const char *magic)
    3.39 +WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic)
    3.40  {
    3.41  	WAVStream *wave;
    3.42  	SDL_AudioSpec wavespec;
    3.43 @@ -128,16 +146,16 @@
    3.44  	if ( wave ) {
    3.45  		memset(wave, 0, (sizeof *wave));
    3.46  		if ( strcmp(magic, "RIFF") == 0 ) {
    3.47 -			wave->wavefp = LoadWAVStream(file, &wavespec,
    3.48 +			wave->rw = LoadWAVStream(rw, &wavespec,
    3.49  					&wave->start, &wave->stop);
    3.50  		} else
    3.51  		if ( strcmp(magic, "FORM") == 0 ) {
    3.52 -			wave->wavefp = LoadAIFFStream(file, &wavespec,
    3.53 +			wave->rw = LoadAIFFStream(rw, &wavespec,
    3.54  					&wave->start, &wave->stop);
    3.55  		} else {
    3.56  			Mix_SetError("Unknown WAVE format");
    3.57  		}
    3.58 -		if ( wave->wavefp == NULL ) {
    3.59 +		if ( wave->rw == NULL ) {
    3.60  			free(wave);
    3.61  			return(NULL);
    3.62  		}
    3.63 @@ -151,8 +169,7 @@
    3.64  /* Start playback of a given WAV stream */
    3.65  void WAVStream_Start(WAVStream *wave)
    3.66  {
    3.67 -	clearerr(wave->wavefp);
    3.68 -	fseek(wave->wavefp, wave->start, SEEK_SET);
    3.69 +	SDL_RWseek (wave->rw, wave->start, SEEK_SET);
    3.70  	music = wave;
    3.71  }
    3.72  
    3.73 @@ -161,7 +178,7 @@
    3.74  {
    3.75  	long pos;
    3.76  
    3.77 -	if ( music && ((pos=ftell(music->wavefp)) < music->stop) ) {
    3.78 +	if ( music && ((pos=SDL_RWtell(music->rw)) < music->stop) ) {
    3.79  		if ( music->cvt.needed ) {
    3.80  			int original_len;
    3.81  
    3.82 @@ -181,7 +198,7 @@
    3.83  			if ( (music->stop - pos) < original_len ) {
    3.84  				original_len = (music->stop - pos);
    3.85  			}
    3.86 -			original_len = fread(music->cvt.buf,1,original_len,music->wavefp);
    3.87 +			original_len = SDL_RWread(music->rw, music->cvt.buf,1,original_len);
    3.88  			/* At least at the time of writing, SDL_ConvertAudio()
    3.89  			   does byte-order swapping starting at the end of the
    3.90  			   buffer. Thus, if we are reading 16-bit samples, we
    3.91 @@ -202,7 +219,7 @@
    3.92  			data = SDL_stack_alloc(Uint8, len);
    3.93  			if (data)
    3.94  			{		
    3.95 -				fread(data, len, 1, music->wavefp);
    3.96 +				SDL_RWread(music->rw, data, len, 1);
    3.97  				SDL_MixAudio(stream, data, len, wavestream_volume);
    3.98  				SDL_stack_free(data);
    3.99  			}	
   3.100 @@ -221,8 +238,8 @@
   3.101  {
   3.102  	if ( wave ) {
   3.103  		/* Clean up associated data */
   3.104 -		if ( wave->wavefp ) {
   3.105 -			fclose(wave->wavefp);
   3.106 +		if ( wave->freerw ) {
   3.107 +			SDL_FreeRW(wave->rw);
   3.108  		}
   3.109  		if ( wave->cvt.buf ) {
   3.110  			free(wave->cvt.buf);
   3.111 @@ -237,7 +254,7 @@
   3.112  	int active;
   3.113  
   3.114  	active = 0;
   3.115 -	if ( music && (ftell(music->wavefp) < music->stop) ) {
   3.116 +	if ( music && (SDL_RWtell(music->rw) < music->stop) ) {
   3.117  		active = 1;
   3.118  	}
   3.119  	return(active);
   3.120 @@ -264,12 +281,10 @@
   3.121  	return(chunk->length);
   3.122  }
   3.123  
   3.124 -static FILE *LoadWAVStream (const char *file, SDL_AudioSpec *spec,
   3.125 +static SDL_RWops *LoadWAVStream (SDL_RWops *src, SDL_AudioSpec *spec,
   3.126  					long *start, long *stop)
   3.127  {
   3.128  	int was_error;
   3.129 -	FILE *wavefp;
   3.130 -	SDL_RWops *src;
   3.131  	Chunk chunk;
   3.132  	int lenread;
   3.133  
   3.134 @@ -281,17 +296,7 @@
   3.135  	/* FMT chunk */
   3.136  	WaveFMT *format = NULL;
   3.137  
   3.138 -	/* Make sure we are passed a valid data source */
   3.139  	was_error = 0;
   3.140 -	wavefp = fopen(file, "rb");
   3.141 -	src = NULL;
   3.142 -	if ( wavefp ) {
   3.143 -		src = SDL_RWFromFP(wavefp, 0);
   3.144 -	}
   3.145 -	if ( src == NULL ) {
   3.146 -		was_error = 1;
   3.147 -		goto done;
   3.148 -	}
   3.149  
   3.150  	/* Check the magic header */
   3.151  	RIFFchunk	= SDL_ReadLE32(src);
   3.152 @@ -367,16 +372,10 @@
   3.153  	if ( format != NULL ) {
   3.154  		free(format);
   3.155  	}
   3.156 -	if ( src ) {
   3.157 -		SDL_RWclose(src);
   3.158 +	if ( was_error ) {
   3.159 +		return NULL;
   3.160  	}
   3.161 -	if ( was_error ) {
   3.162 -		if ( wavefp ) {
   3.163 -			fclose(wavefp);
   3.164 -			wavefp = NULL;
   3.165 -		}
   3.166 -	}
   3.167 -	return(wavefp);
   3.168 +	return(src);
   3.169  }
   3.170  
   3.171  /* I couldn't get SANE_to_double() to work, so I stole this from libsndfile.
   3.172 @@ -405,14 +404,12 @@
   3.173  		| (sanebuf[5] >> 1)) >> (29 - sanebuf[1]);
   3.174  }
   3.175  
   3.176 -static FILE *LoadAIFFStream (const char *file, SDL_AudioSpec *spec,
   3.177 +static SDL_RWops *LoadAIFFStream (SDL_RWops *src, SDL_AudioSpec *spec,
   3.178  					long *start, long *stop)
   3.179  {
   3.180  	int was_error;
   3.181  	int found_SSND;
   3.182  	int found_COMM;
   3.183 -	FILE *wavefp;
   3.184 -	SDL_RWops *src;
   3.185  
   3.186  	Uint32 chunk_type;
   3.187  	Uint32 chunk_length;
   3.188 @@ -431,18 +428,7 @@
   3.189  	Uint8 sane_freq[10];
   3.190  	Uint32 frequency = 0;
   3.191  
   3.192 -
   3.193 -	/* Make sure we are passed a valid data source */
   3.194  	was_error = 0;
   3.195 -	wavefp = fopen(file, "rb");
   3.196 -	src = NULL;
   3.197 -	if ( wavefp ) {
   3.198 -		src = SDL_RWFromFP(wavefp, 0);
   3.199 -	}
   3.200 -	if ( src == NULL ) {
   3.201 -		was_error = 1;
   3.202 -		goto done;
   3.203 -	}
   3.204  
   3.205  	/* Check the magic header */
   3.206  	FORMchunk	= SDL_ReadLE32(src);
   3.207 @@ -531,15 +517,9 @@
   3.208  	spec->samples = 4096;		/* Good default buffer size */
   3.209  
   3.210  done:
   3.211 -	if ( src ) {
   3.212 -		SDL_RWclose(src);
   3.213 +	if ( was_error ) {
   3.214 +		return NULL;
   3.215  	}
   3.216 -	if ( was_error ) {
   3.217 -		if ( wavefp ) {
   3.218 -			fclose(wavefp);
   3.219 -			wavefp = NULL;
   3.220 -		}
   3.221 -	}
   3.222 -	return(wavefp);
   3.223 +	return(src);
   3.224  }
   3.225  
     4.1 --- a/wavestream.h	Tue Feb 26 11:44:20 2008 +0000
     4.2 +++ b/wavestream.h	Tue Feb 26 11:46:22 2008 +0000
     4.3 @@ -27,7 +27,8 @@
     4.4  #include <stdio.h>
     4.5  
     4.6  typedef struct {
     4.7 -	FILE *wavefp;
     4.8 +	SDL_RWops *rw;
     4.9 +	SDL_bool freerw;
    4.10  	long  start;
    4.11  	long  stop;
    4.12  	SDL_AudioCVT cvt;
    4.13 @@ -44,6 +45,9 @@
    4.14  /* Load a WAV stream from the given file */
    4.15  extern WAVStream *WAVStream_LoadSong(const char *file, const char *magic);
    4.16  
    4.17 +/* Load a WAV stream from an SDL_RWops object */
    4.18 +extern WAVStream *WAVStream_LoadSong_RW(SDL_RWops *rw, const char *magic);
    4.19 +
    4.20  /* Start playback of a given WAV stream */
    4.21  extern void WAVStream_Start(WAVStream *wave);
    4.22