Adventures In MIDILand (Part 6)
Part 6. In this final episode Martin Russ returns to base camp, and completes his exploration of the MIDI programming jungle with a de-briefing for his fellow travellers.
What have we been doing for the last six months? Silly games? Pointless manipulations? No! This series has tried to show how MIDI works at its deepest and most complex level, by providing real example programs which can actually be modified by the users themselves. Consequently, anyone who has followed this series and used the programs should have been inspired to try and alter them to do something different. In this case, the series will have succeeded, and at least some of the ignorance concerning MIDI will have been removed from the world. There can be no substitute for actually manipulating the raw MIDI information itself as a way of learning about its innermost secrets.
This month's adventure completes a grand tour of almost all the things that we can explore with MIDI, with the exception of System Exclusive — which was covered in a previous series of mine in Sound On Sound (April 1989 to March 1990). Unlike our previous software safaris, the location of this month's first exploration is in the mind, not in a MIDILand program.
We could consider our explorations so far as taking place within a multi-dimensional space that involves the following elements: pitch events; timbre events; time events.
These are also the elements which make up musical notation. Pitch is usually vertical, whilst time is horizontal, and timbre is usually, well, inadequately described by words. I have concentrated on mapping events — not only within their own categories (pitch transposition, MIDI clock doubling), but also across the groups (Channelising, pitch to velocity). The end result has been to show that almost any mapping is possible, which is certainly not the impression you might get when you first look at the tidy categorised MIDI messages.
Just as a real safari would attempt to show you animals in some sort of context, so this exploration of MIDI has tried to include programs dealing pitch, timbre and time in a meaningful way. We started with simple manipulations to explore ways of using a computer to display and modify MIDI information, and then progressed to programs which implemented running status, thereby allowing interaction with all types of MIDI messages. The powerful technique of mapping was introduced as a way of describing and documenting the changes we were making. Finally, time events were shown to be capable of alteration in very similar ways to those in the other groups.
In all of the examples, the underlying driving force has been the MIDI messages themselves. They have shaped the structure of the programs and the approaches to solving the problems associated with the complexity of MIDI messages. The evolution of MIDI has meant that many features have been added to the basic spec, which means that the decoding of messages can be awkward and tedious, especially with running status to confuse matters.
The programs we have so far used as examples have all implemented just enough decoding of incoming MIDI bytes to produce the changes required. To complete the decoding, a series of decisions need to be made so that the MIDI bytes and the following data bytes can be interpreted correctly. Using this information, we can outline the sort of structure which could be used in a program (see flowchart in Figure 1).
This series of decisions can be thought of as a tree, where you make a decision as each branch splits into several smaller branches, thus reducing the number of possibilities until the type of byte is identified. We could translate this into a program with the same structure, but this would seem tedious, since the decisions are concerned with just simple 'yes' or 'no' answers. Instead it is often easier to use a structure which does some initial yes/no splitting, but which then uses a series of questions looking for a 'yes', and moving on to another similar question if the answer is 'no' — which looks like this:
input = INP(3)
low_nibble = input AND &H0F
top_bit = input AND &H80
IF top_bit = &H80 THEN
nybble = input AND &HF0
IF nybble = &HF0 THEN
IF nybble = &HE0 THEN
IF nybble = &HD0 THEN
system = input AND &H0F
IF system = &H00 THEN
IF system = &H01 THEN
IF system = &H02 THEN
The main program section waits for a valid status byte, and then passes control to the subroutine, which decodes the byte further, possibly passing it to other subroutines for further decoding.
The contrast between the two methods is similar to the game where you have to guess a number (between 1 and 9, for example) in the least number of tries. One approach would be to start at 1 and ask if it is each of the numbers in turn, as you count up. In the worst case, you would have to ask nine questions to find out the answer. Another approach would be to ask if the number is higher than 5, and if yes, then ask if the number is higher than 7, and if yes, then ask if it is higher than 8, and so on, halving the possible range of numbers at each guess. With the second method you can reach the correct answer in four tries at most. Each method has its advantages and disadvantages, which is why the program uses a little of both methods.
In a real application program, it is unlikely that the main MIDI input routine would be in exactly this form, but it would be interrupt driven instead, so that it could deal with MIDI bytes as they arrive by putting partially decoded bytes into buffers for subsequent use by the main program. The technique of splitting the bytes using a structure with a series of decisions is just as relevant, regardless of the implementation.
So what do real world MIDI programs look like? The simplifications which have to be applied to create short understandable programs make the examples given so far in this series rather unrealistic. One of the major problems in any programming task is making sure that the program copes with errors or unexpected results — in the case of MIDI programs, this usually means coping with nothing happening at the MIDI input. All the programs so far will wait for a MIDI input until you press a key (on the computer keyboard) to quit the program — and even to quit you need MIDI messages actually appearing at the ST's MIDI In, otherwise the program will not exit the loop where it waits for a MIDI byte to become available.
Often the process of making the program work despite a plethora of possible disasters means writing program segments that replace the commands of the language itself. In fact, rewriting the standard functions so that they do what you want rather than what the original programmer thought you wanted is often a major part of the programming task. By way of illustration, here is part of the MIDI input routine from one of my programs:
' times out after timeout period
mm = &HFF
t! = TIMER
IF INP(-3) THEN mm=INP(3) AND &HFF
LOOP UNTIL (mm<>&HFF) OR ((TIMER -t!) > timeout!)
IF ((TIMER -t!) >= timeout!) THEN
error_flag = TRUE
error_flag = FALSE
This subroutine approximately replaces the m = INP(3) AND &HFF statement which has appeared in most of the programs so far, but it has the advantage that it either returns a MIDI byte with the Error Flag set to false, or returns nothing after a timeout period with no MIDI activity, but with the Error Flag set to true. The calling loop checks the flag and acts accordingly, in a similar way to the previous examples in this series. The INP(3) function provided by Basic has none of these features, and it is quite easy to write a program which will lock up whilst waiting for a MIDI byte to arrive!
When you add in the problems of unexpected System Real Time messages (like $F8 clock ticks) upsetting the status temporarily, or the problems of interpreting All Notes Off events combined with Sustain Pedal events, then the ways of coping with MIDI input become necessarily complex — and completely outside the scope of a series like this. Even a powerful compiled Basic like HiSoft is not fast enough for many real-world MIDI programming needs, which is why many programmers write their MIDI routines in assembly language.
So, I hope you now have a better grasp of a few of the problems involved in MIDI programming, and some idea of how they can be solved. This series has aimed to show the workings of MIDI by example and by experiment, rather than explain exactly how to write MIDI programs. Even so, I hope that you are now more impressed by the programming skill needed to write a program which can cope with multichannel simultaneous recording or realtime MIDI processing.
The rough guide to the territory that you were given in part one of this series can now be expanded into a sort of index for the series as a whole:
|Part 1:||MIDI Fundamentals|
|The basic MIDI programming loop|
|The MIDI Display program|
|Part 2:||Running Status|
|Note Numbers and Velocity|
|Timing and Controllers|
|The program skeleton|
|The MGRAY bias detector|
|Message type changes|
|The Mapper program|
|Part 5:||Clocks and tempo|
|Merging as mapping|
|The MCLOCK humaniser|
|Things to come|
Similarly, the list of example programs which was given in Part 2 can now be indexed to their relevant positions within the series:
|MKOCT||Keyboard Octave Reverser||4|
|MKADD||Keyboard Add Octave/Fifth etc||2|
|MK2CH||Keyboard 2 Channels at Once||3|
|MK4CH||Keyboard 4 Channels at once||3|
|MKSWP||Keyboard Velocity/Note Swapper||4|
|MKV2N||Keyboard Velocity Transpose||3|
|MKV2T||Keyboard Velocity Transpose with constant velocity||3|
|MKV2P||Keyboard Velocity to Pitch Bend||4|
|RSTAT||Running Status Detector||2|
|MDRS||Running Status Remover||2|
|MBUFF||MIDI Buffer Display||3|
|MDISP||MIDI Hex Display||1|
|MPQNT||Pitch Bend Quantiser||2|
|MCLOCK||MIDI Clock Humaniser||5|
|MDRADD||Note to Drum Converter||4|
|MCLKHA||MIDI Clock Halver||5|
|MCLKDB||MIDI Clock Doubler||5|
|MASCLK||Active Sensing to MIDI Clock||5|
|MKN2D||Note to Start/Stop Control||5|
|MKN2PC||Keyboard Note to Program Change||4|
|MSIMPL||How not to do it!||2|
The 'MIDI Fundamentals' panel in the first part of this series was designed as an introduction to MIDI. Looking back at MIDI with our now experienced eyes, it is possible to rewrite it from a completely different viewpoint. The re-written version might go like this:
"The Musical Instrument Digital Interface specifies a method of communicating information between electronic musical instruments using messages which can be one, two, three or more bytes in length. The initial parts of the first of these bytes (the Status byte) to be received provides information on the type of event which is being conveyed by the MIDI message. The remainder of the initial byte is used for either channel information (MIDI provides 16 separate channels) or for additional information about the type of message. The status byte is indicated by setting the most significant bit high, any following bytes have this bit set to low, thereby restricting the data capacity of a single MIDI data byte to 7 bits.
There are two types of message:
• Channel messages are used to convey information specific to one of the 16 channels and consist of one, two or three bytes. The additional bytes after the initial Status byte are used to indicate extra parameters relevant to the message type. For example, in a Note On message, the second byte gives the note number and the third byte the attack velocity. If the type of message is the same for subsequent messages, the status byte may be dropped and just the data bytes sent under Running Status.
• System messages are designed for transmitting global information to all the equipment on a MIDI network, and they deal with the overall timing and control aspects. Although most of these messages are single bytes (especially the System real Time messages where they are kept as short as possible), messages of any length can be sent by using the System Exclusive header and footer bytes."
If you have followed the series closely, try going back and looking at the original description, and see if your understanding has changed in line with the new version above.
I hope you have enjoyed this unusual journey through the rarely charted depths of MIDI programming. MIDI is a fascinating subject, ripe for exploration and swapping of information, and I would encourage all readers to follow up the series examples with their own investigations, and to share their discoveries, preferably through the UK MIDI Association.
All the programs mentioned in this series can be found on the MIDILand Programs disk set (order code S101) which is available from SOS Software, price £7 inc postage.
SOS Software, PO Box 30, St Ives. Cambridgeshire, PE17 4XQ. 0480 61244.
UK MIDI ASSOCIATION
If you want to find out the latest information, or even make your own contribution to any topic related to MIDI, then the best thing to do is to contact your local official MIDI organisation. In the UK, it is the UKMA.
Vic Lennard, UKMA, (Contact Details).
Feature by Martin Russ
mu:zines is the result of thousands of hours of effort, and will require many thousands more going forward to reach our goals of getting all this content online.
If you value this resource, you can support this project - it really helps!