Mercurial > almixer_isolated
comparison Isolated/LGPL/wav.c @ 38:71b465ff0622
Added support files.
author | Eric Wing <ewing@anscamobile.com> |
---|---|
date | Thu, 28 Apr 2011 16:22:30 -0700 |
parents | |
children | 12e4e093c6e0 |
comparison
equal
deleted
inserted
replaced
37:b346b6608eab | 38:71b465ff0622 |
---|---|
1 /* | |
2 * SDL_sound -- An abstract sound format decoding API. | |
3 * Copyright (C) 2001 Ryan C. Gordon. | |
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 */ | |
19 | |
20 /* | |
21 Attention: This is a stripped down file of SDL_endian for our purposes. | |
22 This code is licensed under the LGPL. | |
23 This means we must not compile this code into anything that we are not willing to | |
24 publicly release source code. | |
25 You should compile this into a separate dynamic library that is isolated from proprietary code. | |
26 */ | |
27 | |
28 /* | |
29 * WAV decoder for SDL_sound. | |
30 * | |
31 * This driver handles Microsoft .WAVs, in as many of the thousands of | |
32 * variations as we can. | |
33 * | |
34 * Please see the file LICENSE.txt in the source's root directory. | |
35 * | |
36 * This file written by Ryan C. Gordon. (icculus@icculus.org) | |
37 */ | |
38 | |
39 #if HAVE_CONFIG_H | |
40 # include <config.h> | |
41 #endif | |
42 | |
43 #ifdef SOUND_SUPPORTS_WAV | |
44 | |
45 #include <stdio.h> | |
46 #include <stdlib.h> | |
47 #include <string.h> | |
48 | |
49 //#include "SDL_sound.h" | |
50 | |
51 //#define __SDL_SOUND_INTERNAL__ | |
52 //#include "SDL_sound_internal.h" | |
53 | |
54 | |
55 #include "SoundDecoder.h" | |
56 | |
57 #include "SoundDecoder_Internal.h" | |
58 #include "SDL_endian_minimal.h" | |
59 #include "ALmixer_RWops.h" | |
60 | |
61 #define ERR_IO_ERROR "I/O error" | |
62 #define assert(x) | |
63 | |
64 static int WAV_init(void); | |
65 static void WAV_quit(void); | |
66 static int WAV_open(Sound_Sample *sample, const char *ext); | |
67 static void WAV_close(Sound_Sample *sample); | |
68 static uint32_t WAV_read(Sound_Sample *sample); | |
69 static int WAV_rewind(Sound_Sample *sample); | |
70 static int WAV_seek(Sound_Sample *sample, uint32_t ms); | |
71 | |
72 static const char *extensions_wav[] = { "WAV", NULL }; | |
73 const Sound_DecoderFunctions __Sound_DecoderFunctions_WAV = | |
74 { | |
75 { | |
76 extensions_wav, | |
77 "Microsoft WAVE audio format", | |
78 "Ryan C. Gordon <icculus@icculus.org>", | |
79 "http://www.icculus.org/SDL_sound/" | |
80 }, | |
81 | |
82 WAV_init, /* init() method */ | |
83 WAV_quit, /* quit() method */ | |
84 WAV_open, /* open() method */ | |
85 WAV_close, /* close() method */ | |
86 WAV_read, /* read() method */ | |
87 WAV_rewind, /* rewind() method */ | |
88 WAV_seek /* seek() method */ | |
89 }; | |
90 | |
91 | |
92 /* Better than SDL_ReadLE16, since you can detect i/o errors... */ | |
93 static __inline__ int read_le16(ALmixer_RWops *rw, uint16_t *ui16) | |
94 { | |
95 int rc = ALmixer_RWread(rw, ui16, sizeof (uint16_t), 1); | |
96 BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0); | |
97 *ui16 = SDL_SwapLE16(*ui16); | |
98 return(1); | |
99 } /* read_le16 */ | |
100 | |
101 | |
102 /* Better than SDL_ReadLE32, since you can detect i/o errors... */ | |
103 static __inline__ int read_le32(ALmixer_RWops *rw, uint32_t *ui32) | |
104 { | |
105 int rc = ALmixer_RWread(rw, ui32, sizeof (uint32_t), 1); | |
106 BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0); | |
107 *ui32 = SDL_SwapLE32(*ui32); | |
108 return(1); | |
109 } /* read_le32 */ | |
110 | |
111 | |
112 /* This is just cleaner on the caller's end... */ | |
113 static __inline__ int read_uint8_t(ALmixer_RWops *rw, uint8_t *ui8) | |
114 { | |
115 int rc = ALmixer_RWread(rw, ui8, sizeof (uint8_t), 1); | |
116 BAIL_IF_MACRO(rc != 1, ERR_IO_ERROR, 0); | |
117 return(1); | |
118 } /* read_uint8_t */ | |
119 | |
120 | |
121 static __inline__ uint16_t SDL_ReadLE16( ALmixer_RWops *rw ) | |
122 { | |
123 uint16_t result = 0; | |
124 | |
125 int rc = read_le16( rw, &result ); | |
126 | |
127 return result; | |
128 } | |
129 static __inline__ uint32_t SDL_ReadLE32( ALmixer_RWops *rw ) | |
130 { | |
131 uint32_t result = 0; | |
132 | |
133 int rc = read_le32( rw, &result ); | |
134 | |
135 return result; | |
136 } | |
137 | |
138 /* Chunk management code... */ | |
139 | |
140 #define riffID 0x46464952 /* "RIFF", in ascii. */ | |
141 #define waveID 0x45564157 /* "WAVE", in ascii. */ | |
142 #define factID 0x74636166 /* "fact", in ascii. */ | |
143 | |
144 | |
145 /***************************************************************************** | |
146 * The FORMAT chunk... * | |
147 *****************************************************************************/ | |
148 | |
149 #define fmtID 0x20746D66 /* "fmt ", in ascii. */ | |
150 | |
151 #define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */ | |
152 #define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */ | |
153 | |
154 typedef struct | |
155 { | |
156 int16_t iCoef1; | |
157 int16_t iCoef2; | |
158 } ADPCMCOEFSET; | |
159 | |
160 typedef struct | |
161 { | |
162 uint8_t bPredictor; | |
163 uint16_t iDelta; | |
164 int16_t iSamp1; | |
165 int16_t iSamp2; | |
166 } ADPCMBLOCKHEADER; | |
167 | |
168 typedef struct S_WAV_FMT_T | |
169 { | |
170 uint32_t chunkID; | |
171 int32_t chunkSize; | |
172 int16_t wFormatTag; | |
173 uint16_t wChannels; | |
174 uint32_t dwSamplesPerSec; | |
175 uint32_t dwAvgBytesPerSec; | |
176 uint16_t wBlockAlign; | |
177 uint16_t wBitsPerSample; | |
178 | |
179 uint32_t next_chunk_offset; | |
180 | |
181 uint32_t sample_frame_size; | |
182 uint32_t data_starting_offset; | |
183 uint32_t total_bytes; | |
184 | |
185 void (*free)(struct S_WAV_FMT_T *fmt); | |
186 uint32_t (*read_sample)(Sound_Sample *sample); | |
187 int (*rewind_sample)(Sound_Sample *sample); | |
188 int (*seek_sample)(Sound_Sample *sample, uint32_t ms); | |
189 | |
190 union | |
191 { | |
192 struct | |
193 { | |
194 uint16_t cbSize; | |
195 uint16_t wSamplesPerBlock; | |
196 uint16_t wNumCoef; | |
197 ADPCMCOEFSET *aCoef; | |
198 ADPCMBLOCKHEADER *blockheaders; | |
199 uint32_t samples_left_in_block; | |
200 int nibble_state; | |
201 int8_t nibble; | |
202 } adpcm; | |
203 | |
204 /* put other format-specific data here... */ | |
205 } fmt; | |
206 } fmt_t; | |
207 | |
208 | |
209 /* | |
210 * Read in a fmt_t from disk. This makes this process safe regardless of | |
211 * the processor's byte order or how the fmt_t structure is packed. | |
212 * Note that the union "fmt" is not read in here; that is handled as | |
213 * needed in the read_fmt_* functions. | |
214 */ | |
215 static int read_fmt_chunk(ALmixer_RWops *rw, fmt_t *fmt) | |
216 { | |
217 /* skip reading the chunk ID, since it was already read at this point... */ | |
218 fmt->chunkID = fmtID; | |
219 | |
220 BAIL_IF_MACRO(!read_le32(rw, &fmt->chunkSize), NULL, 0); | |
221 BAIL_IF_MACRO(fmt->chunkSize < 16, "WAV: Invalid chunk size", 0); | |
222 fmt->next_chunk_offset = ALmixer_RWtell(rw) + fmt->chunkSize; | |
223 | |
224 BAIL_IF_MACRO(!read_le16(rw, &fmt->wFormatTag), NULL, 0); | |
225 BAIL_IF_MACRO(!read_le16(rw, &fmt->wChannels), NULL, 0); | |
226 BAIL_IF_MACRO(!read_le32(rw, &fmt->dwSamplesPerSec), NULL, 0); | |
227 BAIL_IF_MACRO(!read_le32(rw, &fmt->dwAvgBytesPerSec), NULL, 0); | |
228 BAIL_IF_MACRO(!read_le16(rw, &fmt->wBlockAlign), NULL, 0); | |
229 BAIL_IF_MACRO(!read_le16(rw, &fmt->wBitsPerSample), NULL, 0); | |
230 | |
231 return(1); | |
232 } /* read_fmt_chunk */ | |
233 | |
234 | |
235 | |
236 /***************************************************************************** | |
237 * The DATA chunk... * | |
238 *****************************************************************************/ | |
239 | |
240 #define dataID 0x61746164 /* "data", in ascii. */ | |
241 | |
242 typedef struct | |
243 { | |
244 uint32_t chunkID; | |
245 int32_t chunkSize; | |
246 /* Then, (chunkSize) bytes of waveform data... */ | |
247 } data_t; | |
248 | |
249 | |
250 /* | |
251 * Read in a data_t from disk. This makes this process safe regardless of | |
252 * the processor's byte order or how the fmt_t structure is packed. | |
253 */ | |
254 static int read_data_chunk(ALmixer_RWops *rw, data_t *data) | |
255 { | |
256 /* skip reading the chunk ID, since it was already read at this point... */ | |
257 data->chunkID = dataID; | |
258 BAIL_IF_MACRO(!read_le32(rw, &data->chunkSize), NULL, 0); | |
259 return(1); | |
260 } /* read_data_chunk */ | |
261 | |
262 | |
263 | |
264 | |
265 /***************************************************************************** | |
266 * this is what we store in our internal->decoder_private field... * | |
267 *****************************************************************************/ | |
268 | |
269 typedef struct | |
270 { | |
271 fmt_t *fmt; | |
272 int32_t bytesLeft; | |
273 } wav_t; | |
274 | |
275 | |
276 | |
277 | |
278 /***************************************************************************** | |
279 * Normal, uncompressed waveform handler... * | |
280 *****************************************************************************/ | |
281 | |
282 /* | |
283 * Sound_Decode() lands here for uncompressed WAVs... | |
284 */ | |
285 static uint32_t read_sample_fmt_normal(Sound_Sample *sample) | |
286 { | |
287 uint32_t retval; | |
288 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
289 wav_t *w = (wav_t *) internal->decoder_private; | |
290 uint32_t max = (internal->buffer_size < (uint32_t) w->bytesLeft) ? | |
291 internal->buffer_size : (uint32_t) w->bytesLeft; | |
292 | |
293 assert(max > 0); | |
294 | |
295 /* | |
296 * We don't actually do any decoding, so we read the wav data | |
297 * directly into the internal buffer... | |
298 */ | |
299 retval = ALmixer_RWread(internal->rw, internal->buffer, 1, max); | |
300 | |
301 w->bytesLeft -= retval; | |
302 | |
303 /* Make sure the read went smoothly... */ | |
304 if ((retval == 0) || (w->bytesLeft == 0)) | |
305 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
306 | |
307 else if (retval == -1) | |
308 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
309 | |
310 /* (next call this EAGAIN may turn into an EOF or error.) */ | |
311 else if (retval < internal->buffer_size) | |
312 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; | |
313 | |
314 return(retval); | |
315 } /* read_sample_fmt_normal */ | |
316 | |
317 | |
318 static int seek_sample_fmt_normal(Sound_Sample *sample, uint32_t ms) | |
319 { | |
320 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
321 wav_t *w = (wav_t *) internal->decoder_private; | |
322 fmt_t *fmt = w->fmt; | |
323 int offset = __Sound_convertMsToBytePos(&sample->actual, ms); | |
324 int pos = (int) (fmt->data_starting_offset + offset); | |
325 int rc = ALmixer_RWseek(internal->rw, pos, SEEK_SET); | |
326 BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0); | |
327 w->bytesLeft = fmt->total_bytes - offset; | |
328 return(1); /* success. */ | |
329 } /* seek_sample_fmt_normal */ | |
330 | |
331 | |
332 static int rewind_sample_fmt_normal(Sound_Sample *sample) | |
333 { | |
334 /* no-op. */ | |
335 return(1); | |
336 } /* rewind_sample_fmt_normal */ | |
337 | |
338 | |
339 static int read_fmt_normal(ALmixer_RWops *rw, fmt_t *fmt) | |
340 { | |
341 /* (don't need to read more from the RWops...) */ | |
342 fmt->free = NULL; | |
343 fmt->read_sample = read_sample_fmt_normal; | |
344 fmt->rewind_sample = rewind_sample_fmt_normal; | |
345 fmt->seek_sample = seek_sample_fmt_normal; | |
346 return(1); | |
347 } /* read_fmt_normal */ | |
348 | |
349 | |
350 | |
351 /***************************************************************************** | |
352 * ADPCM compression handler... * | |
353 *****************************************************************************/ | |
354 | |
355 #define FIXED_POINT_COEF_BASE 256 | |
356 #define FIXED_POINT_ADAPTION_BASE 256 | |
357 #define SMALLEST_ADPCM_DELTA 16 | |
358 | |
359 | |
360 static __inline__ int read_adpcm_block_headers(Sound_Sample *sample) | |
361 { | |
362 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
363 ALmixer_RWops *rw = internal->rw; | |
364 wav_t *w = (wav_t *) internal->decoder_private; | |
365 fmt_t *fmt = w->fmt; | |
366 ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders; | |
367 int i; | |
368 int max = fmt->wChannels; | |
369 | |
370 if (w->bytesLeft < fmt->wBlockAlign) | |
371 { | |
372 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
373 return(0); | |
374 } /* if */ | |
375 | |
376 w->bytesLeft -= fmt->wBlockAlign; | |
377 | |
378 for (i = 0; i < max; i++) | |
379 BAIL_IF_MACRO(!read_uint8_t(rw, &headers[i].bPredictor), NULL, 0); | |
380 | |
381 for (i = 0; i < max; i++) | |
382 BAIL_IF_MACRO(!read_le16(rw, &headers[i].iDelta), NULL, 0); | |
383 | |
384 for (i = 0; i < max; i++) | |
385 BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp1), NULL, 0); | |
386 | |
387 for (i = 0; i < max; i++) | |
388 BAIL_IF_MACRO(!read_le16(rw, &headers[i].iSamp2), NULL, 0); | |
389 | |
390 fmt->fmt.adpcm.samples_left_in_block = fmt->fmt.adpcm.wSamplesPerBlock; | |
391 fmt->fmt.adpcm.nibble_state = 0; | |
392 return(1); | |
393 } /* read_adpcm_block_headers */ | |
394 | |
395 | |
396 static __inline__ void do_adpcm_nibble(uint8_t nib, | |
397 ADPCMBLOCKHEADER *header, | |
398 int32_t lPredSamp) | |
399 { | |
400 static const int32_t max_audioval = ((1<<(16-1))-1); | |
401 static const int32_t min_audioval = -(1<<(16-1)); | |
402 static const int32_t AdaptionTable[] = | |
403 { | |
404 230, 230, 230, 230, 307, 409, 512, 614, | |
405 768, 614, 512, 409, 307, 230, 230, 230 | |
406 }; | |
407 | |
408 int32_t lNewSamp; | |
409 int32_t delta; | |
410 | |
411 if (nib & 0x08) | |
412 lNewSamp = lPredSamp + (header->iDelta * (nib - 0x10)); | |
413 else | |
414 lNewSamp = lPredSamp + (header->iDelta * nib); | |
415 | |
416 /* clamp value... */ | |
417 if (lNewSamp < min_audioval) | |
418 lNewSamp = min_audioval; | |
419 else if (lNewSamp > max_audioval) | |
420 lNewSamp = max_audioval; | |
421 | |
422 delta = ((int32_t) header->iDelta * AdaptionTable[nib]) / | |
423 FIXED_POINT_ADAPTION_BASE; | |
424 | |
425 if (delta < SMALLEST_ADPCM_DELTA) | |
426 delta = SMALLEST_ADPCM_DELTA; | |
427 | |
428 header->iDelta = delta; | |
429 header->iSamp2 = header->iSamp1; | |
430 header->iSamp1 = lNewSamp; | |
431 } /* do_adpcm_nibble */ | |
432 | |
433 | |
434 static __inline__ int decode_adpcm_sample_frame(Sound_Sample *sample) | |
435 { | |
436 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
437 wav_t *w = (wav_t *) internal->decoder_private; | |
438 fmt_t *fmt = w->fmt; | |
439 ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders; | |
440 ALmixer_RWops *rw = internal->rw; | |
441 int i; | |
442 int max = fmt->wChannels; | |
443 int32_t delta; | |
444 uint8_t nib = fmt->fmt.adpcm.nibble; | |
445 | |
446 for (i = 0; i < max; i++) | |
447 { | |
448 uint8_t byte; | |
449 int16_t iCoef1 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef1; | |
450 int16_t iCoef2 = fmt->fmt.adpcm.aCoef[headers[i].bPredictor].iCoef2; | |
451 int32_t lPredSamp = ((headers[i].iSamp1 * iCoef1) + | |
452 (headers[i].iSamp2 * iCoef2)) / | |
453 FIXED_POINT_COEF_BASE; | |
454 | |
455 if (fmt->fmt.adpcm.nibble_state == 0) | |
456 { | |
457 BAIL_IF_MACRO(!read_uint8_t(rw, &nib), NULL, 0); | |
458 fmt->fmt.adpcm.nibble_state = 1; | |
459 do_adpcm_nibble(nib >> 4, &headers[i], lPredSamp); | |
460 } /* if */ | |
461 else | |
462 { | |
463 fmt->fmt.adpcm.nibble_state = 0; | |
464 do_adpcm_nibble(nib & 0x0F, &headers[i], lPredSamp); | |
465 } /* else */ | |
466 } /* for */ | |
467 | |
468 fmt->fmt.adpcm.nibble = nib; | |
469 return(1); | |
470 } /* decode_adpcm_sample_frame */ | |
471 | |
472 | |
473 static __inline__ void put_adpcm_sample_frame1(void *_buf, fmt_t *fmt) | |
474 { | |
475 uint16_t *buf = (uint16_t *) _buf; | |
476 ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders; | |
477 int i; | |
478 for (i = 0; i < fmt->wChannels; i++) | |
479 *(buf++) = headers[i].iSamp1; | |
480 } /* put_adpcm_sample_frame1 */ | |
481 | |
482 | |
483 static __inline__ void put_adpcm_sample_frame2(void *_buf, fmt_t *fmt) | |
484 { | |
485 uint16_t *buf = (uint16_t *) _buf; | |
486 ADPCMBLOCKHEADER *headers = fmt->fmt.adpcm.blockheaders; | |
487 int i; | |
488 for (i = 0; i < fmt->wChannels; i++) | |
489 *(buf++) = headers[i].iSamp2; | |
490 } /* put_adpcm_sample_frame2 */ | |
491 | |
492 | |
493 /* | |
494 * Sound_Decode() lands here for ADPCM-encoded WAVs... | |
495 */ | |
496 static uint32_t read_sample_fmt_adpcm(Sound_Sample *sample) | |
497 { | |
498 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
499 wav_t *w = (wav_t *) internal->decoder_private; | |
500 fmt_t *fmt = w->fmt; | |
501 uint32_t bw = 0; | |
502 | |
503 while (bw < internal->buffer_size) | |
504 { | |
505 /* write ongoing sample frame before reading more data... */ | |
506 switch (fmt->fmt.adpcm.samples_left_in_block) | |
507 { | |
508 case 0: /* need to read a new block... */ | |
509 if (!read_adpcm_block_headers(sample)) | |
510 { | |
511 if ((sample->flags & SOUND_SAMPLEFLAG_EOF) == 0) | |
512 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
513 return(bw); | |
514 } /* if */ | |
515 | |
516 /* only write first sample frame for now. */ | |
517 put_adpcm_sample_frame2((uint8_t *) internal->buffer + bw, fmt); | |
518 fmt->fmt.adpcm.samples_left_in_block--; | |
519 bw += fmt->sample_frame_size; | |
520 break; | |
521 | |
522 case 1: /* output last sample frame of block... */ | |
523 put_adpcm_sample_frame1((uint8_t *) internal->buffer + bw, fmt); | |
524 fmt->fmt.adpcm.samples_left_in_block--; | |
525 bw += fmt->sample_frame_size; | |
526 break; | |
527 | |
528 default: /* output latest sample frame and read a new one... */ | |
529 put_adpcm_sample_frame1((uint8_t *) internal->buffer + bw, fmt); | |
530 fmt->fmt.adpcm.samples_left_in_block--; | |
531 bw += fmt->sample_frame_size; | |
532 | |
533 if (!decode_adpcm_sample_frame(sample)) | |
534 { | |
535 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
536 return(bw); | |
537 } /* if */ | |
538 } /* switch */ | |
539 } /* while */ | |
540 | |
541 return(bw); | |
542 } /* read_sample_fmt_adpcm */ | |
543 | |
544 | |
545 /* | |
546 * Sound_FreeSample() lands here for ADPCM-encoded WAVs... | |
547 */ | |
548 static void free_fmt_adpcm(fmt_t *fmt) | |
549 { | |
550 if (fmt->fmt.adpcm.aCoef != NULL) | |
551 free(fmt->fmt.adpcm.aCoef); | |
552 | |
553 if (fmt->fmt.adpcm.blockheaders != NULL) | |
554 free(fmt->fmt.adpcm.blockheaders); | |
555 } /* free_fmt_adpcm */ | |
556 | |
557 | |
558 static int rewind_sample_fmt_adpcm(Sound_Sample *sample) | |
559 { | |
560 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
561 wav_t *w = (wav_t *) internal->decoder_private; | |
562 w->fmt->fmt.adpcm.samples_left_in_block = 0; | |
563 return(1); | |
564 } /* rewind_sample_fmt_adpcm */ | |
565 | |
566 | |
567 static int seek_sample_fmt_adpcm(Sound_Sample *sample, uint32_t ms) | |
568 { | |
569 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
570 wav_t *w = (wav_t *) internal->decoder_private; | |
571 fmt_t *fmt = w->fmt; | |
572 uint32_t origsampsleft = fmt->fmt.adpcm.samples_left_in_block; | |
573 int origpos = ALmixer_RWtell(internal->rw); | |
574 int offset = __Sound_convertMsToBytePos(&sample->actual, ms); | |
575 int bpb = (fmt->fmt.adpcm.wSamplesPerBlock * fmt->sample_frame_size); | |
576 int skipsize = (offset / bpb) * fmt->wBlockAlign; | |
577 int pos = skipsize + fmt->data_starting_offset; | |
578 int rc = ALmixer_RWseek(internal->rw, pos, SEEK_SET); | |
579 BAIL_IF_MACRO(rc != pos, ERR_IO_ERROR, 0); | |
580 | |
581 /* The offset we need is in this block, so we need to decode to there. */ | |
582 skipsize += (offset % bpb); | |
583 rc = (offset % bpb); /* bytes into this block we need to decode */ | |
584 if (!read_adpcm_block_headers(sample)) | |
585 { | |
586 ALmixer_RWseek(internal->rw, origpos, SEEK_SET); /* try to make sane. */ | |
587 return(0); | |
588 } /* if */ | |
589 | |
590 /* first sample frame of block is a freebie. :) */ | |
591 fmt->fmt.adpcm.samples_left_in_block--; | |
592 rc -= fmt->sample_frame_size; | |
593 while (rc > 0) | |
594 { | |
595 if (!decode_adpcm_sample_frame(sample)) | |
596 { | |
597 ALmixer_RWseek(internal->rw, origpos, SEEK_SET); | |
598 fmt->fmt.adpcm.samples_left_in_block = origsampsleft; | |
599 return(0); | |
600 } /* if */ | |
601 | |
602 fmt->fmt.adpcm.samples_left_in_block--; | |
603 rc -= fmt->sample_frame_size; | |
604 } /* while */ | |
605 | |
606 w->bytesLeft = fmt->total_bytes - skipsize; | |
607 return(1); /* success. */ | |
608 } /* seek_sample_fmt_adpcm */ | |
609 | |
610 | |
611 /* | |
612 * Read in the adpcm-specific info from disk. This makes this process | |
613 * safe regardless of the processor's byte order or how the fmt_t | |
614 * structure is packed. | |
615 */ | |
616 static int read_fmt_adpcm(ALmixer_RWops *rw, fmt_t *fmt) | |
617 { | |
618 size_t i; | |
619 | |
620 memset(&fmt->fmt.adpcm, '\0', sizeof (fmt->fmt.adpcm)); | |
621 fmt->free = free_fmt_adpcm; | |
622 fmt->read_sample = read_sample_fmt_adpcm; | |
623 fmt->rewind_sample = rewind_sample_fmt_adpcm; | |
624 fmt->seek_sample = seek_sample_fmt_adpcm; | |
625 | |
626 BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.cbSize), NULL, 0); | |
627 BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wSamplesPerBlock), NULL, 0); | |
628 BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.wNumCoef), NULL, 0); | |
629 | |
630 /* fmt->free() is always called, so these malloc()s will be cleaned up. */ | |
631 | |
632 i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef; | |
633 fmt->fmt.adpcm.aCoef = (ADPCMCOEFSET *) malloc(i); | |
634 BAIL_IF_MACRO(fmt->fmt.adpcm.aCoef == NULL, ERR_OUT_OF_MEMORY, 0); | |
635 | |
636 for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++) | |
637 { | |
638 BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef1), NULL, 0); | |
639 BAIL_IF_MACRO(!read_le16(rw, &fmt->fmt.adpcm.aCoef[i].iCoef2), NULL, 0); | |
640 } /* for */ | |
641 | |
642 i = sizeof (ADPCMBLOCKHEADER) * fmt->wChannels; | |
643 fmt->fmt.adpcm.blockheaders = (ADPCMBLOCKHEADER *) malloc(i); | |
644 BAIL_IF_MACRO(fmt->fmt.adpcm.blockheaders == NULL, ERR_OUT_OF_MEMORY, 0); | |
645 | |
646 return(1); | |
647 } /* read_fmt_adpcm */ | |
648 | |
649 | |
650 | |
651 /***************************************************************************** | |
652 * Everything else... * | |
653 *****************************************************************************/ | |
654 | |
655 static int WAV_init(void) | |
656 { | |
657 return(1); /* always succeeds. */ | |
658 } /* WAV_init */ | |
659 | |
660 | |
661 static void WAV_quit(void) | |
662 { | |
663 /* it's a no-op. */ | |
664 } /* WAV_quit */ | |
665 | |
666 | |
667 static int read_fmt(ALmixer_RWops *rw, fmt_t *fmt) | |
668 { | |
669 /* if it's in this switch statement, we support the format. */ | |
670 switch (fmt->wFormatTag) | |
671 { | |
672 case FMT_NORMAL: | |
673 SNDDBG(("WAV: Appears to be uncompressed audio.\n")); | |
674 return(read_fmt_normal(rw, fmt)); | |
675 | |
676 case FMT_ADPCM: | |
677 SNDDBG(("WAV: Appears to be ADPCM compressed audio.\n")); | |
678 return(read_fmt_adpcm(rw, fmt)); | |
679 | |
680 /* add other types here. */ | |
681 | |
682 default: | |
683 #ifdef ANDROID_NDK | |
684 SNDDBG(("WAV: Format is unknown.\n")); | |
685 #else | |
686 SNDDBG(("WAV: Format 0x%X is unknown.\n", | |
687 (unsigned int) fmt->wFormatTag)); | |
688 #endif | |
689 BAIL_MACRO("WAV: Unsupported format", 0); | |
690 } /* switch */ | |
691 | |
692 assert(0); /* shouldn't hit this point. */ | |
693 return(0); | |
694 } /* read_fmt */ | |
695 | |
696 | |
697 /* | |
698 * Locate a specific chunk in the WAVE file by ID... | |
699 */ | |
700 static int find_chunk(ALmixer_RWops *rw, uint32_t id) | |
701 { | |
702 int32_t siz = 0; | |
703 uint32_t _id = 0; | |
704 uint32_t pos = ALmixer_RWtell(rw); | |
705 | |
706 while (1) | |
707 { | |
708 BAIL_IF_MACRO(!read_le32(rw, &_id), NULL, 0); | |
709 if (_id == id) | |
710 return(1); | |
711 | |
712 /* skip ahead and see what next chunk is... */ | |
713 BAIL_IF_MACRO(!read_le32(rw, &siz), NULL, 0); | |
714 assert(siz >= 0); | |
715 pos += (sizeof (uint32_t) * 2) + siz; | |
716 if (siz > 0) | |
717 BAIL_IF_MACRO(ALmixer_RWseek(rw, pos, SEEK_SET) != pos, NULL, 0); | |
718 } /* while */ | |
719 | |
720 return(0); /* shouldn't hit this, but just in case... */ | |
721 } /* find_chunk */ | |
722 | |
723 | |
724 static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt) | |
725 { | |
726 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
727 ALmixer_RWops *rw = internal->rw; | |
728 data_t d; | |
729 wav_t *w; | |
730 uint32_t pos; | |
731 | |
732 BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0); | |
733 SDL_ReadLE32(rw); /* throw the length away; we get this info later. */ | |
734 BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0); | |
735 BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0); | |
736 BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0); | |
737 | |
738 sample->actual.channels = (uint8_t) fmt->wChannels; | |
739 sample->actual.rate = fmt->dwSamplesPerSec; | |
740 if ((fmt->wBitsPerSample == 4) /*|| (fmt->wBitsPerSample == 0) */ ) | |
741 sample->actual.format = AUDIO_S16SYS; | |
742 else if (fmt->wBitsPerSample == 8) | |
743 sample->actual.format = AUDIO_U8; | |
744 else if (fmt->wBitsPerSample == 16) | |
745 sample->actual.format = AUDIO_S16LSB; | |
746 else | |
747 { | |
748 #ifdef ANDROID_NDK | |
749 SNDDBG(("WAV: unsupported sample size.\n")); | |
750 #else | |
751 SNDDBG(("WAV: %d bits per sample!?\n", (int) fmt->wBitsPerSample)); | |
752 #endif | |
753 BAIL_MACRO("WAV: Unsupported sample size.", 0); | |
754 } /* else */ | |
755 | |
756 BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0); | |
757 ALmixer_RWseek(rw, fmt->next_chunk_offset, SEEK_SET); | |
758 BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0); | |
759 BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0); | |
760 | |
761 w = (wav_t *) malloc(sizeof(wav_t)); | |
762 BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0); | |
763 w->fmt = fmt; | |
764 fmt->total_bytes = w->bytesLeft = d.chunkSize; | |
765 fmt->data_starting_offset = ALmixer_RWtell(rw); | |
766 fmt->sample_frame_size = ( ((sample->actual.format & 0xFF) / 8) * | |
767 sample->actual.channels ); | |
768 internal->decoder_private = (void *) w; | |
769 | |
770 internal->total_time = (fmt->total_bytes / fmt->dwAvgBytesPerSec) * 1000; | |
771 internal->total_time += (fmt->total_bytes % fmt->dwAvgBytesPerSec) | |
772 * 1000 / fmt->dwAvgBytesPerSec; | |
773 | |
774 sample->flags = SOUND_SAMPLEFLAG_NONE; | |
775 if (fmt->seek_sample != NULL) | |
776 sample->flags |= SOUND_SAMPLEFLAG_CANSEEK; | |
777 | |
778 SNDDBG(("WAV: Accepting data stream.\n")); | |
779 return(1); /* we'll handle this data. */ | |
780 } /* WAV_open_internal */ | |
781 | |
782 | |
783 static int WAV_open(Sound_Sample *sample, const char *ext) | |
784 { | |
785 int rc; | |
786 | |
787 fmt_t *fmt = (fmt_t *) malloc(sizeof (fmt_t)); | |
788 BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0); | |
789 memset(fmt, '\0', sizeof (fmt_t)); | |
790 | |
791 rc = WAV_open_internal(sample, ext, fmt); | |
792 if (!rc) | |
793 { | |
794 if (fmt->free != NULL) | |
795 fmt->free(fmt); | |
796 free(fmt); | |
797 } /* if */ | |
798 | |
799 return(rc); | |
800 } /* WAV_open */ | |
801 | |
802 | |
803 static void WAV_close(Sound_Sample *sample) | |
804 { | |
805 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
806 wav_t *w = (wav_t *) internal->decoder_private; | |
807 | |
808 if (w->fmt->free != NULL) | |
809 w->fmt->free(w->fmt); | |
810 | |
811 free(w->fmt); | |
812 free(w); | |
813 } /* WAV_close */ | |
814 | |
815 | |
816 static uint32_t WAV_read(Sound_Sample *sample) | |
817 { | |
818 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
819 wav_t *w = (wav_t *) internal->decoder_private; | |
820 return(w->fmt->read_sample(sample)); | |
821 } /* WAV_read */ | |
822 | |
823 | |
824 static int WAV_rewind(Sound_Sample *sample) | |
825 { | |
826 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
827 wav_t *w = (wav_t *) internal->decoder_private; | |
828 fmt_t *fmt = w->fmt; | |
829 int rc = ALmixer_RWseek(internal->rw, fmt->data_starting_offset, SEEK_SET); | |
830 BAIL_IF_MACRO(rc != fmt->data_starting_offset, ERR_IO_ERROR, 0); | |
831 w->bytesLeft = fmt->total_bytes; | |
832 return(fmt->rewind_sample(sample)); | |
833 } /* WAV_rewind */ | |
834 | |
835 | |
836 static int WAV_seek(Sound_Sample *sample, uint32_t ms) | |
837 { | |
838 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
839 wav_t *w = (wav_t *) internal->decoder_private; | |
840 return(w->fmt->seek_sample(sample, ms)); | |
841 } /* WAV_seek */ | |
842 | |
843 #endif /* SOUND_SUPPORTS_WAV */ | |
844 | |
845 /* end of wav.c ... */ | |
846 |