Here a code snippet from what I use in real live production code for converting audio files:
- (BOOL)convertWithDocument:(SoundDocumentCore*)document selection: (SoundSelection*)selection saveTo:(NSString*)path fileType:(UInt32)fileType progress:(ProgressSheet*)progress
{
OSStatus err;
ExtAudioFileRef eafRef;
UInt32 n;
UInt32 dataFormat = [self dataFormat];
SInt32 bitRate = [self bitRate];
// -- Data Source --
// Calculate offsets from selection, if any
UInt64 offset = 0, length = [document numFrames];
SInt32 trackOffset = 0, numTracks = [document numTracks];
if (selection != nil) {
trackOffset = [selection firstTrack];
numTracks = [selection numTracks];
offset = round ([selection startTime] * [document sampleRate]);
length = round ([selection duration] * [document sampleRate]);
}
// -- Extended Audio File --
NSString *parentPath = [path stringByDeletingLastPathComponent];
NSString *fileName = [self flipColonsAndSlashes:[path lastPathComponent]];
FSRef parentDir;
AudioStreamBasicDescription inputFormat, outputFormat;
// Create FSRef from path
err = FSPathMakeRef ((const UInt8*)[parentPath fileSystemRepresentation], &parentDir, nil);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] FSPathMakeRef() error %d", err); return NO;}
// Delete the existing file
[[NSFileManager defaultManager] removeFileAtPath: path handler:nil];
// Set up the input and output data formats
inputFormat.mSampleRate = [document sampleRate];
inputFormat.mFormatID = kAudioFormatLinearPCM;
inputFormat.mFormatFlags = kLinearPCMFormatFlagIsFloat | kAudioFormatFlagsNativeEndian;
inputFormat.mBytesPerFrame = sizeof(float) * numTracks;
inputFormat.mFramesPerPacket = 1;
inputFormat.mBytesPerPacket = inputFormat.mBytesPerFrame * inputFormat.mFramesPerPacket;
inputFormat.mChannelsPerFrame = numTracks;
inputFormat.mBitsPerChannel = 32;
inputFormat.mReserved = 0;
[self getFileDataFormat: &outputFormat];
// Create an audio file and then wrap it with ExtAudioFile
AudioFileID audioFileID;
FSRef audioFileRef;
err = AudioFileCreate(&parentDir, (CFStringRef) fileName, fileType, &outputFormat, nil, &audioFileRef, &audioFileID);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] AudioFileCreate() error %d", err); return NO;}
// Add user data
[self addUserDataToAudioFile:audioFileID];
// Wrap it in ExtAudioFile
err = ExtAudioFileWrapAudioFileID(audioFileID, YES, &eafRef);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileWrapAudioFileID() error %d", err); return NO;}
//err = ExtAudioFileCreateNew (&parentDir, (CFStringRef) fileName, fileType, &outputFormat, nil, &eafRef);
//if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileCreateNew() error %d", err); return NO;}
// Set the client data format
err = ExtAudioFileSetProperty (eafRef, kExtAudioFileProperty_ClientDataFormat, sizeof (AudioStreamBasicDescription), &inputFormat);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileSetProperty() error %d", err); return NO;}
// -- AudioConverter Setup --
AudioConverterRef converter;
n = sizeof (converter);
err = ExtAudioFileGetProperty (eafRef, kExtAudioFileProperty_AudioConverter, &n, &converter);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileGetProperty() error %d", err); return NO;}
// Set quality
UInt32 quality = kAudioCodecQuality_Max;
err = AudioConverterSetProperty(converter, kAudioConverterEncodeBitRate, sizeof (quality), &quality);
// Set bit rate
if ((bitRate != 0) && (dataFormat == kAudioFormatMPEG4AAC)) {
err = AudioConverterSetProperty(converter, kAudioConverterEncodeBitRate, sizeof (bitRate), &bitRate);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] AudioConverterSetProperty() error %d", err);}
}
// Resynchronize ExtAudioFile with AudioConverter
n = 0;
err = ExtAudioFileSetProperty (eafRef, kExtAudioFileProperty_ConverterConfig, sizeof (n), &n);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileSetProperty() error %d", err);}
// -- Write Data --
const UInt32 maxBufferSize = 256 * 1024L;
SInt64 remain = length;
UInt32 frameSize = inputFormat.mBytesPerFrame;
UInt32 maxNumFrames = maxBufferSize / frameSize;
NSMutableData *bufferListData = [NSMutableData dataWithLength: 16];
AudioBufferList *bufferList = [bufferListData mutableBytes];
NSData *bufferData;
NSAutoreleasePool *pool;
BOOL success = YES;
// Loop
while ((remain > 0) && (success == YES)) {
pool = [[NSAutoreleasePool alloc] init];
// Calculate number of frames to write
n = (remain < maxNumFrames)? remain : maxNumFrames;
// Get sample data from document
bufferData = [document interleavedDataAtOffset: offset numFrames: n firstTrack: trackOffset numTracks: numTracks];
// Set up audio buffer list
bufferList->mNumberBuffers = 1;
bufferList->mBuffers[0].mNumberChannels = numTracks;
bufferList->mBuffers[0].mDataByteSize = [bufferData length];
bufferList->mBuffers[0].mData = (void*) [bufferData bytes];
// Write data to disk
err = ExtAudioFileWrite (eafRef, n, bufferList);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileWrite() error %d", err);}
[pool release];
// Update counters
offset += n;
remain -= n;
// Update progress window
[progress setMarkValue: [progress markValue] + n];
if ([progress isCancelled]) success = NO;
}
// -- Clean Up --
err = ExtAudioFileDispose (eafRef);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] ExtAudioFileDispose() error %d", err);}
err = AudioFileClose (audioFileID);
if (err != noErr) {if (mVerbose) NSLog(@"-[AudioFile convertWithDocument:] AudioFileClose() error %d", err);}
return success;
}