audiocore-audioqtkit

How do I create an AIFF file


I have some raw sound data that I want to make into an AIFF file format. I know the specifics of the audio data. I tried creating a wave from the audio, but that didn't work. OS X does have a function to create the header, but it directly addresses a file and I might not want to do that (that and the function, SetupAIFFHeader is deprecated and unavailable in 64-bit code).


Solution

  • Apple's Core Audio API will create and write data to an AIFF file, and other formats. It works pretty well, but in my opinion the API is difficult to use. I'll paste some example code below, but you'd probably want to change it. AudioFileWriteBytes can write more than 2 bytes at a time. There is another wrapper API in AudioToolbox/ExtendedAudioFile.h which will let you write a format like 32 bit floats, and have it translated to an underlying format, be it AIFF/PCM or a compressed format.

    double sampleRate = 44100;
    double duration = ...;
    long nSamples = (long)(sampleRate * duration);
    
    // Format struct for 1 channel, 16 bit PCM audio
    AudioStreamBasicDescription asbd;
    memset(&asbd, 0, sizeof(asbd));
    asbd.mSampleRate = sampleRate;
    asbd.mFormatID = kAudioFormatLinearPCM;
    asbd.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger;
    asbd.mBitsPerChannel = 16;
    asbd.mChannelsPerFrame = 1;
    asbd.mFramesPerPacket = 1;
    asbd.mBytesPerFrame = 2;
    asbd.mBytesPerPacket = 2;
    
    CFURLRef url = makeUrl("hello.aiff");
    
    AudioFileID audioFile;
    OSStatus res;
    res = AudioFileCreateWithURL(url, kAudioFileAIFFType, &asbd, 
                                 kAudioFileFlags_EraseFile, &audioFile);
    checkError(res);
    
    UInt32 numBytes = 2;
    for (int i=0; i<nSamples; i++) {
        SInt16 sample = ... // something between SHRT_MIN and SHRT_MAX;
        sample = OSSwapHostToBigInt16(sample);       
        res = AudioFileWriteBytes(audioFile, false, i*2, &numBytes, &sample);
        checkError(res);
    }
    
    res = AudioFileClose(audioFile);
    checkError(res);
    

    checkError is asserting that res == noErr. makeUrl looks like:

    CFURLRef makeUrl(const char *cstr) {
        CFStringRef path = CFStringCreateWithCString(0, cstr, kCFStringEncodingUTF8);
        CFURLRef url = CFURLCreateWithFileSystemPath(NULL, path, 0, false);
        CFRelease(path);
        return url;
    }