Question

I've used ExtAudioFileCreateWithURL and ExtAudioFileWrite from the AudioToolBox framework to save my samples to a file. But now I need to save it to an NSFileWrapper since I'm now using NSDocument:

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError 

Is there any way to use the ExtAudioFileXXX functions with an NSMutableData object so I can use NSFileWrapper initRegularFileWithContents:(NSData*)contents method?

Stripped down code for saving to file (which works):

AudioStreamBasicDescription file_desc;
FillOutASBDForLPCM(file_desc, _sample_rate, _channel_count, 32, 32, true, false);
OSStatus rv = ExtAudioFileCreateWithURL(url, kAudioFileWAVEType, &file_desc, NULL, kAudioFileFlags_EraseFile, &fout);
if (rv == noErr){
    int buff_size = sizeof(AudioBufferList) + sizeof(AudioBuffer);
    AudioBufferList* bufferList = (AudioBufferList*)malloc(buff_size);
    bufferList->mNumberBuffers = 1;
    bufferList->mBuffers[0].mData = _samples;
    bufferList->mBuffers[0].mNumberChannels = _channel_count;
    bufferList->mBuffers[0].mDataByteSize = _channel_count * _frame_count * sizeof(float);
    ExtAudioFileWrite(fout, _frame_count, bufferList);
    free(bufferList);
    ExtAudioFileDispose(fout);
}
Was it helpful?

Solution

Using an external file is the best solution in most scenarios. Note that NSData has initializers for Uncached and Mapped files. You obviously will want to minimize I/O in the majority of cases, while not consuming a ton of memory (and you have to keep an eye on Cached memory growth). One step further, consider how you can represent your file wrapper object another way for these weighty assets (sub-NSFileWrappers, links) because a document's file is likely not a trivially small file (e.g. single cycle).

If memory is not an issue (e.g. you are only dealing with small samples and finite files and documents), then you could use AudioFileInitializeWithCallbacks, which works with Wave (but not all formats). This allows you to handle your own buffer in memory, for contiguous allocations representing the entire file in memory. Then creating the NSData representation is easy -- just monitor your memory usage and ensure exclusive read/write accesses. Note that NSData does not need to create deep copies -- and factor that into your design. You will obviously have a lot more flexibility using this option on OS X. In this case, make sure you are aware of how much you actually write. In all probability, a good disk based solution (above) could save you a lot of writing to disk.

Anyways, this will require more thought than most NSFileWrapper based implementations, because you could possibly exceed 100 MB in audio file assets per document quite quickly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top