AudioFileWriteBytes立体声文件的性能

时间:2017-11-21 21:44:53

标签: ios core-audio

我正在使用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等),但我没想到它会起作用,但事实并非如此。

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

1 个答案:

答案 0 :(得分:2)

  

我尝试将缓冲区转到LRLRLRLR(左/右),然后只用一个AudioFileWriteBytes调用来编写它。

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

如果可能,请使用Extended Audio File Services,而不是非常低级别的音频文件服务。它是音频文件服务的包装器,内置格式转换器。或者甚至更好,使用AVAudioFile 是扩展音频文件服务的包装,涵盖了大多数常见用例。

如果您开始使用音频文件服务,则必须像尝试一样手动交错音频。也许显示您尝试此操作的代码。