2

I have a midi read proc callback setup in a Swift 3 project. I would like to keep the project in Swift entirely without having to resort to Objective C just to make this work. There are a lot of articles on Core Midi and Swift but as the framework is changing often, the syntax in those articles don't apply any longer.

    //Midi Message Callback
func MIDIReadCallback (pktList :UnsafePointer<MIDIPacketList>, refCon :UnsafeMutableRawPointer?, srcConRef :UnsafeMutableRawPointer?) -> Void{

    let packet = pktList.pointee.packet


    for _ in 0..<Int(pktList.pointee.numPackets) {

        let mirrorData = Mirror(reflecting: packet.data)

        var counter: UInt16 = 0


        for(_, value)in mirrorData.children{

            let packetCount = packet.length


            let n = value as! UInt8

            let st = String(format: "%2X", n)

            messageData.append(st)

            counter += 1

            if(value as! UInt8 == 247){
                processMidiMessage()
                break}

            if(packetCount == counter){break}
        }



    }

}

I put this callback in when creating the input port like this:

    CheckError(error: MIDIInputPortCreate(client, "Input port" as CFString, MIDIReadCallback, &player, &inPort),

This gives me the following exception:

A C function pointer can only be formed from a reference to a 'func' or a literal closure

It is unclear to me what this exception means. The signature of the function matches the expected callback signature and it just looks like a Swift function.

What do I need to change to make the compiler accept my Swift function as a proper c pointer callback?

WJM
  • 1,137
  • 1
  • 15
  • 30
  • 1
    The callback cannot be an instance method. Compare http://stackoverflow.com/questions/33260808/how-to-use-instance-method-as-callback-for-function-which-takes-only-func-or-lit for a similar issue. – Martin R Jan 25 '17 at 15:40

1 Answers1

2

A normal CoreMIDI callback cannot be an instance method, or a closure that uses other variables in the scope, because they must obey @convention(c) semantics.

However, in CoreMIDI 1.3 you can use MIDIInputPortCreateWithBlock instead which takes an @escaping MIDIReadBlock parameter instead of a MIDIReadProc.

Alnitak
  • 334,560
  • 70
  • 407
  • 495