comparison decoders/wav.c @ 124:e46e31fdecfd

Restructured to handle multiple formats.
author Ryan C. Gordon <icculus@icculus.org>
date Mon, 08 Oct 2001 19:13:16 +0000
parents 40de367eb59e
children 1df5c106504e
comparison
equal deleted inserted replaced
123:4996bb1ae449 124:e46e31fdecfd
64 WAV_open, /* open() method */ 64 WAV_open, /* open() method */
65 WAV_close, /* close() method */ 65 WAV_close, /* close() method */
66 WAV_read /* read() method */ 66 WAV_read /* read() method */
67 }; 67 };
68 68
69 69 static int WAV_init(void)
70 /* this is what we store in our internal->decoder_private field... */ 70 {
71 typedef struct 71 return(1); /* always succeeds. */
72 { 72 } /* WAV_init */
73 Sint32 bytesLeft; 73
74 } wav_t; 74
75 static void WAV_quit(void)
76 {
77 /* it's a no-op. */
78 } /* WAV_quit */
79
75 80
76 81
77 /* Chunk management code... */ 82 /* Chunk management code... */
78 83
79 #define riffID 0x46464952 /* "RIFF", in ascii. */ 84 #define riffID 0x46464952 /* "RIFF", in ascii. */
80 #define waveID 0x45564157 /* "WAVE", in ascii. */ 85 #define waveID 0x45564157 /* "WAVE", in ascii. */
81 86
82 87
88 /*****************************************************************************
89 * The FORMAT chunk... *
90 *****************************************************************************/
91
83 #define fmtID 0x20746D66 /* "fmt ", in ascii. */ 92 #define fmtID 0x20746D66 /* "fmt ", in ascii. */
84 93
85 #define FMT_NORMAL 1 /* Uncompressed waveform data. */ 94 #define FMT_NORMAL 0x0001 /* Uncompressed waveform data. */
86 95 #define FMT_ADPCM 0x0002 /* ADPCM compressed waveform data. */
87 typedef struct 96
97 typedef struct {
98 Uint16 iCoef1;
99 Uint16 iCoef2;
100 } ADPCMCOEFSET;
101
102 typedef struct S_FMT_T
88 { 103 {
89 Uint32 chunkID; 104 Uint32 chunkID;
90 Sint32 chunkSize; 105 Sint32 chunkSize;
91 Sint16 wFormatTag; 106 Sint16 wFormatTag;
92 Uint16 wChannels; 107 Uint16 wChannels;
93 Uint32 dwSamplesPerSec; 108 Uint32 dwSamplesPerSec;
94 Uint32 dwAvgBytesPerSec; 109 Uint32 dwAvgBytesPerSec;
95 Uint16 wBlockAlign; 110 Uint16 wBlockAlign;
96 Uint16 wBitsPerSample; 111 Uint16 wBitsPerSample;
112
113 void (*free)(struct S_FMT_T *fmt);
114 Uint32(*read_sample)(Sound_Sample *sample);
115
116 union
117 {
118 struct
119 {
120 Uint16 cbSize;
121 Uint16 wSamplesPerBlock;
122 Uint16 wNumCoef;
123 ADPCMCOEFSET *aCoeff;
124 } adpcm;
125 } fmt;
97 } fmt_t; 126 } fmt_t;
98
99
100 static int WAV_init(void)
101 {
102 return(1); /* always succeeds. */
103 } /* WAV_init */
104
105
106 static void WAV_quit(void)
107 {
108 /* it's a no-op. */
109 } /* WAV_quit */
110 127
111 128
112 /* 129 /*
113 * Read in a fmt_t from disk. This makes this process safe regardless of 130 * Read in a fmt_t from disk. This makes this process safe regardless of
114 * the processor's byte order or how the fmt_t structure is packed. 131 * the processor's byte order or how the fmt_t structure is packed.
132 * Note that the union "fmt" is not read in here; that is handled as
133 * needed in the read_fmt_* functions.
115 */ 134 */
116 static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt) 135 static int read_fmt_chunk(SDL_RWops *rw, fmt_t *fmt)
117 { 136 {
118 /* skip reading the chunk ID, since it was already read at this point... */ 137 /* skip reading the chunk ID, since it was already read at this point... */
119 fmt->chunkID = fmtID; 138 fmt->chunkID = fmtID;
150 fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample); 169 fmt->wBitsPerSample = SDL_SwapLE16(fmt->wBitsPerSample);
151 170
152 return(1); 171 return(1);
153 } /* read_fmt_chunk */ 172 } /* read_fmt_chunk */
154 173
174
175
176 /*****************************************************************************
177 * The DATA chunk... *
178 *****************************************************************************/
155 179
156 #define dataID 0x61746164 /* "data", in ascii. */ 180 #define dataID 0x61746164 /* "data", in ascii. */
157 181
158 typedef struct 182 typedef struct
159 { 183 {
162 /* Then, (chunkSize) bytes of waveform data... */ 186 /* Then, (chunkSize) bytes of waveform data... */
163 } data_t; 187 } data_t;
164 188
165 189
166 /* 190 /*
167 * Read in a fmt_t from disk. This makes this process safe regardless of 191 * Read in a data_t from disk. This makes this process safe regardless of
168 * the processor's byte order or how the fmt_t structure is packed. 192 * the processor's byte order or how the fmt_t structure is packed.
169 */ 193 */
170 static int read_data_chunk(SDL_RWops *rw, data_t *data) 194 static int read_data_chunk(SDL_RWops *rw, data_t *data)
171 { 195 {
172 /* skip reading the chunk ID, since it was already read at this point... */ 196 /* skip reading the chunk ID, since it was already read at this point... */
178 202
179 return(1); 203 return(1);
180 } /* read_data_chunk */ 204 } /* read_data_chunk */
181 205
182 206
207
208
209 /*****************************************************************************
210 * this is what we store in our internal->decoder_private field... *
211 *****************************************************************************/
212
213 typedef struct
214 {
215 fmt_t *fmt;
216 Sint32 bytesLeft;
217 } wav_t;
218
219
220
221
222 /*****************************************************************************
223 * Normal, uncompressed waveform handler... *
224 *****************************************************************************/
225
226 static Uint32 read_sample_fmt_normal(Sound_Sample *sample)
227 {
228 Uint32 retval;
229 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
230 wav_t *w = (wav_t *) internal->decoder_private;
231 Uint32 max = (internal->buffer_size < (Uint32) w->bytesLeft) ?
232 internal->buffer_size : (Uint32) w->bytesLeft;
233
234 assert(max > 0);
235
236 /*
237 * We don't actually do any decoding, so we read the wav data
238 * directly into the internal buffer...
239 */
240 retval = SDL_RWread(internal->rw, internal->buffer, 1, max);
241
242 w->bytesLeft -= retval;
243
244 /* Make sure the read went smoothly... */
245 if ((retval == 0) || (w->bytesLeft == 0))
246 sample->flags |= SOUND_SAMPLEFLAG_EOF;
247
248 else if (retval == -1)
249 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
250
251 /* (next call this EAGAIN may turn into an EOF or error.) */
252 else if (retval < internal->buffer_size)
253 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
254
255 return(retval);
256 } /* read_sample_fmt_normal */
257
258
259 static void free_fmt_normal(fmt_t *fmt)
260 {
261 /* it's a no-op. */
262 } /* free_fmt_normal */
263
264
265 static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt)
266 {
267 fmt->free = free_fmt_normal;
268 fmt->read_sample = read_sample_fmt_normal;
269 return(1);
270 } /* read_fmt_normal */
271
272
273
274 /*****************************************************************************
275 * ADPCM compression handler... *
276 *****************************************************************************/
277
278 static Uint32 read_sample_fmt_adpcm(Sound_Sample *sample)
279 {
280 /* !!! FIXME: Write this. */
281 sample->flags | SOUND_SAMPLEFLAG_ERROR;
282 return(0);
283 } /* read_sample_fmt_adpcm */
284
285
286 static void free_fmt_adpcm(fmt_t *fmt)
287 {
288 if (fmt->fmt.adpcm.aCoeff != NULL)
289 free(fmt->fmt.adpcm.aCoeff);
290 } /* free_fmt_adpcm */
291
292
293 /*
294 * Read in a the adpcm-specific info from disk. This makes this process
295 * safe regardless of the processor's byte order or how the fmt_t
296 * structure is packed.
297 */
298 static int read_fmt_adpcm(SDL_RWops *rw, fmt_t *fmt)
299 {
300 size_t i;
301
302 fmt->fmt.adpcm.aCoeff = NULL;
303 fmt->free = free_fmt_adpcm;
304 fmt->read_sample = read_sample_fmt_adpcm;
305
306 if (SDL_RWread(rw, &fmt->fmt.adpcm.cbSize,
307 sizeof (fmt->fmt.adpcm.cbSize), 1) != 1)
308 {
309 return(0);
310 } /* if */
311 fmt->fmt.adpcm.cbSize = SDL_SwapLE16(fmt->fmt.adpcm.cbSize);
312
313 if (SDL_RWread(rw, &fmt->fmt.adpcm.wSamplesPerBlock,
314 sizeof (fmt->fmt.adpcm.wSamplesPerBlock), 1) != 1)
315 {
316 return(0);
317 } /* if */
318 fmt->fmt.adpcm.wSamplesPerBlock = SDL_SwapLE16(fmt->fmt.adpcm.wSamplesPerBlock);
319
320 if (SDL_RWread(rw, &fmt->fmt.adpcm.wNumCoef,
321 sizeof (fmt->fmt.adpcm.wNumCoef), 1) != 1)
322 {
323 return(0);
324 } /* if */
325 fmt->fmt.adpcm.wNumCoef = SDL_SwapLE16(fmt->fmt.adpcm.wNumCoef);
326
327 i = sizeof (ADPCMCOEFSET) * fmt->fmt.adpcm.wNumCoef;
328 fmt->fmt.adpcm.aCoeff = (ADPCMCOEFSET *) malloc(i);
329 BAIL_IF_MACRO(fmt->fmt.adpcm.aCoeff == NULL, ERR_OUT_OF_MEMORY, 0);
330
331 for (i = 0; i < fmt->fmt.adpcm.wNumCoef; i++)
332 {
333 if (SDL_RWread(rw, &fmt->fmt.adpcm.aCoeff[i].iCoef1,
334 sizeof (fmt->fmt.adpcm.aCoeff[i].iCoef1), 1) != 1)
335 {
336 return(0);
337 } /* if */
338
339 if (SDL_RWread(rw, &fmt->fmt.adpcm.aCoeff[i].iCoef2,
340 sizeof (fmt->fmt.adpcm.aCoeff[i].iCoef2), 1) != 1)
341 {
342 return(0);
343 } /* if */
344 } /* for */
345
346 return(1);
347 } /* read_fmt_adpcm */
348
349
350 /*****************************************************************************
351 * Everything else... *
352 *****************************************************************************/
353
354
355 static int read_fmt(SDL_RWops *rw, fmt_t *fmt)
356 {
357 /* if it's in this switch statement, we support the format. */
358 switch (fmt->wFormatTag)
359 {
360 case FMT_NORMAL:
361 return(read_fmt_normal(rw, fmt));
362
363 case FMT_ADPCM:
364 return(read_fmt_adpcm(rw, fmt));
365 } /* switch */
366
367 SNDDBG(("WAV: Format %d is unknown.\n", (int) fmt->wFormatTag));
368 Sound_SetError("WAV: Unsupported format");
369 return(0); /* not supported whatsoever. */
370 } /* read_fmt */
371
372
373 /*
374 * Locate a specific chunk in the WAVE file by ID...
375 */
183 static int find_chunk(SDL_RWops *rw, Uint32 id) 376 static int find_chunk(SDL_RWops *rw, Uint32 id)
184 { 377 {
185 Sint32 siz = 0; 378 Sint32 siz = 0;
186 Uint32 _id = 0; 379 Uint32 _id = 0;
187 380
199 392
200 return(0); /* shouldn't hit this, but just in case... */ 393 return(0); /* shouldn't hit this, but just in case... */
201 } /* find_chunk */ 394 } /* find_chunk */
202 395
203 396
204 static int WAV_open(Sound_Sample *sample, const char *ext) 397 static int WAV_open_internal(Sound_Sample *sample, const char *ext, fmt_t *fmt)
205 { 398 {
206 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 399 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
207 SDL_RWops *rw = internal->rw; 400 SDL_RWops *rw = internal->rw;
208 fmt_t f;
209 data_t d; 401 data_t d;
210 wav_t *w; 402 wav_t *w;
211 403
212 BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0); 404 BAIL_IF_MACRO(SDL_ReadLE32(rw) != riffID, "WAV: Not a RIFF file.", 0);
213 SDL_ReadLE32(rw); /* throw the length away; we get this info later. */ 405 SDL_ReadLE32(rw); /* throw the length away; we get this info later. */
214 BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0); 406 BAIL_IF_MACRO(SDL_ReadLE32(rw) != waveID, "WAV: Not a WAVE file.", 0);
215 BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0); 407 BAIL_IF_MACRO(!find_chunk(rw, fmtID), "WAV: No format chunk.", 0);
216 BAIL_IF_MACRO(!read_fmt_chunk(rw, &f), "WAV: Can't read format chunk.", 0); 408 BAIL_IF_MACRO(!read_fmt_chunk(rw, fmt), "WAV: Can't read format chunk.", 0);
217 409
218 /* !!! FIXME: This will have to change for compression types... */ 410 sample->actual.channels = (Uint8) fmt->wChannels;
219 BAIL_IF_MACRO(f.wFormatTag != FMT_NORMAL, "WAV: Unsupported encoding.", 0); 411 sample->actual.rate = fmt->dwSamplesPerSec;
220 412 if (fmt->wBitsPerSample <= 8)
221 sample->actual.channels = (Uint8) f.wChannels;
222 sample->actual.rate = f.dwSamplesPerSec;
223
224 if (f.wBitsPerSample <= 8)
225 sample->actual.format = AUDIO_U8; 413 sample->actual.format = AUDIO_U8;
226 else if (f.wBitsPerSample <= 16) 414 else if (fmt->wBitsPerSample <= 16)
227 sample->actual.format = AUDIO_S16LSB; 415 sample->actual.format = AUDIO_S16LSB;
228 else 416 else
229 BAIL_MACRO("WAV: Unsupported sample size.", 0); 417 BAIL_MACRO("WAV: Unsupported sample size.", 0);
230 418
419 BAIL_IF_MACRO(!read_fmt(rw, fmt), NULL, 0);
231 BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0); 420 BAIL_IF_MACRO(!find_chunk(rw, dataID), "WAV: No data chunk.", 0);
232 BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0); 421 BAIL_IF_MACRO(!read_data_chunk(rw, &d), "WAV: Can't read data chunk.", 0);
233 422
234 w = (wav_t *) malloc(sizeof(wav_t)); 423 w = (wav_t *) malloc(sizeof(wav_t));
235 BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0); 424 BAIL_IF_MACRO(w == NULL, ERR_OUT_OF_MEMORY, 0);
425 w->fmt = fmt;
236 w->bytesLeft = d.chunkSize; 426 w->bytesLeft = d.chunkSize;
237 internal->decoder_private = (void *) w; 427 internal->decoder_private = (void *) w;
238 428
239 sample->flags = SOUND_SAMPLEFLAG_NONE; 429 sample->flags = SOUND_SAMPLEFLAG_NONE;
240 430
241 SNDDBG(("WAV: Accepting data stream.\n")); 431 SNDDBG(("WAV: Accepting data stream.\n"));
242 return(1); /* we'll handle this data. */ 432 return(1); /* we'll handle this data. */
433 } /* WAV_open_internal */
434
435
436 static int WAV_open(Sound_Sample *sample, const char *ext)
437 {
438 int rc;
439
440 fmt_t *fmt = (fmt_t *) malloc(sizeof (fmt_t));
441 BAIL_IF_MACRO(fmt == NULL, ERR_OUT_OF_MEMORY, 0);
442 memset(fmt, '\0', sizeof (fmt_t));
443
444 rc = WAV_open_internal(sample, ext, fmt);
445 if (!rc)
446 {
447 if (fmt->free != NULL)
448 fmt->free(fmt);
449 free(fmt);
450 } /* if */
451
452 return(rc);
243 } /* WAV_open */ 453 } /* WAV_open */
244 454
245 455
246 static void WAV_close(Sound_Sample *sample) 456 static void WAV_close(Sound_Sample *sample)
247 { 457 {
248 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
249 free(internal->decoder_private);
250 } /* WAV_close */
251
252
253 static Uint32 WAV_read(Sound_Sample *sample)
254 {
255 Uint32 retval;
256 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; 458 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
257 wav_t *w = (wav_t *) internal->decoder_private; 459 wav_t *w = (wav_t *) internal->decoder_private;
258 Uint32 max = (internal->buffer_size < (Uint32) w->bytesLeft) ? 460 w->fmt->free(w->fmt);
259 internal->buffer_size : (Uint32) w->bytesLeft; 461 free(w->fmt);
260 462 free(w);
261 assert(max > 0); 463 } /* WAV_close */
262 464
263 /* 465
264 * We don't actually do any decoding, so we read the wav data 466 static Uint32 WAV_read(Sound_Sample *sample)
265 * directly into the internal buffer... 467 {
266 */ 468 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
267 retval = SDL_RWread(internal->rw, internal->buffer, 1, max); 469 wav_t *w = (wav_t *) internal->decoder_private;
268 470 return(w->fmt->read_sample(sample));
269 w->bytesLeft -= retval;
270
271 /* Make sure the read went smoothly... */
272 if ((retval == 0) || (w->bytesLeft == 0))
273 sample->flags |= SOUND_SAMPLEFLAG_EOF;
274
275 else if (retval == -1)
276 sample->flags |= SOUND_SAMPLEFLAG_ERROR;
277
278 /* (next call this EAGAIN may turn into an EOF or error.) */
279 else if (retval < internal->buffer_size)
280 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
281
282 return(retval);
283 } /* WAV_read */ 471 } /* WAV_read */
284 472
285 #endif /* SOUND_SUPPORTS_WAV */ 473 #endif /* SOUND_SUPPORTS_WAV */
286 474
287 /* end of wav.c ... */ 475 /* end of wav.c ... */