# HG changeset patch # User Ryan C. Gordon # Date 1007757080 0 # Node ID db3f0ee7aac08ad5fa1e133c1ae5c611b6a925fd # Parent bded4e43ae73e7526718970589028dfadcb96938 Modified to more easily allow for different compression types. diff -r bded4e43ae73 -r db3f0ee7aac0 decoders/aiff.c --- a/decoders/aiff.c Fri Dec 07 20:30:53 2001 +0000 +++ b/decoders/aiff.c Fri Dec 07 20:31:20 2001 +0000 @@ -57,6 +57,9 @@ #define __SDL_SOUND_INTERNAL__ #include "SDL_sound_internal.h" +static Uint32 SANE_to_Uint32 (Uint8 *sanebuf); + + static int AIFF_init(void); static void AIFF_quit(void); static int AIFF_open(Sound_Sample *sample, const char *ext); @@ -81,21 +84,60 @@ }; - /* this is what we store in our internal->decoder_private field... */ -typedef struct { +/***************************************************************************** + * aiff_t is what we store in our internal->decoder_private field... * + *****************************************************************************/ +typedef struct S_AIFF_FMT_T +{ + Uint32 type; + void (*free)(struct S_AIFF_FMT_T *fmt); + Uint32(*read_sample)(Sound_Sample *sample); + +#if 0 +/* + this is ripped from wav.c as ann example of format-specific data. + please replace with something more appropriate when the need arises. +*/ + union + { + struct + { + Uint16 cbSize; + Uint16 wSamplesPerBlock; + Uint16 wNumCoef; + ADPCMCOEFSET *aCoeff; + } adpcm; + + /* put other format-specific data here... */ + } fmt; +#endif +} fmt_t; + + +typedef struct +{ + fmt_t fmt; Sint32 bytesLeft; } aiff_t; + /* Chunk management code... */ -#define formID 0x4d524f46 /* "FORM", in ascii. */ +#define formID 0x4D524F46 /* "FORM", in ascii. */ #define aiffID 0x46464941 /* "AIFF", in ascii. */ #define aifcID 0x43464941 /* "AIFC", in ascii. */ -#define ssndID 0x444e5353 /* "SSND", in ascii. */ -#define commID 0x4d4d4f43 /* "COMM", in ascii. */ +#define ssndID 0x444E5353 /* "SSND", in ascii. */ + -#define noneID 0x454e4f4e /* "NONE", in ascii. */ +/***************************************************************************** + * The COMM chunk... * + *****************************************************************************/ + +#define commID 0x4D4D4F43 /* "COMM", in ascii. */ + +/* format/compression types... */ +#define noneID 0x454E4F4E /* "NONE", in ascii. */ typedef struct { @@ -139,43 +181,6 @@ } comm_t; - -static int AIFF_init(void) -{ - return(1); /* always succeeds. */ -} /* AIFF_init */ - - -static void AIFF_quit(void) -{ - /* it's a no-op. */ -} /* AIFF_quit */ - - -/* - * Sample rate is encoded as an "80 bit IEEE Standard 754 floating point - * number (Standard Apple Numeric Environment [SANE] data type Extended)". - * Whose bright idea was that? - * - * This function was adapted from libsndfile, and while I do know a little - * bit about the IEEE floating point standard I don't pretend to fully - * understand this. - */ - -static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) -{ - /* Is the frequency outside of what we can represent with Uint32? */ - if ( (sanebuf[0] & 0x80) - || (sanebuf[0] <= 0x3F) - || (sanebuf[0] > 0x40) - || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) ) - return 0; - - return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) - | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); -} /* SANE_to_Uint32 */ - - /* * Read in a comm_t from disk. This makes this process safe regardless of * the processor's byte order or how the comm_t structure is packed. @@ -220,11 +225,19 @@ comm->compressionType = SDL_SwapBE32(comm->compressionType); } /* if */ else + { comm->compressionType = noneID; + } /* else */ return(1); } /* read_comm_chunk */ + + +/***************************************************************************** + * The SSND chunk... * + *****************************************************************************/ + typedef struct { Uint32 ckID; @@ -264,100 +277,12 @@ } /* read_ssnd_chunk */ -static int find_chunk(SDL_RWops *rw, Uint32 id) -{ - Sint32 siz = 0; - Uint32 _id = 0; - - while (1) - { - BAIL_IF_MACRO(SDL_RWread(rw, &_id, sizeof (_id), 1) != 1, NULL, 0); - if (SDL_SwapLE32(_id) == id) - return(1); - - BAIL_IF_MACRO(SDL_RWread(rw, &siz, sizeof (siz), 1) != 1, NULL, 0); - siz = SDL_SwapBE32(siz); - assert(siz > 0); - BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0); - } /* while */ - - return(0); /* shouldn't hit this, but just in case... */ -} /* find_chunk */ - - -static int AIFF_open(Sound_Sample *sample, const char *ext) -{ - Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; - SDL_RWops *rw = internal->rw; - Uint32 chunk_id; - int bytes_per_sample; - long pos; - comm_t c; - ssnd_t s; - aiff_t *a; - - BAIL_IF_MACRO(SDL_ReadLE32(rw) != formID, "AIFF: Not a FORM file.", 0); - SDL_ReadBE32(rw); /* throw the length away; we don't need it. */ - - chunk_id = SDL_ReadLE32(rw); - BAIL_IF_MACRO(chunk_id != aiffID && chunk_id != aifcID, - "AIFF: Not an AIFF or AIFC file.", 0); - - /* Chunks may appear in any order, so we establish base camp here. */ - pos = SDL_RWtell(rw); - - BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0); - BAIL_IF_MACRO(!read_comm_chunk(rw, &c), - "AIFF: Can't read common chunk.", 0); - /* !!! FIXME: This will have to change for compression types... */ - BAIL_IF_MACRO(c.compressionType != noneID, - "AIFF: Unsupported encoding.", 0); - - BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0); - - sample->actual.channels = (Uint8) c.numChannels; - sample->actual.rate = c.sampleRate; - - if (c.sampleSize <= 8) - { - sample->actual.format = AUDIO_S8; - bytes_per_sample = 1; - } /* if */ - else if (c.sampleSize <= 16) - { - sample->actual.format = AUDIO_S16MSB; - bytes_per_sample = 2; - } /* if */ - else - BAIL_MACRO("AIFF: Unsupported sample size.", 0); - - SDL_RWseek(rw, pos, SEEK_SET); +/***************************************************************************** + * Normal, uncompressed aiff handler... * + *****************************************************************************/ - BAIL_IF_MACRO(!find_chunk(rw, ssndID), "AIFF: No sound data chunk.", 0); - BAIL_IF_MACRO(!read_ssnd_chunk(rw, &s), - "AIFF: Can't read sound data chunk.", 0); - - a = (aiff_t *) malloc(sizeof(aiff_t)); - BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0); - a->bytesLeft = bytes_per_sample * c.numSampleFrames; - internal->decoder_private = (void *) a; - - sample->flags = SOUND_SAMPLEFLAG_NONE; - - SNDDBG(("AIFF: Accepting data stream.\n")); - return(1); /* we'll handle this data. */ -} /* AIFF_open */ - - -static void AIFF_close(Sound_Sample *sample) -{ - Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; - free(internal->decoder_private); -} /* WAV_close */ - - -static Uint32 AIFF_read(Sound_Sample *sample) +static Uint32 read_sample_fmt_normal(Sound_Sample *sample) { Uint32 retval; Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; @@ -387,9 +312,208 @@ sample->flags |= SOUND_SAMPLEFLAG_EAGAIN; return(retval); +} /* read_sample_fmt_normal */ + + +static void free_fmt_normal(fmt_t *fmt) +{ + /* it's a no-op. */ +} /* free_fmt_normal */ + + +static int read_fmt_normal(SDL_RWops *rw, fmt_t *fmt) +{ + /* (don't need to read more from the RWops...) */ + fmt->free = free_fmt_normal; + fmt->read_sample = read_sample_fmt_normal; + return(1); +} /* read_fmt_normal */ + + + + +/***************************************************************************** + * Everything else... * + *****************************************************************************/ + +static int AIFF_init(void) +{ + return(1); /* always succeeds. */ +} /* AIFF_init */ + + +static void AIFF_quit(void) +{ + /* it's a no-op. */ +} /* AIFF_quit */ + + +/* + * Sample rate is encoded as an "80 bit IEEE Standard 754 floating point + * number (Standard Apple Numeric Environment [SANE] data type Extended)". + * Whose bright idea was that? + * + * This function was adapted from libsndfile, and while I do know a little + * bit about the IEEE floating point standard I don't pretend to fully + * understand this. + */ +static Uint32 SANE_to_Uint32 (Uint8 *sanebuf) +{ + /* Is the frequency outside of what we can represent with Uint32? */ + if ( (sanebuf[0] & 0x80) + || (sanebuf[0] <= 0x3F) + || (sanebuf[0] > 0x40) + || (sanebuf[0] == 0x40 && sanebuf[1] > 0x1C) ) + return 0; + + return ((sanebuf[2] << 23) | (sanebuf[3] << 15) | (sanebuf[4] << 7) + | (sanebuf[5] >> 1)) >> (29 - sanebuf[1]); +} /* SANE_to_Uint32 */ + + +static int find_chunk(SDL_RWops *rw, Uint32 id) +{ + Sint32 siz = 0; + Uint32 _id = 0; + + while (1) + { + BAIL_IF_MACRO(SDL_RWread(rw, &_id, sizeof (_id), 1) != 1, NULL, 0); + if (SDL_SwapLE32(_id) == id) + return(1); + + BAIL_IF_MACRO(SDL_RWread(rw, &siz, sizeof (siz), 1) != 1, NULL, 0); + siz = SDL_SwapBE32(siz); + assert(siz > 0); + BAIL_IF_MACRO(SDL_RWseek(rw, siz, SEEK_CUR) == -1, NULL, 0); + } /* while */ + + return(0); /* shouldn't hit this, but just in case... */ +} /* find_chunk */ + + +static int read_fmt(SDL_RWops *rw, comm_t *c, fmt_t *fmt) +{ + fmt->type = c->compressionType; + + /* if it's in this switch statement, we support the format. */ + switch (fmt->type) + { + case noneID: + SNDDBG(("AIFF: Appears to be uncompressed audio.\n")); + return(read_fmt_normal(rw, fmt)); + + /* add other types here. */ + + default: + SNDDBG(("AIFF: Format %lu is unknown.\n", + (unsigned int) fmt->type)); + Sound_SetError("AIFF: Unsupported format"); + return(0); /* not supported whatsoever. */ + } /* switch */ + + assert(0); /* shouldn't hit this point. */ + return(0); +} /* read_fmt */ + + +static int AIFF_open(Sound_Sample *sample, const char *ext) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + SDL_RWops *rw = internal->rw; + Uint32 chunk_id; + int bytes_per_sample; + long pos; + comm_t c; + ssnd_t s; + aiff_t *a; + + BAIL_IF_MACRO(SDL_ReadLE32(rw) != formID, "AIFF: Not a FORM file.", 0); + SDL_ReadBE32(rw); /* throw the length away; we don't need it. */ + + chunk_id = SDL_ReadLE32(rw); + BAIL_IF_MACRO(chunk_id != aiffID && chunk_id != aifcID, + "AIFF: Not an AIFF or AIFC file.", 0); + + /* Chunks may appear in any order, so we establish base camp here. */ + pos = SDL_RWtell(rw); + + BAIL_IF_MACRO(!find_chunk(rw, commID), "AIFF: No common chunk.", 0); + BAIL_IF_MACRO(!read_comm_chunk(rw, &c), + "AIFF: Can't read common chunk.", 0); + + sample->actual.channels = (Uint8) c.numChannels; + sample->actual.rate = c.sampleRate; + + if (c.sampleSize <= 8) + { + sample->actual.format = AUDIO_S8; + bytes_per_sample = 1; + } /* if */ + else if (c.sampleSize <= 16) + { + sample->actual.format = AUDIO_S16MSB; + bytes_per_sample = 2; + } /* if */ + else + { + BAIL_MACRO("AIFF: Unsupported sample size.", 0); + } /* else */ + + BAIL_IF_MACRO(c.sampleRate == 0, "AIFF: Unsupported sample rate.", 0); + + a = (aiff_t *) malloc(sizeof(aiff_t)); + BAIL_IF_MACRO(a == NULL, ERR_OUT_OF_MEMORY, 0); + + if (!read_fmt(rw, &c, &(a->fmt))) + { + free(a); + return(0); + } /* if */ + + SDL_RWseek(rw, pos, SEEK_SET); /* if the seek fails, let it go... */ + + if (!find_chunk(rw, ssndID)) + { + Sound_SetError("AIFF: No sound data chunk."); + free(a); + return(0); + } /* if */ + + if (!read_ssnd_chunk(rw, &s)) + { + Sound_SetError("AIFF: Can't read sound data chunk."); + free(a); + return(0); + } /* if */ + + a->bytesLeft = bytes_per_sample * c.numSampleFrames; + internal->decoder_private = (void *) a; + + sample->flags = SOUND_SAMPLEFLAG_NONE; + + SNDDBG(("AIFF: Accepting data stream.\n")); + return(1); /* we'll handle this data. */ +} /* AIFF_open */ + + +static void AIFF_close(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + aiff_t *a = (aiff_t *) internal->decoder_private; + a->fmt.free(&(a->fmt)); + free(a); +} /* WAV_close */ + + +static Uint32 AIFF_read(Sound_Sample *sample) +{ + Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; + aiff_t *a = (aiff_t *) internal->decoder_private; + return(a->fmt.read_sample(sample)); } /* AIFF_read */ #endif /* SOUND_SUPPORTS_AIFF */ +/* end of aiff.c ... */ -/* end of aiff.c ... */