Thursday, 27 April 2017

Messing about with MIDI and RealTerm vs Putty

While our guitar neck glue is going off, and since we've pretty much got most of the LED goodness working (that'll probably have to be demonstrated in a later post, once everything has been stuck together) we thought the intervening time could be spent adding some extra cool functionality to our light-up guitar.

To date it allows you to select pentatonic or diatonic scales in any key, include extra notes (such as the "blue note" and flatted/major thirds in the minor pentatonic, major fourths in the major pentatonic and so on). You can also have it display all the major C.A.G.E.D chord shapes in any key too (we really should have made a demo video before this post!)

EDIT: made a quick demo video. Here you go -



In "offline mode" you can display different scales and CAGED chord shapes in any key. A simple flick switch will allow you to quickly change between major and minor (for those pesky I-to-IV and IV chord changes in a 12-bar song!) And, of course, there are some fancy patterns just for show as well!

Now most guitarists who know how to play guitar recognise that it's not just a Guitar Hero clone - where frets light up and if you match them with your fingers, you'll play a tune. By lighting up a particular scale (and different target notes from that scale) you can improvise blues-based solos more easily just by wandering between the dots. But for anyone wanting to play along to their favourite song, we figured it'd be a massive amount of work creating some software that allows you to input tab in such a format that you can then send to the guitar to get the frets to light up.

So when MIDI was suggested, we figured.... hmmmm.
It's always tricky knowing which of a possible five places you should place a dot for a specific note on a guitar. But if we could take the incoming MIDI signal and simply light up all possible alternatives, it would leave the player to decide which fret they found most comfortable to reach for (instead of some crazy algorithm going rogue and forcing you to whizz up and down the guitar neck at lightning speed!)

So we needed to get to grips with handling MIDI in signals (not the infinitely easier generating MIDI out messages). The first thing was to hook up a usb-to-MIDI device so we had an independent way of generating MIDI messages.
Now MIDI uses inverted logic (zero is represented by a HIGH signal, a one is a LOW signal) but other than that, it's simply serial data sent at a funny baud rate. 31250 bps to be precise.

So we downloaded a free MIDI sequencer (Anvil Studio looks gnarly and draws slowly, but it can create, edit and play MIDI files to a MIDI device, so it was good enough for this test) and grabbed something a bit more sophisticated than our usual serial favourite Putty - a little program called RealTerm.

Putty is fine for sniffing data, but RealTerm makes playing with serial data a doddle. Not only can it display the raw incoming data, but it has a myriad of options for decoding it too. We went with hex[space] so that we could visualise the MIDI values in hex, instead of trying to decode non-printable ASCII characters (as Putty likes to do). It's much easier to see what a value like 0xB4 means than a checkerboard patterned glyph!



We hooked up our MIDI out to a socket and introduced an opto-isolator to both isolate and invert the MIDI signal from our usb-to-MIDI device. The circuit was something similar to this one (with a few resistor values changed to match values we had lying around)


The strange this is, we got no data from the circuit. Absolutely nothing.
After fiddling about for about an hour and getting nowhere, we took a bit of a risk. Since the MIDI signal was being generated by a laptop usb port, we figured it wouldn't be more than 5v. So we connected the MIDI out directly to our serial in.....
Instead of a puff of blue smoke, we got serial data appearing in RealTerm. Success! (although we did have to invert the signal, with midi pin 4 connected to ground and midi pin 5 to our serial RX.


It might look like gibberish, but it's pure, raw, MIDI data!
The excellent MIDI resource site (https://www.midi.org/specifications/item/table-1-summary-of-midi-message) gave us an easy way of decoding the data - and thanks to RealTerm's hex view, we could even do it onscreen!


The MIDI messages we're interested in are the note on and note off ones. All other messages can be discarded. Most (but not necessarily all) MIDI messages arrive in three-byte packets. Luckily, the MIDI format also makes it really easy to decode.

The first byte of a MIDI message "packet" always has the first/MSB set to one. The first byte is also the "command" byte, telling us what action is to be carried out. Subsequent bytes, containing data values always have the first/MSB bit cleared (set to zero). So it's dead easy to find the start of each message - just read in bytes from the serial port and as soon as a byte has it's first bit set, you know you're at the first byte of a new packet.

We can see from our received MIDI data, we get a repeating "B" message, every three bytes at the very start. This is the MIDI device sending a "control change" message for each channel being used by our MIDI sequencer (since 0x0B in hex is 1011 in binary, which matches the pattern for "control change" in the MIDI specifications). The second character of the first byte is the channel number (from 0-15). The following two bytes are information about how the controller is set up (volume, left/right balance etc).

For the messages we're interested in,  we can just look for a message beginning with 9 (note on) or 8 (note off). If we dump our serial data capture into notepad and split the data into three-byte packets, it becomes much easier to read.


Our first musical MIDI instruction is 90 28 7F

This decodes as:

  • 9 = note on
  • 0 = channel zero
  • 0x28 = decimal 40 = octave1 note E
  • 0x7F = full volume


(note that normally we'd expect anything "full" to be 0xFF but in MIDI messages, the data bytes always have a leading bit zero, so the maximum value we can achieve is 0x7F)

And as anyone who has ever played "Enter Sandman" on a guitar will tell you, the first note struck is always the low E string. Unless you're Bill Bailey....



Things look quite promising so far - so what's next?
The next message is 90 34 7F. That's another full-volume, note on message, this time for note 0x34 (which is decimal 52, or octave 2 note E)

Following that comes 90 37 7F. Another full-volume note-on message, for note 0x37 (decimal 55, or octave 2 note G).

Now comes our first note off message - 80 28 50. It's that first note, low E. Which tells us that all three note have been ringing out until this time. Again, anyone familiar with the opening bars of Enter Sandman (that bit with the clean guitar tone at the start) will recognise that this is the case.


The reason the low E stops is because, when playing this on a guitar, you normally fret the low E string to play the two-note decending riff. Sure enough, the next messages representing the next two notes are

90 2E 7F
90 2D 7F

Even without decoding these to work out what the notes are, we can see that there's a half-step change in tone; whatever note 0x2E is, the next note is 0x2D, one half-step/semi-tone below it. Being familiar with the tune, we already know that this is correct!

What's interesting to note (although, to be honest, maybe not unless you're a bit of a music nerd) is that if these notes had been generated by a guitar, there'd be a note off between the decending tones. That's because both notes are played on the same string. There's no way that you could get both notes playing, unless they were played on two different strings (and just about everyone who's ever played Enter Sandman on a guitar normally plays it by moving down a fret on the same string). In our MIDI playback, somehow both notes are ringing out at the same time. It's only a few bytes further on that we see the note off message for 0x2E, followed a few bytes later by the note off message for 0x2D.

Our screenshot belies the fact that these on/off messages can appear one after the other, almost instantaneously. But it's just interesting to note that this tune was probably played out on a MIDI keyboard (where it's quite possible to sustain two notes next to each other) and the player's inability to get their fingers out of the way quickly enough has lead to some notes sustaining for slightly longer than they would if played on a different instrument.

Anyway, all that aside, we've now got a way of reading incoming MIDI messages and decoding them into note on and note off messages. In the next post, we'll look at how we can use this data to display the notes on our guitar neck....



No comments:

Post a Comment