Thanks to some help from here I have setup code for using an AudioConverter. I have setup a Playground to test further. I can do
var _buffer:Array<Float> = [Float](count: Int(numOutputPackets), repeatedValue: 0)
var audioBufferList = AudioBufferList(
mNumberBuffers: 1,
mBuffers: AudioBuffer(
mNumberChannels: 1,
mDataByteSize: givenSize,
mData: &_buffer
)
)
withUnsafeMutablePointers(&soundData, &audioBufferList, &_buffer) { soundPointer, audioBufferPtr, bufferPtr in
err = AudioConverterFillComplexBuffer(converter, fillComplexCallback, soundPointer , &numOutputPackets, audioBufferPtr, nil)
}
where soundData is a float array populated with audio samples. The audiosamples are generated and the soundData array is filled as epxected. in my callback function defined as
func fillComplexCallback(myConverter: AudioConverterRef, packetNumber: UnsafeMutablePointer<UInt32>, ioData: UnsafeMutablePointer<AudioBufferList>, aspd: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>>, userInfo: UnsafeMutablePointer<Void>) -> OSStatus
I can access the soundData object like
var soundData:Array<Float> = UnsafeMutablePointer<Array<Float>>(userInfo).memory
That works as expected. The soundData within the callback function is filled with the right samples. Yet the AudioBufferList is always uninitalized or empty. I access it from its memory directly and I get a valid struct which I can access its AudioBuffer. The AudioBuffer has 0 for mDataSize and a nil reference for the data.
var abl = UnsafeMutablePointer<AudioBufferList>(ioData).memory
The audioconvertfillcomplexbuffer call does also give back a size error. After returning from the callback the original AudioBufferList seems "initialized" and is empty as well.
The code base on Obj-C works well. So my guess is the AudioBufferList is causing the problems. Any ideas?
I can supply a playground setup to run exactly the described problem.
Thanks,
Volker
In addition to the above findings I can report that if I give the callback a copy of the AudioBufferList with userInfoData, I can make the AudioConverter run through fully without error. It seems that solves it. So for reference i add the vital code parts:
My callback and a struct that goes in as user info (both defined in a global context)
struct audioIO {
var pos: UInt32 = 0
var srcBuffer: Array<Float>
var srcBufferSize: UInt32 = 0
var srcSizePerPacket: UInt32 = 4
var numPacketsPerRead:UInt32 = 0
var maxPacketsInSound: UInt32 = 0
var abl: AudioBufferList
}
func fillComplexCallback(myConverter: AudioConverterRef, packetNumber: UnsafeMutablePointer<UInt32>, ioData: UnsafeMutablePointer<AudioBufferList>, aspd: UnsafeMutablePointer<UnsafeMutablePointer<AudioStreamPacketDescription>>, userInfo: UnsafeMutablePointer<Void>) -> OSStatus {
let myAIO = UnsafeMutablePointer<audioIO>(userInfo).memory
if (packetNumber.memory > myAIO.numPacketsPerRead) {
packetNumber.memory = myAIO.numPacketsPerRead
}
if (packetNumber.memory + myAIO.pos > myAIO.maxPacketsInSound)
{
packetNumber.memory = myAIO.maxPacketsInSound - myAIO.pos
}
let soundData:Array<Float> = myAIO.srcBuffer
let _buffer: Array<Float> = Array(soundData[Int(myAIO.pos)..<Int(myAIO.pos+packetNumber.memory)])
let outByteSize = packetNumber.memory * 4
UnsafeMutablePointer<audioIO>(userInfo).memory.pos = myAIO.pos + packetNumber.memory
var abl = myAIO.abl
abl.mBuffers.mDataByteSize = outByteSize
abl.mBuffers.mNumberChannels = 1
abl.mBuffers.mData = UnsafeMutablePointer<Void>(_buffer)
UnsafeMutablePointer<AudioBufferList>(ioData).memory = abl
return 0
}
An thats how I call the audioconverter - some variables are left out:
var givenSize: UInt32 = 32768
var packetsPerRead: UInt32 = 32768 / 4
var numOutputPackets = givenSize / outputSizePerPacket
var buffer = [Float]()
var _buffer:Array<Float> = [Float](count: Int(numOutputPackets), repeatedValue: 0)
var audioBufferList = AudioBufferList(mNumberBuffers: 1, mBuffers: AudioBuffer( mNumberChannels: 1, mDataByteSize: givenSize, mData: &_buffer))
var myAudioIO = audioIO(pos: UInt32(0), srcBuffer: soundData, srcBufferSize: givenSize, srcSizePerPacket: UInt32(4), numPacketsPerRead: packetsPerRead, maxPacketsInSound: UInt32(sampleCount), abl: audioBufferList)
var outPos: UInt32 = 0
while 1==1 {
withUnsafeMutablePointers(&myAudioIO, &audioBufferList, &_buffer) { soundPointer, audioBufferPtr, bufferPtr in
err = AudioConverterFillComplexBuffer(converter, fillComplexCallback, soundPointer , &numOutputPackets, audioBufferPtr, nil)
}
if err != 0 {
print("Audio error 4 \(err)")
break
}
if (numOutputPackets < 1) {
print("finished")
break;
}
buffer += Array(_buffer[0..<Int(numOutputPackets)])
outPos += numOutputPackets
}
volker