Search code examples
iphoneobjective-ciosmacosaudiotoolbox

Joining multiple ALAC files.


I am able to join multiple CAF files with encoded PCM audio inside. First I read data format from one of CAF files.

UInt32 size = sizeof(srcFormatDescription);
        status = AudioFileGetProperty(srcAudioFile, kAudioFilePropertyDataFormat, &size, &srcFormatDescription);

for PCM data format looks like this

[Line 7697] mSampleRate: 44100.000000
[Line 7698] mFormatID: 1819304813d
[Line 7699] mFormatFlags: 12d
[Line 7700] mBytesPerPacket: 2d
[Line 7701] mFramesPerPacket: 1d
[Line 7702] mBytesPerFrame: 2d
[Line 7703] mChannelsPerFrame: 1d
[Line 7704] mBitsPerChannel: 16d
[Line 7705] mReserved: 0d

Then i set data format for destination file, which will contain all CAF's.

destFormatDescription = srcFormatDescription;
status = AudioFileCreateWithURL(dest, kAudioFileCAFType, &destFormatDescription, kAudioFileFlags_EraseFile, &destAudioFile);

In next step I read data from CAF

status = AudioFileReadBytes(srcAudioFile,
                                    FALSE,
                                    currentStartForReading,
                                    &bytesNumberToRead,
                                    buffer);

and write it to destAudioFile

status = AudioFileWriteBytes(destAudioFile,
                                     FALSE,
                                     writePosition,
                                     &bytesNumberToWrite,
                                     buffer);

this steps are done in a loop. It works great. However I have big problem, now I try to do the same steps for CAF files, which contains data in ALAC format. It doesn't work. AudioFileWriteBytes return error operation not supported.

for ALAC data format looks like this

[Line 7697] mSampleRate: 44100.000000
[Line 7698] mFormatID: 1634492771d
[Line 7699] mFormatFlags: 1d
[Line 7700] mBytesPerPacket: 0d
[Line 7701] mFramesPerPacket: 4096d
[Line 7702] mBytesPerFrame: 0d
[Line 7703] mChannelsPerFrame: 1d
[Line 7704] mBitsPerChannel: 0d
[Line 7705] mReserved: 0d

Does anybody know how can I join multiple CAF files with Apple Lossless data inside?


Solution

  • I am able to join multiple CAF files with encoded PCM audio inside. First I read data format from one of CAF files.

    If the ASBDs match, then your audio file would be correct. However, if the input file's sample formats do not match, then your data would be corrupt. This is because each CAF file defines exactly one sample data chunk, and one audio description chunk.

    Therefore, it would be an error to attempt to append sample data of multiple formats into one audio data chunk. (whether that is or is not what you are attempting is not specified)

    Furthermore, compressed formats have an additional field which must be set - that is the magic cookie. All cookies would have to be equal (this is an opaque data representation, btw).

    Finally, the proper way to write compressed data is using Packet Table Chunks. The VBR/VFR formats must specify exactly one Packet Table Chunk.

    Does anybody know how can I join multiple CAF files with Apple Lossless data inside?

    What this all means: There will be a high failure rate using the approach you have chosen in the case of ALAC. As well, there's a lot that goes into keeping these files and their chunks correctly synchronized with all the Packet detail that is involved.

    So, let's approach this from another angle:

    • use ExtAudioFileCreateWithURL to create a new ALAC file
    • use ExtAudioFileOpenURL to open your input files
    • determine a common sample format from your input files
    • use ExtAudioFileSetProperty + kExtAudioFileProperty_ClientDataFormat to specify the common PCM format
    • Configure the destination/ALAC file's convertor to expect the common PCM format you have chosen.
    • read an input file's sample data, writing to the destination
    • repeat for remaining files
    • close all files

    That should be it (but it will probably require a few hundred lines of code, if you are dealing with the raw AudioFile APIs).