iPhone:AudioBufferList 初始化和释放

发布于 2024-09-24 10:16:50 字数 140 浏览 4 评论 0原文

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

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

What are the correct ways of initializing (allocating memory) and releasing (freeing) an AudioBufferList with 3 AudioBuffers? (I'm aware that there might be more than one ways of doing this.)

I'd like to use those 3 buffers to read sequential parts of an audio file into them and play them back using Audio Units.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

公布 2024-10-01 10:16:50

我是这样做的:

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;
}

Here is how I do it:

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;
}
玩世 2024-10-01 10:16:50

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

从技术上讲,您没有理由不能拥有具有 3 个交错音频通道的单个缓冲区列表(这意味着左通道和右通道都存储在单个数据缓冲区中),但这违背了 API 的常规使用,并且会有点混乱。

无论如何,CoreAudio API 的这一部分比 Objective-C 更接近 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 本身。

First of all, I think that you actually want 3 AudioBufferLists, not one AudioBufferList with 3 AudioBuffer members. An AudioBuffer represents a single channel of data, so if you have 3 stereo audio files, you should put them in 3 AudioBufferLists, with each list having 2 AudioBuffers, one buffer for the left channel and one for the right. Your code would then process each list (and its respective channel data) separately, and you could store the lists in an NSArray or something like that.

Technically, there's no reason you can't have a single buffer list with 3 interleaved audio channels (meaning that both the left & right channel are stored in a single buffer of data), but this goes against the conventional use of the API and will be a bit confusing.

Anyways, this part of the CoreAudio API is more C-ish than Objective-C-ish, so you'd use malloc/free instead of alloc/release. The code would look something like this:

#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);

The above code is assuming that you are reading in the data as floating point. If you aren't doing any special processing on the files, it's more efficient to read them in as SInt16 (raw PCM data), as the iPhone doesn't have a FPU.

Also, if you aren't using the lists outside of a single method, then it makes more sense to allocate them on the stack instead of the heap by declaring it as a regular object, not a pointer. You still need to malloc() the actual mData member of the AudioBuffer, but at least you don't need to worry about free()'ing the actual AudioBufferList itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文