2

I have the code:

let data = Data(bytes: UnsafePointer<UInt8>(audioBuffer.mData), count: Int(bufferSize))

and

let u16 = UnsafePointer<Int32>(audioBuffer.mData).pointee

Both of which work in Swift 2.3 but not in Swift 3. How do I convert them so they act equivalently? (and why?)

Martin
  • 1,135
  • 1
  • 8
  • 19
  • Possible duplicate of http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer , which answers how to get answer samples out of a Core Audio mData buffer in Swift 3. – hotpaw2 Sep 18 '16 at 16:34

3 Answers3

2

To read 16-bit audio samples from Audio Unit callback buffers in Swift 3, I use:

let bufferPointer = UnsafeMutableRawPointer(mBuffers.mData)
if var bptr = bufferPointer {
  for i in 0..<(Int(frameCount)) {
    let oneSampleI16 = bptr.assumingMemoryBound(to: Int16.self).pointee
    // do something with the audio sample
    bptr += 1
  }
}

The rest of the Audio Session and Audio Unit code is in this gist: https://gist.github.com/hotpaw2/630a466cc830e3d129b9

hotpaw2
  • 70,107
  • 14
  • 90
  • 153
  • `++` operator has bee removed from Swift 3. Seems your code in the gist is written without using `++`, and I believe you can improve your code snippet in this answer. – OOPer Sep 18 '16 at 18:27
  • @OOPer : Thanks. Copy-paste error from old version fixed. – hotpaw2 Sep 18 '16 at 19:18
1

I can't say I understand this well, nor have I read the document, but it looks like swift3 pointer casts are scoped to avoid or limit aliasing, so you can't (easily) have two different views of the same piece of memory, or at least not for very long. This means you must either copy the cast data out or do whatever you need to do within a cast callback.

Why eliminate aliasing? I guess it makes for happier compilers.

For Data:

// [NS]Data. probably copying the data 
Data(bytes: audioBuffer.mData!, count: Int(audioBuffer.mDataByteSize))

For numeric arrays:

// cast the data to Int32s & (optionally) copy the data out
let umpInt32 = audioBuffer.mData!.assumingMemoryBound(to: Int32.self)

let frameCount = Int(audioBuffer.mDataByteSize/4)
var u32 = [Int32](repeating: 0, count: frameCount)

// copy data from buffer
u32.withUnsafeMutableBufferPointer {
    $0.baseAddress!.initialize(from: umpInt32, count: frameCount)
}

p.s. there's some confusion in your code. is u16 supposed to be an array of Int32s? Or UInt16s? Or something else?

Rhythmic Fistman
  • 34,352
  • 5
  • 87
  • 159
0

Check the latest reference of Data.init(bytes:count:).

The type of the parameter bytes is UnsafeRawPointer, which accepts UnsafeMutableRawPointer. And the type of AudioBuffer.mData is UnsafeMutableRawPointer?. You have no need to convert using initializer.

let data = Data(bytes: audioBuffer.mData!, count: Int(bufferSize))

(You just need to explicitly unwrap mData, as it is imported as nullable type, UnsafeMutableRawPointer?, but you need to pass non-nil UnsafeRawPointer (or UnsafeMutableRawPointer).


The second example, you'd better check what sort of methods are available for UnsafeMutableRawPointer. You can find load(fromByteOffset:as:) method, and can use it like this.

let i32 = audioBuffer.mData!.load(as: Int32.self)

`load(

OOPer
  • 47,149
  • 6
  • 107
  • 142