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