iPhone:如何初始化和释放AudioBufferList

13

如何正确初始化(分配内存)和释放(释放内存)带有3个AudioBuffers的AudioBufferList?(我知道可能有多种方法可以做到这一点。)

我想使用这三个缓冲区将音频文件的连续部分读入它们中,并使用Audio Units回放。

2个回答

18

这是我的做法:

AudioBufferList *
AllocateABL(UInt32 channelsPerFrame, UInt32 bytesPerFrame, bool interleaved, UInt32 capacityFrames)
{
    AudioBufferList *bufferList = NULL;

    UInt32 numBuffers = interleaved ? 1 : channelsPerFrame;
    UInt32 channelsPerBuffer = interleaved ? channelsPerFrame : 1;

    bufferList = static_cast<AudioBufferList *>(calloc(1, offsetof(AudioBufferList, mBuffers) + (sizeof(AudioBuffer) * numBuffers)));

    bufferList->mNumberBuffers = numBuffers;

    for(UInt32 bufferIndex = 0; bufferIndex < bufferList->mNumberBuffers; ++bufferIndex) {
        bufferList->mBuffers[bufferIndex].mData = static_cast<void *>(calloc(capacityFrames, bytesPerFrame));
        bufferList->mBuffers[bufferIndex].mDataByteSize = capacityFrames * bytesPerFrame;
        bufferList->mBuffers[bufferIndex].mNumberChannels = channelsPerBuffer;
    }

    return bufferList;
}

14
首先,我认为您实际上需要三个AudioBufferLists,而不是一个带有三个AudioBuffer成员的AudioBufferList。AudioBuffer表示单个数据通道,因此如果您有三个立体声音频文件,应该将它们放入三个AudioBufferLists中,每个列表都有两个AudioBuffers,一个缓冲区用于左声道,另一个用于右声道。然后您的代码将分别处理每个列表(以及其各自的通道数据),您可以将这些列表存储在NSArray或类似数组中。
从技术上讲,您没有理由不能使用具有3个交错音频通道的单个缓冲区列表(意味着左和右声道都存储在单个数据缓冲区中),但这与API的常规用法相违背,会有点混淆。
无论如何,CoreAudio API的这一部分更加C式而不是Objective-C式,因此您需要使用malloc/free而不是alloc/release。代码将类似于以下内容:
#define kNumChannels 2
AudioBufferList *bufferList = (AudioBufferList*)malloc(sizeof(AudioBufferList) * kNumChannels);
bufferList->mNumberBuffers = kNumChannels; // 2 for stereo, 1 for mono
for(int i = 0; i < 2; i++) {
  int numSamples = 123456; // Number of sample frames in the buffer
  bufferList->mBuffers[i].mNumberChannels = 1;
  bufferList->mBuffers[i].mDataByteSize = numSamples * sizeof(Float32);
  bufferList->mBuffers[i].mData = (Float32*)malloc(sizeof(Float32) * numSamples);
}

// Do stuff...

for(int i = 0; i < 2; i++) {
  free(bufferList->mBuffers[i].mData);
}
free(bufferList);

上面的代码假设您将数据读取为浮点数。如果您没有对文件进行任何特殊处理,以SInt16(原始PCM数据)的形式读取它们更加高效,因为iPhone没有FPU。

此外,如果您不在单个方法之外使用列表,则通过将其声明为普通对象而不是指针,在堆栈上分配它们比在堆上更有意义。您仍然需要malloc() AudioBuffer的实际mData成员,但至少您不需要担心free()实际的AudioBufferList本身。


谢谢。所以,如果我有交错的音频通道,我应该创建3个单独的AudioBufferLists,每个里面只有一个AudioBuffer,对吗?但是那么使用AudioBufferLists的意义在哪里呢?如果我正确理解你的话,我最好使用3个AudioBuffers(而不是AudioBufferLists)-至少在这种情况下是这样。 - Tom Ilsinszki
1
是的,那是正确的。使用AudioBufferLists的目的是为了更容易地管理多通道数据,因为通常交错数据在进行DSP操作时真的很麻烦。最好将立体声信号分离成各自的缓冲区,每个通道都有一个。想象一下处理4.1立体声信号--那么你将有一个包含5个交错通道的单个缓冲区!这不是很好玩。 - Nik Reiman
1
啊,但我并没有说完全不使用AudioBufferLists。虽然在AudioBufferList中传递单个AudioBuffer可能看起来很傻,但它们在CoreAudio API内部传递要容易得多。此外,AudioBufferList结构本身并不会带来太多的内存开销。 - Nik Reiman
这段代码可能会导致内存崩溃。分配的ABL只有足够容纳一个AudioBuffer的空间,但你却存储了两个。你需要将ABL的分配大小增加一个AudioBuffer。 - sbooth
@Nik 你解决了内存抖动的问题,但是分配的大小仍然不正确。请参见https://github.com/sbooth/SFBAudioEngine/blob/master/AllocateABL.cpp - sbooth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接