How to manipulate MIDI with CoreMidi and C#

thread_icoIn my free time I like to create visuals and present them at parties as a visualist (VJ). My favourit software is the Modul8 from GarageCUBE which is one of best known visual software. The software is great because it’s easy to extend and use it like you want to.

 

But there are two big negative points about the Modul8:

  • Midi Mapping is not supported two ways (in / out)
  • Midi Mapping is not supported for controller with NoteOn / NoteOff events

So, it was not possible to map every button of my controller (XONE:K2) and either it was not possible to get my controller buttons highlighted if they are active.

And so I decided to develop a software which could manipulate midi messages and send them to Modul8, of course in C# ;)

The Idea of the Project

layerdiag

The idea was simple:

  • Read Midi Data from Device (XONE:K2)
  • Manipulate the data in my software (e.g. NoteOn to Controller Message)
  • Send it to Module8
  • And the same backwards

First I have developed a prototype to read data from a device. Xamarin provides a library in their MonoMac Framework which wraps the the CoreMidi API of MacOSX. With this library it’s easy to set up the listener and get the midi data from a device. Here is a simple version of this code.

//create midi client to use core midi features MidiClient client = new MidiClient ("MidiMod"); MidiP\nort inputPort = client.CreateInputPort ("MidiMod Input Port"); inputPort.MessageReceived += delegate(object sender, MidiPacketsEventArgs e) { Console.WriteLine("message received"); }; var ep = MidiEndpoint.GetSource (0); inputPort.ConnectSource (ep);

(This is just an example, if you would like to see my whole code, download the MidiMod source zip from bitbucket.)

I noticed that there are no classes to parse a midi message and convert it from the byte values into objects. So I began to develop a small lib to handle and parse midi messages, called MidiInterface. It contains a MidiHandler which connects all devices and the class MidiMessage which parses a new message. It was very interesting because I didn’t know so much about the midi protocol. Maybe someday I’m going to write another article about this MidiInterface library.

Routing Midi Data

Based on the knowledge I gathered while developing the MidiInterface lib, I implemented a class which was able to connect to two devices. It looks like the MidiHandler but has two inputs and two outputs (one for each device). It’s called MidiRouter, because it’s the point where my software connects those two devices.

Image – ClassDiag MidiRouter

With the MidiRouter it was easy to connect the hardware midi controller but I was not able to connect to Modul8. Or more precisely I was not able to send data from my software to Modul8 because this software does not create a new VirtualSource where I could have connected. It’s only possible to connect an Endpoint to Modul8. But there is no “CreateVirtualEndPoint” method in the CoreMidi Wrapper of Xamarin. There is only a “CreateVirtualSource” method and so I contacted Miguel De Icaza but sadly I never got an answer.

So I had to find a workaround to send data to Modul8 and luckily I am a (hobby) musician and have knowledge about the virtual midi environment under MacOSX. So the solution was to create a new ICA Driver in and outport. I could use the in port to send data and the outport to receive it. And because the IAC Driver was recognised by Modul8 as a VirtualEndpoint, I was able to connect them.

IACDriver

Receive Midi Data from Modul8

After solving this problem I stood in front of the next one:

  • As told above, Modul8 is not able to send MIDI data back

Luckily again, Udart (Vibeke Bertelsen) has already developed a Modul8 Module to send back midi data. It’s called TwoWayMidi and is very easy to use. Thank you Vibeke!

midi_udart_twoway

Manipulate Midi Data

After setting up the midi routing queue I was able to develop the MidiManipulator (I used to call it MidiModulator in my PoC).

My idea was to define rules and if a message has been received, the modulator would check if a rule for that specific message does exist. If so, it would call the method to manipulate this message:

flowchart_msghandling

I capsuled those rules into “ControlObjects” because my idea was to create a rule for each control on my midi controller (Button, Fader, ToggleButton usw.). Each controlobject is able to “handle” incoming and outgoing messages. So I was able to implement logic into buttons which only had two status (on / off). For example I could develop a ToggleButton which could store the current status. Or use a fader as a button, or or or…

And I was able to send a new MidiMessage for each controller. To configurate this, I ended up with a class where the whole config for one controller was defined (Xone.cs):

... List<ControlObject> controls = new List<ControlObject> (); for(int i = 0; i <= 3; i++) { controls.Add (new TwoWayEncoder (MidiMessageType.ControlChange, channel, i, ctrlCount)); } for(int i = 20; i <= 21; i++) { controls.Add (new TwoWayEncoder (MidiMessageType.ControlChange, channel, i, ctrlCount)); } ...

Of course this could be done better with a config file, but this software is just a proof of concept.

Conclusion

After developing this software I couldn’t wait till I had the chance to try it out. And at new year 2013/14 it was the time to use it! And it worked like a charm. I expected some delays because of so much routing and C# on Mac, but there was no lag. It just flowed and worked as it should.

Now I share this project because maybe someone can use my experiences and take the parts they need for their own projects. At the moment I’m not developing on this project because I have so much other things to do ;)

Bitbucket Repo

Comments are now closed for this article