Believe it or not, I do still exist. And I do some projects still.
Sometimes.
Anyway, I've been starting to play more with hardware synths because I don't have a dedicated studio space right now to set up softsynths and I just want to play around without messing with computers and wiring everything up. Regardless of the reason I wanted to be able to connect my KMI kboard up to my Korg Volca FM or my just arrived AMYboard but to do so requires a USB Midi Host. There are devices for sale that do this, but I realized that I have a device in a box that will do this already.
So I dug out my raspberry pi zero W and a new project was born.
I just used the pi foundation's imager with the lite pi OS and set up so I could ssh into it for the rest of the configuration. That actually was the hardest part: getting ssh to work. For some reason the imager didn't create my user profile I tried to set up so I spent a while troubleshooting. Once that was going the rest was fairly straight ahead.
First thing I set up on the pi was a bash script that will parse the output of aconnect (an alsa utility that can list all midi devices/ports). It looks like this:
#!/bin/bash
LOGFILE="/var/log/midi-connector.log"
echo "$(date) - MIDI event triggered" >> $LOGFILE
# Function to connect available MIDI ports
connect_midi()
{
# Find the client IDs of all connected mid devices
# This grabs any non-system MIDI ports available
PORTS=($(aconnect -l | awk '/^client/ { if (/card=/) { c=$2; sub(/:/,"",c); v=1 } else { v=0 } } v && /^ +[0-9]+/ { print c":"$1 }'))
# Then loop through them:
for port in "${PORTS[@]}"; do
echo "Found hardware port: $port" >> $LOGFILE
done
listsize=${#PORTS[@]}
for (( i=0; i < listsize; i++ )); do
for (( j=i+1; j < listsize; j++ )); do
port_a="${PORTS[i]}"
port_b="${PORTS[j]}"
# Extract just the client number (everything before the colon)
client_a="${port_a%:*}"
client_b="${port_b%:*}"
# Only connect if they belong to different hardware clients
if [ "$client_a" != "$client_b" ]; then
# Connect Port A to Port B
aconnect "$port_a" "$port_b"
# Connect Port B to Port A
aconnect "$port_b" "$port_a"
echo "connecting $port_a $port_b" >> $LOGFILE
fi
done
done
}
connect_midi
I saved that as /usr/local/bin/midi-connector.sh then did a chmod to make it executable.
sudo chmod 700 /usr/local/bin/midi-connector.sh
Next you need a udev rule that will run whenever a USB device is connected. Paste this one line into /etc/udev/rules.d/99-usb-midi.rules:
ACTION=="add",
SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:0103*", TAG+="systemd",
ENV{SYSTEMD_WANTS}+="midi-connect@$env{NAME}.service"
That line tells the USB manager that when a newly connected USB device is a midi device then run a systemd service. So we have to make that systemd service next.
In a new file called /etc/systemd/system/midi-connect.service put the following:
[Unit]
Description=Auto-connect USB MIDI for %I
After=sound.target alsa-restore.service local-fs.target
[Service]
Type=oneshot
# Give ALSA 2 seconds to fully spawn the client nodes in the background safely
ExecStartPre=/bin/sleep 2
ExecStart=/usr/local/bin/midi-connector.sh
[Install]
WantedBy=multi-user.target
Alsa takes a second after the udev rule fires to get the midi port ready so we have a little delay before we run the connector script, then the script goes and takes care of it. We also have this set up to run once at boot in addition to when udev launches it in case I power it on with everything connected (or in case the system browns out which happened a couple times).
That's all it takes. If you don't want to reboot just run:
sudo udevadm control --reload-rules
sudo systemctl daemon-reload
to reload the pieces then you should be able to plug in any usb midi devices and they'll all start sending messages to each other.
So overall how well does it achieve the goal? I don't love how long it takes to boot (a couple minutes). And it seems like the system is fickle. Not sure I'm ready to rely on it if I were doing real gigs or something. The USB hat POGO pins aren't a supre great connection so I found better luck powering through the Pi USB port directly rather than through the USB hat power input. If I were to do this properly I'd use a rp2040 based chip and make a custom firmware which should boot much faster than a full OS on a single core that I have now. But this was quicker.
Anyway. I did a thing. You can now too. Enjoy!
No comments:
Post a Comment