/* SDL_mixer: An audio mixer library based on the SDL library Copyright (C) 1997, 1998, 1999, 2000, 2001 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) */ /* $id:$ */ #include #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" */ /* 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; long start; 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; Uint32 numsamples; Uint16 samplesize; Uint8 sane_freq[10]; Uint32 frequency; /* 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) ) { SDL_SetError("Unrecognized file type (not AIFF)"); was_error = 1; goto done; } /* TODO: Better santity-checking. */ found_SSND = 0; found_COMM = 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; default: break; } } while ( ( !found_SSND || !found_COMM ) && SDL_RWseek(src, next_chunk, SEEK_SET) != 1 ); if ( !found_SSND ) { SDL_SetError("Bad AIFF (no SSND chunk)"); was_error = 1; goto done; } if ( !found_COMM ) { SDL_SetError("Bad AIFF (no COMM 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); }