立体声文件的 AudioFileWriteBytes 性能

AudioFileWriteBytes performance for stereo file

我正在用 AudioFileWriteBytes (CoreAudio / iOS) 编写一个立体声波形文件,我让它工作的唯一方法是为每个通道上的每个样本调用它。

以下代码有效:

// Prepare the format AudioStreamBasicDescription;
AudioStreamBasicDescription asbd = {
    .mSampleRate       = session.samplerate,
    .mFormatID         = kAudioFormatLinearPCM,
    .mFormatFlags      = kAudioFormatFlagIsBigEndian| kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
    .mChannelsPerFrame = 2,
    .mBitsPerChannel   = 16,
    .mFramesPerPacket  = 1, // Always 1 for uncompressed formats
    .mBytesPerPacket   = 4, // 16 bits for 2 channels = 4 bytes
    .mBytesPerFrame    = 4  // 16 bits for 2 channels = 4 bytes
};

// Set up the file
AudioFileID audioFile;
OSStatus audioError = noErr;
audioError = AudioFileCreateWithURL((__bridge CFURLRef)fileURL, kAudioFileAIFFType, &asbd, kAudioFileFlags_EraseFile, &audioFile);
if (audioError != noErr) {
    NSLog(@"Error creating file");
    return;
}    

// Write samples
UInt64 currentFrame = 0;
while (currentFrame < totalLengthInFrames) {
    UInt64 numberOfFramesToWrite = totalLengthInFrames - currentFrame;
    if (numberOfFramesToWrite > 2048) {
        numberOfFramesToWrite = 2048;
    }

    UInt32 sampleByteCount = sizeof(int16_t);
    UInt32 bytesToWrite = (UInt32)numberOfFramesToWrite * sampleByteCount;
    int16_t *sampleBufferLeft = (int16_t *)malloc(bytesToWrite);
    int16_t *sampleBufferRight = (int16_t *)malloc(bytesToWrite);

    // Some magic to fill the buffers

    for (int j = 0; j < numberOfFramesToWrite; j++) {
        int16_t left  = CFSwapInt16HostToBig(sampleBufferLeft[j]);
        int16_t right = CFSwapInt16HostToBig(sampleBufferRight[j]);

        audioError = AudioFileWriteBytes(audioFile, false, (currentFrame + j) * 4, &sampleByteCount, &left);
        assert(audioError == noErr);
        audioError = AudioFileWriteBytes(audioFile, false, (currentFrame + j) * 4 + 2, &sampleByteCount, &right);
        assert(audioError == noErr);
    }

    free(sampleBufferLeft);
    free(sampleBufferRight);

    currentFrame += numberOfFramesToWrite;
}

然而,它(显然)非常缓慢且效率低下。 我找不到任何关于如何将它与大缓冲区一起使用的信息,这样我就可以在编写 2 个通道的同时编写多个样本。

我尝试制作一个缓冲区变为 LRLRLRLR(左/右),然后只用一个 AudioFileWriteBytes 调用写入它。我希望它能工作,但它产生了一个充满噪音的文件。 这是代码:

UInt64 currentFrame = 0;
UInt64 bytePos = 0;
while (currentFrame < totalLengthInFrames) {
    UInt64 numberOfFramesToWrite = totalLengthInFrames - currentFrame;
    if (numberOfFramesToWrite > 2048) {
        numberOfFramesToWrite = 2048;
    }

    UInt32 sampleByteCount = sizeof(int16_t);
    UInt32 bytesInBuffer = (UInt32)numberOfFramesToWrite * sampleByteCount;
    UInt32 bytesInOutputBuffer = (UInt32)numberOfFramesToWrite * sampleByteCount * 2;
    int16_t *sampleBufferLeft = (int16_t *)malloc(bytesInBuffer);
    int16_t *sampleBufferRight = (int16_t *)malloc(bytesInBuffer);
    int16_t *outputBuffer = (int16_t *)malloc(bytesInOutputBuffer);

    // Some magic to fill the buffers

    for (int j = 0; j < numberOfFramesToWrite; j++) {
        int16_t left  = CFSwapInt16HostToBig(sampleBufferLeft[j]);
        int16_t right = CFSwapInt16HostToBig(sampleBufferRight[j]);

        outputBuffer[(j * 2)] = left;
        outputBuffer[(j * 2) + 1] = right;
    }

    audioError = AudioFileWriteBytes(audioFile, false, bytePos, &bytesInOutputBuffer, &outputBuffer);
    assert(audioError == noErr);

    free(sampleBufferLeft);
    free(sampleBufferRight);
    free(outputBuffer);

    bytePos += bytesInOutputBuffer;
    currentFrame += numberOfFramesToWrite;
}

我还尝试过一次只写入缓冲区(2048*L、2048*R 等),但我没想到它会起作用,但它没有。

如何加快速度并获得工作波形文件?

I tried making a buffer going LRLRLRLR (left / right), and then write that with just one AudioFileWriteBytes call.

如果使用(相当困难的)音频文件服务,这是正确的方法。

如果可能,请使用 Extended Audio File Services. It is a wrapper around Audio File Services that has built in format converters. Or even better yet, use AVAudioFile 而不是非常低级别的音频文件服务 是扩展音频文件服务的包装器,涵盖了最常见的用例。

如果您打算使用音频文件服务,则必须像您尝试过的那样手动插入音频。也许显示您尝试此操作的代码。