Category

Swift MIDI Trampoline

Swift Language

Swift MIDI Trampoline

Swift does not support C Function pointers. I’ve written about that a few times.

So, what do you do if you need to use a C API that relies on C callbacks? Core MIDI is just one example of C APIs that rely on function pointers.

Introduction

Core MIDI has three C callbacks – to read incoming MIDI data, to read incoming Sysex data, and to be notified when MIDI inputs or outputs have changed. You can write a pure Swift app using MIDI if you only want to send data, but not if you want to read it.

To read incoming MIDI data (or use the other callbacks), you need to write the callbacks in Objective-C. Then if you want to handle the data in Swift, you give the Objective-C callback a Swift closure. So, the Objective-C code is like a trampoline – it hits the Objective-C code then bounces the data to Swift.

Table of Contents

Notify Callback

To use Core MIDI, the first thing you need to do is create the client reference by calling MIDIClientCreate. This function takes the notification callback as a parameter.

Core MIDI defines the notification callback like this:

We will write this callback in Objective-C.

MIDIClientCreate also takes a void pointer (notifyRefCon) to a parameter that will be passed into your callback as the second parameter. We will use this parameter to pass in a Swift closure. The callback will then invoke the Swift closure.

So, let’s wrap MIDIClientCreate with an Objective-C utility that will register the callback. This utility will take a block (your Swift closure) as a parameter. The signature of the Swift closure is specified here: it takes a MIDINotification as a parameter. This utility will copy the block and store it in the refCon passed to MIDIClientCreate. The trampoline will convert it back to a block and invoke it.

This is the trampoline. The void pointer refCon is converted back into a block and then invoked with the notification.

Here is the Swift code to call the Objective-C utility. myNotifyCallback is the Swift function that will be the callback.

The Swift callback is defined with the single MIDINotification parameter like this.

Cool, huh?
More like a pain in the neck, IMHO. But this is what you have to do until Swift supports function pointers.

Table of Contents

Read callback

You specify the read callback when you create the MIDI Input Port via MIDIInputPortCreate.

This is how the read callback is defined:

Notice that it also has a void pointer parameter that we will use to point to a Swift closure.

So, here is the Objective-C utility to create the input port. It uses the same pattern as the notify function. The last parameter readRefCon will be your Swift closure.

The read trampoline converts the void pointer back into a block that is then invoked.
I’m not passing the MIDIPacketList back to Swift, because Swift is not able to handle it. We have to iterate through it in Objective-C. (If you know a way to iterate through it in Swift, let me know!). So, the callback simply takes each MIDIPacket‘s data.

Here is how you call it from Swift.

And your Swift callback will be something like this.

Table of Contents

Summary

Yeah, I know. You have to jump through hoops. That’s just the status of Swift and C APIs at this point.

Resources

5 thoughts on “Swift MIDI Trampoline”

  1. Regards:

    My name is Juan Manuel, I am currently working in the cathedral mosque of Córdoba as a pipe organ builder, for two years we have been working so that our organ has the communication capabilities with the “RTP-MIDI” protocol and we have achieved it. But now we have arrived at the moment to implement an application that allows us to manage all the functions of the organ of tubes from a mobile device or an iPad.

    Thanks to its example code, I managed to send MIDI packages to the organ, activating and deactivating notes and even playing the same with a small virtual keyboard on the screen of my Ipad. The problem comes when I have tried to implement in my code, the creation of a ” MIDIInputPortCreate” using Swift. I have seen that there are some problems to receive the calls since swift does not support the reference to pointers.

    In your example project “Swift Midi trampoline” but the code is written in swift 2 and I can not make the application work.

    I would be very grateful if you could help me in some way to understand how I can create a ” MIDIInputPortCreate”.

    1. Yes, this is an old blog post containing a hack to get Core MIDI to run with Swift 2. As you’ve noted, Apple actually fixed things a bit and this is no longer necessary. You will find dozens of repos with working Swift MIDI code on my github account.
      Try this one: https://github.com/genedelisa/Swift3MIDI It works for Swift 4 also.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.