Mercurial > SDL_sound_CoreAudio
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 ... */ |