J'ai une fonction de pontage dans Swift, dont l'un des arguments dans C est AudioBufferList *
. Dans Swift, ceci génère un UnsafePointer<AudioBufferList>
. J'ai réussi à déférer le pointeur en appelant audioData[0]
(existe-t-il un meilleur moyen?). Mais je suis aux sockets avec les deux niveaux suivants: le tableau .mBuffers
des AudioBuffer
et leurs membres void *
/ UnsafePointer<()>
.mData
.
En C, ce serait simplement
Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData; output = audioData[sampleNum]...
Dans Swift, la première chose étrange est qu'il ne me laisse pas accéder aux éléments de mBuffers
mais il est parfaitement content quand j'y accède en tant que propriété. En d'autres termes, cela fonctionne et a même des données correctes (pour le premier membre de mBuffers
je présume) …
println(abl[0].mBuffers.mNumberChannels) // But .mBuffers should be an []!
Ensuite, .mData
sous- .mData
mais la valeur est toujours ()
println(abl[0].mBuffers.mData[10]) // Prints '()'
J'ai essayé différentes opérations de casting et d'access avec plusieurs indices mais en vain … des idées?
Voici les définitions C et Swift pour AudioBufferList
et AudioBuffer
pour plus de commodité …
// 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<()> }
Edit: La réponse d'Adam Ritenauer est probablement la meilleure maintenant. Pour développer cela, vous pouvez regarder les nouvelles fonctions / types d'utilitaires dans les changements iOS 8.3 Core Audio .
UnsafeMutableAudioBufferListPointer
peut être utilisé pour lire / accéder à certaines données:
struct UnsafeMutableAudioBufferListPointer { init(_ p: UnsafeMutablePointer<AudioBufferList>) var count: Int subscript (index: Int) -> AudioBuffer { get nonmutating set } }
Et vous pouvez utiliser les extensions sur AudioBuffer & AudioBufferList pour allouer les vôtres:
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) }
Vieille réponse:
C'est un peu compliqué car AudioBufferList
est en fait une structure de taille variable. Cela signifie qu'il est déclaré comme ayant un seul AudioBuffer
, mais en réalité, il en a autant que spécifié par le membre mNumberBuffers
. Cette notion ne se traduit pas très bien dans Swift, c'est pourquoi vous voyez var mBuffers: (AudioBuffer)
.
Ainsi, la façon canonique d'accéder à ces tampons, et à leurs données, serait d'utiliser UnsafeArray
. Le code ci-dessous fournit quelques idées, mais UnsafePointer
et UnsafeArray
ne sont pas bien documentés, donc cela pourrait être faux.
// ***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...
Cela semble fonctionner dans la cour de récréation mais il m'est difficile de tester sur de vraies données audio. En particulier, je ne suis pas sûr à 100% que l'utilisation de start: &foo.memory.mBuffers
fonctionnera comme prévu. (Il renvoie un pointeur différent de l'original, bien que datatables semblent être là.) Donnez-lui un coup de feu et faites un rapport!
Edit: pour déboguer cela, au fait, vous pouvez par exemple:
(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 ...
Je l'ai trouvé par hasard. Bizarrement le type à venir fonctionnait réellement avec Swift quand il a suggéré UnsafeMutableAudioBufferListPointer. Que vous pouvez initialiser avec un argument UnsafeMutablePointer. Ce type est un MutableCollectionType et fournit un access en indice et en générateur aux tampons audio contenus.
Par exemple, vous pouvez mettre un ABL en silence avec le code suivant
func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus { let abl = UnsafeMutableAudioBufferListPointer(ioData) for buffer in abl { memset(buffer.mData, 0, Int(buffer.mDataByteSize)) } return noErr }
J'ai trouvé que cela fonctionne bien. abl
est une AudioBufferList créée à partir du chargement d'un file audio AIFF 16 bits.
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(" ") }
Cela fonctionne pour moi avec Swift 1.2
var ddata: NSData buf = AudioBuffer(mNumberChannels: 1, mDataByteSize: numberOfFrames * UInt32(sizeof(Float32)), mData: &ddata) var audioBuffers = AudioBufferList(mNumberBuffers: 1, mBuffers: buf!)