Mercurial > SDL_sound_CoreAudio
comparison decoders/aiff.c @ 180:db3f0ee7aac0
Modified to more easily allow for different compression types.
author | Ryan C. Gordon <icculus@icculus.org> |
---|---|
date | Fri, 07 Dec 2001 20:31:20 +0000 |
parents | 1df5c106504e |
children | 47cc2de2ae36 |
comparison
equal
deleted
inserted
replaced
179:bded4e43ae73 | 180:db3f0ee7aac0 |
---|---|
54 | 54 |
55 #include "SDL_sound.h" | 55 #include "SDL_sound.h" |
56 | 56 |
57 #define __SDL_SOUND_INTERNAL__ | 57 #define __SDL_SOUND_INTERNAL__ |
58 #include "SDL_sound_internal.h" | 58 #include "SDL_sound_internal.h" |
59 | |
60 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf); | |
61 | |
59 | 62 |
60 static int AIFF_init(void); | 63 static int AIFF_init(void); |
61 static void AIFF_quit(void); | 64 static void AIFF_quit(void); |
62 static int AIFF_open(Sound_Sample *sample, const char *ext); | 65 static int AIFF_open(Sound_Sample *sample, const char *ext); |
63 static void AIFF_close(Sound_Sample *sample); | 66 static void AIFF_close(Sound_Sample *sample); |
79 AIFF_close, /* close() method */ | 82 AIFF_close, /* close() method */ |
80 AIFF_read /* read() method */ | 83 AIFF_read /* read() method */ |
81 }; | 84 }; |
82 | 85 |
83 | 86 |
84 /* this is what we store in our internal->decoder_private field... */ | 87 /***************************************************************************** |
85 typedef struct { | 88 * aiff_t is what we store in our internal->decoder_private field... * |
89 *****************************************************************************/ | |
90 typedef struct S_AIFF_FMT_T | |
91 { | |
92 Uint32 type; | |
93 void (*free)(struct S_AIFF_FMT_T *fmt); | |
94 Uint32(*read_sample)(Sound_Sample *sample); | |
95 | |
96 #if 0 | |
97 /* | |
98 this is ripped from wav.c as ann example of format-specific data. | |
99 please replace with something more appropriate when the need arises. | |
100 */ | |
101 union | |
102 { | |
103 struct | |
104 { | |
105 Uint16 cbSize; | |
106 Uint16 wSamplesPerBlock; | |
107 Uint16 wNumCoef; | |
108 ADPCMCOEFSET *aCoeff; | |
109 } adpcm; | |
110 | |
111 /* put other format-specific data here... */ | |
112 } fmt; | |
113 #endif | |
114 } fmt_t; | |
115 | |
116 | |
117 typedef struct | |
118 { | |
119 fmt_t fmt; | |
86 Sint32 bytesLeft; | 120 Sint32 bytesLeft; |
87 } aiff_t; | 121 } aiff_t; |
88 | 122 |
89 | 123 |
124 | |
90 /* Chunk management code... */ | 125 /* Chunk management code... */ |
91 | 126 |
92 #define formID 0x4d524f46 /* "FORM", in ascii. */ | 127 #define formID 0x4D524F46 /* "FORM", in ascii. */ |
93 #define aiffID 0x46464941 /* "AIFF", in ascii. */ | 128 #define aiffID 0x46464941 /* "AIFF", in ascii. */ |
94 #define aifcID 0x43464941 /* "AIFC", in ascii. */ | 129 #define aifcID 0x43464941 /* "AIFC", in ascii. */ |
95 #define ssndID 0x444e5353 /* "SSND", in ascii. */ | 130 #define ssndID 0x444E5353 /* "SSND", in ascii. */ |
96 #define commID 0x4d4d4f43 /* "COMM", in ascii. */ | 131 |
97 | 132 |
98 #define noneID 0x454e4f4e /* "NONE", in ascii. */ | 133 /***************************************************************************** |
134 * The COMM chunk... * | |
135 *****************************************************************************/ | |
136 | |
137 #define commID 0x4D4D4F43 /* "COMM", in ascii. */ | |
138 | |
139 /* format/compression types... */ | |
140 #define noneID 0x454E4F4E /* "NONE", in ascii. */ | |
99 | 141 |
100 typedef struct | 142 typedef struct |
101 { | 143 { |
102 Uint32 ckID; | 144 Uint32 ckID; |
103 Uint32 ckDataSize; | 145 Uint32 ckDataSize; |
137 pstring compressionName; | 179 pstring compressionName; |
138 #endif | 180 #endif |
139 } comm_t; | 181 } comm_t; |
140 | 182 |
141 | 183 |
142 | |
143 static int AIFF_init(void) | |
144 { | |
145 return(1); /* always succeeds. */ | |
146 } /* AIFF_init */ | |
147 | |
148 | |
149 static void AIFF_quit(void) | |
150 { | |
151 /* it's a no-op. */ | |
152 } /* AIFF_quit */ | |
153 | |
154 | |
155 /* | |
156 * Sample rate is encoded as an "80 bit IEEE Standard 754 floating point | |
157 * number (Standard Apple Numeric Environment [SANE] data type Extended)". | |
158 * Whose bright idea was that? | |
159 * | |
160 * This function was adapted from libsndfile, and while I do know a little | |
161 * bit about the IEEE floating point standard I don't pretend to fully | |
162 * understand this. | |
163 */ | |
164 | |
165 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) | |
166 { | |
167 /* Is the frequency outside of what we can represent with Uint32? */ | |
168 if ( (sanebuf[0] & 0x80) | |
169 || (sanebuf[0] <= 0x3F) | |
170 || (sanebuf[0] > 0x40) | |
171 || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) ) | |
172 return 0; | |
173 | |
174 return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) | |
175 | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); | |
176 } /* SANE_to_Uint32 */ | |
177 | |
178 | |
179 /* | 184 /* |
180 * Read in a comm_t from disk. This makes this process safe regardless of | 185 * Read in a comm_t from disk. This makes this process safe regardless of |
181 * the processor's byte order or how the comm_t structure is packed. | 186 * the processor's byte order or how the comm_t structure is packed. |
182 */ | 187 */ |
183 | 188 |
218 sizeof (comm->compressionType), 1) != 1) | 223 sizeof (comm->compressionType), 1) != 1) |
219 return(0); | 224 return(0); |
220 comm->compressionType = SDL_SwapBE32(comm->compressionType); | 225 comm->compressionType = SDL_SwapBE32(comm->compressionType); |
221 } /* if */ | 226 } /* if */ |
222 else | 227 else |
228 { | |
223 comm->compressionType = noneID; | 229 comm->compressionType = noneID; |
230 } /* else */ | |
224 | 231 |
225 return(1); | 232 return(1); |
226 } /* read_comm_chunk */ | 233 } /* read_comm_chunk */ |
234 | |
235 | |
236 | |
237 /***************************************************************************** | |
238 * The SSND chunk... * | |
239 *****************************************************************************/ | |
227 | 240 |
228 typedef struct | 241 typedef struct |
229 { | 242 { |
230 Uint32 ckID; | 243 Uint32 ckID; |
231 Uint32 ckDataSize; | 244 Uint32 ckDataSize; |
262 | 275 |
263 return(1); | 276 return(1); |
264 } /* read_ssnd_chunk */ | 277 } /* read_ssnd_chunk */ |
265 | 278 |
266 | 279 |
280 | |
281 /***************************************************************************** | |
282 * Normal, uncompressed aiff handler... * | |
283 *****************************************************************************/ | |
284 | |
285 static Uint32 read_sample_fmt_normal(Sound_Sample *sample) | |
286 { | |
287 Uint32 retval; | |
288 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | |
289 aiff_t *a = (aiff_t *) internal->decoder_private; | |
290 Uint32 max = (internal->buffer_size < (Uint32) a->bytesLeft) ? | |
291 internal->buffer_size : (Uint32) a->bytesLeft; | |
292 | |
293 assert(max > 0); | |
294 | |
295 /* | |
296 * We don't actually do any decoding, so we read the AIFF data | |
297 * directly into the internal buffer... | |
298 */ | |
299 retval = SDL_RWread(internal->rw, internal->buffer, 1, max); | |
300 | |
301 a->bytesLeft -= retval; | |
302 | |
303 /* Make sure the read went smoothly... */ | |
304 if ((retval == 0) || (a->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 void free_fmt_normal(fmt_t *fmt) | |
319 { | |
320 /* it's a no-op. */ | |
321 } /* free_fmt_normal */ | |
322 | |
323 | |
324 static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt) | |
325 { | |
326 /* (don't need to read more from the RWops...) */ | |
327 fmt->free = free_fmt_normal; | |
328 fmt->read_sample = read_sample_fmt_normal; | |
329 return(1); | |
330 } /* read_fmt_normal */ | |
331 | |
332 | |
333 | |
334 | |
335 /***************************************************************************** | |
336 * Everything else... * | |
337 *****************************************************************************/ | |
338 | |
339 static int AIFF_init(void) | |
340 { | |
341 return(1); /* always succeeds. */ | |
342 } /* AIFF_init */ | |
343 | |
344 | |
345 static void AIFF_quit(void) | |
346 { | |
347 /* it's a no-op. */ | |
348 } /* AIFF_quit */ | |
349 | |
350 | |
351 /* | |
352 * Sample rate is encoded as an "80 bit IEEE Standard 754 floating point | |
353 * number (Standard Apple Numeric Environment [SANE] data type Extended)". | |
354 * Whose bright idea was that? | |
355 * | |
356 * This function was adapted from libsndfile, and while I do know a little | |
357 * bit about the IEEE floating point standard I don't pretend to fully | |
358 * understand this. | |
359 */ | |
360 static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) | |
361 { | |
362 /* Is the frequency outside of what we can represent with Uint32? */ | |
363 if ( (sanebuf[0] & 0x80) | |
364 || (sanebuf[0] <= 0x3F) | |
365 || (sanebuf[0] > 0x40) | |
366 || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) ) | |
367 return 0; | |
368 | |
369 return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) | |
370 | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); | |
371 } /* SANE_to_Uint32 */ | |
372 | |
373 | |
267 static int find_chunk(SDL_RWops *rw, Uint32 id) | 374 static int find_chunk(SDL_RWops *rw, Uint32 id) |
268 { | 375 { |
269 Sint32 siz = 0; | 376 Sint32 siz = 0; |
270 Uint32 _id = 0; | 377 Uint32 _id = 0; |
271 | 378 |
281 BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0); | 388 BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0); |
282 } /* while */ | 389 } /* while */ |
283 | 390 |
284 return(0); /* shouldn't hit this, but just in case... */ | 391 return(0); /* shouldn't hit this, but just in case... */ |
285 } /* find_chunk */ | 392 } /* find_chunk */ |
393 | |
394 | |
395 static int read_fmt(SDL_RWops *rw, comm_t *c, fmt_t *fmt) | |
396 { | |
397 fmt->type = c->compressionType; | |
398 | |
399 /* if it's in this switch statement, we support the format. */ | |
400 switch (fmt->type) | |
401 { | |
402 case noneID: | |
403 SNDDBG(("AIFF: Appears to be uncompressed audio.\n")); | |
404 return(read_fmt_normal(rw, fmt)); | |
405 | |
406 /* add other types here. */ | |
407 | |
408 default: | |
409 SNDDBG(("AIFF: Format %lu is unknown.\n", | |
410 (unsigned int) fmt->type)); | |
411 Sound_SetError("AIFF: Unsupported format"); | |
412 return(0); /* not supported whatsoever. */ | |
413 } /* switch */ | |
414 | |
415 assert(0); /* shouldn't hit this point. */ | |
416 return(0); | |
417 } /* read_fmt */ | |
286 | 418 |
287 | 419 |
288 static int AIFF_open(Sound_Sample *sample, const char *ext) | 420 static int AIFF_open(Sound_Sample *sample, const char *ext) |
289 { | 421 { |
290 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | 422 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
308 | 440 |
309 BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0); | 441 BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0); |
310 BAIL_IF_MACRO(!read_comm_chunk(rw, &c), | 442 BAIL_IF_MACRO(!read_comm_chunk(rw, &c), |
311 "AIFF: Can't read common chunk.", 0); | 443 "AIFF: Can't read common chunk.", 0); |
312 | 444 |
313 /* !!! FIXME: This will have to change for compression types... */ | |
314 BAIL_IF_MACRO(c.compressionType != noneID, | |
315 "AIFF: Unsupported encoding.", 0); | |
316 | |
317 BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0); | |
318 | |
319 sample->actual.channels = (Uint8) c.numChannels; | 445 sample->actual.channels = (Uint8) c.numChannels; |
320 sample->actual.rate = c.sampleRate; | 446 sample->actual.rate = c.sampleRate; |
321 | 447 |
322 if (c.sampleSize <= 8) | 448 if (c.sampleSize <= 8) |
323 { | 449 { |
328 { | 454 { |
329 sample->actual.format = AUDIO_S16MSB; | 455 sample->actual.format = AUDIO_S16MSB; |
330 bytes_per_sample = 2; | 456 bytes_per_sample = 2; |
331 } /* if */ | 457 } /* if */ |
332 else | 458 else |
459 { | |
333 BAIL_MACRO("AIFF: Unsupported sample size.", 0); | 460 BAIL_MACRO("AIFF: Unsupported sample size.", 0); |
334 | 461 } /* else */ |
335 SDL_RWseek(rw, pos, SEEK_SET); | 462 |
336 | 463 BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0); |
337 BAIL_IF_MACRO(!find_chunk(rw, ssndID), "AIFF: No sound data chunk.", 0); | |
338 BAIL_IF_MACRO(!read_ssnd_chunk(rw, &s), | |
339 "AIFF: Can't read sound data chunk.", 0); | |
340 | 464 |
341 a = (aiff_t *) malloc(sizeof(aiff_t)); | 465 a = (aiff_t *) malloc(sizeof(aiff_t)); |
342 BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0); | 466 BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0); |
467 | |
468 if (!read_fmt(rw, &c, &(a->fmt))) | |
469 { | |
470 free(a); | |
471 return(0); | |
472 } /* if */ | |
473 | |
474 SDL_RWseek(rw, pos, SEEK_SET); /* if the seek fails, let it go... */ | |
475 | |
476 if (!find_chunk(rw, ssndID)) | |
477 { | |
478 Sound_SetError("AIFF: No sound data chunk."); | |
479 free(a); | |
480 return(0); | |
481 } /* if */ | |
482 | |
483 if (!read_ssnd_chunk(rw, &s)) | |
484 { | |
485 Sound_SetError("AIFF: Can't read sound data chunk."); | |
486 free(a); | |
487 return(0); | |
488 } /* if */ | |
489 | |
343 a->bytesLeft = bytes_per_sample * c.numSampleFrames; | 490 a->bytesLeft = bytes_per_sample * c.numSampleFrames; |
344 internal->decoder_private = (void *) a; | 491 internal->decoder_private = (void *) a; |
345 | 492 |
346 sample->flags = SOUND_SAMPLEFLAG_NONE; | 493 sample->flags = SOUND_SAMPLEFLAG_NONE; |
347 | 494 |
351 | 498 |
352 | 499 |
353 static void AIFF_close(Sound_Sample *sample) | 500 static void AIFF_close(Sound_Sample *sample) |
354 { | 501 { |
355 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | 502 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
356 free(internal->decoder_private); | 503 aiff_t *a = (aiff_t *) internal->decoder_private; |
504 a->fmt.free(&(a->fmt)); | |
505 free(a); | |
357 } /* WAV_close */ | 506 } /* WAV_close */ |
358 | 507 |
359 | 508 |
360 static Uint32 AIFF_read(Sound_Sample *sample) | 509 static Uint32 AIFF_read(Sound_Sample *sample) |
361 { | 510 { |
362 Uint32 retval; | |
363 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; | 511 Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; |
364 aiff_t *a = (aiff_t *) internal->decoder_private; | 512 aiff_t *a = (aiff_t *) internal->decoder_private; |
365 Uint32 max = (internal->buffer_size < (Uint32) a->bytesLeft) ? | 513 return(a->fmt.read_sample(sample)); |
366 internal->buffer_size : (Uint32) a->bytesLeft; | |
367 | |
368 assert(max > 0); | |
369 | |
370 /* | |
371 * We don't actually do any decoding, so we read the AIFF data | |
372 * directly into the internal buffer... | |
373 */ | |
374 retval = SDL_RWread(internal->rw, internal->buffer, 1, max); | |
375 | |
376 a->bytesLeft -= retval; | |
377 | |
378 /* Make sure the read went smoothly... */ | |
379 if ((retval == 0) || (a->bytesLeft == 0)) | |
380 sample->flags |= SOUND_SAMPLEFLAG_EOF; | |
381 | |
382 else if (retval == -1) | |
383 sample->flags |= SOUND_SAMPLEFLAG_ERROR; | |
384 | |
385 /* (next call this EAGAIN may turn into an EOF or error.) */ | |
386 else if (retval < internal->buffer_size) | |
387 sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; | |
388 | |
389 return(retval); | |
390 } /* AIFF_read */ | 514 } /* AIFF_read */ |
391 | 515 |
392 #endif /* SOUND_SUPPORTS_AIFF */ | 516 #endif /* SOUND_SUPPORTS_AIFF */ |
393 | 517 |
394 | |
395 /* end of aiff.c ... */ | 518 /* end of aiff.c ... */ |
519 |