123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- /*
- SDL_mixer: An audio mixer library based on the SDL library
- Copyright (C) 1997-2013 Sam Lantinga <[email protected]>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- 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 ([email protected])
- 8SVX file support added by Marc Le Douarain ([email protected])
- in december 2002.
- */
- /* $Id$ */
- #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;
- Sint64 start = 0;
- Uint32 chunk_type;
- Uint32 chunk_length;
- Sint64 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, RW_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 */
- SDL_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 *)SDL_malloc(*audio_len);
- if ( *audio_buf == NULL ) {
- SDL_SetError("Out of memory");
- return(NULL);
- }
- SDL_RWseek(src, start, RW_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);
- }
|