Swift fail: MIDIClientCreate
Swift fail: MIDIClientCreate
There is a problem with calling Core MIDI’s MIDIClientCreate function from Swift.
N.B.
This article was true when published. Apple has since fixed the problem.
Introduction
Let’s start with a simple call to Core MIDI’s client create function. You need the midi client to create MIDI input and output ports.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
func midi() { var status = OSStatus(noErr) var s:CFString = "MyClient" var client = MIDIClientRef() status = MIDIClientCreate(s, MIDINotifyProc( COpaquePointer( [ MyMIDINotifyProc ] ) ), nil, &client) if status == OSStatus(noErr) { println("created client") } else { println("error creating client : \(status)") } // etc } func MyMIDINotifyProc (np:UnsafePointer<MIDINotification>, refCon:UnsafeMutablePointer<Void>) { var notification = np.memory println("MIDI Notify, messageId= \(notification.messageID)") //etc } |
Works great!
Problem
So, what’s the problem?
The above code compiled just fine when the scheme was an iPhone 6. I then plugged in my iPhone 4s and the problem raised its ugly head. If you don’t have an older iOS device, just select the scheme in XCode.
To verify that this was the problem I tried checking the arch and then calling separate init methods. The initial code for both was what you see in the first example here.
1 2 3 4 5 6 7 |
// The iPhone 4S has a 32 bit 1 GHz dual-core Apple A5 processor and 512 MB of RAM // The iPhone 5S has a 64 bit 1.3 GHz dual-core Apple A7 processor and 1 GB of RAM #if arch(arm64) || arch(x86_64) // >= iPhone 5 init64() #else // < iPhone 5 init32() #endif |
XCode will give you this love letter for 32 bit devices. This refers to the line where you create the client variable. (var client = MIDIClientRef())
1 |
'MIDIClientRef' cannot be constructed because it has no accessible initializers |
Ok, just do this then.
1 |
var client:MIDIClientRef |
Nope.
1 |
'MIDIClientRef' is not identical to 'Unmanaged<MIDIClient>?' |
Ok, then
1 |
var client : Unmanaged<MIDIClientRef>? = nil |
Works!
Go back to 64 bits.
Problem.
1 |
Type 'MIDIClientRef' does not conform to protocol 'AnyObject' |
[expletive deleted]
Here are the definitions in CoreMIDI/MIDIServices.h
1 2 |
typealias MIDIObjectRef = UnsafeMutablePointer<Void> typealias MIDIClientRef = MIDIObjectRef |
Well, actually in Objective-C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#if __LP64__ typedef UInt32 MIDIObjectRef; typedef MIDIObjectRef MIDIClientRef; typedef MIDIObjectRef MIDIPortRef; typedef MIDIObjectRef MIDIDeviceRef; typedef MIDIObjectRef MIDIEntityRef; typedef MIDIObjectRef MIDIEndpointRef; #else typedef void * MIDIObjectRef; typedef struct OpaqueMIDIClient * MIDIClientRef; typedef struct OpaqueMIDIPort * MIDIPortRef; typedef struct OpaqueMIDIDevice * MIDIDeviceRef; typedef struct OpaqueMIDIEntity * MIDIEntityRef; typedef struct OpaqueMIDIEndpoint * MIDIEndpointRef; #endif |
Suggestions?
Summary
You can’t create a MIDI client on older iOS devices using Swift.
If you have a solution, I’d love to hear it!
In the meantime, I’ll create the Core MIDI code (i.e. creating the client and ports) in Objective-C and call that from my Swift code.
2 thoughts on “Swift fail: MIDIClientCreate”