******************************************************************************/
/*
* libaiff.c -- library routines for dealing with AIFF
*
* 1991-1992 Charles J Williams III ([email protected])
* Naval Research Lab/Research Computation Division Visualization Lab
*/
/*
* NRL/RCD Visualization Lab
*
* Source code and documentation developed at NRL/RCD Visualization Lab
* are in the public domain. Hence, no limitation exists on the right to use,
* publish, or resale the source code and documentation.
*
* We ask, but do not require, that the following message be included in all
* derived works
*
* THE NAVAL RESEARCH LABORATORY GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR
* THE SOFTWARE AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION,
* WARRANTY OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE
*
*/
#include <stdio.h>
#include <string.h>
#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#define kFORM "FORM"
#define kAIFF "AIFF"
#define kCOMM "COMM"
#define kSSND "SSND"
typedef char ID[4];
typedef unsigned long ulong;
double ConvertFromIeeeExtended();
typedef struct {
ID ckID;
long ckDataSize;
char *ckData;
} Chunk;
typedef struct {
ID ckID; /* "FORM" */
long ckDataSize;
ID formType; /* "AIFF" for AIFF files */
} FormChunk;
typedef struct {
ID ckID; /* "COMM" */
long ckDataSize;
short numChannels;
ulong numSampleFrames;
short sampleSize;
double sampleRate;
} CommChunk;
typedef struct {
ID ckID;
long ckDataSize;
ulong offset;
ulong blockSize;
char *soundData;
} SsndChunk;
/* global variables */
char *AIFFerr;
#ifdef standalone
int
main(argc, argv)
int argc;
char **argv;
{
FILE *audioFile;
char *audiofile;
Chunk tempChunk;
FormChunk formChunk;
ID ckID;
long savepos;
int nchan, nsamp, ssize;
double srate;
char *sdata;
audiofile = argv[1];
audioFile = fopen( audiofile, "r" );
if ( !audioFile )
{
fprintf(stderr,"can't open file %s, aborting!\n", audiofile);
exit(1);
}
if ( !readAIFFfile( audioFile,&nchan,&nsamp,&ssize,&srate,sdata ))
{
fprintf(stderr,"%s\n", AIFFerr );
}
else
{
fprintf(stderr,"for file %s:\n", audiofile );
fprintf(stderr,"number of Channels: %d\n", nchan );
fprintf(stderr,"samples per channels: %d\n", nsamp );
fprintf(stderr,"sample size (bits): %d\n", ssize );
fprintf(stderr,"sample rate (Hz): %f\n", srate );
}
fclose(audioFile);
}
#endif /* standalone */
int
readAIFFfile( audioFile , nChannels, nSamples, sSize, sRate, sData)
FILE *audioFile;
int *nChannels;
int *nSamples;
int *sSize;
double *sRate;
char **sData;
{
static FormChunk formChunk;
static CommChunk commChunk;
static SsndChunk ssndChunk;
ReadFormChunk( audioFile, &formChunk );
if ( strncmp( formChunk.ckID, kFORM, 4 )!=0 &&
strncmp( formChunk.formType, kAIFF, 4)!=0)
{
AIFFerr = "not an AIFF standard audio recording";
return -1;
}
if ( readCOMMandSSNDchunks(audioFile, &commChunk, &ssndChunk) )
return 0;
*nChannels = commChunk.numChannels;
*nSamples = commChunk.numSampleFrames;
*sSize = commChunk.sampleSize;
*sRate = commChunk.sampleRate;
*sData = (char *) ssndChunk.soundData;
return 1;
}
int
readCOMMandSSNDchunks( file , commChunk, ssndChunk)
FILE *file;
CommChunk *commChunk;
SsndChunk *ssndChunk;
{
Chunk chunk;
int haveCOMM = 0, haveSSND = 0;
int i;
AIFFerr = "missing SSND or COMM chunk";
for(;;)
{
if ( ! ReadChunk( file, &chunk ) )
{
return(-1);
}
if ( strncmp( chunk.ckID, kCOMM, 4) == 0 )
{
fprintf(stderr,"reading COMM Chunk...\n");
fseek( file, -8L, SEEK_CUR );
if ( ! ReadCommChunk( file, commChunk ) )
return -1;
haveCOMM = 1;
AIFFerr = "missing SSND chunk";
}
else if ( strncmp( chunk.ckID, kSSND, 4 ) == 0 )
{
fprintf(stderr,"reading SSND Chunk...\n");
fseek( file, -8L, SEEK_CUR );
if ( ! ReadSsndChunk( file, ssndChunk ) )
return -1;
haveSSND = 1;
AIFFerr = "missing COMM Chunk";
}
else
{
fprintf(stderr,"skipping unknown Chunk '");
for(i=0; i<4; ++i)
fputc(chunk.ckID[i], stderr);
fprintf(stderr,"'...\n");
fseek( file, chunk.ckDataSize, SEEK_CUR );
if ( chunk.ckDataSize % 2 == 1 )
fseek( file, 1L, SEEK_CUR );
}
if ( haveCOMM && haveSSND )
{
AIFFerr = "no error";
return(0);
}
}
}
int
ReadChunk( file, chunk )
FILE *file;
Chunk *chunk;
{
if ( ! ReadID( file, chunk->ckID ) ) return 0;
if ( ! ReadLong( file, &(chunk->ckDataSize)) ) return 0;
return 1;
}
int
ReadFormChunk( file, chunk )
FILE *file;
FormChunk *chunk;
{
ReadID( file, chunk->ckID );
ReadLong( file, &(chunk->ckDataSize));
ReadID( file, chunk->formType );
}
int
ReadCommChunk( file, chunk )
FILE *file;
CommChunk *chunk;
{
AIFFerr = "error reading COMM chunk";
if ( ! ReadID(file, chunk->ckID ) ) return 0;
if ( ! ReadLong( file, &chunk->ckDataSize ) ) return 0;
if ( ! ReadShort( file, &chunk->numChannels ) ) return 0;
if ( ! ReadULong( file, &chunk->numSampleFrames ) ) return 0;
if ( ! ReadShort( file, &chunk->sampleSize )) return 0;
if ( ! ReadExtended( file, &chunk->sampleRate ) ) return 0;
return 1;
}
int
ReadSsndChunk( file, chunk )
FILE *file;
SsndChunk *chunk;
{
int rawsize;
if ( ! ReadID(file, chunk->ckID ) ) return 0;
if ( ! ReadLong( file, &chunk->ckDataSize ) ) return 0;
if ( ! ReadULong( file, &chunk->offset ) ) return 0;
if ( ! ReadULong( file, &chunk->blockSize ) ) return 0;
rawsize = chunk->ckDataSize - chunk->offset - 8;
chunk->soundData = (char *) malloc( rawsize );
fseek( file, (long) chunk->offset, SEEK_CUR );
if ( fread( chunk->soundData, sizeof(char), rawsize, file ) != rawsize)
{
AIFFerr = "read error for SSND sound data";
return 0;
}
return 1;
}
int
ReadID( file, ckID )
FILE *file;
ID *ckID;
{
if (fread( (void *) ckID, sizeof(char), 4, file ) != 4) return 0;
return 1;
}
int
ReadLong( file, val )
FILE *file;
long *val;
{
unsigned char b[4];
int i;
for( i=0; i<4; ++i)
if (fread( (void *) &b[i], sizeof(char), 1, file ) != 1 )
return 0;
*val = b[0]*16777216 + b[1]*65536 + b[2]*256 + b[3];
return 1;
}
int
ReadShort( file, val )
FILE *file;
short *val;
{
unsigned char b[2];
int i;
for ( i=0; i<2; ++i)
if ( fread( (void *) &b[i], sizeof(char), 1, file) != 1 )
return 0;
*val = b[0]*256 + b[1];
return 1;
}
int
ReadULong( file, val )
FILE *file;
long *val;
{
unsigned char b[4];
int i;
for( i=0; i<4; ++i)
if (fread( (void *) &b[i], sizeof(char), 1, file ) != 1 )
return 0;
*val = b[0]*16777216 + b[1]*65536 + b[2]*256 + b[3];
return 1;
}
int
ReadExtended( file, val )
FILE *file;
double *val;
{
unsigned char b[10]; /* ieee extended is 80 bits */
if ( fread( &b[0], sizeof(char), 10, file ) != 10 ) return 0;
*val = ConvertFromIeeeExtended(b);
return 1;
}