diff decoders/flac.c @ 155:72ff7d3a25b6

Initial add.
author Ryan C. Gordon <icculus@icculus.org>
date Fri, 09 Nov 2001 21:43:11 +0000
parents
children 77482005beb6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decoders/flac.c	Fri Nov 09 21:43:11 2001 +0000
@@ -0,0 +1,319 @@
+/*
+ * SDL_sound -- An abstract sound format decoding API.
+ * Copyright (C) 2001  Ryan C. Gordon.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * FLAC decoder for SDL_sound.
+ *
+ * This driver handles FLAC audio, that is to say the Free Lossless Audio
+ *  Codec. It depends on libFLAC for decoding, which can be grabbed from:
+ *  http://flac.sourceforge.net
+ *
+ * Please see the file LICENSE in the source's root directory.
+ *
+ *  This file written by Torbjörn Andersson. (d91tan@Update.UU.SE)
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef SOUND_SUPPORTS_FLAC
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "SDL_sound.h"
+
+#define __SDL_SOUND_INTERNAL__
+#include "SDL_sound_internal.h"
+
+#include "FLAC/all.h"
+
+
+static int FLAC_init(void);
+static void FLAC_quit(void);
+static int FLAC_open(Sound_Sample *sample, const char *ext);
+static void FLAC_close(Sound_Sample *sample);
+static Uint32 FLAC_read(Sound_Sample *sample);
+
+static const char *extensions_flac[] = { "FLAC", "FLA", NULL };
+
+const Sound_DecoderFunctions __Sound_DecoderFunctions_FLAC =
+{
+    {
+        extensions_flac,
+        "Free Lossless Audio Codec",
+        "Torbjörn Andersson <d91tan@Update.UU.SE>",
+        "http://flac.sourceforge.net/"
+    },
+
+    FLAC_init,       /* init() method       */
+    FLAC_quit,       /* quit() method       */
+    FLAC_open,       /* open() method       */
+    FLAC_close,      /* close() method       */
+    FLAC_read        /* read() method       */
+};
+
+    /* This is what we store in our internal->decoder_private field. */
+typedef struct
+{
+    FLAC__StreamDecoder *decoder;
+    SDL_RWops *rw;
+    Sound_Sample *sample;
+    Uint32 frame_size;
+} flac_t;
+
+
+static FLAC__StreamDecoderReadStatus FLAC_read_callback(
+    const FLAC__StreamDecoder *decoder, FLAC__byte buffer[],
+    unsigned int *bytes, void *client_data)
+{
+    flac_t *f = (flac_t *) client_data;
+    Uint32 retval;
+
+#if 0
+    SNDDBG(("FLAC: Read callback\n"));
+#endif
+    
+    retval = SDL_RWread(f->rw, (Uint8 *) buffer, 1, *bytes);
+
+    if (retval == 0)
+    {
+        SNDDBG(("FLAC: End of file\n"));
+        *bytes = 0;
+        f->sample->flags |= SOUND_SAMPLEFLAG_EOF;
+        return(FLAC__STREAM_DECODER_READ_END_OF_STREAM);
+    } /* if */
+
+    if (retval == -1)
+    {
+        *bytes = 0;
+        f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+        return(FLAC__STREAM_DECODER_READ_ABORT);
+    } /* if */
+
+    if (retval < *bytes)
+    {
+        *bytes = retval;
+        f->sample->flags |= SOUND_SAMPLEFLAG_EAGAIN;
+    } /* if */
+
+    return(FLAC__STREAM_DECODER_READ_CONTINUE);
+} /* FLAC_read_callback */
+
+
+static FLAC__StreamDecoderWriteStatus FLAC_write_callback(
+    const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
+    const FLAC__int32 *buffer[], void *client_data)
+{
+    flac_t *f = (flac_t *) client_data;
+    Uint32 i, j;
+    Uint8 *dst;
+
+#if 0
+    SNDDBG(("FLAC: Write callback.\n"));
+#endif
+
+    f->frame_size = frame->header.channels * frame->header.blocksize
+        * frame->header.bits_per_sample / 8;
+
+    if (f->frame_size > f->sample->buffer_size)
+        Sound_SetBufferSize(f->sample, f->frame_size);
+
+    dst = f->sample->buffer;
+
+    if (frame->header.bits_per_sample == 8)
+    {
+        for (i = 0; i < frame->header.blocksize; i++)
+            for (j = 0; j < frame->header.channels; j++)
+                *dst++ = buffer[j][i] & 0x000000ff;
+    } /* if */
+    else
+    {
+        for (i = 0; i < frame->header.blocksize; i++)
+            for (j = 0; j < frame->header.channels; j++)
+            {
+                *dst++ = (buffer[j][i] & 0x0000ff00) >> 8;
+                *dst++ = buffer[j][i] & 0x000000ff;
+            } /* for */
+    } /* else */
+
+    return(FLAC__STREAM_DECODER_WRITE_CONTINUE);
+} /* FLAC_write_callback */
+
+
+void FLAC_metadata_callback(
+    const FLAC__StreamDecoder *decoder, const FLAC__StreamMetaData *metadata,
+    void *client_data)
+{
+    flac_t *f = (flac_t *) client_data;
+    
+    SNDDBG(("FLAC: Metadata callback.\n"));
+
+    if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
+    {
+        SNDDBG(("FLAC: Metadata is streaminfo.\n"));
+        f->sample->actual.channels = metadata->data.stream_info.channels;
+        f->sample->actual.rate = metadata->data.stream_info.sample_rate;
+
+            /* !!! FIXME: I believe bits_per_sample may be anywhere between
+             * 4 and 24. We can only handle 8 and 16 at present.
+             */
+        switch (metadata->data.stream_info.bits_per_sample)
+        {
+            case 8:
+                f->sample->actual.format = AUDIO_S8;
+                break;
+            case 16:
+                f->sample->actual.format = AUDIO_S16MSB;
+                break;
+            default:
+                Sound_SetError("FLAC: Unsupported sample width.\n");
+                f->sample->actual.format = 0;
+                break;
+        } /* switch */
+    } /* if */
+} /* FLAC_metadata_callback */
+
+
+void FLAC_error_callback(
+    const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status,
+    void *client_data)
+{
+    flac_t *f = (flac_t *) client_data;
+    
+    SNDDBG(("FLAC: Error callback.\n"));
+    f->sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+} /* FLAC_error_callback */
+
+
+static int FLAC_init(void)
+{
+    return(1);  /* always succeeds. */
+} /* FLAC_init */
+
+
+static void FLAC_quit(void)
+{
+    /* it's a no-op. */
+} /* FLAC_quit */
+
+
+static int FLAC_open(Sound_Sample *sample, const char *ext)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    SDL_RWops *rw = internal->rw;
+    FLAC__StreamDecoder *decoder;
+    Uint8 flac_magic[4];
+    flac_t *f;
+
+    if (SDL_RWread(rw, flac_magic, sizeof (flac_magic), 1) != 1)
+    {
+        Sound_SetError("FLAC: Could not read FLAC magic.");
+        return(0);
+    } /* if */
+
+    if (strncmp(flac_magic, "fLaC", sizeof (flac_magic)) != 0)
+    {
+        Sound_SetError("FLAC: Not a FLAC stream.");
+        return(0);
+    } /* if */
+
+    SDL_RWseek(internal->rw, -sizeof (flac_magic), SEEK_CUR);
+
+    f = (flac_t *) malloc(sizeof (flac_t));
+    BAIL_IF_MACRO(f == NULL, ERR_OUT_OF_MEMORY, 0);
+    
+    decoder = FLAC__stream_decoder_new();
+    if (decoder == NULL)
+    {
+        Sound_SetError(ERR_OUT_OF_MEMORY);
+        free(f);
+        return(0);
+    } /* if */       
+
+    FLAC__stream_decoder_set_read_callback(decoder, FLAC_read_callback);
+    FLAC__stream_decoder_set_write_callback(decoder, FLAC_write_callback);
+    FLAC__stream_decoder_set_metadata_callback(decoder, FLAC_metadata_callback);
+    FLAC__stream_decoder_set_error_callback(decoder, FLAC_error_callback);
+    FLAC__stream_decoder_set_client_data(decoder, f);
+
+    f->rw = internal->rw;
+    f->sample = sample;
+    f->decoder = decoder;
+    
+    FLAC__stream_decoder_init(decoder);
+    internal->decoder_private = f;
+
+    SNDDBG(("FLAC: Accepting data stream.\n"));
+
+    FLAC__stream_decoder_process_metadata(decoder);
+
+    if (f->sample->actual.format == 0)
+    {
+        FLAC__stream_decoder_finish(decoder);
+        FLAC__stream_decoder_delete(decoder);
+        free(f);
+        return(0);
+    } /* if */
+
+    sample->flags = SOUND_SAMPLEFLAG_NONE;
+    return(1);
+} /* FLAC_open */
+
+
+static void FLAC_close(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    flac_t *f = (flac_t *) internal->decoder_private;
+
+    FLAC__stream_decoder_finish(f->decoder);
+    FLAC__stream_decoder_delete(f->decoder);
+    free(f);
+} /* FLAC_close */
+
+
+static Uint32 FLAC_read(Sound_Sample *sample)
+{
+    Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque;
+    flac_t *f = (flac_t *) internal->decoder_private;
+    Uint32 len;
+
+    if (FLAC__stream_decoder_get_state(f->decoder) == FLAC__STREAM_DECODER_END_OF_STREAM)
+    {
+        sample->flags |= SOUND_SAMPLEFLAG_EOF;
+        return(0);
+    } /* if */
+
+    if (!FLAC__stream_decoder_process_one_frame(f->decoder))
+    {
+        SNDDBG(("FLAC: Couldn't decode frame.\n"));
+        sample->flags |= SOUND_SAMPLEFLAG_ERROR;
+        return(0);
+    } /* if */
+
+    return(f->frame_size);
+} /* FLAC_read */
+
+#endif /* SOUND_SUPPORTS_FLAC */
+
+
+/* end of flac.c ... */