Ios 将AudioBufferList与Swift结合使用

Ios 将AudioBufferList与Swift结合使用,ios,objective-c,pointers,casting,swift,Ios,Objective C,Pointers,Casting,Swift,我在Swift中有一个桥接函数,它在C中的一个参数是AudioBufferList*。在Swift中,这将生成一个UnsafePointer。我通过调用audioData[0](有更好的方法吗?)。但我正在努力解决接下来的两层问题:.mbuffer音频缓冲区数组及其void*/未安全指针.mData成员 在C语言中,它只是 Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData; output = audioData[sampl

我在Swift中有一个桥接函数,它在C中的一个参数是
AudioBufferList*
。在Swift中,这将生成一个
UnsafePointer
。我通过调用
audioData[0]
(有更好的方法吗?)。但我正在努力解决接下来的两层问题:
.mbuffer
音频缓冲区数组及其
void*
/
未安全指针
.mData
成员

在C语言中,它只是

Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData;
output = audioData[sampleNum]...
在Swift中,第一件奇怪的事情是,它不允许我访问
mBuffers
的元素,但当我作为一个属性访问它时,它非常高兴。换言之,这是有效的,甚至有正确的数据(我想是针对
mbuffer
的第一个成员)

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

我尝试过各种各样的施法操作和访问多个索引,但都没有用…有什么想法吗

以下是C和Swift对
AudioBufferList
AudioBuffer
的定义,以方便使用

// 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
结构音频缓冲列表{
变量mNumberBuffers:UInt32
变量mBuffers:(音频缓冲区)
}
结构音频缓冲区{
变量mNumberChannels:UInt32
变量mDataByteSize:UInt32
var-mData:UnsafePointer
}

编辑:亚当·里特纳的答案现在可能是最好的。要扩展它,您可以查看中的新实用程序函数/类型

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

struct UnsafeMutableAudioBufferListPointer {
    init(_ p: UnsafeMutablePointer<AudioBufferList>)
    var count: Int
    subscript (index: Int) -> AudioBuffer { get nonmutating set }
}
这似乎在操场上起作用,但我很难测试真实的音频数据。特别是,我不能100%确定使用
start:&foo.memory.mBuffers
是否能按预期工作。(它返回一个与原始指针不同的指针,尽管数据似乎在那里。)给它一个镜头并报告回来

编辑:顺便说一下,要调试它,您可以:

(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
...
(lldb)p foo
(非安全指针)$R1=(值=内置的.RawPointer=0x0000000100700740)
(lldb)expr-lc——((int*)0x0000000100700740)[0]
(int)$2=42
(lldb)expr-lc——((int*)0x0000000100700740)[1]
(int)$3=43
...

我发现这很好用<代码>abl
是通过加载16位AIFF音频文件创建的音频缓冲列表

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(" ")
}
让mBuffers=abl.memory.mBuffers
let data=UnsafePointer(mBuffers.mData)
让dataArray=UnsafeBufferPointer(start:data,count:Int(mBuffers.mDataByteSize)/sizeof(Int16))
//检查结果数组
let count=dataArray.count//这与我的案例中预期的样本数相匹配

因为我在0..中偶然发现了这个。奇怪的是,前面的类型实际上与Swift一起工作,它建议使用UnsafeMutableAudioBufferListPointer。您可以使用unsafemeutablepointer参数初始化它。此类型是MutableCollectionType,提供对包含的音频缓冲区的下标和生成器访问

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

func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {

    let abl = UnsafeMutableAudioBufferListPointer(ioData)

    for buffer in abl {

        memset(buffer.mData, 0, Int(buffer.mDataByteSize))
    }

    return noErr
}
func renderCallback(ioData:UnsafeMutablePointer)->OSStatus{
设abl=UnsafemeutableAudioBufferListPointer(ioData)
用于abl中的缓冲区{
memset(buffer.mData,0,Int(buffer.mDataByteSize))
}
返回noErr
}

这对我来说适用于Swift 1.2

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

您好,我还没有机会在我的项目中尝试这一点,但我只是想快速地说,
reinterpretCast
可能也会有帮助……这是一个很好的观点,但我不确定如何在这里使用它。它是没有文档记录的,所以我不知道它是否在内存中的同一个位置上工作,复制周围的东西,或者什么…thx。决定给你荣誉,即使亚当的更好:)很好,这似乎是相当新的。问题:我有一个
UnsafePointer
,但UnsafeMutableAudioBufferListPointer需要一个
UnsafeMutablePointer
。您知道如何转换它吗?设置为静音是一回事,但以编程方式生成声音似乎是完全不同的。我使用正弦波生成纯音,但无法找到从浮点振幅转换为memset所需的Int32的正确方法。我只听到可怕的爆裂声。有什么想法吗?@Georg你想要
UnsafeMutablePointer(mutating:myImmutableAudoBufferList)
// ***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...
(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
...
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(" ")
}
func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {

    let abl = UnsafeMutableAudioBufferListPointer(ioData)

    for buffer in abl {

        memset(buffer.mData, 0, Int(buffer.mDataByteSize))
    }

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