Mercurial > sdl-ios-xcode
annotate src/audio/SDL_wave.c @ 1199:2d6dc7de1145
From: Mike Frysinger <vapier@gentoo.org>
To: sdl@libsdl.org
Date: Sun, 11 Dec 2005 22:57:37 -0500
Subject: [SDL] exec stack in libsdl update
i posted back in September a patch to remove executable stacks:
http://www.devolution.com/pipermail/sdl/2005-September/070626.html
later in November, a similar patch was merged it seems:
http://www.libsdl.org/cgi/cvsweb.cgi/SDL12/src/hermes/mmx_main.asm
however, this lacks the additional output format checks that i posted in my
patch ... this isnt a problem if the hermes asm code is only ever used to
produce ELF objects, but if this is not true, then the additional checks in
my original patch will need to be merged
-mike
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Mon, 12 Dec 2005 09:13:12 +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 */ |