Mercurial > sdl-ios-xcode
annotate src/audio/SDL_wave.c @ 940:bb1588ebe47b
Date: Sat, 10 Jul 2004 21:02:33 +0200
From: "Philippe Plantier (ayin)"
Subject: [SDL] Problems allocating large surfaces
There are problems when allocating large surfaces using SDL_CreateRGBSurface.
When, for example, we try to allocate a surface wider than 16384 pixels,
the calculation of the pitch overflows; this leads to a surface that
has the w and h flags correctly set, but whose "pixels" buffer is too
small. That may lead to heap corruption.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Sat, 21 Aug 2004 05:29:45 +0000 |
parents | b8d311d90021 |
children | 80f8c94b5199 |
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; | |
421 Uint32 wavelen; | |
422 Uint32 WAVEmagic; | |
423 | |
424 /* FMT chunk */ | |
425 WaveFMT *format = NULL; | |
426 | |
427 /* Make sure we are passed a valid data source */ | |
428 was_error = 0; | |
429 if ( src == NULL ) { | |
430 was_error = 1; | |
431 goto done; | |
432 } | |
433 | |
434 /* Check the magic header */ | |
435 RIFFchunk = SDL_ReadLE32(src); | |
436 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
|
437 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
|
438 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
|
439 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
|
440 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
|
441 } 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
|
442 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
|
443 } |
0 | 444 if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) { |
445 SDL_SetError("Unrecognized file type (not WAVE)"); | |
446 was_error = 1; | |
447 goto done; | |
448 } | |
449 | |
450 /* Read the audio data format chunk */ | |
451 chunk.data = NULL; | |
452 do { | |
453 if ( chunk.data != NULL ) { | |
454 free(chunk.data); | |
455 } | |
456 lenread = ReadChunk(src, &chunk); | |
457 if ( lenread < 0 ) { | |
458 was_error = 1; | |
459 goto done; | |
460 } | |
461 } while ( (chunk.magic == FACT) || (chunk.magic == LIST) ); | |
462 | |
463 /* Decode the audio data format */ | |
464 format = (WaveFMT *)chunk.data; | |
465 if ( chunk.magic != FMT ) { | |
466 SDL_SetError("Complex WAVE files not supported"); | |
467 was_error = 1; | |
468 goto done; | |
469 } | |
470 MS_ADPCM_encoded = IMA_ADPCM_encoded = 0; | |
471 switch (SDL_SwapLE16(format->encoding)) { | |
472 case PCM_CODE: | |
473 /* We can understand this */ | |
474 break; | |
475 case MS_ADPCM_CODE: | |
476 /* Try to understand this */ | |
477 if ( InitMS_ADPCM(format) < 0 ) { | |
478 was_error = 1; | |
479 goto done; | |
480 } | |
481 MS_ADPCM_encoded = 1; | |
482 break; | |
483 case IMA_ADPCM_CODE: | |
484 /* Try to understand this */ | |
485 if ( InitIMA_ADPCM(format) < 0 ) { | |
486 was_error = 1; | |
487 goto done; | |
488 } | |
489 IMA_ADPCM_encoded = 1; | |
490 break; | |
491 default: | |
492 SDL_SetError("Unknown WAVE data format: 0x%.4x", | |
493 SDL_SwapLE16(format->encoding)); | |
494 was_error = 1; | |
495 goto done; | |
496 } | |
497 memset(spec, 0, (sizeof *spec)); | |
498 spec->freq = SDL_SwapLE32(format->frequency); | |
499 switch (SDL_SwapLE16(format->bitspersample)) { | |
500 case 4: | |
501 if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { | |
502 spec->format = AUDIO_S16; | |
503 } else { | |
504 was_error = 1; | |
505 } | |
506 break; | |
507 case 8: | |
508 spec->format = AUDIO_U8; | |
509 break; | |
510 case 16: | |
511 spec->format = AUDIO_S16; | |
512 break; | |
513 default: | |
514 was_error = 1; | |
515 break; | |
516 } | |
517 if ( was_error ) { | |
518 SDL_SetError("Unknown %d-bit PCM data format", | |
519 SDL_SwapLE16(format->bitspersample)); | |
520 goto done; | |
521 } | |
522 spec->channels = (Uint8)SDL_SwapLE16(format->channels); | |
523 spec->samples = 4096; /* Good default buffer size */ | |
524 | |
525 /* Read the audio data chunk */ | |
526 *audio_buf = NULL; | |
527 do { | |
528 if ( *audio_buf != NULL ) { | |
529 free(*audio_buf); | |
530 } | |
531 lenread = ReadChunk(src, &chunk); | |
532 if ( lenread < 0 ) { | |
533 was_error = 1; | |
534 goto done; | |
535 } | |
536 *audio_len = lenread; | |
537 *audio_buf = chunk.data; | |
538 } while ( chunk.magic != DATA ); | |
539 | |
540 if ( MS_ADPCM_encoded ) { | |
541 if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
542 was_error = 1; | |
543 goto done; | |
544 } | |
545 } | |
546 if ( IMA_ADPCM_encoded ) { | |
547 if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { | |
548 was_error = 1; | |
549 goto done; | |
550 } | |
551 } | |
552 | |
553 /* Don't return a buffer that isn't a multiple of samplesize */ | |
554 samplesize = ((spec->format & 0xFF)/8)*spec->channels; | |
555 *audio_len &= ~(samplesize-1); | |
556 | |
557 done: | |
558 if ( format != NULL ) { | |
559 free(format); | |
560 } | |
561 if ( freesrc && src ) { | |
562 SDL_RWclose(src); | |
563 } | |
564 if ( was_error ) { | |
565 spec = NULL; | |
566 } | |
567 return(spec); | |
568 } | |
569 | |
570 /* Since the WAV memory is allocated in the shared library, it must also | |
571 be freed here. (Necessary under Win32, VC++) | |
572 */ | |
573 void SDL_FreeWAV(Uint8 *audio_buf) | |
574 { | |
575 if ( audio_buf != NULL ) { | |
576 free(audio_buf); | |
577 } | |
578 } | |
579 | |
580 static int ReadChunk(SDL_RWops *src, Chunk *chunk) | |
581 { | |
582 chunk->magic = SDL_ReadLE32(src); | |
583 chunk->length = SDL_ReadLE32(src); | |
584 chunk->data = (Uint8 *)malloc(chunk->length); | |
585 if ( chunk->data == NULL ) { | |
586 SDL_Error(SDL_ENOMEM); | |
587 return(-1); | |
588 } | |
589 if ( SDL_RWread(src, chunk->data, chunk->length, 1) != 1 ) { | |
590 SDL_Error(SDL_EFREAD); | |
591 free(chunk->data); | |
592 return(-1); | |
593 } | |
594 return(chunk->length); | |
595 } | |
596 | |
597 #endif /* ENABLE_FILE */ |