iPhone:AudioBufferList 初始化和释放

Posted

技术标签:

【中文标题】iPhone:AudioBufferList 初始化和释放【英文标题】:iPhone: AudioBufferList init and release 【发布时间】:2010-09-22 08:30:56 【问题描述】:

初始化(分配内存)和释放(释放)具有 3 个 AudioBuffers 的 AudioBufferList 的正确方法是什么? (我知道这样做的方法可能不止一种。)

我想使用这 3 个缓冲区将音频文件的连续部分读入其中并使用音频单元播放它们。

【问题讨论】:

【参考方案1】:

这是我的做法:

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;

【讨论】:

【参考方案2】:

首先,我认为您实际上想要 3 个 AudioBufferList,而不是一个具有 3 个 AudioBuffer 成员的 AudioBufferList。一个 AudioBuffer 代表一个数据通道,所以如果你有 3 个立体声音频文件,你应该把它们放在 3 个 AudioBufferLists 中,每个列表有 2 个 AudioBuffers,一个缓冲区用于左声道,一个缓冲区用于右声道。然后,您的代码将分别处理每个列表(及其各自的频道数据),您可以将列表存储在 NSArray 或类似的东西中。

从技术上讲,没有理由不能拥有一个包含 3 个交错音频通道的缓冲区列表(这意味着左右声道都存储在一个数据缓冲区中),但这与传统的使用API,会有点混乱。

无论如何,CoreAudio API 的这一部分比 Objective-C-ish 更 C-ish,所以您应该使用 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) - 至少在这种情况下。 是的,那是正确的。使用 AudioBufferLists 的目的是更容易管理多通道数据,因为通常交错的数据对于进行 DSP 操作来说是一件非常痛苦的事情。将立体声通道与每个通道都放在自己的缓冲区中会更好。想象一下使用 4.1 立体声信号——那么您将拥有一个带有 5 个隔行扫描通道的缓冲区!一起工作没有太多乐趣。 啊,但我并没有说完全不使用 AudioBufferLists。尽管在 AudioBufferList 中传递单个 AudioBuffer 似乎很愚蠢,但在 CoreAudio API 中传递它们要容易得多。此外,AudioBufferList 结构体本身不会产生太多的内存开销。 此代码可能会破坏内存。分配的 ABL 仅具有足够的空间用于单个 AudioBuffer,但您正在存储两个。您需要将 ABL 的分配大小增加一个 AudioBuffer。 @Nik 您修复了内存抖动问题,但分配的大小仍然不正确。见github.com/sbooth/SFBAudioEngine/blob/master/AllocateABL.cpp

以上是关于iPhone:AudioBufferList 初始化和释放的主要内容,如果未能解决你的问题,请参考以下文章

AudioBufferList 的 AurioTouch 用途

如何在渲染回调中交错非交错的 AudioBufferList?

AudioUnit inputCallback 与 AudioUnitRender -> audioBufferList.mBuffers[0].mDataByteSize 之间不匹配!= in

aurioTouch2 录音问题。我需要将数据从一个 AudioBufferList 添加到另一个

如何将该 UnsafeMutablePointer<UnsafeMutablePointer<Float>> 变量转换为 AudioBufferList?

用于AUHAL单元的AudioBufferList,其输出流格式被压缩。