changeset 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 bded4e43ae73
children 993dd477eb4c
files decoders/aiff.c
diffstat 1 files changed, 260 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- 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 ... */