Logo Search packages:      
Sourcecode: ia32-libs-sdl version File versions  Download package

load_aiff.c

/*
    SDL_mixer:  An audio mixer library based on the SDL library
    Copyright (C) 1997-2004 Sam Lantinga

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    This is the source needed to decode an AIFF file into a waveform.
    It's pretty straightforward once you get going. The only
    externally-callable function is Mix_LoadAIFF_RW(), which is meant to
    act as identically to SDL_LoadWAV_RW() as possible.

    This file by Torbjörn Andersson (torbjorn.andersson@eurotime.se)
    8SVX file support added by Marc Le Douarain (mavati@club-internet.fr)
    in december 2002.
*/

/* $Id: load_aiff.c,v 1.7 2004/01/04 17:37:04 slouken Exp $ */

#include <stdlib.h>
#include <string.h>

#include "SDL_endian.h"
#include "SDL_mixer.h"
#include "load_aiff.h"

/*********************************************/
/* Define values for AIFF (IFF audio) format */
/*********************************************/
#define FORM            0x4d524f46        /* "FORM" */

#define AIFF            0x46464941        /* "AIFF" */
#define SSND            0x444e5353        /* "SSND" */
#define COMM            0x4d4d4f43        /* "COMM" */

#define _8SVX           0x58565338        /* "8SVX" */
#define VHDR            0x52444856        /* "VHDR" */
#define BODY            0x59444F42        /* "BODY" */

/* This function was taken from libsndfile. I don't pretend to fully
 * understand it.
 */

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]);
}

/* This function is based on SDL_LoadWAV_RW(). */

SDL_AudioSpec *Mix_LoadAIFF_RW (SDL_RWops *src, int freesrc,
      SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
{
      int was_error;
      int found_SSND;
      int found_COMM;
      int found_VHDR;
      int found_BODY;
      long start = 0;

      Uint32 chunk_type;
      Uint32 chunk_length;
      long next_chunk;

      /* AIFF magic header */
      Uint32 FORMchunk;
      Uint32 AIFFmagic;

      /* SSND chunk */
      Uint32 offset;
      Uint32 blocksize;

      /* COMM format chunk */
      Uint16 channels = 0;
      Uint32 numsamples = 0;
      Uint16 samplesize = 0;
      Uint8 sane_freq[10];
      Uint32 frequency = 0;

      /* Make sure we are passed a valid data source */
      was_error = 0;
      if ( src == NULL ) {
            was_error = 1;
            goto done;
      }

      FORMchunk   = SDL_ReadLE32(src);
      chunk_length      = SDL_ReadBE32(src);
      if ( chunk_length == AIFF ) { /* The FORMchunk has already been read */
            AIFFmagic    = chunk_length;
            chunk_length = FORMchunk;
            FORMchunk    = FORM;
      } else {
            AIFFmagic    = SDL_ReadLE32(src);
      }
      if ( (FORMchunk != FORM) || ( (AIFFmagic != AIFF) && (AIFFmagic != _8SVX) ) ) {
            SDL_SetError("Unrecognized file type (not AIFF nor 8SVX)");
            was_error = 1;
            goto done;
      }

      /* TODO: Better santity-checking. */

      found_SSND = 0;
      found_COMM = 0;
      found_VHDR = 0;
      found_BODY = 0;

      do {
            chunk_type  = SDL_ReadLE32(src);
            chunk_length      = SDL_ReadBE32(src);
            next_chunk  = SDL_RWtell(src) + chunk_length;
            /* Paranoia to avoid infinite loops */
            if (chunk_length == 0)
                  break;

            switch (chunk_type) {
                  case SSND:
                        found_SSND  = 1;
                        offset            = SDL_ReadBE32(src);
                        blocksize   = SDL_ReadBE32(src);
                        start       = SDL_RWtell(src) + offset;
                        break;

                  case COMM:
                        found_COMM  = 1;
                        channels    = SDL_ReadBE16(src);
                        numsamples  = SDL_ReadBE32(src);
                        samplesize  = SDL_ReadBE16(src);
                        SDL_RWread(src, sane_freq, sizeof(sane_freq), 1);
                        frequency   = SANE_to_Uint32(sane_freq);
                        if (frequency == 0) {
                              SDL_SetError("Bad AIFF sample frequency");
                              was_error = 1;
                              goto done;
                        }
                        break;

                  case VHDR:
                        found_VHDR  = 1;
                        SDL_ReadBE32(src);
                        SDL_ReadBE32(src);
                        SDL_ReadBE32(src);
                        frequency = SDL_ReadBE16(src);
                        channels = 1;
                        samplesize = 8;
                        break;

                  case BODY:
                        found_BODY  = 1;
                        numsamples  = chunk_length;
                        start       = SDL_RWtell(src);
                        break;

                  default:
                        break;
            }
            /* a 0 pad byte can be stored for any odd-length chunk */
            if (chunk_length&1)
                  next_chunk++;
      } while ( ( ( (AIFFmagic == AIFF) && ( !found_SSND || !found_COMM ) )
              || ( (AIFFmagic == _8SVX ) && ( !found_VHDR || !found_BODY ) ) )
              && SDL_RWseek(src, next_chunk, SEEK_SET) != 1 );

      if ( (AIFFmagic == AIFF) && !found_SSND ) {
            SDL_SetError("Bad AIFF (no SSND chunk)");
            was_error = 1;
            goto done;
      }

      if ( (AIFFmagic == AIFF) && !found_COMM ) {
            SDL_SetError("Bad AIFF (no COMM chunk)");
            was_error = 1;
            goto done;
      }

      if ( (AIFFmagic == _8SVX) && !found_VHDR ) {
            SDL_SetError("Bad 8SVX (no VHDR chunk)");
            was_error = 1;
            goto done;
      }

      if ( (AIFFmagic == _8SVX) && !found_BODY ) {
            SDL_SetError("Bad 8SVX (no BODY chunk)");
            was_error = 1;
            goto done;
      }

      /* Decode the audio data format */
      memset(spec, 0, sizeof(*spec));
      spec->freq = frequency;
      switch (samplesize) {
            case 8:
                  spec->format = AUDIO_S8;
                  break;
            case 16:
                  spec->format = AUDIO_S16MSB;
                  break;
            default:
                  SDL_SetError("Unsupported AIFF samplesize");
                  was_error = 1;
                  goto done;
      }
      spec->channels = (Uint8) channels;
      spec->samples = 4096;         /* Good default buffer size */

      *audio_len = channels * numsamples * (samplesize / 8);
      *audio_buf = (Uint8 *)malloc(*audio_len);
      if ( *audio_buf == NULL ) {
            SDL_SetError("Out of memory");
            return(NULL);
      }
      SDL_RWseek(src, start, SEEK_SET);
      if ( SDL_RWread(src, *audio_buf, *audio_len, 1) != 1 ) {
            SDL_SetError("Unable to read audio data");
            return(NULL);
      }

      /* Don't return a buffer that isn't a multiple of samplesize */
      *audio_len &= ~((samplesize / 8) - 1);

done:
      if ( freesrc && src ) {
            SDL_RWclose(src);
      }
      if ( was_error ) {
            spec = NULL;
      }
      return(spec);
}


Generated by  Doxygen 1.6.0   Back to index