2014-07-19 46 views
15

Tôi có chức năng chuyển tiếp trong Swift, một trong các đối số của nó trong C là AudioBufferList *. Trong Swift, điều này tạo ra một UnsafePointer<AudioBufferList>. Tôi đã quản lý để trì hoãn con trỏ bằng cách gọi audioData[0] (có cách nào tốt hơn không?). Nhưng tôi đang vật lộn với 2 tầng tiếp theo: mảng .mBuffers của AudioBuffervoid */UnsafePointer<()>.mData thành viên của chúng tôi.Sử dụng AudioBufferList với Swift

Trong C nó sẽ chỉ đơn giản là

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

Trong Swift điều kỳ lạ đầu tiên là nó sẽ không cho phép tôi truy cập vào các yếu tố của mBuffers nhưng là hoàn toàn hạnh phúc khi tôi truy cập vào nó như là một tài sản. Nói cách khác, các công trình này và thậm chí còn có dữ liệu chính xác (đối với thành viên đầu tiên của mBuffers tôi đoán) ...

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

Thứ hai, nó cho phép của tôi in ra .mData subscript nhưng giá trị luôn luôn là ()

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

Tôi đã thử nhiều tính năng truyền khác nhau và truy cập với nhiều chỉ mục nhưng không có kết quả ... bất kỳ ý tưởng nào?

Dưới đây là C và định nghĩa Swift cho AudioBufferListAudioBuffer để thuận tiện ...

// 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<()> 
} 

Trả lời

9

Edit: câu trả lời Adam Ritenauer có lẽ là tốt nhất hiện nay . Để mở rộng trên đó, bạn có thể xem các chức năng/loại tiện ích mới trong the iOS 8.3 Core Audio changes.

UnsafeMutableAudioBufferListPointer có thể được sử dụng để đọc/truy cập một số dữ liệu nhất định:

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

Và bạn có thể sử dụng các phần mở rộng trên AudioBuffer & AudioBufferList phân bổ của riêng bạn:

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

Cũ trả lời:

Đây là một chút khó khăn bởi vì AudioBufferList thực sự là một cấu trúc biến kích thước. Điều này có nghĩa là nó được khai báo là có một AudioBuffer duy nhất, nhưng thực sự nó có nhiều như được chỉ định bởi thành viên mNumberBuffers. Khái niệm này không dịch rất tốt cho Swift, đó là lý do tại sao bạn thấy var mBuffers: (AudioBuffer).

Vì vậy, cách kinh điển để truy cập các bộ đệm này và dữ liệu của chúng sẽ sử dụng UnsafeArray. Mã bên dưới cung cấp một số ý tưởng, nhưng UnsafePointerUnsafeArray không được ghi lại đầy đủ, vì vậy điều này có thể sai.

// ***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... 

Điều này dường như hoạt động trong sân chơi nhưng thật khó để tôi thử nghiệm trên dữ liệu âm thanh thực. Đặc biệt, tôi không chắc chắn 100% rằng việc sử dụng start: &foo.memory.mBuffers sẽ hoạt động như mong đợi.(Nó trả về một con trỏ khác với bản gốc, mặc dù dữ liệu có vẻ ở đó.) Cho nó một ảnh và báo cáo lại!

Edit: để gỡ lỗi này, bằng cách này, bạn có thể ví dụ:

(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 
... 
+0

Hi, đã không có một cơ hội để thử này ra trong dự án của tôi nhưng chỉ muốn nói nhanh rằng 'reinterpretCast' có thể giúp quá ... –

+0

Đó là một điểm tốt, nhưng tôi không chắc chắn làm thế nào để sử dụng nó ở đây. Nó không có giấy tờ nên tôi không biết liệu nó có tác dụng trên cùng một vị trí trong bộ nhớ, sao chép mọi thứ xung quanh hay không ... – jtbandes

+0

thx. quyết định cho bạn tín dụng ngay cả khi Adam tốt hơn :) –

1

tôi đã tìm thấy công trình này OK. abl là một AudioBufferList được tạo từ tải một tệp âm thanh AIFF 16 bit.

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(" ") 
} 
14

Tôi đã vô tình tìm thấy điều này. Kỳ lạ thay, kiểu gõ phía trước thực sự làm việc với Swift khi nó đề xuất UnsafeMutableAudioBufferListPointer. Mà bạn có thể khởi tạo với đối số UnsafeMutablePointer. Loại này là một MutableCollectionType và cung cấp truy cập subscript và máy phát cho bộ đệm âm thanh chứa.

Ví dụ bạn có thể đặt một ABL để bịt miệng với đoạn mã sau

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

    let abl = UnsafeMutableAudioBufferListPointer(ioData) 

    for buffer in abl { 

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

    return noErr 
} 
+0

Tìm kiếm tuyệt vời! :) –

+0

Đẹp, điều này có vẻ khá mới mẻ. – jtbandes

+0

Câu hỏi: Tôi có một 'UnsafePointer ' nhưng UnsafeMutableAudioBufferListPointer yêu cầu một 'UnsafeMutablePointer '. Bạn có biết cách chuyển đổi nó không? – Georg

1

này làm việc cho tôi với Swift 1,2

 var ddata: NSData 
     buf = AudioBuffer(mNumberChannels: 1, mDataByteSize: numberOfFrames * UInt32(sizeof(Float32)), mData: &ddata) 
     var audioBuffers = AudioBufferList(mNumberBuffers: 1, mBuffers: buf!) 
Các vấn đề liên quan