Sunday, 15 November 2015

Creating a web-based php MIDI to tablature system

A few days ago we managed to crack the secret behind parsing MIDI files - namely how to deal with variable length values (and bit-shifting seven instead of eight places left when multi-byte values were encountered).

We spent a bit of time reading through our midi files, which returned something like:

delta 183749 [4] note on 64
delta 183749 [4] note on 61
delta 183749 [4] note on 57

delta 184861 [4] note on 64
delta 184861 [4] note on 61
delta 184861 [4] note on 57

delta 185972 [4] note on 64
delta 185972 [4] note on 61
delta 185972 [4] note on 57

and using a MIDI note look-up table re-wrote the clusters of notes as their equivalent note names.
Where groups of notes share the same "delta time" they are all played together, as a chord (rather than individual notes).

So we looked up note 64 and found it was an E
Note 61 is a C# and note 57 is an A.

From simple music theory, we can work out that this is an A major triad. And looking back at some known tab for this particular song (Need Your Love So Bad) we can see that the song does indeed begin with an A major chord.

We checked a few other note combinations, later on in the MIDI file and found that they do indeed correspond to other chords throughout the song sequence. Yay! We're reading the midi files correctly.

But where to go from here?

TablEdit is a great program for converting MIDI files into readable guitar tablature. So we took a single track from our multi-track MIDI file and imported into TablEdit. It looked something like this:

We're just focussing on the first few chords to begin with

And in our php code, we loop through our midi note/time code values to see which notes appear where. When we find a bunch of notes that make up a chord (the same principle even applies to single notes, but this approach also works well for two or more notes played at once) we (bubble) sort them so that the highest pitched note comes first.

Now for an assumption. When playing guitar, particularly in a band, it's preferable to play "little chords" rather than full-on, six-note open ringing chords. Imagine you're playing guitar in a band that has a bass and a piano/keys, as well as a pretty good drummer (yeah, right, like you're ever going to make the grade in that band!). That's a lot going on. If you hit a full six-note barre chord over that, you're potentially playing a lot of the low-end/bass notes that the bass player is filling, and possibly even some of the mid-range notes that the keyboard player might be hammering out.

In short, when playing in an band, it's often preferable to keep the guitar to the high-end notes, and play two-or three note chords, to leave plenty of "room" for the other band members to fill.

With this in mind, we're making the assumption that we should always try to play on the high, treble strings on the guitar, where possible. So for each note in our MIDI chord, we're going to try to put it on the highest (high E) string first.

So we look at the numerical value of our first note (64) and we see if this will fit on the highest E string. If this value is greater than the MIDI value of the open string (but less than the open string plus 21, since there are only 21 frets on our light-up guitar neck) then this note can, indeed, be played on the high E string. If the midi value does not fall into the range available for the high E string, we try again on the next string, lower down (in tone).

Once we've successfully placed a note on a string, any future notes (in the same chord remember) must be placed on a lower (in tone) string. That's because it's not possible to have two notes on the same string, and have them both ring out, when played as a chord.

In our case, we can't put note 64 onto the high E string, since high E is MIDI value 76. So we try on the next string down (in tone). The B string is 5 frets "lower" in tone than the high E, and so has a MIDI value of 71. We can't  place our opening note (value 64) on the B string either. The open G string (stop sniggering at the back) has a MIDI value of 67 so we can't put our opening note on that string either. We can put it on the open D string, since this has a MIDI value of 62. Subtracting our note value from 62 gives us 64-2 = 2. So this note goes on the second fret of the D string.

Now we move onto the next note in the chord and repeat the whole process, but with one extra provision - since we already sorted the notes of the chord into descending order, we know that our second note won't fit onto strings 6-4. BUT we've already put a note on string 3, so we make that "out of bounds".

So when we come to place our second note (MIDI value 61) onto the tab, we're only interested in strings 2 or 1 (even if it would have fit on string three, that string is already taken by the previous note).  As it turns out, our second note (61) does fit on the second string since the open A string has a MIDI value of 57. Our fret number is therefore 61-57 = 4.

Repeating this process for the final note in the chord, we can't use strings 6-to-4 and 3 and 2 are already taken, so we have to put our final note (57) onto the first string. The open low E string has a MIDI note value of 52, so the fret number is 57-52 = 5.

If we look at the chord patterns drawn out by TablEdit, we can see that the opening chord of A major is played on the frets 2-4-5 which is exactly the pattern we created!

Although we haven't created the fancy-looking musical notes, and since we're only interested in "note on" messages (we'd have to compare note on and note off times to calculate note lengths) our note values are looking very encouraging indeed!

Transcribing the entire song, we ended up with exactly the same note clusters as the TablEdit software - which indicates that we're doing something right!

The "note spacing" isn't quite right - notes are supposed to be spaced according to the relative time between playing them - but the values look ok so far. Which means we're not far off being able to parse a MIDI file, create an array of "note on" values and squirt these over serial into our playable light-up fretboard; allowing players to see where their notes are and play them one step at a time. Very encouraging!