与Swift一起使用AudioBufferList

我在Swift中有一个桥接函数,其中一个在C中的参数是AudioBufferList * 。 在Swift中,这会生成一个UnsafePointer<AudioBufferList> 。 我设法通过调用audioData[0]来尊重指针(还有更好的方法吗?)。 但是,我正在苦苦挣扎下面两层: .mBuffers数组和它们的void * / UnsafePointer<()> .mData成员。

在C中,它将是简单的

 Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData; output = audioData[sampleNum]... 

在Swift中,第一个奇怪的是,它不会让我访问mBuffers的元素,但是当我作为一个属性来访问时,它是非常高兴的。 换句话说,这个工作,甚至有正确的数据(对于我认为的第一个mBuffers成员)…

 println(abl[0].mBuffers.mNumberChannels) // But .mBuffers should be an []! 

其次,让我打印.mData下标,但是值总是()

 println(abl[0].mBuffers.mData[10]) // Prints '()' 

我尝试了各种铸造操作和访问与多个指标,但无济于事…任何想法?

这里是AudioBufferListAudioBuffer的C和Swift定义,以方便…

 // C struct AudioBufferList { UInt32 mNumberBuffers; AudioBuffer mBuffers[1]; // this is a variable length array of mNumberBuffers elements // ...and a bit more for c++ } struct AudioBuffer { UInt32 mNumberChannels; UInt32 mDataByteSize; void* mData; }; 

 // SWIFT struct AudioBufferList { var mNumberBuffers: UInt32 var mBuffers: (AudioBuffer) } struct AudioBuffer { var mNumberChannels: UInt32 var mDataByteSize: UInt32 var mData: UnsafePointer<()> } 

编辑:亚当Ritenauer的答案可能是现在最好的。 为了扩展它,你可以看看iOS 8.3核心audio变化中的新的效用函数/types。

UnsafeMutableAudioBufferListPointer可用于读取/访问某些给定的数据:

 struct UnsafeMutableAudioBufferListPointer { init(_ p: UnsafeMutablePointer<AudioBufferList>) var count: Int subscript (index: Int) -> AudioBuffer { get nonmutating set } } 

你可以使用AudioBuffer&AudioBufferList上的扩展来分配你自己的:

 extension AudioBufferList { static func sizeInBytes(maximumBuffers maximumBuffers: Int) -> Int static func allocate(maximumBuffers maximumBuffers: Int) -> UnsafeMutableAudioBufferListPointer } extension AudioBuffer { init<Element>(_ typedBuffer: UnsafeMutableBufferPointer<Element>, numberOfChannels: Int) } 

老答案:

这有点棘手,因为AudioBufferList实际上是一个可变大小的结构。 这意味着它被声明为有一个单一的AudioBuffer ,但它确实有mNumberBuffers成员指定的那么mNumberBuffers 。 这个概念不能很好地转换成Swift,这就是为什么你看到var mBuffers: (AudioBuffer)

因此,访问这些缓冲区的规范方法及其数据将使用UnsafeArray 。 下面的代码提供了一些想法,但是UnsafePointerUnsafeArray没有很好的logging,所以这可能是错误的。

 // ***WARNING: UNTESTED CODE AHEAD*** let foo: UnsafePointer<AudioBufferList> // from elsewhere... // This looks intuitive, but accessing `foo.memory` may be doing a copy. let bufs = UnsafeArray<AudioBuffer>(start: &foo.memory.mBuffers, length: Int(foo.memory.mNumberBuffers)) // This is another alternative that should work... let bufsStart = UnsafePointer<AudioBuffer>(UnsafePointer<UInt32>(foo) + 1) // Offset to mBuffers member let bufs = UnsafeArray<AudioBuffer>(start: bufsStart, length: Int(foo.memory.mNumberBuffers)) // Hopefully this isn't doing a copy, but it shouldn't be too much of a problem anyway. let buf: AudioBuffer = bufs[0] // or you could use a for loop over bufs, etc. typealias MySample = Float32 let numSamples = Int(buf.mDataByteSize / UInt32(sizeof(MySample))) let samples = UnsafeArray<MySample>(start: UnsafePointer<MySample>(buf.mData), length: numSamples) // Now use the samples array... 

这似乎在操场上工作,但我真的很难testing真正的audio数据。 特别是,我不是100%确定使用start: &foo.memory.mBuffers将按预期工作。 (它会返回与原始指针不同的指针,虽然数据似乎在那里)。给它一个镜头,并报告回来!

编辑:debugging这个,顺便说一下,你可以例如:

 (lldb) p foo (UnsafePointer<AudioBufferList>) $R1 = (value = Builtin.RawPointer = 0x0000000100700740) (lldb) expr -lc -- ((int*)0x0000000100700740)[0] (int) $2 = 42 (lldb) expr -lc -- ((int*)0x0000000100700740)[1] (int) $3 = 43 ... 

我偶然发现了这个 奇怪的是,前面提到的types实际上是在使用Swift时,它提出了UnsafeMutableAudioBufferListPointer。 你可以用一个UnsafeMutablePointer参数来初始化它。 这种types是MutableCollectionType,它提供了对所包含的audio缓冲区的下标和发生器访问。

例如,您可以使用以下代码将ABL设置为无声

 func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus { let abl = UnsafeMutableAudioBufferListPointer(ioData) for buffer in abl { memset(buffer.mData, 0, Int(buffer.mDataByteSize)) } return noErr } 

我发现这个工程确定。 abl是从加载16位AIFFaudio文件创build的AudioBufferList。

 let mBuffers=abl.memory.mBuffers let data=UnsafePointer<Int16>(mBuffers.mData) let dataArray=UnsafeBufferPointer<Int16>(start:data, count: Int(mBuffers.mDataByteSize)/sizeof(Int16)) //checking resulting array let count=dataArray.count //this matches the expected number of samples in my case for i in 0..<count { print(dataArray[i]) //values look OK in my case print(" ") } 

这适用于Swift 1.2

  var ddata: NSData buf = AudioBuffer(mNumberChannels: 1, mDataByteSize: numberOfFrames * UInt32(sizeof(Float32)), mData: &ddata) var audioBuffers = AudioBufferList(mNumberBuffers: 1, mBuffers: buf!)