Allocate an AudioBufferList with two buffers for stereo audio stream
Asked Answered
O

2

8

I have the following code in C that allocate an AudioBufferList with the appropriate length.

  UInt32 bufferSizeBytes = bufferSizeFrames * sizeof(Float32);
  propertySize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * mRecordSBD.mChannelsPerFrame);

  mBufferList = (AudioBufferList *) malloc(propertySize);
  mBufferList->mNumberBuffers = mRecordSBD.mChannelsPerFrame;
  for(UInt32 i = 0; i < mBufferList->mNumberBuffers; ++i)
  {
    mBufferList->mBuffers[i].mNumberChannels = 1;
    mBufferList->mBuffers[i].mDataByteSize = bufferSizeBytes;
    mBufferList->mBuffers[i].mData = malloc(bufferSizeBytes);
  }

Most of the time, mChannelsPerFrame is 2, so the above code creates two buffers, one for each channel. Each buffer has a reserved memory worths bufferSizeBytes.

How can I replicate the same behaviour in Swift?

Ocotillo answered 3/3, 2018 at 18:14 Comment(0)
B
11

Unfortunately in Swift, a C array is treated as a tuple, so AudioBufferList.mBuffers is imported a tuple with a single AudioBuffer. C lets you just access the neighboring memory by using pointer math (or array subscript in this case) in order to create a variable length struct, Swift does not.

AudioBufferList just plain doesn't translate to Swift very well. Apple have mitigated this issue with a few helper functions and types. They created a static allocate function that returns an UnsafeMutableAudioBufferListPointer which is a special type where subscript returns the audioBuffers.

let bufferSizeBytes = MemoryLayout<Float>.size * 1234

var bufferlist = AudioBufferList.allocate(maximumBuffers: 2)
bufferlist[0] = AudioBuffer(mNumberChannels: 1,
                            mDataByteSize: UInt32(bufferSizeBytes),
                            mData: malloc(bufferSizeBytes))
bufferlist[1] = AudioBuffer(mNumberChannels: 1,
                            mDataByteSize: UInt32(bufferSizeBytes),
                            mData: malloc(bufferSizeBytes))

// Free your buffers and the pointer when you're done.
for buffer in bufferlist {
    free(buffer.mData)
}
free(&bufferlist)
Birdt answered 8/3, 2018 at 6:49 Comment(2)
Thank you, this has immeasurably improved my life!Holmic
The answer works. Except that, instead of free(&bufferlist), I need to call free(bufferlist.unsafeMutablePointer). Found here.Imbrue
T
0

You can create an AudioBufferList with 2 buffers for 2 interleaved streams using a Core Audio API:

import AudioUnit
import AVFoundation

var myBufferList = AudioBufferList(
              mNumberBuffers: 2,
              mBuffers: AudioBuffer(
                  mNumberChannels: UInt32(2),
                  mDataByteSize: myBufferSizeBytes,
                  mData: nil) )
Tesstessa answered 6/3, 2018 at 17:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.