Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
_source/AIFF.c
/* |
File: AIFF.c |
Contains: Routine demonstrating how to parse AIFF sound files. |
Written by: Mark Cookson |
Copyright: Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved. |
You may incorporate this Apple sample source code into your program(s) without |
restriction. This Apple sample source code has been provided "AS IS" and the |
responsibility for its operation is yours. You are not permitted to redistribute |
this Apple sample source code as "Apple sample source code" after having made |
changes. If you're going to re-distribute the source, we require that you make |
it clear in the source that the code was descended from Apple sample source |
code, but that you've made changes. |
Change History (most recent first): |
8/31/1999 Karl Groethe Updated for Metrowerks Codewarror Pro 2.1 |
*/ |
#include "MyAIFF.h" |
/* |
need to substitute this code where using long doubles |
typedef struct myLongDouble { |
double firstHalf; |
double secondHalf; |
} myLongDouble; |
*/ |
/* Given an AIFF File gets the sample rate and other relavent pieces of information. |
This has been modified from its orignal form found in the Develop 11 MultiBuffer source. */ |
/*-----------------------------------------------------------------------*/ |
OSErr ASoundGetAIFFHeader (SoundInfoPtr theSoundInfo, |
long *dataStart, |
long *length) |
/*-----------------------------------------------------------------------*/ |
{ |
ChunkTemplatePtr chunkTemplate = nil; /* ...for ease of access */ |
unsigned long type = kInit; |
long filePosition = kInit, |
byteCount = kInit; |
Fixed sampleRate = kInit; |
unsigned short chunkFlags = kInit; /* remember chunks we've seen */ |
OSErr err = noErr; |
char chunkBuffer[kChunkBufferSize]; |
*dataStart = kInit; |
/* Parse the AIFF (or AIFC) header */ |
do { |
/* Position ourselves at the beginning of the next chunk and read in |
a hunk-o-data... */ |
err = SetFPos (theSoundInfo->refNum, fsFromStart, filePosition); |
if (err != noErr) { |
DebugPrint ("\pSetFPos failed!"); |
break; |
} |
byteCount = kChunkBufferSize; |
err = FSRead (theSoundInfo->refNum, &byteCount, chunkBuffer); /* read a chunk */ |
if ((err != noErr) && (err != eofErr)) { |
DebugPrint ("\pFSRead failed!"); |
break; |
} |
/* Now, position the template over the data... */ |
chunkTemplate = (ChunkTemplatePtr) chunkBuffer; |
/* assume a failure and break out of the do {} while loop if the next case isn't found. |
if the case is found and no other error is detected, then each case needs to set noErr */ |
err = badFileFormat; |
switch (chunkTemplate->generic.ckID) { |
case FORMID: /* Format Version Chunk? */ |
/* make sure that this is a standard, noncompressed AIFF file. */ |
if ((chunkFlags & kFORM) == false) { /* see if this chunk already exists */ |
chunkFlags |= kFORM; /* otherwise mark it found */ |
*length = chunkTemplate->container.ckSize; |
filePosition += sizeof (ContainerChunk); /* Can't use ckSize because it's the size of the file, not this header */ |
type = chunkTemplate->container.formType; |
err = noErr; |
} |
break; |
case FormatVersionID: /* Format Version Chunk? */ |
if ((chunkFlags & kFormatVersion) == false) { /* see if this chunk already exists */ |
chunkFlags |= kFormatVersion; /* otherwise mark it found */ |
filePosition += chunkTemplate->formatVersion.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
if (chunkTemplate->formatVersion.timestamp != AIFCVersion1) { |
err = kUnknownFormat; |
} |
else { |
err = noErr; |
} |
} |
break; |
case CommonID: |
if ((chunkFlags & kCommon) == false) { /* see if this chunk already exists */ |
long double tempLD = 0.0; |
chunkFlags |= kCommon; /* otherwise mark it found */ |
filePosition += chunkTemplate->common.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
#ifdef powerc |
x80told (&(chunkTemplate->common.sampleRate), &tempLD); |
#else |
tempLD = chunkTemplate->common.sampleRate; |
#endif |
sampleRate = ASoundLongDoubleToFix (tempLD); |
if (type == AIFCID) { |
err = SetupDBHeader (theSoundInfo, |
sampleRate, |
chunkTemplate->common.sampleSize, |
chunkTemplate->common.numChannels, |
fixedCompression, |
chunkTemplate->extCommon.compressionType); |
theSoundInfo->needsMasking = false; |
} |
else { |
err = SetupDBHeader (theSoundInfo, |
sampleRate, |
chunkTemplate->common.sampleSize, |
chunkTemplate->common.numChannels, |
notCompressed, |
NoneType); |
if (chunkTemplate->common.sampleSize == kSixteen) { |
theSoundInfo->needsMasking = false; |
} |
else { |
theSoundInfo->needsMasking = true; |
} |
} |
} |
break; |
case SoundDataID: |
if ((chunkFlags & kSoundData) == false) { /* see if this chunk already exists */ |
/* Let's remember where the Sound Data starts, so we can find the position in the file later. |
The mark will be positioned at the beginning of the chunk, so move 16 bytes past to get past |
the header information to the data. */ |
*dataStart = filePosition + 16; |
chunkFlags |= kSoundData; /* otherwise mark it found */ |
filePosition += chunkTemplate->soundData.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
/* |
The following list of chunks we don't care about, so we'll just skip over them. |
*/ |
case MarkerID: |
if ((chunkFlags & kMarker) == false) { /* see if this chunk already exists */ |
chunkFlags |= kMarker; /* otherwise mark it found */ |
filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case CommentID: |
if ((chunkFlags & kComment) == false) { /* see if this chunk already exists */ |
chunkFlags |= kComment; /* otherwise mark it found */ |
filePosition += chunkTemplate->marker.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case InstrumentID: |
if ((chunkFlags & kInstrument) == false) { /* see if this chunk already exists */ |
chunkFlags |= kInstrument; /* otherwise mark it found */ |
filePosition += chunkTemplate->instrument.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case MIDIDataID: |
if ((chunkFlags & kMIDIData) == false) { /* see if this chunk already exists */ |
chunkFlags |= kMIDIData; /* otherwise mark it found */ |
filePosition += chunkTemplate->midiData.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case AudioRecordingID: |
if ((chunkFlags & kAudioRecording) == false) { /* see if this chunk already exists */ |
chunkFlags |= kAudioRecording; /* otherwise mark it found */ |
filePosition += chunkTemplate->audioRecording.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case ApplicationSpecificID: |
if ((chunkFlags & kApplicationSpecific) == false) { /* see if this chunk already exists */ |
chunkFlags |= kApplicationSpecific; /* otherwise mark it found */ |
filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case NameID: |
if ((chunkFlags & kName) == false) { /* see if this chunk already exists */ |
chunkFlags |= kName; /* otherwise mark it found */ |
filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case AuthorID: |
if ((chunkFlags & kAuthor) == false) { /* see if this chunk already exists */ |
chunkFlags |= kAuthor; /* otherwise mark it found */ |
filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case CopyrightID: |
if ((chunkFlags & kCopyright) == false) { /* see if this chunk already exists */ |
chunkFlags |= kCopyright; /* otherwise mark it found */ |
filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
case AnnotationID: |
if ((chunkFlags & kAnnotation) == false) { /* see if this chunk already exists */ |
chunkFlags |= kAnnotation; /* otherwise mark it found */ |
filePosition += chunkTemplate->generic.ckSize + kChunkHeaderSize; /* calculate next chunk's position */ |
err = noErr; |
} |
break; |
default : /* Unrecognized?? croak. */ |
DebugPrint ("\pran into an undefined chunk!!"); |
/* If we hit an unrecognized chunk, clear chunkFlags to drop out of the loop |
with the assumed error code. */ |
chunkFlags = kInit; |
break; |
} |
/* We're only done when the the FORM, FormatVersion, Common and Sound Data chunks. This is only |
true of this incarnation - your needs may vary, so you'll have to modify the following statement |
accordingly... |
I know, this clause is a pain in the ass: what it really says is this: |
As long as we have a FORM Chunk and we don't have all of the {Formatversion, Common, SoundData} chunks |
keep going... AND we haven't gotten an error from the file system. */ |
} while (stillMoreDataToRead); |
if (err != noErr) { |
DebugPrint ("\pError in ASoundGetAIFFHeader"); |
} |
return err; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-03-14