Google and Amazon are your Friends

They're not actually your friends. They're evil corporate behemoths. But in the case of our previous question, "how do we translate between websocket and MIDI messages", they're really, really useful.

The first issue of translation is one of hardware. Our theatrical control consoles had dedicated MIDI ports, which take a 5-pin DIN connector. Turns out, for about $15 on Amazon, you can get a simple USB-MIDI hardware interface. You just plug it into your USB port and it's available as a MIDI port to send and receive messages. That was easy.

Well, except that we have to figure out how to send and receive those messages. Surely someone has done this before. What if we just Googled "node midi"?

Turns out, there's a Node module called, well, node-midi. And it's for sending and receiving MIDI messages from Node.js applications over arbitrary ports. That was easy.

Except for one more thing. MIDI stands for Musical Instrument Digital Interface. It was originally designed to run synthesizers and such. MIDI messages are just an array of numeric values, where each value has a predefined meaning. A typical message might look like this:

// using hexadecimal values by convention
const message = [
  0x05, // send message to instrument number 5
  0x63, // play pitch 99
  0x6e // with volume (aka velocity) 110
];

Theatrical controllers run on an extension of MIDI called Midi Show Control (MSC). You indicate with the first two bytes that you're sending what's called a SysEx (system extension) message, then the rest of the values in the message conform to whatever flavor SysEx you're using.

A MSC message looks more like this:

const message = [
  0xf0, // indicates sysex message
  0x7f, // indicates sysex message
  0x01, // id of device that should respond to this message
  0x02, // defines message as MSC
  0x10, // specifies the commandFormat, eg "sound.general"
  0x01, // specifies the command, eg "go"
  0x32, // -|
  0x35, //  |- cue number 25.5
  0x2e, //  |
  0x35, // -|
  0x00, // delimiter
  0x33, // -|
  0x2e, //  |- cue list 3.1
  0x31, // -|
  0x00, // delimiter
  0x31, // -|
  0x2e, //  |- cue path 1.9
  0x39, // -|
  0xf7 // end of message
];

Do you want to wrangle all of those hex values when you're sending and receiving messages? I sure didn't. I'd rather have some kind of object I could create that represented a message, with human-readable options.

So I wrote a little library to do just that.

Our initial problem was "How do we get a dozen different devices to talk to each other". By identifying the sub-problems and leaning on existing solutions, we were able to essentially reduce the problem space to a pair of functions that translate back and forth between an array of byte values and an object of human-readable values.

This is what I mean when I say "Decompose Problems, Compose Solutions".

Next Up:
How Do You Define the Term 'Bug'?

Previously:
Fun with Abstractions: Multimedia Edition


Want to impress your boss?

Useful articles delivered to your inbox. Learn to to think about software development like a professional.

Icon