Update: Code has been added for Swift 3 and XCode 8
These examples do little to no error checking and it is assumed your system has at least one source and one destination. Run them in a macOS Playground.
List the MIDI sources and destinations (Swift 3)
// // Swift MIDI Playground : Matt Grippaldi 10/17/2016 // // Sources & Destinations // // Updated for Swift 3 / XCode 8 // import Cocoa import CoreMIDI import PlaygroundSupport func getDisplayName(_ obj: MIDIObjectRef) -> String { var param: Unmanaged<CFString>? var name: String = "Error" let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m) if err == OSStatus(noErr) { name = param!.takeRetainedValue() as String } return name } func getDestinationNames() -> [String] { var names:[String] = []; let count: Int = MIDIGetNumberOfDestinations(); for i in 0..<count { let endpoint:MIDIEndpointRef = MIDIGetDestination(i); if (endpoint != 0) { names.append(getDisplayName(endpoint)); } } return names; } func getSourceNames() -> [String] { var names:[String] = []; let count: Int = MIDIGetNumberOfSources(); for i in 0..<count { let endpoint:MIDIEndpointRef = MIDIGetSource(i); if (endpoint != 0) { names.append(getDisplayName(endpoint)); } } return names; } let destNames = getDestinationNames(); print("Number of MIDI Destinations: \(destNames.count)"); for destName in destNames { print(" Destination: \(destName)"); } let sourceNames = getSourceNames(); print("\nNumber of MIDI Sources: \(sourceNames.count)"); for sourceName in sourceNames { print(" Source: \(sourceName)"); }
List the MIDI sources and destinations (Swift 2)
// // Swift MIDI Playground : Matt Grippaldi 1/1/2016 // import Cocoa import CoreMIDI func getDisplayName(obj: MIDIObjectRef) -> String { var param: Unmanaged? var name: String = "Error"; let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m) if err == OSStatus(noErr) { name = param!.takeRetainedValue() as String } return name; } func getDestinationNames() -> [String] { var names:[String] = [String](); let count: Int = MIDIGetNumberOfDestinations(); for (var i=0; i < count; ++i) { let endpoint:MIDIEndpointRef = MIDIGetDestination(i); if (endpoint != 0) { names.append(getDisplayName(endpoint)); } } return names; } func getSourceNames() -> [String] { var names:[String] = [String](); let count: Int = MIDIGetNumberOfSources(); for (var i=0; i < count; ++i) { let endpoint:MIDIEndpointRef = MIDIGetSource(i); if (endpoint != 0) { names.append(getDisplayName(endpoint)); } } return names; } let destNames = getDestinationNames(); for destName in destNames { print("Destination: \(destName)"); } let sourceNames = getSourceNames(); for sourceName in sourceNames { print("Source: \(sourceName)"); }
Create a client, connect a destination, and play a note (Swift 3)
// // // Swift MIDI Playground : Matt Grippaldi 10/17/2016 // // Sources & Destinations // // Updated for Swift 3 / XCode 8 // Added code to display destinations (11/25/2016) // import Cocoa import CoreMIDI import PlaygroundSupport func getDisplayName(_ obj: MIDIObjectRef) -> String { var param: Unmanaged? var name: String = "Error"; let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m) if err == OSStatus(noErr) { name = param!.takeRetainedValue() as String } return name; } func getDestinationNames() -> [String] { var names:[String] = [String](); let count: Int = MIDIGetNumberOfDestinations(); for i in 0 ..< count { let endpoint:MIDIEndpointRef = MIDIGetDestination(i); if (endpoint != 0) { names.append(getDisplayName(endpoint)); } } return names; } var midiClient: MIDIClientRef = 0; var outPort:MIDIPortRef = 0; MIDIClientCreate("MidiTestClient" as CFString, nil, nil, &midiClient); MIDIOutputPortCreate(midiClient, "MidiTest_OutPort" as CFString, &outPort); var packet1:MIDIPacket = MIDIPacket(); packet1.timeStamp = 0; packet1.length = 3; packet1.data.0 = 0x90 + 0; // Note On event channel 1 packet1.data.1 = 0x3C; // Note C3 packet1.data.2 = 100; // Velocity var packetList:MIDIPacketList = MIDIPacketList(numPackets: 1, packet: packet1); let destinationNames = getDestinationNames() for (index,destName) in destinationNames.enumerated() { print("Destination #\(index): \(destName)") } let destNum = 0 print("Using destination #\(destNum)") var dest:MIDIEndpointRef = MIDIGetDestination(destNum); print("Playing note for 1 second on channel 1") MIDISend(outPort, dest, &packetList); packet1.data.0 = 0x80 + 0; // Note Off event channel 1 packet1.data.2 = 0; // Velocity sleep(1); packetList = MIDIPacketList(numPackets: 1, packet: packet1); MIDISend(outPort, dest, &packetList); print("Note off sent")
Create a client, connect a destination, and play a note (Swift 2)
// // Swift MIDI Playground : Matt Grippaldi 1/1/2016 // import Cocoa import CoreMIDI var midiClient: MIDIClientRef = 0; var outPort:MIDIPortRef = 0; MIDIClientCreate("MidiTestClient", nil, nil, &midiClient); MIDIOutputPortCreate(midiClient, "MidiTest_OutPort", &outPort); var packet1:MIDIPacket = MIDIPacket(); packet1.timeStamp = 0; packet1.length = 3; packet1.data.0 = 0x90 + 0; // Note On event channel 1 packet1.data.1 = 0x3C; // Note C3 packet1.data.2 = 100; // Velocity var packetList:MIDIPacketList = MIDIPacketList(numPackets: 1, packet: packet1); // Get the first destination var dest:MIDIEndpointRef = MIDIGetDestination(0); MIDISend(outPort, dest, &packetList); packet1.data.0 = 0x80 + 0; // Note Off event channel 1 packet1.data.2 = 0; // Velocity sleep(1); packetList = MIDIPacketList(numPackets: 1, packet: packet1); MIDISend(outPort, dest, &packetList);
Connect an input source and receive data via a callback (Swift 3)
// // Swift MIDI Playground : Matt Grippaldi 10/17/2016 // // MIDI Callbacks // // Updated for Swift 3 / XCode 8 // import Cocoa import CoreMIDI import PlaygroundSupport func getDisplayName(_ obj: MIDIObjectRef) -> String { var param: Unmanaged<CFString>? var name: String = "Error" let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m) if err == OSStatus(noErr) { name = param!.takeRetainedValue() as String } return name } func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>, readProcRefCon: UnsafeMutableRawPointer?, srcConnRefCon: UnsafeMutableRawPointer?) -> Void { let packetList:MIDIPacketList = pktList.pointee let srcRef:MIDIEndpointRef = srcConnRefCon!.load(as: MIDIEndpointRef.self) print("MIDI Received From Source: \(getDisplayName(srcRef))") var packet:MIDIPacket = packetList.packet for _ in 1...packetList.numPackets { let bytes = Mirror(reflecting: packet.data).children var dumpStr = "" // bytes mirror contains all the zero values in the ridiulous packet data tuple // so use the packet length to iterate. var i = packet.length for (_, attr) in bytes.enumerated() { dumpStr += String(format:"$%02X ", attr.value as! UInt8) i -= 1 if (i <= 0) { break } } print(dumpStr) packet = MIDIPacketNext(&packet).pointee } } var midiClient: MIDIClientRef = 0 var inPort:MIDIPortRef = 0 var src:MIDIEndpointRef = MIDIGetSource(0) MIDIClientCreate("MidiTestClient" as CFString, nil, nil, &midiClient) MIDIInputPortCreate(midiClient, "MidiTest_InPort" as CFString, MyMIDIReadProc, nil, &inPort) MIDIPortConnectSource(inPort, src, &src) // Keep playground running PlaygroundPage.current.needsIndefiniteExecution = true
Connect an input source and receive data via a callback (Swift 2)
// // Swift MIDI Playground : Matt Grippaldi 1/1/2016 // import Cocoa import CoreMIDI import XCPlayground func getDisplayName(obj: MIDIObjectRef) -> String { var param: Unmanaged? var name: String = "Error"; let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m) if err == OSStatus(noErr) { name = param!.takeRetainedValue() as String } return name; } func MyMIDIReadProc(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void { let packetList:MIDIPacketList = pktList.memory; let srcRef:MIDIEndpointRef = UnsafeMutablePointer(COpaquePointer(srcConnRefCon)).memory; print("MIDI Received From Source: \(getDisplayName(srcRef))"); var packet:MIDIPacket = packetList.packet; for _ in 1...packetList.numPackets { let bytes = Mirror(reflecting: packet.data).children; var dumpStr = ""; // bytes mirror contains all the zero values in the ridiulous packet data tuple // so use the packet length to iterate. var i = packet.length; for (_, attr) in bytes.enumerate() { dumpStr += String(format:"$%02X ", attr.value as! UInt8); --i; if (i <= 0) { break; } } print(dumpStr) packet = MIDIPacketNext(&packet).memory; } } var midiClient: MIDIClientRef = 0; var inPort:MIDIPortRef = 0; var src:MIDIEndpointRef = MIDIGetSource(0); MIDIClientCreate("MidiTestClient", nil, nil, &midiClient); MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort); MIDIPortConnectSource(inPort, src, &src); // Keep playground running XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;