midi-relay was written by Joseph Adams and is distributed under the MIT License.
It is not sold, authorized, or associated with any other company or product.
To contact the author or for more information, please visit www.techministry.blog.
midi-relay is designed to allow you to send an HTTP POST request, with JSON data in the body, to the server, which will then send out the appropriate MIDI message to a MIDI port/device available to that server. It can be used to send MIDI across networks and subnets. It can also listen to incoming MIDI messages on ports available to the server and then act on them, sending HTTP requests, running scripts, etc.
RUNNING THIS SOFTWARE FROM BINARY:
- Download a binary release from https://github.com/josephdadams/midi-relay/releases for your OS.
- Open a terminal window and change directory to the folder where you placed the binary release.
- Run the executable from this folder.
- If this folder does not contain the
midi_triggers.jsonfile, a new one will be created the next time you add a trigger either via the API or the Settings page.
RUNNING DIRECTLY WITHIN NODE:
- Install
nodeif not already installed. https://nodejs.org/en/download/ - Download the midi-relay source code.
- Open a terminal window and change directory to the folder where you placed the source code.
- Type
node main.jswithin the this folder. - If this folder does not contain the
midi_triggers.jsonfile, a new one will be created the next time you add a trigger either via the API or the Settings page.
RUNNING AS A SERVICE:
- Open a terminal window and change directory to the folder where you placed the source code.
- Install the Node.js library,
pm2, by typingnpm install -g pm2. This will install it globally on your system. - After
pm2is installed, typepm2 start main.js --name midi-relayto daemonize it as a service. - If you would like it to start automatically upon bootup, type
pm2 startupand follow the instructions on-screen. - To view the console output while running the software with
pm2, typepm2 logs midi-relay.
This program runs an HTTP server listening on port 4000. If this port is in use and cannot be opened, you will receive an error.
Upon startup, the program will enumerate through the available MIDI input and output ports. It will also process the stored output triggers into memory and open any MIDI ports mentioned and start listening to them for incoming MIDI messages.
A web interface is available to view MIDI ports, triggers, and other information at /settings: http://127.0.0.1:4000/settings
- Make an
HTTP POSTrequest with JSON data in the request body to/sendmidion the server running midi-relay to relay a MIDI Message. - You can also make an
HTTP GETrequest with the parameters passed as querystrings. - Requests can be sent from any computer or device reachable to the midi-relay server.
-
Note On
{ midiport: 'MIDI Port Name', midicommand: 'noteon', channel: 0, note: 21, velocity: 1 }
channelshould be a integer between 0 and 15.noteshould be an integer of the MIDI Number value that represents the note, between 21 (A0) and 108 (C8).velocityshould be a integer between 1 and 127. Defaults to 127 if excluded. A value of 0 is considered a Note Off message.- A response of
{result: 'noteon-sent-successfully'}indicates the note on message was successfully sent.
-
Note Off
{ midiport: 'MIDI Port Name', midicommand: 'noteoff', channel: 0, note: 21, velocity: 0 }
channelshould be a integer between 0 and 15.noteshould be an integer of the MIDI Number value that represents the note, between 0 and 127.velocityshould be 0.- A response of
{result: 'noteoff-sent-successfully'}indicates the note off message was successfully sent.
-
Polyphonic Aftertouch
{ midiport: 'MIDI Port Name', midicommand: 'aftertouch', channel: 0, note: 21, value: 1 }
channelshould be a integer between 0 and 15.noteshould be an integer of the MIDI Number value that represents the note, between 0 and 127.valueshould be a integer between 0 and 127.- A response of
{result: 'aftertouch-sent-successfully'}indicates the Aftertouch message was successfully sent.
-
CC (Control Change)
{ midiport: 'MIDI Port Name', midicommand: 'cc', channel: 0, controller: 0, value: 0 }
channelshould be a integer between 0 and 15.controllershould be a integer between 0 and 127.valueshould be a integer between 0 and 127.- A response of
{result: 'cc-sent-successfully'}indicates the CC message was successfully sent.
-
PC (Program Change)
{ midiport: 'MIDI Port Name', midicommand: 'pc', channel: 0, value: 0 }
channelshould be a integer between 0 and 15.valueshould be a integer between 0 and 127.- A response of
{result: 'pc-sent-successfully'}indicates the PC message was successfully sent.
-
Channel Pressure / Aftertouch
{ midiport: 'MIDI Port Name', midicommand: 'pressure', channel: 0, value: 1 }
channelshould be a integer between 0 and 15.valueshould be a integer between 0 and 127.- A response of
{result: 'pressure-sent-successfully'}indicates the Channel Pressure / Aftertouch message was successfully sent.
-
Pitch Bend / Pitch Wheel
{ midiport: 'MIDI Port Name', midicommand: 'pitchbend', channel: 0, value: 0 }
channelshould be a integer between 0 and 15.valueshould be a integer between 0 and 16,383.- A response of
{result: 'pitchbend-sent-successfully'}indicates the Pitch Bend message was successfully sent.
-
MSC (MIDI Show Control)
{ midiport: 'MIDI Port Name', midicommand: 'msc', deviceid: 0, commandformat: 'lighting.general', command: 'go', cue: '10', cuelist: '13', cuepath: '' }
-
deviceidshould be an integer between 0 and 111. It can also be a string 'g1' through 'g15' to represent groups, or it can be 'all'. -
commandformatshould be a string with one of the following values:- lighting.general
- sound.general
- machinery.general
- video.general
- projection.general
- processcontrol.general
- pyro.general
- all
- Any other value for commandformat will default to 'all'.
-
commandshould be a string with one of the following values:- go
- stop
- gojam
- gooff
- resume
- timedgo
- load
- set
- fire
- alloff
- restore
- reset
- opencuelist
- closecuelist
- startclock
- stopclock
- Any other value for
commandwill default to 'go'.
-
Values for
cue,cuelist, andcuepathare all optional strings. If left blank ('') or not included in the object, those will not be included in the MIDI command that is generated. -
A response of
{result: 'msc-sent-successfully'}indicates the MSC message was successfully sent. Themessagewill also be returned containing the exact MIDI message that was sent, in decimal form.
-
-
Sysex MIDI Message
{ midiport: 'MIDI Port Name', midicommand: 'sysex', message: '0x90, 63, 127' }
messageshould contain the actual MIDI message in bytes. Bytes can be either in hexadecimal or decimal, separated by commas.- A response of
{result: 'sysex-sent-successfully'}indicates the SysEx MIDI message was successfully sent.
All values for channel are zero-based. (e.g., Channel of 1 should be sent as 0.)
Make a GET request to /midi_outputs to return a JSON list of MIDI Output ports/devices available on the server.
The midi-relay server can also listen for incoming MIDI messages and act on them.
A MIDI Input Port must be specifically opened in order to receive and process the MIDI data.
The following incoming MIDI Messages are currently supported:
- Note On
- Note Off
- Polyphonic Aftertouch
- Control Change
- Program Change
- Channel Pressure / Aftertouch
- Pitch Bend / Pitch Wheel
- SysEx (System Exclusive)
Make a POST request to /openport with a JSON object:
{
midiport: 'MIDI Port Name'
}Make a POST request to /closeport with a JSON object:
{
midiport: 'MIDI Port Name'
}You can make a GET request to /midi_inputs if you need the names of available MIDI input ports on the server. If a port is already opened, that object in the returned array will have a property of opened: true.
In order for midi-relay to act on an incoming MIDI message, a trigger must exist that matches the conditions of the incoming message on the specified MIDI port.
You can make a GET request to /triggers to see a list of currently stored triggers.
Make a POST request with JSON object data to /addtrigger with the following options:
Each trigger must specify a midiport using the name of the port as a string.
A midicommand property must also be included:
noteon(Note On)- Must include properties
channel,note, andvelocityin the trigger. You can use an asterisk"*"as a wildcard to match anychannel, orvelocityvalue. Anotevalue must always be specific.
- Must include properties
noteoff(Note Off)- Same as
noteon. Anynoteonornoteoffmessage with avelocityvalue of0, it will be treated as anoteoffmessage when processed.
- Same as
aftertouch(Polyphonic Aftertouch)- Must include properties
channel,note, andvaluein the trigger. An asterisk"*"can be used as a wildcard forchanneland/orvalue.
- Must include properties
cc(Control Change)- Must include properties
channel,controller, andvaluein the trigger. An asterisk"*"can be used as a wildcard forchanneland/orvalue.
- Must include properties
pc(Program Change)- Must include properties
channelandvaluein the trigger. An asterisk"*"can be used as a wildcard forchanneland/orvalue.
- Must include properties
pressure(Channel Pressure / Aftertouch)- Must include properties
channelandvaluein the trigger. An asterisk"*"can be used as a wildcard forchanneland/orvalue.
- Must include properties
pitchbend(Pitch Bend / Pitch Wheel)- Must include properties
channelandvaluein the trigger. An asterisk"*"can be used as a wildcard forchanneland/orvalue.
- Must include properties
sysex(System Exclusive)- Must include
messageproperty in the trigger as a string with values separated by spaces or commas. All values will be converted to decimal.
- Must include
In addition to specifying a midicommand and related command properties, an actiontype must also be specified.
The following action types are currently supported:
http(HTTP GET or POST)- Include a object property of
urlto send the URL. - Include
jsondatawith the stringified JSON to send as HTTP POST. Otherwise, it will send as HTTP GET.
- Include a object property of
applescript(AppleScript, MacOS only)- Results of script or any errors will appear in the console/terminal.
shellscript(Shell Script)- Output of shell scripts will appear in the console/terminal.
You can also include a description field to store information related to the trigger, what it does, etc.
{
midiport: 'IAC Driver Bus 1',
midicommand: 'noteon',
note: 73,
channel: 1,
velocity: 100,
actiontype: 'http',
url: 'http://127.0.0.1/test',
description: 'description of the trigger'
}To delete an existing trigger, make a GET request to /deletetrigger/[trigger-id].
The trigger ID is autogenerated by the system and viewable in the midi-triggers.json file.
- Making a GET request to
/refreshwill refresh the list of available MIDI ports and update the internal variables with these ports. - Making a GET request to
/versionwill send the version of the software, based on the information inpackage.json.
The API will respond with JSON messages for each action received.
invalid-midi-port: The MIDI port you specified is invalid or is no longer available. Call/refreshto get the latest list of available ports.invalid-midi-command: The MIDI command you sent is invalid or not implemented.midiin-port-cannot-be-opened: The MIDI Input port cannot be opened due to an internal error.midiin-port-opened: The MIDI Input port is now open.midiin-port-already-opened: The MIDI Input port was already open.midiin-port-cannot-be-closed: The MIDI Input port cannot be closed due to an internal error.midiin-port-closed: The MIDI Input port is now closed.ports-refreshed-successfully: MIDI Input/Output ports were refreshed and updated successfully.noteon-sent-successfully: The Note On message was sent successfully.noteoff-sent-successfully: The Note Off message was sent successfully.aftertouch-sent-successfully: The Polyphonic Aftertouch message was sent successfully.cc-sent-successfully: The Control Change message was sent successfully.pc-sent-successfully: The Program Change message was sent successfully.pressure-sent-successfully: The Channel Pressure / Aftertouch message was sent successfully.pitchbend-sent-successfully: The Pitch Bend message was sent successfully.msc-sent-successfully: The MSC (MIDI Show Control) message was sent successfully.sysex-sent-successfully: The SysEx MIDI message was sent successfully.sysex-invalid: The provided message was not a valid SysEx message.could-not-open-midi-out: The specified MIDI-Out port could not be opened. The message was not sent.invalid-action-type: The action type specified in the Add Trigger API was not valid.trigger-added: The trigger was added successfully.trigger-added-midiin-port-cannot-be-opened: The trigger was added, but the MIDI In port could not be automatically opened.trigger-edited: The trigger was edited successfully.trigger-edited-midiin-port-cannot-be-opened: The trigger was edited, but the MIDI In port could not be automatically opened.trigger-deleted: The trigger was deleted successfully.trigger-not-found: The Trigger could not be found due to an invalid/incorrect Trigger ID, or it was already deleted.error: An unexpected error occurred. Check theerrorproperty for more information.
The console/terminal output running the server process is also verbose and will report on the current status of the server.
The midi-relay server will broadcast itself on the network as midi-relay on the listening port. It will also monitor for other midi-relay servers available on the network. This list can be accessed by making a GET request to /hosts.
