Back in the summer, I posted about a project I had recently finished, which involved sending HTTP requests to a server that would then relay a MIDI output message based on the request that was sent.
We’ve been using that software (dubbed midi-relay) since then to be able to control our Chroma-Q Vista lighting desks remotely across vlans by using stream decks running Companion. It works pretty well, especially since the midi-relay software is configured to run directly on the lighting consoles upon startup. We have even set up a few crontab entries to send CURL commands to the light desks to turn them on at certain times when we don’t want to be on-site just to press a button.
In anticipation of completing my most recent project, “LiveCaption“, which takes audio and transcribes it to text in real-time, I started working on midi-relay 2.0: listening to MIDI input and using that to trigger a response or action.

In both auditoriums at my church, we have Avid S6L audio consoles. These consoles can do a lot, and like most consoles, they have GPIO pinouts to allow you to trigger things remotely, whether as an action originating from the sound console, or externally that then triggers something on the console like recalling a snapshot, muting an input, etc.


I started looking at the possibility of using the GPO pins on the console to trigger an external action like sending an HTTP request to Ross Dashboard, Companion, etc. However, there are only 8 GPO pins on this audio board, so I knew that could be a limiting factor down the road in terms of the number of possible triggers I could have.
The S6L also has MIDI In and Out, and through the Events section of the console, it can be used as either a trigger (MIDI In) or an action (MIDI Out) on just about anything.

We already have a snapshot that we load when we go to the sermon/message that mutes things, sets up aux sends, etc. and I wanted to be able to use that snapshot event to automatically start the captioning service via the REST API I had already built into LiveCaption.
In the previous version, midi-relay could only send Note On/Off messages and the custom MSC (MIDI Show Control) message type I had written just for controlling our Vista lighting consoles. With version 2.0, midi-relay can now send MIDI out of all of the channel voice MIDI message types:
- Note On / Note Off
- Polyphonic Aftertouch
- Control Change
- Program Change
- Pitch Bend
- Channel Pressure / Aftertouch
It can also send out:
- MSC (MIDI Show Control), which is actually a type of SysEx message
- Raw SysEx messages, formatted in either decimal or hexadecimal
And, midi-relay can now listen for all of those channel voice and SysEx messages and use it to trigger one of the following:
- HTTP GET/POST (with JSON data if needed)
- AppleScript (if running midi-relay on MacOS)
- Shell Script (for all OS’s)
There are a few software and hardware products out there that can do similar things, like the BomeBox, but I wanted to build something less-expensive and something that could run on a Raspberry Pi, which is exactly how we’ve deployed midi-relay in this case.

Now we can easily and automatically trigger the caption service to start and stop listening just by running the snapshots on the audio console that we were already doing during that transition in the service. This makes it easier for our volunteers and they don’t really have to learn a new thing.
Here’s a video of it in action:
If you’d like to check out version 2.0 of midi-relay, you can download both the source code and binaries from GitHub: https://github.com/josephdadams/midi-relay
The documentation is pretty thorough if you want to use the API to send relay messages or set up new triggers, but you can also use the new Settings page running on the server to do all that and more.

And if you’re a Companion user for your stream deck, I updated the module for Companion to support the new channel voice MIDI relay messages as well! You’ll need to download an early alpha release of Companion 2.0 to be able try that out. Search for “Tech Ministry MIDI Relay” in Companion.
Here’s a list of the Raspberry Pi parts I used, off Amazon:
- Raspberry Pi 4 Model B (2GB) $48
https://www.amazon.com/gp/product/B07TD42S27 - CanaKit Raspberry Pi 4 Power Supply (USB-C) $10
https://www.amazon.com/gp/product/B07TYQRXTK - MazerPi Raspberry Pi 4 Case $9
https://www.amazon.com/gp/product/B07W3ZMVP1 - USB to MIDI cable $17
https://www.amazon.com/gp/product/B07FTJXFLT
I hope this is helpful to you and your projects! If you need any help implementing along the way, or have ideas for improvement, don’t hesitate to reach out!
That looks so cool. I’m still a Raspberry Pi n00b for the most part, but I hope to reach the point where I can do things like that.
LikeLike
Thanks! The biggest motivating factor for me is having a problem I need to solve. Now, the real question is, if I wasn’t looking to solve them, would they be problems?
LikeLike
I am using Tally Arbiter on a Raspberry Pi 4 together with 3 x M5StickC’s for live streaming our church meetings. I love it – thanks so much for producing this! I am building a roadcase and want to make the PI startup and run headless. Can you give me any advice on how I can automate the three steps I currently have to do each time at startup – 1) login 2) change directory 3) start node index.js
Sorry I am not very code savvy! I would be much obliged 🙂
LikeLike
Hey John! I’m so glad my software is valuable to you. I wasn’t sure if you needed midi-relay instructions or Tally Arbiter instructions since you commented on a midi relay post. But both of them can work with pm2 on a raspberry pi and I have instructions posted in each repository on Github that walk you through that process. Try that and if you get stuck, reach out to me via the contact form and we can get it figured out!
LikeLike
Hi. I’m trying to set up MIDI control for a Roland V-1HD through MIDI relay, I can get the Basic CC/PC commands working, but i’m having trouble with the SysEx messages.
There is a short tutorial that i have linked below that shows the examples of the CC/PC and SysEx commands, though the provided SysEx commands do not work for me. Do you have any ideas. I’m fairly sure something is wrong with my formatting, but I cant find any examples of a SysEx message
https://rolandus.zendesk.com/hc/en-us/articles/360031884432-V-1HD-How-to-Control-Your-Switcher-Using-MIDI-Commands
LikeLike
Try typing it in either decimal or hexadecimal with each value separated by commas.
LikeLike
Did that work?
LikeLike
Hi, I managed to get it to work with decimal. Hex was disagreeing.
I’m now starting to work on a derivative of the midi relay companion app that will let me have full control over the V-1HD with state feedback thanks to this. Though even without the state feedback. midi relay has helped with simplifying the process of streaming our church services. So thanks for your work.
LikeLiked by 1 person
Hi, I managed to get it to work with decimal. Hex was disagreeing.
I’m now starting to work on a derivative of the midi relay companion app that will let me have full control over the V-1HD with state feedback thanks to this. Though even without the state feedback. midi relay has helped with simplifying the process of streaming our church services. So thanks for your work.
LikeLike
hi joseph
just found your midi relay , it is so cool ; i need to send sysex message to control my boss gt1 multi effect with my footpedal board roland fcb1010
question is if i try to send sysex like F0 41 00 00 00 00 30 12 60 00 01 40 01 5E F7 your monitor replied sysex-invalid
so i try F0,41,00…… but same
could you please help me to convert message in right format , thank you
LikeLike
Are you running from source or from an executable?
LikeLike
Hi Joseph
Very nice module, thank you.
On Windows 10 everything is working with our companion setting, our plan is now to install this module on a raspberry pi. We have the companion raspberry image what is based on Raspberry Pi OS Lite, after installing node.js its not possible to start the module.
root@raspberrypi:/home/pi/midi-relay-2.2.0# node main.js
internal/modules/cjs/loader.js:670
throw err;
^
Error: Cannot find module ‘request’
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:668:15)
at Function.Module._load (internal/modules/cjs/loader.js:591:27)
at Module.require (internal/modules/cjs/loader.js:723:19)
at require (internal/modules/cjs/helpers.js:14:16)
at Object. (/home/pi/midi-relay-2.2.0/main.js:6:17)
at Module._compile (internal/modules/cjs/loader.js:816:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:827:10)
at Module.load (internal/modules/cjs/loader.js:685:32)
at Function.Module._load (internal/modules/cjs/loader.js:620:12)
at Function.Module.runMain (internal/modules/cjs/loader.js:877:12)
root@raspberrypi:/home/pi/midi-relay-2.2.0# L
Running as service was also not successful.
root@raspberrypi:/home/pi/midi-relay-2.2.0# npm install -g pm2
npm WARN deprecated uuid@3.4.0: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.
/usr/bin/pm2 -> /usr/lib/node_modules/pm2/bin/pm2
/usr/bin/pm2-dev -> /usr/lib/node_modules/pm2/bin/pm2-dev
/usr/bin/pm2-docker -> /usr/lib/node_modules/pm2/bin/pm2-docker
/usr/bin/pm2-runtime -> /usr/lib/node_modules/pm2/bin/pm2-runtime
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@~2.3.2 (node_modules/pm2/node_modules/chokidar/node_modules/fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@2.3.2: wanted {“os”:”darwin”,”arch”:”any”} (current: {“os”:”linux”,”arch”:”arm”})
npm WARN ws@7.4.6 requires a peer of bufferutil@^4.0.1 but none is installed. You must install peer dependencies yourself.
npm WARN ws@7.4.6 requires a peer of utf-8-validate@^5.0.2 but none is installed. You must install peer dependencies yourself.
+ pm2@5.1.0
updated 1 package in 34.312s
root@raspberrypi:/home/pi/midi-relay-2.2.0#
Do we need another Raspberry OS or can we download an image?
Thanks for your help
Aron
LikeLike
Did you run the command “npm install” after downloading the code?
LikeLike
Hello Joseph,
I want to cobtrol some things of my smart Home through http-requests over bitfocus companion with a spare behringer X-Touch Mini Controller with your great Tool ‘midi-relay’ on a raspberry pi zero (thanks for that great piece of Software, it’s just what i was looking for!) . The Software runs, i can See the midi controller with /midi_inputs but the Web gui doesnt Show anything but empty fields and the Buttons have no functions at all. Could you figure out what May be wrong here?
Thank you in advance for your help!
Stefan
LikeLike
The web gui is broken in the binary releases, you will have to run it from source if you want it to work.
LikeLike
Hello Joseph,
Thank you for your Quick answer. I run it as a service with pm2 from the binaries, but it doesn’t run neither. Refreshing the midi Devices doesn’t show anything.
Any hint?
Best regards,
Stefan
LikeLike
The web gui just uses the backend API, so try using the API directly and see if it works
LikeLike
Hello Joseph,
When trying to open a port using the API directly I get an error
SyntaxError: Unexpected token m in JSON at position 11 at JSON.parse () at parse (/home/pi/midi-relay/linux-armv7/midi-relay-2.0/node_modules/body-parser/lib/types/json.js:89:19) at /home/pi/midi-relay/linux-armv7/midi-relay-2.0/node_modules/body-parser/lib/read.js:128:18 at AsyncResource.runInAsyncScope (async_hooks.js:190:9) at invokeCallback (/home/pi/midi-relay/linux-armv7/midi-relay-2.0/node_modules/raw-body/index.js:231:16) at done (/home/pi/midi-relay/linux-armv7/midi-relay-2.0/node_modules/raw-body/index.js:220:7) at IncomingMessage.onEnd (/home/pi/midi-relay/linux-armv7/midi-relay-2.0/node_modules/raw-body/index.js:280:7) at IncomingMessage.emit (events.js:314:20) at endReadableNT (_stream_readable.js:1241:12) at processTicksAndRejections (internal/process/task_queues.js:84:21)
Seems there’s a general problem..
Best regards, Stefan
LikeLike
This sounds like bad JSON being sent. Make sure the object keys are surrounded by quotes
LikeLike
Hi Joseph,
that seems to be the problem. API works now, I had to change the way I set the quotes. That was my mistake. Sorry.
The web-gui isnt working at all (on my Rapsberry Pi Zero W), but thats not that important now, because I can change the triggers over the json-file directly now.
Thank you for your help!
Best regards, Stefan
LikeLike