diff options
Diffstat (limited to 'apps/plugins/sdl/src/audio/SDL_wave.c')
-rw-r--r-- | apps/plugins/sdl/src/audio/SDL_wave.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/apps/plugins/sdl/src/audio/SDL_wave.c b/apps/plugins/sdl/src/audio/SDL_wave.c new file mode 100644 index 0000000000..b4ad6c7876 --- /dev/null +++ b/apps/plugins/sdl/src/audio/SDL_wave.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | SDL - Simple DirectMedia Layer | ||
3 | Copyright (C) 1997-2012 Sam Lantinga | ||
4 | |||
5 | This library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Lesser General Public | ||
7 | License as published by the Free Software Foundation; either | ||
8 | version 2.1 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 | Lesser General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Lesser General Public | ||
16 | License along with this library; if not, write to the Free Software | ||
17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
18 | |||
19 | Sam Lantinga | ||
20 | slouken@libsdl.org | ||
21 | */ | ||
22 | #include "SDL_config.h" | ||
23 | |||
24 | /* Microsoft WAVE file loading routines */ | ||
25 | |||
26 | #include "SDL_audio.h" | ||
27 | #include "SDL_wave.h" | ||
28 | |||
29 | |||
30 | static int ReadChunk(SDL_RWops *src, Chunk *chunk); | ||
31 | |||
32 | struct MS_ADPCM_decodestate { | ||
33 | Uint8 hPredictor; | ||
34 | Uint16 iDelta; | ||
35 | Sint16 iSamp1; | ||
36 | Sint16 iSamp2; | ||
37 | }; | ||
38 | static struct MS_ADPCM_decoder { | ||
39 | WaveFMT wavefmt; | ||
40 | Uint16 wSamplesPerBlock; | ||
41 | Uint16 wNumCoef; | ||
42 | Sint16 aCoeff[7][2]; | ||
43 | /* * * */ | ||
44 | struct MS_ADPCM_decodestate state[2]; | ||
45 | } MS_ADPCM_state; | ||
46 | |||
47 | static int InitMS_ADPCM(WaveFMT *format) | ||
48 | { | ||
49 | Uint8 *rogue_feel; | ||
50 | int i; | ||
51 | |||
52 | /* Set the rogue pointer to the MS_ADPCM specific data */ | ||
53 | MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | ||
54 | MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | ||
55 | MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | ||
56 | MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | ||
57 | MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | ||
58 | MS_ADPCM_state.wavefmt.bitspersample = | ||
59 | SDL_SwapLE16(format->bitspersample); | ||
60 | rogue_feel = (Uint8 *)format+sizeof(*format); | ||
61 | if ( sizeof(*format) == 16 ) { | ||
62 | rogue_feel += sizeof(Uint16); | ||
63 | } | ||
64 | MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | ||
65 | rogue_feel += sizeof(Uint16); | ||
66 | MS_ADPCM_state.wNumCoef = ((rogue_feel[1]<<8)|rogue_feel[0]); | ||
67 | rogue_feel += sizeof(Uint16); | ||
68 | if ( MS_ADPCM_state.wNumCoef != 7 ) { | ||
69 | SDL_SetError("Unknown set of MS_ADPCM coefficients"); | ||
70 | return(-1); | ||
71 | } | ||
72 | for ( i=0; i<MS_ADPCM_state.wNumCoef; ++i ) { | ||
73 | MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1]<<8)|rogue_feel[0]); | ||
74 | rogue_feel += sizeof(Uint16); | ||
75 | MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1]<<8)|rogue_feel[0]); | ||
76 | rogue_feel += sizeof(Uint16); | ||
77 | } | ||
78 | return(0); | ||
79 | } | ||
80 | |||
81 | static Sint32 MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state, | ||
82 | Uint8 nybble, Sint16 *coeff) | ||
83 | { | ||
84 | const Sint32 max_audioval = ((1<<(16-1))-1); | ||
85 | const Sint32 min_audioval = -(1<<(16-1)); | ||
86 | const Sint32 adaptive[] = { | ||
87 | 230, 230, 230, 230, 307, 409, 512, 614, | ||
88 | 768, 614, 512, 409, 307, 230, 230, 230 | ||
89 | }; | ||
90 | Sint32 new_sample, delta; | ||
91 | |||
92 | new_sample = ((state->iSamp1 * coeff[0]) + | ||
93 | (state->iSamp2 * coeff[1]))/256; | ||
94 | if ( nybble & 0x08 ) { | ||
95 | new_sample += state->iDelta * (nybble-0x10); | ||
96 | } else { | ||
97 | new_sample += state->iDelta * nybble; | ||
98 | } | ||
99 | if ( new_sample < min_audioval ) { | ||
100 | new_sample = min_audioval; | ||
101 | } else | ||
102 | if ( new_sample > max_audioval ) { | ||
103 | new_sample = max_audioval; | ||
104 | } | ||
105 | delta = ((Sint32)state->iDelta * adaptive[nybble])/256; | ||
106 | if ( delta < 16 ) { | ||
107 | delta = 16; | ||
108 | } | ||
109 | state->iDelta = (Uint16)delta; | ||
110 | state->iSamp2 = state->iSamp1; | ||
111 | state->iSamp1 = (Sint16)new_sample; | ||
112 | return(new_sample); | ||
113 | } | ||
114 | |||
115 | static int MS_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | ||
116 | { | ||
117 | struct MS_ADPCM_decodestate *state[2]; | ||
118 | Uint8 *freeable, *encoded, *decoded; | ||
119 | Sint32 encoded_len, samplesleft; | ||
120 | Sint8 nybble, stereo; | ||
121 | Sint16 *coeff[2]; | ||
122 | Sint32 new_sample; | ||
123 | |||
124 | /* Allocate the proper sized output buffer */ | ||
125 | encoded_len = *audio_len; | ||
126 | encoded = *audio_buf; | ||
127 | freeable = *audio_buf; | ||
128 | *audio_len = (encoded_len/MS_ADPCM_state.wavefmt.blockalign) * | ||
129 | MS_ADPCM_state.wSamplesPerBlock* | ||
130 | MS_ADPCM_state.wavefmt.channels*sizeof(Sint16); | ||
131 | *audio_buf = (Uint8 *)SDL_malloc(*audio_len); | ||
132 | if ( *audio_buf == NULL ) { | ||
133 | SDL_Error(SDL_ENOMEM); | ||
134 | return(-1); | ||
135 | } | ||
136 | decoded = *audio_buf; | ||
137 | |||
138 | /* Get ready... Go! */ | ||
139 | stereo = (MS_ADPCM_state.wavefmt.channels == 2); | ||
140 | state[0] = &MS_ADPCM_state.state[0]; | ||
141 | state[1] = &MS_ADPCM_state.state[stereo]; | ||
142 | while ( encoded_len >= MS_ADPCM_state.wavefmt.blockalign ) { | ||
143 | /* Grab the initial information for this block */ | ||
144 | state[0]->hPredictor = *encoded++; | ||
145 | if ( stereo ) { | ||
146 | state[1]->hPredictor = *encoded++; | ||
147 | } | ||
148 | state[0]->iDelta = ((encoded[1]<<8)|encoded[0]); | ||
149 | encoded += sizeof(Sint16); | ||
150 | if ( stereo ) { | ||
151 | state[1]->iDelta = ((encoded[1]<<8)|encoded[0]); | ||
152 | encoded += sizeof(Sint16); | ||
153 | } | ||
154 | state[0]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | ||
155 | encoded += sizeof(Sint16); | ||
156 | if ( stereo ) { | ||
157 | state[1]->iSamp1 = ((encoded[1]<<8)|encoded[0]); | ||
158 | encoded += sizeof(Sint16); | ||
159 | } | ||
160 | state[0]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | ||
161 | encoded += sizeof(Sint16); | ||
162 | if ( stereo ) { | ||
163 | state[1]->iSamp2 = ((encoded[1]<<8)|encoded[0]); | ||
164 | encoded += sizeof(Sint16); | ||
165 | } | ||
166 | coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor]; | ||
167 | coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor]; | ||
168 | |||
169 | /* Store the two initial samples we start with */ | ||
170 | decoded[0] = state[0]->iSamp2&0xFF; | ||
171 | decoded[1] = state[0]->iSamp2>>8; | ||
172 | decoded += 2; | ||
173 | if ( stereo ) { | ||
174 | decoded[0] = state[1]->iSamp2&0xFF; | ||
175 | decoded[1] = state[1]->iSamp2>>8; | ||
176 | decoded += 2; | ||
177 | } | ||
178 | decoded[0] = state[0]->iSamp1&0xFF; | ||
179 | decoded[1] = state[0]->iSamp1>>8; | ||
180 | decoded += 2; | ||
181 | if ( stereo ) { | ||
182 | decoded[0] = state[1]->iSamp1&0xFF; | ||
183 | decoded[1] = state[1]->iSamp1>>8; | ||
184 | decoded += 2; | ||
185 | } | ||
186 | |||
187 | /* Decode and store the other samples in this block */ | ||
188 | samplesleft = (MS_ADPCM_state.wSamplesPerBlock-2)* | ||
189 | MS_ADPCM_state.wavefmt.channels; | ||
190 | while ( samplesleft > 0 ) { | ||
191 | nybble = (*encoded)>>4; | ||
192 | new_sample = MS_ADPCM_nibble(state[0],nybble,coeff[0]); | ||
193 | decoded[0] = new_sample&0xFF; | ||
194 | new_sample >>= 8; | ||
195 | decoded[1] = new_sample&0xFF; | ||
196 | decoded += 2; | ||
197 | |||
198 | nybble = (*encoded)&0x0F; | ||
199 | new_sample = MS_ADPCM_nibble(state[1],nybble,coeff[1]); | ||
200 | decoded[0] = new_sample&0xFF; | ||
201 | new_sample >>= 8; | ||
202 | decoded[1] = new_sample&0xFF; | ||
203 | decoded += 2; | ||
204 | |||
205 | ++encoded; | ||
206 | samplesleft -= 2; | ||
207 | } | ||
208 | encoded_len -= MS_ADPCM_state.wavefmt.blockalign; | ||
209 | } | ||
210 | SDL_free(freeable); | ||
211 | return(0); | ||
212 | } | ||
213 | |||
214 | struct IMA_ADPCM_decodestate { | ||
215 | Sint32 sample; | ||
216 | Sint8 index; | ||
217 | }; | ||
218 | static struct IMA_ADPCM_decoder { | ||
219 | WaveFMT wavefmt; | ||
220 | Uint16 wSamplesPerBlock; | ||
221 | /* * * */ | ||
222 | struct IMA_ADPCM_decodestate state[2]; | ||
223 | } IMA_ADPCM_state; | ||
224 | |||
225 | static int InitIMA_ADPCM(WaveFMT *format) | ||
226 | { | ||
227 | Uint8 *rogue_feel; | ||
228 | |||
229 | /* Set the rogue pointer to the IMA_ADPCM specific data */ | ||
230 | IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding); | ||
231 | IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels); | ||
232 | IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency); | ||
233 | IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate); | ||
234 | IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign); | ||
235 | IMA_ADPCM_state.wavefmt.bitspersample = | ||
236 | SDL_SwapLE16(format->bitspersample); | ||
237 | rogue_feel = (Uint8 *)format+sizeof(*format); | ||
238 | if ( sizeof(*format) == 16 ) { | ||
239 | rogue_feel += sizeof(Uint16); | ||
240 | } | ||
241 | IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1]<<8)|rogue_feel[0]); | ||
242 | return(0); | ||
243 | } | ||
244 | |||
245 | static Sint32 IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state,Uint8 nybble) | ||
246 | { | ||
247 | const Sint32 max_audioval = ((1<<(16-1))-1); | ||
248 | const Sint32 min_audioval = -(1<<(16-1)); | ||
249 | const int index_table[16] = { | ||
250 | -1, -1, -1, -1, | ||
251 | 2, 4, 6, 8, | ||
252 | -1, -1, -1, -1, | ||
253 | 2, 4, 6, 8 | ||
254 | }; | ||
255 | const Sint32 step_table[89] = { | ||
256 | 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, | ||
257 | 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, | ||
258 | 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, | ||
259 | 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, | ||
260 | 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, | ||
261 | 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, | ||
262 | 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, | ||
263 | 22385, 24623, 27086, 29794, 32767 | ||
264 | }; | ||
265 | Sint32 delta, step; | ||
266 | |||
267 | /* Compute difference and new sample value */ | ||
268 | step = step_table[state->index]; | ||
269 | delta = step >> 3; | ||
270 | if ( nybble & 0x04 ) delta += step; | ||
271 | if ( nybble & 0x02 ) delta += (step >> 1); | ||
272 | if ( nybble & 0x01 ) delta += (step >> 2); | ||
273 | if ( nybble & 0x08 ) delta = -delta; | ||
274 | state->sample += delta; | ||
275 | |||
276 | /* Update index value */ | ||
277 | state->index += index_table[nybble]; | ||
278 | if ( state->index > 88 ) { | ||
279 | state->index = 88; | ||
280 | } else | ||
281 | if ( state->index < 0 ) { | ||
282 | state->index = 0; | ||
283 | } | ||
284 | |||
285 | /* Clamp output sample */ | ||
286 | if ( state->sample > max_audioval ) { | ||
287 | state->sample = max_audioval; | ||
288 | } else | ||
289 | if ( state->sample < min_audioval ) { | ||
290 | state->sample = min_audioval; | ||
291 | } | ||
292 | return(state->sample); | ||
293 | } | ||
294 | |||
295 | /* Fill the decode buffer with a channel block of data (8 samples) */ | ||
296 | static void Fill_IMA_ADPCM_block(Uint8 *decoded, Uint8 *encoded, | ||
297 | int channel, int numchannels, struct IMA_ADPCM_decodestate *state) | ||
298 | { | ||
299 | int i; | ||
300 | Sint8 nybble; | ||
301 | Sint32 new_sample; | ||
302 | |||
303 | decoded += (channel * 2); | ||
304 | for ( i=0; i<4; ++i ) { | ||
305 | nybble = (*encoded)&0x0F; | ||
306 | new_sample = IMA_ADPCM_nibble(state, nybble); | ||
307 | decoded[0] = new_sample&0xFF; | ||
308 | new_sample >>= 8; | ||
309 | decoded[1] = new_sample&0xFF; | ||
310 | decoded += 2 * numchannels; | ||
311 | |||
312 | nybble = (*encoded)>>4; | ||
313 | new_sample = IMA_ADPCM_nibble(state, nybble); | ||
314 | decoded[0] = new_sample&0xFF; | ||
315 | new_sample >>= 8; | ||
316 | decoded[1] = new_sample&0xFF; | ||
317 | decoded += 2 * numchannels; | ||
318 | |||
319 | ++encoded; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | static int IMA_ADPCM_decode(Uint8 **audio_buf, Uint32 *audio_len) | ||
324 | { | ||
325 | struct IMA_ADPCM_decodestate *state; | ||
326 | Uint8 *freeable, *encoded, *decoded; | ||
327 | Sint32 encoded_len, samplesleft; | ||
328 | unsigned int c, channels; | ||
329 | |||
330 | /* Check to make sure we have enough variables in the state array */ | ||
331 | channels = IMA_ADPCM_state.wavefmt.channels; | ||
332 | if ( channels > SDL_arraysize(IMA_ADPCM_state.state) ) { | ||
333 | SDL_SetError("IMA ADPCM decoder can only handle %d channels", | ||
334 | SDL_arraysize(IMA_ADPCM_state.state)); | ||
335 | return(-1); | ||
336 | } | ||
337 | state = IMA_ADPCM_state.state; | ||
338 | |||
339 | /* Allocate the proper sized output buffer */ | ||
340 | encoded_len = *audio_len; | ||
341 | encoded = *audio_buf; | ||
342 | freeable = *audio_buf; | ||
343 | *audio_len = (encoded_len/IMA_ADPCM_state.wavefmt.blockalign) * | ||
344 | IMA_ADPCM_state.wSamplesPerBlock* | ||
345 | IMA_ADPCM_state.wavefmt.channels*sizeof(Sint16); | ||
346 | *audio_buf = (Uint8 *)SDL_malloc(*audio_len); | ||
347 | if ( *audio_buf == NULL ) { | ||
348 | SDL_Error(SDL_ENOMEM); | ||
349 | return(-1); | ||
350 | } | ||
351 | decoded = *audio_buf; | ||
352 | |||
353 | /* Get ready... Go! */ | ||
354 | while ( encoded_len >= IMA_ADPCM_state.wavefmt.blockalign ) { | ||
355 | /* Grab the initial information for this block */ | ||
356 | for ( c=0; c<channels; ++c ) { | ||
357 | /* Fill the state information for this block */ | ||
358 | state[c].sample = ((encoded[1]<<8)|encoded[0]); | ||
359 | encoded += 2; | ||
360 | if ( state[c].sample & 0x8000 ) { | ||
361 | state[c].sample -= 0x10000; | ||
362 | } | ||
363 | state[c].index = *encoded++; | ||
364 | /* Reserved byte in buffer header, should be 0 */ | ||
365 | if ( *encoded++ != 0 ) { | ||
366 | /* Uh oh, corrupt data? Buggy code? */; | ||
367 | } | ||
368 | |||
369 | /* Store the initial sample we start with */ | ||
370 | decoded[0] = (Uint8)(state[c].sample&0xFF); | ||
371 | decoded[1] = (Uint8)(state[c].sample>>8); | ||
372 | decoded += 2; | ||
373 | } | ||
374 | |||
375 | /* Decode and store the other samples in this block */ | ||
376 | samplesleft = (IMA_ADPCM_state.wSamplesPerBlock-1)*channels; | ||
377 | while ( samplesleft > 0 ) { | ||
378 | for ( c=0; c<channels; ++c ) { | ||
379 | Fill_IMA_ADPCM_block(decoded, encoded, | ||
380 | c, channels, &state[c]); | ||
381 | encoded += 4; | ||
382 | samplesleft -= 8; | ||
383 | } | ||
384 | decoded += (channels * 8 * 2); | ||
385 | } | ||
386 | encoded_len -= IMA_ADPCM_state.wavefmt.blockalign; | ||
387 | } | ||
388 | SDL_free(freeable); | ||
389 | return(0); | ||
390 | } | ||
391 | |||
392 | SDL_AudioSpec * SDL_LoadWAV_RW (SDL_RWops *src, int freesrc, | ||
393 | SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len) | ||
394 | { | ||
395 | int was_error; | ||
396 | Chunk chunk; | ||
397 | int lenread; | ||
398 | int MS_ADPCM_encoded, IMA_ADPCM_encoded; | ||
399 | int samplesize; | ||
400 | |||
401 | /* WAV magic header */ | ||
402 | Uint32 RIFFchunk; | ||
403 | Uint32 wavelen = 0; | ||
404 | Uint32 WAVEmagic; | ||
405 | Uint32 headerDiff = 0; | ||
406 | |||
407 | /* FMT chunk */ | ||
408 | WaveFMT *format = NULL; | ||
409 | |||
410 | /* Make sure we are passed a valid data source */ | ||
411 | was_error = 0; | ||
412 | if ( src == NULL ) { | ||
413 | was_error = 1; | ||
414 | goto done; | ||
415 | } | ||
416 | |||
417 | /* Check the magic header */ | ||
418 | RIFFchunk = SDL_ReadLE32(src); | ||
419 | wavelen = SDL_ReadLE32(src); | ||
420 | if ( wavelen == WAVE ) { /* The RIFFchunk has already been read */ | ||
421 | WAVEmagic = wavelen; | ||
422 | wavelen = RIFFchunk; | ||
423 | RIFFchunk = RIFF; | ||
424 | } else { | ||
425 | WAVEmagic = SDL_ReadLE32(src); | ||
426 | } | ||
427 | if ( (RIFFchunk != RIFF) || (WAVEmagic != WAVE) ) { | ||
428 | SDL_SetError("Unrecognized file type (not WAVE)"); | ||
429 | was_error = 1; | ||
430 | goto done; | ||
431 | } | ||
432 | headerDiff += sizeof(Uint32); /* for WAVE */ | ||
433 | |||
434 | /* Read the audio data format chunk */ | ||
435 | chunk.data = NULL; | ||
436 | do { | ||
437 | if ( chunk.data != NULL ) { | ||
438 | SDL_free(chunk.data); | ||
439 | chunk.data = NULL; | ||
440 | } | ||
441 | lenread = ReadChunk(src, &chunk); | ||
442 | if ( lenread < 0 ) { | ||
443 | was_error = 1; | ||
444 | goto done; | ||
445 | } | ||
446 | /* 2 Uint32's for chunk header+len, plus the lenread */ | ||
447 | headerDiff += lenread + 2 * sizeof(Uint32); | ||
448 | } while ( (chunk.magic == FACT) || (chunk.magic == LIST) ); | ||
449 | |||
450 | /* Decode the audio data format */ | ||
451 | format = (WaveFMT *)chunk.data; | ||
452 | if ( chunk.magic != FMT ) { | ||
453 | SDL_SetError("Complex WAVE files not supported"); | ||
454 | was_error = 1; | ||
455 | goto done; | ||
456 | } | ||
457 | MS_ADPCM_encoded = IMA_ADPCM_encoded = 0; | ||
458 | switch (SDL_SwapLE16(format->encoding)) { | ||
459 | case PCM_CODE: | ||
460 | /* We can understand this */ | ||
461 | break; | ||
462 | case MS_ADPCM_CODE: | ||
463 | /* Try to understand this */ | ||
464 | if ( InitMS_ADPCM(format) < 0 ) { | ||
465 | was_error = 1; | ||
466 | goto done; | ||
467 | } | ||
468 | MS_ADPCM_encoded = 1; | ||
469 | break; | ||
470 | case IMA_ADPCM_CODE: | ||
471 | /* Try to understand this */ | ||
472 | if ( InitIMA_ADPCM(format) < 0 ) { | ||
473 | was_error = 1; | ||
474 | goto done; | ||
475 | } | ||
476 | IMA_ADPCM_encoded = 1; | ||
477 | break; | ||
478 | case MP3_CODE: | ||
479 | SDL_SetError("MPEG Layer 3 data not supported", | ||
480 | SDL_SwapLE16(format->encoding)); | ||
481 | was_error = 1; | ||
482 | goto done; | ||
483 | default: | ||
484 | SDL_SetError("Unknown WAVE data format: 0x%.4x", | ||
485 | SDL_SwapLE16(format->encoding)); | ||
486 | was_error = 1; | ||
487 | goto done; | ||
488 | } | ||
489 | SDL_memset(spec, 0, (sizeof *spec)); | ||
490 | spec->freq = SDL_SwapLE32(format->frequency); | ||
491 | switch (SDL_SwapLE16(format->bitspersample)) { | ||
492 | case 4: | ||
493 | if ( MS_ADPCM_encoded || IMA_ADPCM_encoded ) { | ||
494 | spec->format = AUDIO_S16; | ||
495 | } else { | ||
496 | was_error = 1; | ||
497 | } | ||
498 | break; | ||
499 | case 8: | ||
500 | spec->format = AUDIO_U8; | ||
501 | break; | ||
502 | case 16: | ||
503 | spec->format = AUDIO_S16; | ||
504 | break; | ||
505 | default: | ||
506 | was_error = 1; | ||
507 | break; | ||
508 | } | ||
509 | if ( was_error ) { | ||
510 | SDL_SetError("Unknown %d-bit PCM data format", | ||
511 | SDL_SwapLE16(format->bitspersample)); | ||
512 | goto done; | ||
513 | } | ||
514 | spec->channels = (Uint8)SDL_SwapLE16(format->channels); | ||
515 | spec->samples = 4096; /* Good default buffer size */ | ||
516 | |||
517 | /* Read the audio data chunk */ | ||
518 | *audio_buf = NULL; | ||
519 | do { | ||
520 | if ( *audio_buf != NULL ) { | ||
521 | SDL_free(*audio_buf); | ||
522 | *audio_buf = NULL; | ||
523 | } | ||
524 | lenread = ReadChunk(src, &chunk); | ||
525 | if ( lenread < 0 ) { | ||
526 | was_error = 1; | ||
527 | goto done; | ||
528 | } | ||
529 | *audio_len = lenread; | ||
530 | *audio_buf = chunk.data; | ||
531 | if(chunk.magic != DATA) headerDiff += lenread + 2 * sizeof(Uint32); | ||
532 | } while ( chunk.magic != DATA ); | ||
533 | headerDiff += 2 * sizeof(Uint32); /* for the data chunk and len */ | ||
534 | |||
535 | if ( MS_ADPCM_encoded ) { | ||
536 | if ( MS_ADPCM_decode(audio_buf, audio_len) < 0 ) { | ||
537 | was_error = 1; | ||
538 | goto done; | ||
539 | } | ||
540 | } | ||
541 | if ( IMA_ADPCM_encoded ) { | ||
542 | if ( IMA_ADPCM_decode(audio_buf, audio_len) < 0 ) { | ||
543 | was_error = 1; | ||
544 | goto done; | ||
545 | } | ||
546 | } | ||
547 | |||
548 | /* Don't return a buffer that isn't a multiple of samplesize */ | ||
549 | samplesize = ((spec->format & 0xFF)/8)*spec->channels; | ||
550 | *audio_len &= ~(samplesize-1); | ||
551 | |||
552 | done: | ||
553 | if ( format != NULL ) { | ||
554 | SDL_free(format); | ||
555 | } | ||
556 | if ( src ) { | ||
557 | if ( freesrc ) { | ||
558 | SDL_RWclose(src); | ||
559 | } else { | ||
560 | /* seek to the end of the file (given by the RIFF chunk) */ | ||
561 | SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR); | ||
562 | } | ||
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 | SDL_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 *)SDL_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 | SDL_free(chunk->data); | ||
592 | chunk->data = NULL; | ||
593 | return(-1); | ||
594 | } | ||
595 | return(chunk->length); | ||
596 | } | ||