Tuesday, December 20, 2011

MIDI and the Arduino : Part I

I am intending to do a series of in-depth posts about how you can do MIDI on your Arduino or AVR. It may take me a while, though; I have a show up this week and four more already in meetings.

This post, then, is about getting to "Hello, World."

To be precise, it is about basic output from Arduino via the MIDI hardware level.

First the hardware. I can not do better than this schematic from the Arduino Playground itself.

The connector is a five-pin din. In the MIDI world, unlike most audio cables, all jacks are female and all cables are male. Even though it is a five-pin connector, only three of the connectors are actually used.

If your local electronics supplier does not have them, and you don't want to order online you can always cut a short MIDI cable in two and make a tail from it.

The 220 ohm resistor (color band code red-red-brown) is the only passive component you need. Actually, you can do without, but it is a lot safer with it (the risk is blowing the opto-isolator in the MIDI gear you are connecting to.)

And that's the physical layer.

On the software side, MIDI Library 3.1 is at SourceForge, with a small tutorial at the official Arduino website.

Of course I wrote my own, much simpler library. All I needed was output. I'm going to try to comment my way through an example here with as little actual explanation as possible:

int channel = 0;
int note = 60; // these set up default values for the later function
int velocity = 100; // in case the code doesn't specify any

void setup()
Serial.begin(31250) /* this is a key line; we are using the Arduino's serial port but it has to be set to the BAUD rate of MIDI in order for ordinary MIDI devices to see it. */

void loop()
noteOn(channel, note, velocity); //here's the function call
noteOff(channel, note, velocity);
delay(2000); /* the way I set this up, there is no test condition for the noteOn and noteOff events; once the program has initiated it cycles endlessly, sending out a note with the default values every few seconds. */

void noteOn(char channel, char note, char velocity)
Serial.print(channel + 144, BYTE);
Serial.print(note, BYTE);
Serial.print(velocity, BYTE);

/* okay, this takes a little explanation. First, the "char" and "BYTE" nonsense is my (sloppy) way of forcing type conversion. It's a C thing; if you specify the kind of integer inside a statement like this, it creates and uses an image of that integer that is truncated or otherwise fit into the specified type. Weird stuff can happen with type forcing, though. The advantage here is that I'm able to state the note number and velocity the way most MIDI players will present them; as a number from 0 to 127 (middle C is 60). When you get into more complex commands it often helps to think of them in hexadecimal pairs (which is how they are presented in the index of most MIDI hardware).

The (channel + 144) has to do with how MIDI messages are constructed. The first byte sent is always a command (or part of a command). Since noteOn messages are not global, they are sent individually to any of the 16 possible channels given by the MIDI specification. Thus "144" indicates "noteOn event for channel 0," and "159" would indicate "noteOn event for channel 15."

(Yes...within the actual data stream we count from 0. Most of the front panel of your MIDI device will count from 1, however, thus channels 1 through 16 instead of channels 0 through 15.)

A noteOn message creates an expectation by the receiver that it will be followed by two more bytes of information, specifying the note number and the velocity. */

void noteOff(char channel, char note, char velocity)
Serial.print(channel + 128), BYTE);
Serial.print(note, BYTE);
Serial.print(velocity, BYTE);

/* This function stops the note. In MIDI, unless the device is a drum machine or something else that plays a single sample and stops, the note requested will continue to play until the device is asked to stop that note -- or until an AllOff command -- a system-wide command -- is received.

There are two ways legitimized in the MIDI spec for stopping a note; one is to send a noteOff command for the same channel and note number. Cut-off velocity is interpreted by some MIDI instruments but most of them ignore it. The other way is to send a noteOn event with a velocity of 0.

This latter can really mess you up when you are using a keyboard to trigger an external effect, by the way! You have to insert a filter to trap all "noteOn" events with velocities of 0 so they don't cause false triggers. */

And that's it. The above was hand-typed, and I can't guarantee it against typos.

In practice, of course, your software will be testing some condition -- a sensor trip or button press -- and sending out various kinds of MIDI signals with the defaults replaced by, say, a different note number for each button pressed or for the intensity of light falling on a photocell or whatever.

But I need to say something even more basic here. This is, as I stated in my Thompsonian "To be precise;" above, is MIDI output on using the hardware standard.

That is, this is how to send a signal from an Arduino that will go down a MIDI cable, into the MIDI IN connector on a MIDI device, and be interpreted as a command.

Which is to say; the above will play a note on a keyboard or a drum machine, can be used to trigger a cue in Qlab (given a MIDI input connected to the host computer), and may do strange things with a lighting console or sound board or DJ laser display that has a MIDI input jack.

And lastly, this is not the simplest option. The simplest option is a MIDIsense board from Lady Ada, or a MIDI shield from SparkFun Electronics. Both of these options come with tested libraries in addition to the complete hardware. Lady Ada's framework has the advantage of being able to adjust via software on a host computer the sensitivity and response curve of sensors you attach to the board. Plus it even includes a 9V battery compartment for on-the-road use! The SparkFun board is cheaper and faster to set up, and includes buttons and pots to mess around with. Both, of course, include the opto-isolator of a MIDI-in port -- which is the subject for a later entry here.

Part II is here:

No comments:

Post a Comment