MIKMIDI is a library intended to simplify implementing MIDI functionality in OS X and iOS apps. We at Mixed In Key have released MIKMIDI as an open source project so that others can use it, and hopefully contribute to improving it. MIKMIDI is available on GitHub here and can also be installed using CocoaPods. In this post I will introduce the library, our motivation for creating it, along with an overview of the library itself.
Origins and Motivation
My day job is doing Mac and iOS development at Mixed In Key. Recently, we released our first live performance DJ software, Flow. I spent most of 2013 working on Flow, and really enjoyed the work we did (and continue to do) on it.
Like most DJ performance software, Flow allows you to connect a DJ controller (like this one, for example) to control the software when you’re on stage. There are many such controllers available from a wide variety of manufacturers, but they all use MIDI to communicate with a Mac or PC.
OS X and iOS include a system framework for dealing with MIDI, called CoreMIDI. CoreMIDI allows you to connect to and communicate with MIDI devices, as well as with other MIDI enabled apps. CoreMIDI is very powerful, but it’s a pure C API, and like its sister framework, CoreAudio, can be a bit daunting and difficult to get started with. Also, as a C API it’s not always a natural fit for a codebase mostly written in Objective-C.
MIKMIDI attempts to alleviate the difficulties of using CoreMIDI directly, by providing a well-written, purely Objective-C API for MIDI. It also adds a number of higher level features useful in a MIDI enabled app beyond the things CoreMIDI already allows.
Overview
There are essentially three major parts of MIKMIDI:
- Device support – includes support for device discovery, connection/disconnection, and sending/receiving MIDI messages.
- MIDI commands – includes a number of Objective-C classes that various represent MIDI message types.
- MIDI mapping – support for generating, saving, loading, and using mapping files that associate physical MIDI controls with corresponding application features.
The first two of these, device support, and MIDI commands, mostly consist of a straightforward Objective-C wrapper for existing CoreMIDI functionality, with functionality enhancements where it makes sense. MIDI Mapping is something that CoreMIDI does not provide at all.
Note that currently, MIKMIDI is focused on working with MIDI communication rather than recorded MIDI files containing music. However, contributions to add features for working with MIDI files are certainly welcome, and I may work on them myself at some point. MIKMIDI’s ultimate goal is to make working with all aspects of MIDI easier in Objective-C.
Device Support
With MIKMIDI device support functionality, you can get a list of available MIDI devices as simply as this:
NSArray *availableDevices = [[MIKMIDIDeviceManager sharedManager] availableDevices];
MIKMIDIDeviceManager
’s availableDevices
property is Key Value Observing (KVO) compliant, and NSNotifications are also posted anytime a device is connected or disconnected. This makes it quite easy to create a UI that displays a list of connected devices and updates automatically as devices are added and removed.
MIKMIDIDeviceManager
also makes it easy to connect to and disconnect from MIDI sources. When connecting to a source, you pass in an event handler block, which is called anytime MIDI messages are received from that source. Multiple event handlers can be connected, allowing multiple objects in an application to receive MIDI messages from the same source.
Sending a MIDI command is as simple as creating an MIKMIDICommand
instance and passing it to MIKMIDIDeviceManager
’s -sendCommands:toEndpoint:error:
method.
MIDI devices are represented by instances of MIKMIDIDevice
. MIKMIDIDevice
includes properties to get the manufacturer and model name of the device, as well as to access its entities, which contain its endpoints.
MIKMIDI also allows for connecting to virtual MIDI endpoints, in order to communicate with other MIDI apps on the same computer. Available virtual ports can be found by MIKMIDIDeviceManager
’s virtualSources
and virtualDestinations
properties.
MIDI Commands
In MIKMIDI, MIDI messages (aka commands) are Objective-C objects. Specifically, they’re instances of MIKMIDICommand
or one of its subclasses. Each of MIKMIDICommand
’s subclasses is used to represent a specific type of message. That way, for example, a control change message has methods for accessing controller number and value, while a note on message has methods for note number and velocity. Support for command types beyond those currently directly supported by MIKMIDI can easily be added by subclassing MIKMIDICommand
.
The library includes a category on NS/UIApplication to allow easy routing of MIDI messages to interested objects in an application. This system is inspired by the Cocoa event handling architecture. This functionality will be detailed in a later blog post, and more information can be found in the documentation.
MIDI Mapping
MIKMIDI includes features to help with adding MIDI mapping support to an application. MIDI mapping refers to the ability to map physical controls on a particular hardware controller to specific functions in the application. MIKMIDI’s mapping support includes the ability to generate, save, load, and use mapping files that associate physical controls with an application’s specific functionality. A mapping between a specific controller and the application’s UI is represented by an MIKMIDIMapping
object. MIKMIDIMappingGenerator
can be used to manage mapping files on disk, including both user-generated and application-bundled mappings. Also included is MIKMIDIMappingGenerator
, which helps with implementing a system that allows end users to easily generate their own mappings using a “MIDI learn” style interface.
In developing Flow, we found out that MIDI DJ controllers each have their own quirks and differences. The data format for MIKMIDIMapping
was informed and driven by our experiences with various controllers, and the different ways they transmit control actions by the user. MIKMIDIMappingGenerator
includes algorithms that attempt to interpret the messages coming from a controller and associate them with a control type (e.g. knob, button, jog wheel), without the programmer needing to know about the specific quirks of the controller being used.
What Next?
Complete documentation for MIKMIDI can be found on CocoaDocs. In follow up blog posts, I’ll provide some examples for working with MIKMIDI, including sample code. If you have any questions about MIKMIDI, suggestions for future improvement, or would like to contribute to its development, please email me, or comment below!