2014-07-19 17 views
15

Mam funkcję mostkowania w Swift, jeden z argumentów w C jest AudioBufferList *. W Swift generuje to UnsafePointer<AudioBufferList>. Udało mi się ocenić wskaźnik, dzwoniąc pod numer audioData[0] (czy jest lepszy sposób?). Ale zmagam się z następnymi 2 poziomami w dół: tablica .mBuffers z AudioBuffer i ich członkami.Używanie AudioBufferList z Swift

W C to po prostu być

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

w Swift pierwszy Najdziwniejsze jest to, że nie pozwoli mi uzyskać dostęp do elementów mBuffers ale jest w pełni szczęśliwy, kiedy do niego dostęp w domu. Innymi słowy, to działa i nawet ma poprawnych danych (dla pierwszego członka mBuffers ja przypuszczam) ...

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

Po drugie, niech mi wydrukować .mData indeksów, ale wartość jest zawsze ()

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

Próbowałem różnych operacji rzucania i dostępu do wielu wskaźników, ale bezskutecznie ... żadnych pomysłów?

Oto C i Swift definicje dla AudioBufferList i AudioBuffer dla wygody ...

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

Odpowiedz

9

Edycja: Odpowiedź Adama Ritenauer jest prawdopodobnie jednym z najlepszych obecnie . Aby go rozwinąć, możesz przejrzeć nowe funkcje/typy narzędzi w the iOS 8.3 Core Audio changes.

UnsafeMutableAudioBufferListPointer może być używany do odczytu/dostęp do niektórych danych:

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

I można używać rozszerzeń na AudioBuffer & AudioBufferList przeznaczyć własne:

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

Stary odpowiedź:

Jest to nieco trudne, ponieważ AudioBufferList jest w rzeczywistości strukturą o zmiennej wielkości. Oznacza to, że jest on zadeklarowany jako pojedyncza AudioBuffer, ale tak naprawdę ma tyle, ile określono przez element mNumberBuffers. To pojęcie nie przekłada się bardzo dobrze na Swift, dlatego widzisz var mBuffers: (AudioBuffer).

Więc kanoniczny sposób dostępu do tych buforów i ich danych będzie użyty UnsafeArray. Poniższy kod zawiera pewne pomysły, ale UnsafePointer i UnsafeArray nie są dobrze udokumentowane, więc może to być nieprawidłowe.

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

To wydaje się działać na placu zabaw, ale jest to trudne dla mnie do testowania na prawdziwych danych audio. W szczególności nie jestem w 100% pewien, że używanie start: &foo.memory.mBuffers będzie działać zgodnie z oczekiwaniami.(Zwraca inny wskaźnik od oryginału, chociaż dane wydają się tam być.) Daj mu strzał i zgłoś go ponownie!

Edycja: do debugowania to, nawiasem mówiąc, można na przykład:

(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

Cześć, nie mieli okazję spróbować tego w mój projekt, ale chciałem tylko szybko powiedzieć, że 'reinterpretCast' może pomóc też ... –

+0

To dobra uwaga, ale nie jestem pewna jak tego użyć tutaj. Jest nieudokumentowana, więc nie wiem, czy działa w tej samej lokalizacji w pamięci, kopiuje rzeczy dookoła, czy ... – jtbandes

+0

thx. Postanowiłem dać ci kredyt, nawet jeśli Adam's jest lepszy :) –

1

Znalazłem to działa OK. abl jest listą AudioBufferList utworzoną podczas ładowania pliku audio AIFF 16bit.

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

Znalazłem to przez przypadek. Co dziwne, typ z wyprzedzeniem pracował z Swift, gdy sugerował UnsafeMutableAudioBufferListPointer. Które można zainicjować za pomocą argumentu UnsafeMutablePointer. Ten typ jest typem MutableCollectionType i zapewnia dostęp do dołączonych buforów dźwięku w indeksie dolnym i generatorze.

Na przykład można ustawić ABL uciszyć z następującego kodu

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

    let abl = UnsafeMutableAudioBufferListPointer(ioData) 

    for buffer in abl { 

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

    return noErr 
} 
+0

Świetne odkrycie! :) –

+0

Miło, to wydaje się całkiem nowe. – jtbandes

+0

Pytanie: Mam 'UnsafePointer ', ale UnsafeMutableAudioBufferListPointer wymaga 'UnsafeMutablePointer . Czy wiesz, jak to przekształcić? – Georg

1

Działa to dla mnie Swift 1,2

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