Friday, 13 February 2015

Converting music theory into bits and bytes

Without getting too bogged down in musical theory (between us, a handful of people probably know enough to fill a half of an A4 sheet of paper!) we're looking for ways of getting particular scales and chords to appear on the keyboard by lighting up the appropriate LEDs.

The easiest way to do this is to create a byte value, where each bit indicates whether an LED is on or off. We're going to do a straight mapping from the LEDs to the piano keyboard (we'll worry about guitar fretboards later!)

Now the more astute readers will have already spotted that, despite what we were all taught in high school music lessons, an octave doesn't have just eight notes in it! While it may have eight intervals (let's not got bogged down with tones and semi-tones at this stage) between one note on the keyboard and the same note an octave higher, there are twelve individual "notes". The distance between each note (ignoring the colours, whether black or white at this stage) is one "semi-tone".

On a guitar, the "distance" between each note on the fretboard is also one semi-tone.

We're not going to the trouble of naming all the notes on our keyboard/fretboard. At this stage, all we're concerned about is identifying the intervals between each note in a scale (i.e. how many semi-tones apart they are) rather than whether the note is a C or B-flat or whatever.

By focussing on intervals rather than note names, we should be able to change each chord/scale into a different key really easily, by simply shifting the entire pattern up or down the keyboard/guitar. This is easier to visualise on a guitar, as there are no pesky black notes to get in the way:

Here's the famous "first position" A minor pentatonic scale on a guitar fretboard.

On the guitar diagram above, the lower (bass) notes are on the bottom, with the higher notes at the top of the diagram. The pitch of the notes goes higher towards the right of the diagram.
Here's the same scale on a piano keyboard

Notice that if both scales are starting on the same note (A) on the guitar (lowest string) there is a gap of two frets before the next note (drawn on the eighth fret on the low E string) and, similarly, on the piano keyboard above, there are two notes (the black, B-flat and the white note B) between the first and second notes of the scale.

So whether playing a guitar, or a keyboard, we can work with intervals rather than note names and still get the same result. Now let's move the scale into another key. For us guitar players, it's really easy. For some crazy reason, we're going to play this same scale, but in F#. On the guitar, simply slide the entire shape down the guitar neck, so that the scale starts on the note F#.

But on a piano keyboard, things aren't quite so straight forward. We still need to move all the keys down three semi-tones, but in doing so, we've made the scale look much more complicated:

And moving scales around on a keyboard which uses both black and white notes can result in some pretty crazy combinations of black and white notes. Normally keyboard players simply commit these to memory and "just know" which notes to hit when playing in a particular key.

But when you're starting out, knowing which note to hit is a bit of a nightmare. Which is why we're building this MIDI keyboard in the first place! If we imagined using binary to represent the keyboard diagram above, starting with the first note (C) and mapping each bit in the binary value to each key of the keyboard (so bit zero is C, bit one is C#, bit two is D, bit three is E-flat, bit four is F - if you look, there is no black note between the E and the F on the keyboard - and so on) we can illuminate the keys for the F# minor pentatonic scale (as shown above) by the value


We simply read the binary value as a sequence of on/off signals, starting from the left, and apply the signal to each key on the keyboard, also starting from the left.

Interestingly (see, I told you this was fascinating!) we can see in our binary value, the first two notes are represented by 1001. This is the interval of two semi-tones we were banging on about earlier.

In fact, any pentatonic scale can be represented by the binary value 0100101010010
We simply change the number of leading zeros, to place the pentatonic scale in a different key. The intervals remain the same. Adding more zeros at the start makes it start on a different note, so each note in the scale gets a different name, but the "gaps" between the notes of the scale are always the same.

(Another really interesting thing to note - for those of you still awake at this point - is that there are five values of one in the binary string above. Five "on" notes; five notes in the scale are what make it pentatonic)

Using this technique, we can come up with binary values for a whole range of different scales:

The "major scale" - the one everyone knows as doh-ray-me-fah-so-la-te-doh has seven notes (we repeated "doh" at the start and at the end, which is why it's written with eight). The intervals between the notes in a major scale are

play-a-note, skip one, play-a-note, skip one, play-a-note, play-the-next, skip one, play-a-note, skip one, play-a-note, skip one, play-a-note.

This is often written as tone, tone, semi-tone, tone, tone, tone, semi-tone (but that's a lot like music theory, so we'll stick with our garbled interpretation of things).

Look at the diagram of a piano keyboard. If you played only the white notes, starting at C, you'd be playing the "C Major" scale. So you hit C, then miss the black note, then hit the next (white) note D, then miss the next black note, then hit the next note, E. Now there's no black note between E and F, but in our major scale, we need to play the next note anyway, so we play the F note. Then we skip the next note (which is the black F# in this case) and play the next, G. And so on, right through the scale.

The intervals for a major scale can be written in binary as:


And if we wanted to continue the scale, we would simply repeat from the start:


Note also that the first binary representation of our C Major scale had twelve characters in it, and a total of seven values of one. We already identified that our major scale has seven notes in it, and one complete octave has twelve intervals. So things are looking good for our binary representations of scales (and chords - scales and chords are very closely linked and for simplicity we're going to use the terms interchangeably here - things might change as we get deeper into the project, but for now we can think of scales and chords as the same thing).

Other commonly used scales and chords, as written in binary:

a blues scale is a pentatonic with a few added "blue notes"

a C major chord (triad) includes the notes C, E and G

a C minor chord is the same as the major chord, with a "flatted third" - this basically means that the "middle note" in this case should be moved down one interval.

a C major 7th chord is the same as the major chord, with an extra note

To play a D major 7th chord, we simply take the C version and move it up two intervals (increasing one interval would make it C#maj7) and in binary we do this by adding two leading zeros:

Now the binary string is more than twelve digits long. We could wrap the 13th and 14th bits around, and place them in positions zero and one in our binary string, to create 

but now we're entering the world of chord inversions, and some pretty heavy-going music theory. So we'll keep things simple for now (though we will be using this technique later, in our firmware programming).

Now we've a way of converting musical ideas into binary, we can simply create a lookup table of values for each of the major, minor, pentatonic, 7th and other chords/scales, and simply bit-shift them left or right, to convert them into their respective key(s).

Phew time for a break!