38
|
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
|