Skip to main content

Using a Raspberry Pi as a MIDI USB/5-pin bridge

In my constant... need... to get everything music instrument related to communicate with each other, I wanted to look into ways to get some of my keyboards/synths with only MIDI over USB to talk to devices with regular good old-fashioned 5-pin MIDI ports from the eighties.

Cables!

First I had a quick look at off the shelf solutions. The most interesting one being the Kenton MIDI USB Host – providing MIDI host functionality for USB devices as well as regular MIDI in and out in a small box. Unfortunately it is rather expensive (~125 €) and a reliable online source warned me that it was not entirely stable in collaboration with my OP-1, so I started thinking of more... home-grown solutions.

I decided to try to use my old Raspberry Pi and see if that would serve as a USB host with a borrowed MIDI USB adapter. (Thanks Simon.) A cheaper, and, as an added boon, a nerdier solution.

Step 1: Get the USB MIDI device up and running

This was the easy part. The device I have been lent is a very straight forward Creative Technology, Ltd E-Mu Xmidi 1x1. This was picked up by the ALSA drivers on the Pi. (If you don't have ALSA already installed it is just a matter of doing a sudo apt-get install alsa, basically.) The USB-only MIDI device I wanted to use for testing was my good old road-worn class-compliant M-Audio KeyStation 32. Plugged and it in and it was picked up by the system.

Step 2: Connect the two worlds

To be able to route MIDI from the one to the other we need to use aconnect. (This should come with your ALSA installation.) A quick aconnect -i will list all the input ports of your connected MIDI devices. (Along with some concepts of through and system.) Here's what my system looks like at this point:

pi@raspberrypi ~ $ aconnect -i
client 0: 'System' [type=kernel]
    0 'Timer           '
    1 'Announce        '
client 14: 'Midi Through' [type=kernel]
    0 'Midi Through Port-0'
client 16: 'Keystation Mini 32' [type=kernel]
    0 'Keystation Mini 32 MIDI 1'
client 20: 'E-MU XMidi1X1' [type=kernel]
    0 'E-MU XMidi1X1 MIDI 1' 

The important part is the number after each keyword client. They tell you how to refer to the different devices when connecting them. So, if we want to send signals from the only port (0) of the Keystation Mini (client 16) to the only port (0) of the 5-pin out (client 20) we can set up a connection using the command:

pi@raspberrypi ~ $ aconnect 16:0 20:0

Voila, if we inspect the connections again (with an added -l) it will report this:

pi@raspberrypi ~ $ aconnect -i -l
client 0: 'System' [type=kernel]
    0 'Timer           '
    1 'Announce        '
client 14: 'Midi Through' [type=kernel]
    0 'Midi Through Port-0'
client 16: 'Keystation Mini 32' [type=kernel]
    0 'Keystation Mini 32 MIDI 1'
Connecting To: 20:0
client 20: 'E-MU XMidi1X1' [type=kernel]
    0 'E-MU XMidi1X1 MIDI 1'
Connected From: 16:0

To test this marvel I hooked up my Volca FM to the receiving end of the MIDI chain, and lo and behold it received glorious MIDI signals and spat out magnificent frequency modulated digital synthesis!

The way this works at this point in the story is that I hook the Pi up to the ethernet at home – with the midi devices already hooked up. Then I SSH to it from my computer and execute the commands listed above. Hardly ideal for a situation anywhere out in the real world, so I looked into ways to automate it. I wanted to automatically create the connections when I plug the devices...

Step 3: Automatic connection

The first thing I did was to write a script that connects the various devices as they are connected. I picked Ruby as scripting language of choice. (bash would probably be a more sane choice, but I like my daily dose of ruby...)

pi@raspberrypi ~ $ cat dev/ruby/midiconnect/connectall.rb
#!/usr/bin/ruby
#

t = `aconnect -i -l`
ports = []
t.lines.each do |l|
  /client (\d*)\:/=~l
  port = $1
  # we skip empty lines and the "Through" port
  ports << port unless $1.nil? || $1 == '0' || /Through/=~l
end

ports.each do |p1|
  ports.each do |p2|
    unless p1 == p2 # probably not a good idea to connect a port to itself
      system  "aconnect #{p1}:0 #{p2}:0"
    end
  end
end

(This is a rather brute force way of doing this as it will connect everything to everything but itself. The bonus is that if I connect several MIDI related devices using a USB hub everything will be connected to everything.)

And it worked, so I created a convenience wrapper in a bash script for it, like so:

pi@raspberrypi ~ $ cat bin/connectall.sh
#!/bin/bash
#
/usr/bin/ruby /home/pi/dev/ruby/midiconnect/connectall.rb

One chmod +x later and it is really easy to reestablish connections semi-automatically.

I added this script to the boot up sequence of the Pi, but that meant that I needed to reboot it if I do any changes. Hardly ideal, so I wanted to take it further.

Step 4: Automatic detection

Next up is to set up automatic detection of my USB devices. To accomplish this I'll rely on udev and sets of rules based on hardware IDs of the devices in question – lsusb to the resque.

If we run lsusb we get a list of USB devices connected to the system. Like so, for example:

pi@raspberrypi ~ $ lsusb
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 012: ID 0a4d:129d Evolution Electronics, Ltd
Bus 001 Device 009: ID 041e:3f07 Creative Technology, Ltd E-Mu Xmidi 1x1

The devices we are after are the two last entries. (Sometimes the list might be slightly cryptic, so you might want to run lsusb before and after connecting the device to see what has changed.)

We see that the Keystation has a hexadecimal vendor ID of 0a4d and a ditto device ID of 129d, so we can add a file called, for example, 99-keystation-mini.rules in the /etc/udev/rules.d/ folder containing:

ATTRS{idVendor}=="0a4d", ATTRS{idProduct}=="129d", RUN+="/home/pi/bin/connectall.sh" 

I added one similar file per USB MIDI device I want the Pi to be able to talk to and we are good to go. Reload the udev rules with a sudo udevadm control --reload-rules and we can plug and play as we want.

Final notes

Now I have a stand alone little gadget that bridges the world of USB MIDI and the world of standard 5-pin MIDI. The Raspberry Pi is powered by standard 5V over micro USB, so I've hooked it up to the USB port of my power bank I use for guitar pedals, volcas, etc. This means it can be used in the shade in a parc.
Outdoor season with 1bisHill.

There must be more generic solutions to this – using other things than udev, maybe? But, hey, this works for me for now, so further optimisation will have to wait. Other kinds of things to look into would be:

  • Fancy routing options? Especially if more devices are hooked up with a USB hub?
  • MIDI filtering/translations?
  • Security-wise it is probably not a good idea to let the udev call scripts in my home dir, but this is really handy... (I should look into what user level these things run under...)
I have had some weird issues with my OP-1 not sending MIDI signals some times with this setup just after hooking things up. (The solution, bizarrely, seems to be swapping between COM programs, and then going into synth mode, and it works again.) However this is also happening when I use it as a MIDI controller hooked up to my mac so I won't blame the Pi for this yet. Also, once things are connected it works like a charm. (Touch wood.)

If I need more on the fly configurability I might still want to try to use my iPad coupled with a USB hub as a bridge (using apps like midiflow or similar to do the routing), but I'm happy with the added portability (and nerd-cred) from the solving this with the Pi.

References

Luckily others has done some of this before, so I could base my work on their findings. I found the following URLs helpful:

Comments

  1. Great article, thank you. In my installation i receive this erroe when i launch connectall.rb.

    ""
    /usr/local/bin/connectall.rb:12:in `block in ': undefined local variable or method `names' for main:Object (NameE rror)
    from /usr/local/bin/connectall.rb:6:in `each'
    from /usr/local/bin/connectall.rb:6:in `'

    culd you help me please?

    ReplyDelete
    Replies
    1. I have a raspberry pi 3 b+.

      Delete
    2. Thanks. I don't know why this error would occur. It mentions a local variable 'names' that is not in my code above... Can you paste your entire connectall.rb here, maybe?
      Thanks.

      Delete
  2. Hi I've executed your idea successfully. BUT now there is an extra challenge. I. have a Roland A-800 PRO controller keyboard. This keyboard has three midi ports, one physical midi port and 2 over USB. The script is automatically connecting 'client':0 but not 'client':1 and :2. (which are both USB ports) Is there a way to change the script to connect to all ports?

    When running connect -l I get:

    client 0: 'System' [type=kernel]
    0 'Timer '
    1 'Announce '
    client 14: 'Midi Through' [type=kernel]
    0 'Midi Through Port-0'
    client 20: 'A-PRO' [type=kernel,card=1]
    0 'A-PRO MIDI 1 '
    Connecting To: 24:0
    Connected From: 24:0
    1 'A-PRO MIDI 2 '
    2 'A-PRO MIDI 3 '
    client 24: 'mio' [type=kernel,card=2]
    0 'mio MIDI 1 '
    Connecting To: 20:0
    Connected From: 20:0

    I'd like to get to (I've connected 1 and 2 manually, this works) automatically:

    client 0: 'System' [type=kernel]
    0 'Timer '
    1 'Announce '
    client 14: 'Midi Through' [type=kernel]
    0 'Midi Through Port-0'
    client 20: 'A-PRO' [type=kernel,card=1]
    0 'A-PRO MIDI '
    Connecting To: 24:0
    Connected From: 24:0
    1 'A-PRO 1 '
    Connecting To: 24:0
    2 'A-PRO 2 '
    Connecting To: 24:0
    client 24: 'mio' [type=kernel,card=2]
    0 'mio MIDI 1 '
    Connecting To: 20:0
    Connected From: 20:0, 20:1, 20:2

    Can you help me out?

    ReplyDelete
    Replies
    1. I have the same sort of issue. My LaunchPad X has two subports a '0' port that connects and a '1' port. The 1 port is actually the on that I need connected. I can make a manual connection but would love for the '1' ports to automatically connect, too.

      Delete
    2. Here's a version that works with multi-port MIDI devices: https://gist.github.com/chmanie/4f2838f4548d25b9c883f7d6d074f67c

      Delete
    3. Great! Thanks Chris!

      Delete

Post a Comment

Popular posts from this blog

Fix your rapid blinking Marantz SR-6004 using nothing but 3 fingers - and a thumb

A couple of years ago my (most of the time excellent) Maranz SR6004 acted up. It did't want to turn itself on. Properly. Just stood there and blinked rapidly. Its little red light that is. At me. The solution was so simple that I didn't bother to write it down as I was sure to remember it. Alas, no. Some weeks ago it did it again. (Can it be the heat?) Just stood there blinking rapidly at me. The manual just said - as it said last time around - that it was time to return the unit to it's maker. Or similar. Some googling led me to this page:  http://www.allquests.com/question/4056803/Marantz-XXX4-Series-Failure-Issues.html  The technical term for what I had experienced seems to be "The Pop of Death". Aïe. But!, humongous letters said: YOU CAN SOMETIMES RESET THE UNIT BY PRESSING SURR MODE, CLEAR AND EXIT SIMULTANEOUSLY And so I did. And so it was fixed. And all was well. (And now I have written it down for the next time.)

Fix upside down Skype video in Ubuntu 12.10 [UPDATED]

When launching Skype in 64-bit Ubuntu 12.10 on my Asus U35J the webcam image was all topsy-turvy. Since I don't live in Australia, or something (tsk-tsk), this was not really cutting it for me.  Some quick googling led me to this forum post:  http://forums.pcpitstop.com/index.php?/topic/198236-why-is-my-skype-video-showing-upside-down/   After making sure that the necessary packages was installed (notably  libv4l-0) I adapted the command from the forum post to: LD_PRELOAD=/usr/lib/i386-linux-gnu/libv4l/v4l1compat.so skype and voila, the image was OK. Next step is for this to be set to default, which seems to be outlined here (in steps 2 and 3):  http://pc-freak.net/blog/how-to-fix-upside-down-inverted-web-camera-laptop-asus-k51ac-issue-on-ubuntu-linux-and-debian-gnu-linux/  (Actually this post seems to cover most of what is useful from the forum post above...) UPDATE (19/04/2013): Since my laptop was working fine, I decided it was abou...