Re: Getting raw audio data from an AIFF file
Re: Getting raw audio data from an AIFF file
- Subject: Re: Getting raw audio data from an AIFF file
- From: Brian Willoughby <email@hidden>
- Date: Tue, 18 Feb 2003 04:19:52 -0800
Hi John,
[ Too add to this discussion if you're interested, here is some ObjC
[ code for reading an AIFF file modified from SOX I think and just
[ has basic support. Supporting the sowt type (for the audio CD)
[ would be a quick check, but it's not in the code now. There may
[ very well be problems/mistakes with this, but it does work.
SOX includes some really awful code. I've always run into bugs whenever using
it. Fortunately, they are easy to fix, given the source.
The AIFF spec mentions a common mistake - namely, that all chunks are padded
to be an even number of bytes long, even if the chunk size itself indicates an
odd number of bytes. I assume that this quirk of the spec was designed to
circumvent the original slowdown which occurs on 68000 processors when
accessing 16-bit or 32-bit values not aligned on 16-bit address boundaries. In
any event, the attached code modifications should correct for this.
Another common problem is assuming that the SSND chunk is last, which is not
guaranteed by the spec, even though it is incredibly rare.
I recently found a suite of test files which should be useful for testing any
AIFF code. Don't have the URL handy at the moment.
- (BOOL)examineFile: (NSFileHandle*)theFileHandle
{
char chunkHeader[4];
unsigned long totalFileSize = 0;
unsigned long chunkSize = 0;
unsigned long chunkSizeActual = 0;
unsigned short channels = 0;
unsigned long frames = 0;
unsigned short bits = 0;
UInt8 theRate[10];
BOOL foundCOMM = NO;
BOOL foundSSND = NO;
unsigned long offset = 0;
unsigned long blockSize = 0;
unsigned long audioDataSize = 0;
unsigned long audioOffset = 0;
// seek to the first bit
[theFileHandle seekToFileOffset: 0];
// get the bytes we need
[[theFileHandle readDataOfLength: 4] getBytes: &chunkHeader];
// make sure it is the FORM chunk
if (strncmp(chunkHeader, "FORM", 4) != 0)
{ // return out of here
return NO;
}
// get the reported file size
[[theFileHandle readDataOfLength: 4] getBytes: &totalFileSize];
// get the bytes we need
[[theFileHandle readDataOfLength: 4] getBytes: &chunkHeader];
// make sure this is the AIFF chunk
if ((strncmp(chunkHeader, "AIFF", 4) != 0) && (strncmp(chunkHeader,
"AIFC", 4) != 0))
{ // return out of here
return NO;
}
// we just skip everything but the COMM chunk and the SSND chunk
while (!(foundCOMM) || !(foundSSND))
{
// break if we've hit the end of the file
if (totalFileSize == [theFileHandle offsetInFile])
{ // post to the log
break;
}
// read some bytes
[[theFileHandle readDataOfLength: 4] getBytes: &chunkHeader];
// get our chunk size
[[theFileHandle readDataOfLength: 4] getBytes: &chunkSize];
chunkSizeActual = chunkSize;
if (1 & chunkSizeActual)
chunkSizeActual++;
// see if we are at the COMM chunk
if (strncmp(chunkHeader, "COMM", 4) == 0)
{ // read the bits we need
[[theFileHandle readDataOfLength: 2] getBytes: &channels];
[[theFileHandle readDataOfLength: 4] getBytes: &frames];
[[theFileHandle readDataOfLength: 2] getBytes: &bits];
// read the rate
[[theFileHandle readDataOfLength: 10] getBytes: &theRate];
// do this so we know how much there is left to read
chunkSize -= 18;
chunkSizeActual -= 18;
// if there is still some size left?
if (chunkSize > 0)
{
char miscHeader[4];
// read the next 4 bytes
[[theFileHandle readDataOfLength: 4] getBytes:
&miscHeader];
// decrement this too
chunkSize -= 4;
chunkSizeActual -= 4;
// see if we have compressed data
if (strncmp(miscHeader, "NONE", 4) != 0)
{ // break out of here
break;
}
}
// if we have bytes left
if (chunkSizeActual > 0)
{
// just increment the file position
[theFileHandle seekToFileOffset: ([theFileHandle
offsetInFile] + chunkSizeActual)];
}
// update so we know we found this
foundCOMM = YES;
}
// else if we're at the SSND chunk
else if (strncmp(chunkHeader, "SSND", 4) == 0)
{ // read in the bits we need
[[theFileHandle readDataOfLength: 4] getBytes: &offset];
[[theFileHandle readDataOfLength: 4] getBytes: &blockSize];
// subtract this
chunkSizeActual -= 8;
// save these
audioDataSize = chunkSize - 8;
// must calculate this based on where we are
audioOffset = offset + 12 + [theFileHandle offsetInFile];
// update this so we know
foundSSND = YES;
[theFileHandle seekToFileOffset: ([theFileHandle offsetInFile] +
chunkSizeActual)];
}
// else we're at another chunk type we don't care about
else
{ // is this a bogus file, probably from the Mac?
if ((chunkHeader[0] < 'A' || chunkHeader[0] > 'Z') ||
(chunkHeader[1] < 'A' || chunkHeader[1] > 'Z')
||
(chunkHeader[2] < 'A' || chunkHeader[2] > 'Z')
||
(chunkHeader[3] < 'A' || chunkHeader[3] > 'Z'))
break;
// if we have bytes
if (chunkSize > 0)
{ // make this just skip the data
// just increment the file position
[theFileHandle seekToFileOffset: ([theFileHandle
offsetInFile] + chunkSizeActual)];
}
}
}
// if we found the COMM and SSND chunks
if (foundCOMM && foundSSND)
{
// decide if we support this file
}
// else if we didn't find it
else
{ // just return that we can't support this file
return NO;
}
// return YES
return YES;
}
_______________________________________________
coreaudio-api mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/coreaudio-api
Do not post admin requests to the list. They will be ignored.