Log: RPI2 as USB_MIDI to 5Pin MIDI converter and merger

Written by  on November 29, 2016 

Troubleshooting log of RPI2 as a USB_MIDI to 5PIN MIDI interface

Note – this is a troubleshooting log, not a tutorial. If you want to get the same results I did then read carefully as some of the code here is my documented failures and you shouldn’t just copy and paste it. Also I’m really not a linux person, so if you are try not to laugh too much.

———–
What is this project?

I have a couple of USB MIDI controllers. I want to send their data down one real midi cable. I’ll do the conversion using an RPI2 and send the output via a cheapo USB to 5pin midi converter.

———–
Why do it?

Basically I have a pair of USB midi controllers called a Midi Fighter Twister and a Midi Fighter Spectra, and for a particular performance I want to drag them all around the stage.
This is problematic as both have a fairly short usb cable, and no hardwired midi output.
My experience with extending usb cables or running them through hubs is that it often makes usb unreliable, particularly with a relatively high current (250ma) device such as the twister.
These problems are compounded with many audio software packages requiring a restart before they will recognise usb devices that have dropped out and reconnected. If you get some momentary drop out during a show you can easily be screwed until you can restart.

So what I want to do is put a dedicated device close to the USB Midi controller that will convert to a real 5 pin midi connection. I can then use a 5-pin midi cable to go to my existing sound interface on my laptop. There are some off the shelf products for this but I’m going to make my own, and as a bonus get it to merge the data from the two usb controllers into one output so I only need one converter box. (This is only possible because of existing fixed channel numbers on the controllers being compatible).

The last motivation to solve the problem with this particular method is to use the stuff I already have laying around. I’d much prefer to do this in C on an Arduino but I don’t have any Arduino USB host shields. Ah well, it’s a good opportunity to learn something on the RPI.

———
To begin

I already have an RPI2 with Raspbian Debian Wheezy OS installed on an SD card. It’s on my network and has access to the internet (for this development session, it won’t need internet access to actually work for the performance)
I already know how to SSH into it.
I know what SSH and BASH is and I know what the sudo command is.

If you can gather those pieces of knowledge yourself then you should be able to follow along.

——-
Problem solving

/////Problem 1 – get a class compliant USB midi device talking to the RPI2/////////

To be clear a USB midi device is one that communicates via the MIDI protocol over the USB connection. It may or may not have the actual 5-pin MIDI connectors as well.
A ‘class compliant’ USB midi device is one that follows a standard driver implementation such that is is plug and play on modern OSs. Some midi controllers are not class compliant and contain their own USB hubs with multiple devices and may require custom driver software from the manufacturer.

//Sources:
http://andrewdotni.ch/blog/2015/02/28/midi-synth-with-raspberry-p/
http://linuxcommand.org/man_pages/aconnect1.html

//Try:

Looking at some other peoples guide the command aconnect seems pretty important. Looking at the reference documentation aconnect appears to be for discovering midi devices and then interally connecting the in and out ports.
Trying

aconnect -o

will give us some information about output ports of plugged in midi devices. It seems we have a midi through port by default as well as whatever device is plugged in. My results look like this

pi@TK-RPI1 ~ $ aconnect -o
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
client 20: 'Midi Fighter Twister' [type=kernel]
0 'Midi Fighter Twister MIDI 1'

I’m sure those client numbers will be significant later.
aconnect -i gives us input port information as well.

pi@TK-RPI1 ~ $ aconnect -i
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
client 20: 'Midi Fighter Twister' [type=kernel]
0 'Midi Fighter Twister MIDI 1'

Well that doesn’t mean much to me at this point. It makes sense that the midi fighter twister is also in the input list as it supports feedback to set the LED indicators around its knobs.

Lets see if we can look at some live data.

Andrew Dotnichs helpful blog suggest ‘aseqdump -p xx’ where xx is the client number will give us some live data. And it does.

^Cpi@TK-RPI1 ~ $ aseqdump -p 20
Waiting for data. Press Ctrl+C to end.
Source Event Ch Data
20:0 Control change 0, controller 16, value 82
20:0 Control change 0, controller 16, value 83
20:0 Control change 0, controller 16, value 84
20:0 Control change 0, controller 16, value 85
20:0 Control change 0, controller 16, value 86
20:0 Control change 0, controller 16, value 87
20:0 Control change 0, controller 16, value 88
20:0 Control change 0, controller 16, value 89
20:0 Control change 0, controller 16, value 90
20:0 Control change 0, controller 16, value 91
20:0 Control change 0, controller 16, value 92
20:0 Control change 0, controller 16, value 93
20:0 Control change 0, controller 16, value 94

Great. Well that’s a good way to test the USB Midi connection actually works.
Ctrl-C seems to exit out of this utility.

/////Problem 2 – Route the USB midi devices reliably to the output ////

Ok the midi fighter spectra sends notes on channel 2, control changes on ch 3
The Midi fighter twister sends control from turning knobs on channel 0, pressing knobs on channel 1

We are dealing with

pi@TK-RPI1 ~ $ aconnect -io
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
client 16: 'Midi Fighter Twister' [type=kernel]
0 'Midi Fighter Twister MIDI 1'
client 20: 'USB2.0-MIDI' [type=kernel]
0 'USB2.0-MIDI MIDI 1'
1 'USB2.0-MIDI MIDI 2'
client 24: 'Midi Fighter Spectra' [type=kernel]
0 'Midi Fighter Spectra MIDI 1'

Will these stay the same on restart? I think we can use actual names so this is less confusing

the aconnect command connects devices. See here for usage
http://linuxcommand.org/man_pages/aconnect1.html

aconnect 20 24

Works as expected.
What if we connect both of them to 24?
It merges the data! fantastic. In this particular case it works really well as the channels the Midi Fighter Twister and Midi Fighter Spectra send out on don’t overlap.

remember aconnect -x disconnects if everything goes wrong

Next problem. on restart the client numbers change. Apparently you can feed device names to aconnect instead of client numbers though.

pi@TK-RPI1 ~ $ aconnect Midi Fighter Twister USB2.0-MIDI
invalid sender address Midi

Hmm. Doesn’t work, I guess it uses spaces as delimiters to understand the argument. How about

pi@TK-RPI1 ~ $ aconnect 'Midi Fighter Twister' 'USB2.0-MIDI'
invalid destination address USB2.0-MIDI

Ok so the single quotes helped it understand the name of Midi Fighter Twister, but it still doesn’t like USB2.0-MIDI. Weird. Is the dot or hyphen a special character that needs escaping?
Note that it does remove the single quotes when it says its an invalid destination so it’s intepreting those correctly. Perhaps its the hypen that’s the issue as thats how you specify options for aconnect (eg -i or -x). What if we escape that with a backslash?

pi@TK-RPI1 ~ $ sudo aconnect 'Midi Fighter Twister' USB2.0\-MIDI
invalid destination address USB2.0-MIDI

Damn, it sees the backslash as an escape char but it still doesn’t work.

Ok if we can’t use the names for some reason what else can we do? Maybe we can make a shell script that retrieves the port numbers by analysing the output of aconnect -io
Thre is something similar on Teds Linux Midi Guide
http://tedfelix.com/linux/linux-midi.html

to create a new script (nano is a text editor)

nano midiConnect.sh

Then put this in (based on Teds script)

#!/bin/bash

# Connect ports based on names
# Based on a script by Ted Felix, who based his on a script by Antonio Bonifati.

# Use aconnect to get the ports
MFTport=$(aconnect -i | grep "Midi Fighter Twister" | cut -d ' ' -f 2)0
MFSport=$(aconnect -i | grep "Midi Fighter Spectra" | cut -d ' ' -f 2)0
USBport=$(aconnect -i | grep "USB2.0-MIDI" | cut -d ' ' -f 2)0

echo MFT output port: $MFTport
echo MFS output port: $MFSport
echo USB input port: $USBport

# Connect the ports
aconnect $MFTport $USBport
aconnect $MFSport $USBport

When done ctrl-x to exit and make sure you save.

then make the script executable with

chmod 755 midiConnect.sh

run the script with

./midiConnect.sh

check the connections are correct with

aconnect -lio

What I get is

pi@TK-RPI1 ~ $ aconnect -lio
client 0: 'System' [type=kernel]
0 'Timer '
1 'Announce '
client 14: 'Midi Through' [type=kernel]
0 'Midi Through Port-0'
client 16: 'Midi Fighter Twister' [type=kernel]
0 'Midi Fighter Twister MIDI 1'
Connecting To: 20:0
client 20: 'USB2.0-MIDI' [type=kernel]
0 'USB2.0-MIDI MIDI 1'
Connected From: 16:0, 24:0
1 'USB2.0-MIDI MIDI 2'
client 24: 'Midi Fighter Spectra' [type=kernel]
0 'Midi Fighter Spectra MIDI 1'
Connecting To: 20:0

Perfect. A quick test indicates communication is working the way it should.

/////Problem 3 – Make the script run on restart ////

Last step is to make this script run on restart.

I’m just going to use root crontab to schedule it. I’m sure there is some nicer way but this is literally all this RPI2 will ever do so don’t see why not. If something gets disconnected I’ll just restart the pi.

Edit the crontab with

sudo su
crontab -e

Add this line

@reboot ./midiConnect.sh

To test it reboot the pi and run ‘aconnect -lio’ to check connections each time
Experiment with unplugging and replugging usb devices to see what happens

If it doesn’t work use this command to see what cron has been spitting out

sudo grep CRON /var/log/syslog

Getting this error ‘(CRON) info (No MTA installed, discarding output)’
Which means Cron has some info for me about the job, but can’t tell me because it needs a mail client installed? see here, scroll down to the answer by Martin Carstens
http://askubuntu.com/questions/222512/cron-info-no-mta-installed-discarding-output-error-in-the-syslog

We need to install an email client to read crons feedback about the command

sudo aptitude install postfix

choose local during setup. After running the cron job again (I.e after a restart) use this to read the mail. (Note now with a mail client installed cron in the system log wont indicate anything other than it ran the job, not obvious there if there is an error anymore)

sudo tail -f /var/mail/root

And found the error was ./midiConnect.sh not found. It’s on what I think of as the root but knowing linux is probably my user directory…. use ctrl c to get out of that view.
Use readlink to get the real location

readlink -f midiConnect.sh

gives me /home/pi/midiConnect.sh. Let’s add that to the crontab file. It also occurs to me it might need to wait before USB devices are available. Lets put a sleep in there for 10 seconds. The new crontab entry is now:

@reboot sleep 10; /home/pi/midiConnect.sh

Dont forget to edit the root crontab as above.
AND IT WORKS ON RESTART. Hoorah. Lets do some more tests with usbs plugged unplugged rearranged.
Working pretty well.

Category : Uncategorized