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.
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 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.
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.
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
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
to create a new script (nano is a text editor)
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
check the connections are correct with
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
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
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.