Extracting data from AudioBufferList in Swift 3 - ios

I'm trying to extract the native [Float] array out of a rendered AudioBufferList where the audio unit's stream is set up for 32-bit floating point. In Swift 1 & 2 I did this:
var monoSamples = [Float]()
for i in 0..<Int(inNumberFrames) {
withUnsafePointer(to: &bufferList.mBuffers.mData, {
let ptr = $0
let newPtr = ptr + i
let sample = unsafeBitCast(newPtr.pointee, to: Float.self)
monoSamples.append(sample)
})
}
Undoubtedly not the fastest method, but it worked. In Swift 3 this compiles without error but at runtime I get a crash:
fatal error: can't unsafeBitCast between types of different sizes
That's a bit surprising; Swift's Float is 32-bit and the stream's data is 32-bit.
What I'd like to do is simply:
withUnsafeMutablePointer(to: &bufferList.mBuffers.mData, {
let monoSamples = [Float](UnsafeBufferPointer(start: $0, count:Int(inNumberFrames)))
})
But there I get a compile error:
Expression type '[Float]' is ambiguous without more context
What's the right way to do this?

If you un-converted your code to Swift 2, it does not work. You may have modified too much when converting your code to Swift 3.
Try this:
var monoSamples = [Float]()
let ptr = bufferList.mBuffers.mData?.assumingMemoryBound(to: Float.self)
monoSamples.append(contentsOf: UnsafeBufferPointer(start: ptr, count: Int(inNumberFrames)))

Try this may be?
Yeah you are correct, You have to input your $0 as UnsafePointer. Choose any type of UnsafePointer initializer and pass that value here, for the explanation purpose I have used bitPattern here.
UnsafeBufferPointer<Float>(start: UnsafePointer(bitPattern: i), count: Int(inNumberFrames))

Related

use fscanf() function in swift code

In objective c, I use fscanf to read stream from file and assign the value to variables:
int count;
char type[5];
fscanf(myFile, “count is %d, type is %4s ”, &count, type)
I want to do the same thing in swift code, I tried:
//ERROR: Type annotation missing in pattern
//What type should I use for `count`?
var count
//ERROR: consecutive statement on a line must be separated by ‘;’
var type[5] : char
fscanf(myFile, “count is %d, type is %4s ”, &count, type)
But I got compiler errors showing above. What is the correct way to use fscanf in swift ?
If you know any swift way to achieve the same thing (without using fscanf), it would be great too!
I recommend you use Foundation framework solution for reading/writing file data. A sample code to read contents of files which I used in my app to stream file into NSData:
if let fileHandle = NSFileHandle(forReadingAtPath: "path/to/file") {
fileHandle.seekToFileOffset(0)
var data = fileHandle.readDataOfLength(5)
var chars = [UInt8](count: 5, repeatedValue: 0)
data.getBytes(&chars, length: 5)
fileHandle.closeFile()
}
In case you need read Int64 data from file at a specific location:
if let fileHandle = NSFileHandle(forReadingAtPath: "path/to/file") {
fileHandle.seekToFileOffset(0)
var data = fileHandle.readDataOfLength(500)
var intFetched: Int64 = 0
let location = 100 // start at 101st character of file
data.getBytes(&intFetched, range: NSMakeRange(location, 8))
println(intFetched.littleEndian)
fileHandle.closeFile()
}

Swift UnsafeMutablePointer<Unmanaged<CFString>?> allocation and print

I'm new to swift and I have some difficulties to deal with pointers of unmanaged CFString (or NSString).
I'm working on a CoreMIDI project that implies usage of UnsafeMutablePointer?> as you can see in this function :
func MIDIObjectGetStringProperty(_ obj: MIDIObjectRef,
_ propertyID: CFString!,
_ str: UnsafeMutablePointer<Unmanaged<CFString>?>) -> OSStatus
My problem is that I want to allocate a buffer to receive the content of the property (_str) then call the function above, and finally print the content in the console by using println.
At the moment I wrote this :
// Get the first midi source (I know it exists)
var midiEndPoint : Unmanaged<MIDIEndpointRef> = MIDIGetSource(0)
//C reate a "constant" of 256
let buf = NSMutableData(capacity: 256)
// Allocate a string buffer of 256 characters (I'm not even sure this does what I want)
var name = UnsafeMutablePointer<Unmanaged<CFString>?>(buf!.bytes)
// Call the function to fill the string buffer with the display name of the midi device
var err : OSStatus = MIDIObjectGetStringProperty(&midiEndPoint,kMIDIPropertyDisplayName,name)
// Print the string ... here no surprises I don't know what to write to print the content of the pointer, so it prints the address for the moment
println(name)
I didn't find any sample code to use CoreMIDI functions on apple developper library not on the internet.
I really confused because I come from cpp and things are a lot different in swift.
EDIT :
After Rintaro and Martin answers I still have a problem, all my test are done on iOS 8.1 and if I copy the code you brought to me the compiler tells me that I can't write :
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
Results in 'Unmanaged' is not convertible to 'MIDIObjectRef'.
So I added a "&" because MIDIObjectRef is a UnsafeMutablePointer<void>.
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
Now : 'Unmanaged<MIDIEndpoint>' is not convertible to '#lvalue inout $T2'. Finally I had to change the first let to var, without understanding why ?!?
var midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
The code now compiles and runs but MIDIObjectGetStringProperty returns OSStatus err -50 which corresponds to IOW or from MacErros.h :
paramErr = -50, /*error in user parameter list*/
So it seems that the parameters are not the ones that MIDIObjectGetStringProperty is waiting for.
The source "0" does exist on my iPad because MIDIGetNumberOfSources() returns 1. Here's the complete code :
var numDestinations: ItemCount = MIDIGetNumberOfDestinations()
println("MIDI Destinations : " + String(numDestinations))
for var i : ItemCount = 0 ; i < numDestinations; ++i{
var midiEndPoint = MIDIGetDestination(i)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(&midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println(displayName)
}else{
println("error : "+String(err))
}
}
Displays :
MIDI Destinations : 1
error : -50
I really don't understand anything ...
UPDATE :
Finally Martin found the solution, it seems that there are two different definitions of MIDIObjectRef in 32 and 64bits architectures. As I run the code on an old iPad 2 my code tried to compile in 32bits mode where MIDIGetSource(i) return value is not convertible into MIDIObjectRef. The solution is to "unsafe cast" the midi endpoint on 32 bits architectures :
#if arch(arm64) || arch(x86_64)
let midiEndPoint = MIDIGetDestination(i)
#else
let midiEndPoint = unsafeBitCast(MIDIGetDestination(i), MIDIObjectRef.self)
#endif
... Or to buy a new 64bit device ...
Thank you for the precious help
I have no experience with CoreMIDI and could not test it, but this is how it should work:
let midiEndPoint = MIDIGetSource(0)
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println(displayName)
}
As #rintaro correctly noticed, takeRetainedValue() is the right choice here because it is the callers responsibility to release the string. This is different from the
usual Core Foundation memory management rules, but documented in the
MIDI Services Reference:
NOTE
When passing a Core Foundation object to a MIDI function, the MIDI
function will never consume a reference to the object. The caller
always retains a reference which it is responsible for releasing by
calling the CFRelease function.
When receiving a Core Foundation object as a return value from a MIDI
function, the caller always receives a new reference to the object,
and is responsible for releasing it.
See "Unmanaged Objects" in "Working with Cocoa Data Types" for more information.
UPDATE: The above code works only when compiling in 64-bit mode. In 32-bit mode,
MIDIObjectRef and MIDIEndpointRef are defined as different kind of pointers.
This is no problem in (Objective-)C, but Swift does not allow a direct conversion, an
"unsafe cast" is necessary here:
let numSrcs = MIDIGetNumberOfSources()
println("number of MIDI sources: \(numSrcs)")
for srcIndex in 0 ..< numSrcs {
#if arch(arm64) || arch(x86_64)
let midiEndPoint = MIDIGetSource(srcIndex)
#else
let midiEndPoint = unsafeBitCast(MIDIGetSource(srcIndex), MIDIObjectRef.self)
#endif
var property : Unmanaged<CFString>?
let err = MIDIObjectGetStringProperty(midiEndPoint, kMIDIPropertyDisplayName, &property)
if err == noErr {
let displayName = property!.takeRetainedValue() as String
println("\(srcIndex): \(displayName)")
} else {
println("\(srcIndex): error \(err)")
}
}

Convert NSData bytes to custom object

I am starting a project to create an iOS app to communicate with a device over BLE. Being a new effort, I am trying to do this is Swift if possible. The interface uses GATT and an existing set of custom message structures. I get to a point where I have the data from BLE in an NSData object. I'd like to cast it or directly convert it to my message structure in a fairly generic way.
I know that I can extract the data by hand either directly from the byte array from the NSData object or using an NSInputStream. While that works, it could be a maintenance issue and the interface has a number of different messages in it.
Is there an easier ways to do this?
I'd be willing to create the message structures in Objective-C and do the casting there, but my knowledge of Objective-C is not much better than my knowledge of Swift.
Some sample code of what I've been playing in my playground is shown below. It all works as expected.
func getBytesFromNSData(data: NSData, start: Int) -> [UInt8] {
let count = data.length / sizeof(UInt8)
let remaining = count - start
let range = NSMakeRange(start, remaining )
var dataArray = [UInt8](count: remaining, repeatedValue: 0)
data.getBytes(&dataArray, range: range)
return dataArray
}
class TestObject {
var a: Byte
var b: Byte
init() {
a = 0x01
b = 0x02
}
init(data: NSData) {
let dataBytes = getBytesFromNSData(data, 0)
a = Byte(dataBytes[0])
b = Byte(dataBytes[1])
}
func populateFromStream(data: NSData) {
var stream = NSInputStream(data: data)
stream.open()
var bytesRead = stream.read(&a, maxLength: 1)
println("\(bytesRead)")
bytesRead = stream.read(&b, maxLength: 1)
println("\(bytesRead)")
}
func toArray() -> [Byte] {
var result = [Byte](count: 2, repeatedValue: 0)
result[0] = a
result[1] = b
return result
}
}
let test = TestObject()
let testArray = test.toArray()
let length = testArray.count
let testData = NSData(bytes: testArray, length: length)
println("\(testData)")
let testIn = [ Byte(0x0d), Byte(0x0e) ]
let testDataIn = NSData(bytes: testIn, length: testIn.count)
println("\(testDataIn)")
let testConstructor = TestObject(data: testDataIn)
var testObject = TestObject()
testObject.populateFromStream(testDataIn)
I found a method that is fairly generic that may work is some cases.
Create an Objective-C riding header
Create the data structure as an Objective-C structure
Import the header with the data structure into the bridging header
Assuming that you have a struct called Foo and an NSData object called rawData:
Use the following code to get an cast a pointer.
let structureSize = sizeof(Foo)
var myObject = UnsafeMutablePointer<Foo>.alloc(1).memory
rawData.getbytes(&myObject, length: structureSize)
This will not work in all instances and unfortunately does work in my particular case. The specific problems I have found are:
The Objective-C structure is word aligned. If your structure is not properly aligned to work boundaries, you may have a size that is incorrect. (something I ran into in my particular interface)
If you and dealing with a system that doesn't send the data in the same order you are expecting, this will not handle any byte order conversion, that would still need to be done and the structure would possibly need to be reordered to compensate. That work might negate any saving from this method.
This is the most concise method I have found if it happens to work with your particular message formats.

Using AudioBufferList with Swift

I have a bridging function in Swift, one of whose arguments in C is AudioBufferList *. In Swift this generates an UnsafePointer<AudioBufferList>. I've manage to deference the pointer by calling audioData[0] (is there a better way?). But I'm struggling with the next 2 tiers down: the .mBuffers array of AudioBuffer's and their void * / UnsafePointer<()> .mData members.
In C it would simply be
Float32 *audioData = (Float 32*)abl->mBuffers[0]->mData;
output = audioData[sampleNum]...
In Swift the first odd thing is that it won't let me access the elements of mBuffers but is perfectly happy when I access it as a property. In other words, this works and even has correct data (for the first member of mBuffers I presume)...
println(abl[0].mBuffers.mNumberChannels) // But .mBuffers should be an []!
Second, it let's me print out .mData subscripts but the value is always ()
println(abl[0].mBuffers.mData[10]) // Prints '()'
I've tried various casting ops and accessing with multiple indices but to no avail...any ideas?
Here are the C and Swift definitions for AudioBufferList and AudioBuffer for convenience...
// 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<()>
}
I found this by accident. Oddly the type ahead was actually working with Swift when it suggested UnsafeMutableAudioBufferListPointer. Which you can initialize with an UnsafeMutablePointer argument. This type is a MutableCollectionType and provides subscript and generator access to the contained Audio Buffers.
For example you can set an ABL to silence with the following code
func renderCallback(ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus {
let abl = UnsafeMutableAudioBufferListPointer(ioData)
for buffer in abl {
memset(buffer.mData, 0, Int(buffer.mDataByteSize))
}
return noErr
}
Edit: Adam Ritenauer's answer is probably the best one now. To expand on it, you can look at the new utility functions/types in the iOS 8.3 Core Audio changes.
UnsafeMutableAudioBufferListPointer can be used to read/access some given data:
struct UnsafeMutableAudioBufferListPointer {
init(_ p: UnsafeMutablePointer<AudioBufferList>)
var count: Int
subscript (index: Int) -> AudioBuffer { get nonmutating set }
}
And you can use the extensions on AudioBuffer & AudioBufferList to allocate your own:
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)
}
Old answer:
This is a bit tricky because AudioBufferList is actually a variable-size struct. This means it's declared as having a single AudioBuffer, but really it has as many as specified by the mNumberBuffers member. This notion doesn't translate very well to Swift, which is why you see var mBuffers: (AudioBuffer).
So the canonical way to access these buffers, and their data, would be using UnsafeArray. The code below provides some ideas, but UnsafePointer and UnsafeArray aren't well documented, so this could be wrong.
// ***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...
This seems to work in the playground but it's hard for me to test on real audio data. In particular, I'm not 100% sure that using start: &foo.memory.mBuffers will work as expected. (It returns a different pointer from the original, although the data seem to be there.) Give it a shot and report back!
Edit: to debug this, by the way, you can for example:
(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
...
I've found this works OK. abl is an AudioBufferList created from loading a 16bit AIFF audio file.
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(" ")
}
This works for me with Swift 1.2
var ddata: NSData
buf = AudioBuffer(mNumberChannels: 1, mDataByteSize: numberOfFrames * UInt32(sizeof(Float32)), mData: &ddata)
var audioBuffers = AudioBufferList(mNumberBuffers: 1, mBuffers: buf!)

Swift - converting from ConstUnsafePointer<()>

I'm on beta 3. Consider the following Objective-C line:
const uint8_t *reportData = [data bytes];
where data is a NSData object.
How would this line be re-written in Swift?
data.bytes is of type ConstUnsafePointer<()>, and while there's plenty of documentation on how to create a pointer type in Swift, there isn't much info on how to work with them.
edit:
To add some context, I'm trying to port Apple's HeartRateMonitor sample code to Swift. This code interacts with BLE heart rate monitors. This code I'm working on translates the data received by the Bluetooth system into an int for use in the UI. The data received from BT is expected to be an array of uints, element 0 is used to check for a flag and element 1 contains the value.
Here's the same Objective-C line in context:
const uint8_t *reportData = [data bytes];
uint16_t bpm = 0;
if ((reportData[0] & 0x01) == 0)
{
/* uint8 bpm */
bpm = reportData[1];
}
What you were looking for was how to convert NSData to an array of UInt8. Here's how.
import Foundation
let path = "/etc/csh.cshrc" // something existent
let data = NSData(contentsOfFile: path)
var aofb = [UInt8](count:data.length, repeatedValue:0)
data.getBytes(&aofb, length:data.length)
for c in aofb {
let s = UnicodeScalar(Int(c)).escape(asASCII:true)
println("\(c):\(s)")
}
Just built following code (Note code below works on Beta 3, ConstUnsafePointer<()> needs to be changed to COpaquePointer in order to work on Beta 2, please see edit history for more information)
var dataPath = NSBundle.mainBundle().pathForResource("TestData", ofType: "") // What I have in TestData is "GREETINGS WORLD"
var originalData = NSData(contentsOfFile: dataPath)
var dataLength = originalData.length
println("original data: \(originalData)") // Output original data
// Data to bytes
var reportBytes: ConstUnsafePointer<()> = originalData.bytes
var bytesToString = NSString(bytes: reportBytes, length: dataLength, encoding: NSUTF8StringEncoding)
println("string from bytes: \(bytesToString)")
// Bytes to data
var bytesToData = NSData(bytes: reportBytes, length: dataLength)
println("data from bytes: \(bytesToData)")
Console log
original data: <47524545 54494e47 5320574f 524c44>
string from bytes: GREETINGS WORLD
data from bytes: <47524545 54494e47 5320574f 524c44>
Also found this may help
ConstUnsafePointer<T>
/// This type stores a pointer to an object of type T. It provides no
/// automated memory management, and therefore the user must take care
/// to allocate and free memory appropriately.
Hope this shed light.
Looking at handling bluetooth heart rate monitors in Swift now I found the simplest way to get the NSData byte values to UInt8 format:
let bytes = UnsafePointer<UInt8>(data.bytes)
if bytes[0] & 0x01 == 0 {
NSLog("BPM \(bytes[1]")
}

Resources