Mercurial > sdl-ios-xcode
annotate src/audio/SDL_wave.c @ 1260:80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
From: Mike Shal
Subject: [SDL] Bug in SDL_wave.c?
Hey everyone, I'm not sure if this is a bug in SDL, or if I just have
incorrect WAV files. The problem I'm having is loading multiple
concatenated WAVs from SDL_LoadWAV_RW. Some WAV files put comments at
the end of the file (which may be bad form), and SDL doesn't skip past
them when reading from the RWops. So the next WAV I try to load will
start at the comment section of the previous WAV, which obviously
doesn't work. If anyone else is having this problem, one quick fix you
can do is run sox on the bad WAVs, which strips out all of the comment
sections.
Eg:
$ sox sound.wav tmp.wav
$ mv -f tmp.wav sound.wav
The other fix is to patch SDL_wave.c, which is included with this email.
(Assuming I made the patch correctly :). All it does is calculate how
much remaining space there is in the WAV file after the data chunk, and
does SDL_RWseek to skip it. I don't think it should interfere with
anything else, but if someone could check it that would be nice :). If
the bug is really with SDL and not with my WAVs, can someone work this
into the next version of SDL? Thanks,
-Mike Shal
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Tue, 24 Jan 2006 07:20:18 +0000 |
parents | b8d311d90021 |
children | c9b51268668f |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
769
b8d311d90021
Updated copyright information for 2004 (Happy New Year!)
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
3 Copyright (C) 1997-2004 Sam Lantinga |
0 | 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 | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
171
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
22 | |
23 #ifdef SAVE_RCSID | |
24 static char rcsid = | |
25 "@(#) $Id$"; | |
26 #endif | |
27 | |
28 #ifndef DISABLE_FILE | |
29 | |
30 /* Microsoft WAVE file loading routines */ | |
31 | |
32 #include <stdlib.h> | |
33 #include <string.h> | |
34 | |
35 #include "SDL_error.h" | |
36 #include "SDL_audio.h" | |
37 #include "SDL_wave.h" | |
38 #include "SDL_endian.h" | |
39 | |
40 #ifndef NELEMS | |
41 #define NELEMS(array) ((sizeof array)/(sizeof array[0])) | |
42 #endif | |
43 | |
44 static int ReadChunk(SDL_RWops *src, Chunk *chunk); | |
45 | |
46 struct MS_ADPCM_decodestate { | |
47 Uint8 hPredictor; | |
48 Uint16 iDelta; | |
49 Sint16 iSamp1; | |
50 Sint16 iSamp2; | |
51 }; | |
52 static struct MS_ADPCM_decoder { | |
53 WaveFMT wavefmt; | |
54 Uint16 wSamplesPerBlock; | |
55 Uint16 wNumCoef; | |
56 Sint16 aCoeff[7][2]; | |
57 /* * * */ | |
58 struct MS_ADPCM_decodestate state[2]; | |
59 } MS_ADPCM_state; | |
60 | |
61 static int InitMS_ADPCM(WaveFMT *format) | |
62 { | |
63 Uint8 *rogue_feel; | |
64 Uint16 extra_info; | |
65 int i; | |
66 | |
67 /* Set the rogue pointer to the MS_ADPCM specific data */ | |
68 MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | |
69 MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | |
70 MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | |
71 MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | |
72 MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | |
73 MS_ADPCM_state.wavefmt.bitspersample = | |
74 SDL_SwapLE16(format->bitspersample); | |
75 rogue_feel = (Uint8 *)format+sizeof(*format); | |
76 if ( sizeof(*format) == 16 ) { | |
77 extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
78 rogue_feel += sizeof(Uint16); | |
79 } | |
80 MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
81 rogue_feel += sizeof(Uint16); | |
82 MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
83 rogue_feel += sizeof(Uint16); | |
84 if ( MS_ADPCM_state.wNumCoef != 7 ) { | |
85 SDL_SetError("Unknown set of MS_ADPCM coefficients"); | |
86 return(-1); | |
87 } | |
88 for ( i=0; i<MS_ADPCM_state.wNumCoef; ++i ) { | |
89 MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
90 rogue_feel += sizeof(Uint16); | |
91 MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
92 rogue_feel += sizeof(Uint16); | |
93 } | |
94 return(0); | |
95 } | |
96 | |
97 static Sint32 MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state, | |
98 Uint8 nybble, Sint16 *coeff) | |
99 { | |
100 const Sint32 max_audioval = ((1<<(16-1))-1); | |
101 const Sint32 min_audioval = -(1<<(16-1)); | |
102 const Sint32 adaptive[] = { | |
103 230, 230, 230, 230, 307, 409, 512, 614, | |
104 768, 614, 512, 409, 307, 230, 230, 230 | |
105 }; | |
106 Sint32 new_sample, delta; | |
107 | |
108 new_sample = ((state->iSamp1 * coeff[0]) + | |
109 (state->iSamp2 * coeff[1]))/256; | |
110 if ( nybble & 0x08 ) { | |
111 new_sample += state->iDelta * (nybble-0x10); | |
112 } else { | |
113 new_sample += state->iDelta * nybble; | |
114 } | |
115 if ( new_sample < min_audioval ) { | |
116 new_sample = min_audioval; | |
117 } else | |
118 if ( new_sample > max_audioval ) { | |
119 new_sample = max_audioval; | |
120 } | |
121 delta = ((Sint32)state->iDelta * adaptive[nybble])/256; | |
122 if ( delta < 16 ) { | |
123 delta = 16; | |
124 } | |
125 state->iDelta = delta; | |
126 state->iSamp2 = state->iSamp1; | |
127 state->iSamp1 = new_sample; | |
128 return(new_sample); | |
129 } | |
130 | |
131 static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | |
132 { | |
133 struct MS_ADPCM_decodestate *state[2]; | |
134 Uint8 *freeable, *encoded, *decoded; | |
135 Sint32 encoded_len, samplesleft; | |
136 Sint8 nybble, stereo; | |
137 Sint16 *coeff[2]; | |
138 Sint32 new_sample; | |
139 | |
140 /* Allocate the proper sized output buffer */ | |
141 encoded_len = *audio_len; | |
142 encoded = *audio_buf; | |
143 freeable = *audio_buf; | |
144 *audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) * | |
145 MS_ADPCM_state.wSamplesPerBlock* | |
146 MS_ADPCM_state.wavefmt.channels*sizeof(Sint16); | |
147 *audio_buf = (Uint8 *)malloc(*audio_len); | |
148 if ( *audio_buf == NULL ) { | |
149 SDL_Error(SDL_ENOMEM); | |
150 return(-1); | |
151 } | |
152 decoded = *audio_buf; | |
153 | |
154 /* Get ready... Go! */ | |
155 stereo = (MS_ADPCM_state.wavefmt.channels == 2); | |
156 state[0] = &MS_ADPCM_state.state[0]; | |
157 state[1] = &MS_ADPCM_state.state[stereo]; | |
158 while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) { | |
159 /* Grab the initial information for this block */ | |
160 state[0]->hPredictor = *encoded++; | |
161 if ( stereo ) { | |
162 state[1]->hPredictor = *encoded++; | |
163 } | |
164 state[0]->iDelta = ((encoded[1]<<8)|encoded[0]); | |
165 encoded += sizeof(Sint16); | |
166 if ( stereo ) { | |
167 state[1]->iDelta = ((encoded[1]<<8)|encoded[0]); | |
168 encoded += sizeof(Sint16); | |
169 } | |
170 state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | |
171 encoded += sizeof(Sint16); | |
172 if ( stereo ) { | |
173 state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | |
174 encoded += sizeof(Sint16); | |
175 } | |
176 state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | |
177 encoded += sizeof(Sint16); | |
178 if ( stereo ) { | |
179 state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | |
180 encoded += sizeof(Sint16); | |
181 } | |
182 coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor]; | |
183 coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor]; | |
184 | |
185 /* Store the two initial samples we start with */ | |
186 decoded[0] = state[0]->iSamp2&0xFF; | |
187 decoded[1] = state[0]->iSamp2>>8; | |
188 decoded += 2; | |
189 if ( stereo ) { | |
190 decoded[0] = state[1]->iSamp2&0xFF; | |
191 decoded[1] = state[1]->iSamp2>>8; | |
192 decoded += 2; | |
193 } | |
194 decoded[0] = state[0]->iSamp1&0xFF; | |
195 decoded[1] = state[0]->iSamp1>>8; | |
196 decoded += 2; | |
197 if ( stereo ) { | |
198 decoded[0] = state[1]->iSamp1&0xFF; | |
199 decoded[1] = state[1]->iSamp1>>8; | |
200 decoded += 2; | |
201 } | |
202 | |
203 /* Decode and store the other samples in this block */ | |
204 samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)* | |
205 MS_ADPCM_state.wavefmt.channels; | |
206 while ( samplesleft > 0 ) { | |
207 nybble = (*encoded)>>4; | |
208 new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]); | |
209 decoded[0] = new_sample&0xFF; | |
210 new_sample >>= 8; | |
211 decoded[1] = new_sample&0xFF; | |
212 decoded += 2; | |
213 | |
214 nybble = (*encoded)&0x0F; | |
215 new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]); | |
216 decoded[0] = new_sample&0xFF; | |
217 new_sample >>= 8; | |
218 decoded[1] = new_sample&0xFF; | |
219 decoded += 2; | |
220 | |
221 ++encoded; | |
222 samplesleft -= 2; | |
223 } | |
224 encoded_len -= MS_ADPCM_state.wavefmt.blockalign; | |
225 } | |
226 free(freeable); | |
227 return(0); | |
228 } | |
229 | |
230 struct IMA_ADPCM_decodestate { | |
231 Sint32 sample; | |
232 Sint8 index; | |
233 }; | |
234 static struct IMA_ADPCM_decoder { | |
235 WaveFMT wavefmt; | |
236 Uint16 wSamplesPerBlock; | |
237 /* * * */ | |
238 struct IMA_ADPCM_decodestate state[2]; | |
239 } IMA_ADPCM_state; | |
240 | |
241 static int InitIMA_ADPCM(WaveFMT *format) | |
242 { | |
243 Uint8 *rogue_feel; | |
244 Uint16 extra_info; | |
245 | |
246 /* Set the rogue pointer to the IMA_ADPCM specific data */ | |
247 IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | |
248 IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | |
249 IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | |
250 IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | |
251 IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | |
252 IMA_ADPCM_state.wavefmt.bitspersample = | |
253 SDL_SwapLE16(format->bitspersample); | |
254 rogue_feel = (Uint8 *)format+sizeof(*format); | |
255 if ( sizeof(*format) == 16 ) { | |
256 extra_info = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
257 rogue_feel += sizeof(Uint16); | |
258 } | |
259 IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | |
260 return(0); | |
261 } | |
262 | |
263 static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble) | |
264 { | |
265 const Sint32 max_audioval = ((1<<(16-1))-1); | |
266 const Sint32 min_audioval = -(1<<(16-1)); | |
267 const int index_table[16] = { | |
268 -1, -1, -1, -1, | |
269 2, 4, 6, 8, | |
270 -1, -1, -1, -1, | |
271 2, 4, 6, 8 | |
272 }; | |
273 const Sint32 step_table[89] = { | |
274 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, | |
275 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, | |
276 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, | |
277 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, | |
278 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, | |
279 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, | |
280 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, | |
281 22385, 24623, 27086, 29794, 32767 | |
282 }; | |
283 Sint32 delta, step; | |
284 | |
285 /* Compute difference and new sample value */ | |
286 step = step_table[state->index]; | |
287 delta = step >> 3; | |
288 if ( nybble & 0x04 ) delta += step; | |
289 if ( nybble & 0x02 ) delta += (step >> 1); | |
290 if ( nybble & 0x01 ) delta += (step >> 2); | |
291 if ( nybble & 0x08 ) delta = -delta; | |
292 state->sample += delta; | |
293 | |
294 /* Update index value */ | |
295 state->index += index_table[nybble]; | |
296 if ( state->index > 88 ) { | |
297 state->index = 88; | |
298 } else | |
299 if ( state->index < 0 ) { | |
300 state->index = 0; | |
301 } | |
302 | |
303 /* Clamp output sample */ | |
304 if ( state->sample > max_audioval ) { | |
305 state->sample = max_audioval; | |
306 } else | |
307 if ( state->sample < min_audioval ) { | |
308 state->sample = min_audioval; | |
309 } | |
310 return(state->sample); | |
311 } | |
312 | |
313 /* Fill the decode buffer with a channel block of data (8 samples) */ | |
314 static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded, | |
315 int channel, int numchannels, struct IMA_ADPCM_decodestate *state) | |
316 { | |
317 int i; | |
318 Sint8 nybble; | |
319 Sint32 new_sample; | |
320 | |
321 decoded += (channel * 2); | |
322 for ( i=0; i<4; ++i ) { | |
323 nybble = (*encoded)&0x0F; | |
324 new_sample = IMA_ADPCM_nibble(state, nybble); | |
325 decoded[0] = new_sample&0xFF; | |
326 new_sample >>= 8; | |
327 decoded[1] = new_sample&0xFF; | |
328 decoded += 2 * numchannels; | |
329 | |
330 nybble = (*encoded)>>4; | |
331 new_sample = IMA_ADPCM_nibble(state, nybble); | |
332 decoded[0] = new_sample&0xFF; | |
333 new_sample >>= 8; | |
334 decoded[1] = new_sample&0xFF; | |
335 decoded += 2 * numchannels; | |
336 | |
337 ++encoded; | |
338 } | |
339 } | |
340 | |
341 static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | |
342 { | |
343 struct IMA_ADPCM_decodestate *state; | |
344 Uint8 *freeable, *encoded, *decoded; | |
345 Sint32 encoded_len, samplesleft; | |
346 int c, channels; | |
347 | |
348 /* Check to make sure we have enough variables in the state array */ | |
349 channels = IMA_ADPCM_state.wavefmt.channels; | |
350 if ( channels > NELEMS(IMA_ADPCM_state.state) ) { | |
351 SDL_SetError("IMA ADPCM decoder can only handle %d channels", | |
352 NELEMS(IMA_ADPCM_state.state)); | |
353 return(-1); | |
354 } | |
355 state = IMA_ADPCM_state.state; | |
356 | |
357 /* Allocate the proper sized output buffer */ | |
358 encoded_len = *audio_len; | |
359 encoded = *audio_buf; | |
360 freeable = *audio_buf; | |
361 *audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) * | |
362 IMA_ADPCM_state.wSamplesPerBlock* | |
363 IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16); | |
364 *audio_buf = (Uint8 *)malloc(*audio_len); | |
365 if ( *audio_buf == NULL ) { | |
366 SDL_Error(SDL_ENOMEM); | |
367 return(-1); | |
368 } | |
369 decoded = *audio_buf; | |
370 | |
371 /* Get ready... Go! */ | |
372 while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) { | |
373 /* Grab the initial information for this block */ | |
374 for ( c=0; c<channels; ++c ) { | |
375 /* Fill the state information for this block */ | |
376 state[c].sample = ((encoded[1]<<8)|encoded[0]); | |
377 encoded += 2; | |
378 if ( state[c].sample & 0x8000 ) { | |
379 state[c].sample -= 0x10000; | |
380 } | |
381 state[c].index = *encoded++; | |
382 /* Reserved byte in buffer header, should be 0 */ | |
383 if ( *encoded++ != 0 ) { | |
384 /* Uh oh, corrupt data? Buggy code? */; | |
385 } | |
386 | |
387 /* Store the initial sample we start with */ | |
388 decoded[0] = state[c].sample&0xFF; | |
389 decoded[1] = state[c].sample>>8; | |
390 decoded += 2; | |
391 } | |
392 | |
393 /* Decode and store the other samples in this block */ | |
394 samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels; | |
395 while ( samplesleft > 0 ) { | |
396 for ( c=0; c<channels; ++c ) { | |
397 Fill_IMA_ADPCM_block(decoded, encoded, | |
398 c, channels, &state[c]); | |
399 encoded += 4; | |
400 samplesleft -= 8; | |
401 } | |
402 decoded += (channels * 8 * 2); | |
403 } | |
404 encoded_len -= IMA_ADPCM_state.wavefmt.blockalign; | |
405 } | |
406 free(freeable); | |
407 return(0); | |
408 } | |
409 | |
410 SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc, | |
411 SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) | |
412 { | |
413 int was_error; | |
414 Chunk chunk; | |
415 int lenread; | |
416 int MS_ADPCM_encoded, IMA_ADPCM_encoded; | |
417 int samplesize; | |
418 | |
419 /* WAV magic header */ | |
420 Uint32 RIFFchunk; | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
421 Uint32 wavelen = 0; |
0 | 422 Uint32 WAVEmagic; |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
423 Uint32 headerDiff = 0; |
0 | 424 |
425 /* FMT chunk */ | |
426 WaveFMT *format = NULL; | |
427 | |
428 /* Make sure we are passed a valid data source */ | |
429 was_error = 0; | |
430 if ( src == NULL ) { | |
431 was_error = 1; | |
432 goto done; | |
433 } | |
434 | |
435 /* Check the magic header */ | |
436 RIFFchunk = SDL_ReadLE32(src); | |
437 wavelen = SDL_ReadLE32(src); | |
171
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
438 if ( wavelen == WAVE ) { /* The RIFFchunk has already been read */ |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
439 WAVEmagic = wavelen; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
440 wavelen = RIFFchunk; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
441 RIFFchunk = RIFF; |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
442 } else { |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
443 WAVEmagic = SDL_ReadLE32(src); |
02e27b705645
Handle the case where the WAVE magic number was already read in a non-seekable
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
444 } |
0 | 445 if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) { |
446 SDL_SetError("Unrecognized file type (not WAVE)"); | |
447 was_error = 1; | |
448 goto done; | |
449 } | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
450 headerDiff += sizeof(Uint32); // for WAVE |
0 | 451 |
452 /* Read the audio data format chunk */ | |
453 chunk.data = NULL; | |
454 do { | |
455 if ( chunk.data != NULL ) { | |
456 free(chunk.data); | |
457 } | |
458 lenread = ReadChunk(src, &chunk); | |
459 if ( lenread < 0 ) { | |
460 was_error = 1; | |
461 goto done; | |
462 } | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
463 // 2 Uint32's for chunk header+len, plus the lenread |
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
464 headerDiff += lenread + 2 * sizeof(Uint32); |
0 | 465 } while ( (chunk.magic == FACT) || (chunk.magic == LIST) ); |
466 | |
467 /* Decode the audio data format */ | |
468 format = (WaveFMT *)chunk.data; | |
469 if ( chunk.magic != FMT ) { | |
470 SDL_SetError("Complex WAVE files not supported"); | |
471 was_error = 1; | |
472 goto done; | |
473 } | |
474 MS_ADPCM_encoded = IMA_ADPCM_encoded = 0; | |
475 switch (SDL_SwapLE16(format->encoding)) { | |
476 case PCM_CODE: | |
477 /* We can understand this */ | |
478 break; | |
479 case MS_ADPCM_CODE: | |
480 /* Try to understand this */ | |
481 if ( InitMS_ADPCM(format) < 0 ) { | |
482 was_error = 1; | |
483 goto done; | |
484 } | |
485 MS_ADPCM_encoded = 1; | |
486 break; | |
487 case IMA_ADPCM_CODE: | |
488 /* Try to understand this */ | |
489 if ( InitIMA_ADPCM(format) < 0 ) { | |
490 was_error = 1; | |
491 goto done; | |
492 } | |
493 IMA_ADPCM_encoded = 1; | |
494 break; | |
495 default: | |
496 SDL_SetError("Unknown WAVE data format: 0x%.4x", | |
497 SDL_SwapLE16(format->encoding)); | |
498 was_error = 1; | |
499 goto done; | |
500 } | |
501 memset(spec, 0, (sizeof *spec)); | |
502 spec->freq = SDL_SwapLE32(format->frequency); | |
503 switch (SDL_SwapLE16(format->bitspersample)) { | |
504 case 4: | |
505 if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { | |
506 spec->format = AUDIO_S16; | |
507 } else { | |
508 was_error = 1; | |
509 } | |
510 break; | |
511 case 8: | |
512 spec->format = AUDIO_U8; | |
513 break; | |
514 case 16: | |
515 spec->format = AUDIO_S16; | |
516 break; | |
517 default: | |
518 was_error = 1; | |
519 break; | |
520 } | |
521 if ( was_error ) { | |
522 SDL_SetError("Unknown %d-bit PCM data format", | |
523 SDL_SwapLE16(format->bitspersample)); | |
524 goto done; | |
525 } | |
526 spec->channels = (Uint8)SDL_SwapLE16(format->channels); | |
527 spec->samples = 4096; /* Good default buffer size */ | |
528 | |
529 /* Read the audio data chunk */ | |
530 *audio_buf = NULL; | |
531 do { | |
532 if ( *audio_buf != NULL ) { | |
533 free(*audio_buf); | |
534 } | |
535 lenread = ReadChunk(src, &chunk); | |
536 if ( lenread < 0 ) { | |
537 was_error = 1; | |
538 goto done; | |
539 } | |
540 *audio_len = lenread; | |
541 *audio_buf = chunk.data; | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
542 if(chunk.magic != DATA) headerDiff += lenread + 2 * sizeof(Uint32); |
0 | 543 } while ( chunk.magic != DATA ); |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
544 headerDiff += 2 * sizeof(Uint32); // for the data chunk and len |
0 | 545 |
546 if ( MS_ADPCM_encoded ) { | |
547 if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
548 was_error = 1; | |
549 goto done; | |
550 } | |
551 } | |
552 if ( IMA_ADPCM_encoded ) { | |
553 if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
554 was_error = 1; | |
555 goto done; | |
556 } | |
557 } | |
558 | |
559 /* Don't return a buffer that isn't a multiple of samplesize */ | |
560 samplesize = ((spec->format & 0xFF)/8)*spec->channels; | |
561 *audio_len &= ~(samplesize-1); | |
562 | |
563 done: | |
564 if ( format != NULL ) { | |
565 free(format); | |
566 } | |
567 if ( freesrc && src ) { | |
568 SDL_RWclose(src); | |
569 } | |
1260
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
570 else { |
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
571 // seek to the end of the file (given by the RIFF chunk) |
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
572 SDL_RWseek(src, wavelen - chunk.length - headerDiff, SEEK_CUR); |
80f8c94b5199
Date: 10 Jun 2003 15:30:59 -0400
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
573 } |
0 | 574 if ( was_error ) { |
575 spec = NULL; | |
576 } | |
577 return(spec); | |
578 } | |
579 | |
580 /* Since the WAV memory is allocated in the shared library, it must also | |
581 be freed here. (Necessary under Win32, VC++) | |
582 */ | |
583 void SDL_FreeWAV(Uint8 *audio_buf) | |
584 { | |
585 if ( audio_buf != NULL ) { | |
586 free(audio_buf); | |
587 } | |
588 } | |
589 | |
590 static int ReadChunk(SDL_RWops *src, Chunk *chunk) | |
591 { | |
592 chunk->magic = SDL_ReadLE32(src); | |
593 chunk->length = SDL_ReadLE32(src); | |
594 chunk->data = (Uint8 *)malloc(chunk->length); | |
595 if ( chunk->data == NULL ) { | |
596 SDL_Error(SDL_ENOMEM); | |
597 return(-1); | |
598 } | |
599 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { | |
600 SDL_Error(SDL_EFREAD); | |
601 free(chunk->data); | |
602 return(-1); | |
603 } | |
604 return(chunk->length); | |
605 } | |
606 | |
607 #endif /* ENABLE_FILE */ |