Wednesday, April 19, 2006

Strumming the guitar - stage one

Programming realistic guitar strumming into a MIDI file is very difficult. Played on a keyboard, such a chord might consist of three or four notes, all them starting simultaneously and with the same volume. Apart from the trivial fact that a guitar has six strings and so any chord produced will be musically different from the basic keyboard version, a strum cannot play each string simultaneously. The notes have to be staggered by a varying amount and will have differing volumes. There are upstrokes and downstrokes, meaning that the resulting arpeggio will have notes played in a different order. Also downstrokes (from top string down to bottom) tend to be quieter than upstrokes. This is why there are very few realistic sounding guitar parts in MIDI files which one can download from the Internet, and virtually no guitar parts whatsoever in any of my files. 

Two and a half years ago, being aware of some of the above problems and thinking it about time that a guitarist have some guitar parts in his MIDI files, I started work on a program which would export a MIDI file containing notes purporting to come from a guitar strumming a series of chords. Apart from defining a mechanism allowing the user to enter chord shapes, I didn't do very much with the progam, and it's lain abandoned ever since. I was reminded of it the other day after deciding to purchase a library of MIDI guitar strumming. Obviously, one gets what one pays for, and 15 pounds sterling didn't get me very much. On the other hand, there wasn't much of a choice: most of the programs and libraries which I saw were either for the Macintosh or as add-ons to sequencing programs that I don't own. The library itself consists of several pairs of files, each file containing one strum pattern for several chord shapes (the second file in the pair consists of the same pattern for more exotic chords). I tried creating a sample song, in order to get an idea of what the files were like when I ran into a fairly major problem: a song is going to have a chord sequence, which means either copying the strum pattern for one chord and then editing it, or copying a bar from one chord followed by a bar from another chord. This might be practical (if rather tiresome) but for one problem: in order to make the strums sound realistic, they would often start before the beat. Copying and pasting would not only be tiresome but would also involve a fair amount of tedious editing, moving several notes backward in time. It's a shame that the library creators didn't think of this: starting the first note of the strum on the first beat/tick of a bar. Although this wouldn't be very realistic, it would at least allow the user to create a proper chord sequence, which could then be moved back eight or twelve ticks and thus attempt the realism. 

I was considering editing the library to achieve the above (and may still do) when I remembered the strum program which I had tried to write. In preparation for the MIDI export part, I had analysed several simple MIDI files as well as perusing the MIDI specification. I had even written a small program which exported a MIDI file containing a four note staggered chord; this was enough to show me that writing a strummer program was going to be much more difficult than I had originally imagined. When sequencing MIDI, one places the notes on the stave where one wants them, defining their length - just like writing music on manuscript paper. 

But a MIDI file is not like that at all: it consists of events (such as note on and note off), where each event has a delta time - the number of ticks before the next event. This might be manageable when programming a monophonic instrument such as a flute, but is exceedingly difficult when trying to program a guitar, which could have six 'instruments' playing simultaneously, although each with its own start and stop time. To do this properly requires laying out all the events on a time line and then figuring out the delta time for each event, not a trivial exercise. Then there are variable length quantities - a strange concept to a veteran Pascal programmer, used to values such as 127 and 129 requiring the same amount of storage. I suppose the idea was to minimise the amount of data flowing between different MIDI machines which were communicating at a rate barely capable of maintaining the latency required. One forgets that the MIDI format was initially developed to allow machines such as analogue synthesizers to communicate with other machines, such as tape recorders; it was not developed as a file format for programs to output music from a sound card on a computer. Anyway, the variable length quantities means that 127 can be stored in a single byte, whereas 129 has to be stored in two bytes (of which the first has to have its most significant byte turned on, even though it's not part of the value); total anathema to Pascal/Delphi requiring a very low level of programming to get right. 

I analysed one bar of a strumming pattern for one chord: this had 46 separate "note on" events! After listing them on paper, I calculated their delta times and then hand encoded the data into a test program. I ran the program and looked at the resulting MIDI file. My sequencer barfed on it (as the Americans would say). I went to sleep and dreamt of MIDI files. I woke up with the answer of my lips: my original test programs had all had a length of less than 127 bytes, so I could get away with a length of one byte. The new test program was longer and so needed two bytes for storage (but not in the same format as a delta time longer than 127 ticks!). Once I got that sorted out, along with a few other minor problems, the test program actually worked! 

Until now, I had been looking at the internals of the MIDI file with that venerable tool left over from DOS - Debug. One of the major drawbacks of using this program was that I couldn't print a dump of the file being examined, essential for further study. So I wrote a hex dump program which sends its output to the printer. Yes, I did look on the internet for such a program, and although I found one which seemed suitable, it didn't print a chunk of the file - a strange bug. So what the hell - ten minutes work and I had a simple hex dump program. 

Then came the fun of integrating my test program into the guitar strum program. The MIDI part was actually quite successful and barely needed changing. The major problems were in parsing the chord sequence (harder than I thought), getting the appropriate chord shape and then translating the chord shape (which would be fret numbers, ie 022100 for E Major) into MIDI note numbers. Eventually all these problems were solved. So stage one has been done. It's easy to list now the things the program doesn't do.
  1. I need a mechanism for allowing alternate chord shapes for the same chord name (eg 020000 and 022030 for E minor), let alone using chords in higher positions
  2. What to do with chords which don't use all six strings? Diminished chords immediately come to mind, but there are plenty of others.
  3. The program 'knows' only one strum pattern. I'll have to 'teach' the program other patterns (which probably means laborious translations from MIDI data), as well as having to figure out a mechanism for choosing which pattern to use.
  4. Chords are on a strict one-per-bar basis. How can I do half bar chords? This might actually be left for editing within the MIDI sequencer.

One idea which I am considering is taking the actual MIDI output from the library and converting it into some canonical form of length one bar, where the notes are represented in some format totally illegal to MIDI but easy to substitute from. When a bar of E is called for, the sequence is poured into temporary storage, with notes from the E chord being substituted for their place holders. If the next bar is A, the same process occurs, but of course different notes are placed in the note on/off events. This technique will enable me to avoid the laborious and error prone method of calculating the delta time for each event, which can be even more difficult if the strum pattern tends to the staccato (the one which I translated by hand had continous - legato - notes without pauses).

I now need a week for further cogitation on the subject.

No comments: