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;