Home -> Magazines -> Issues -> Articles in this issue -> View
Adventures In MIDILand (Part 3) | |
Article from Sound On Sound, October 1990 |
Part 3: Martin Russ hacks his way deeper into the heart of the MIDI jungle. This month: Buffer size, and how to deal with status swaps.
As we assemble around the Land Rover for our third safari, one of the locals comes up and speaks to the guide. After a few moments of rapid and intense conversation, the guide turns to us and says: "Can I have your attention, please. It appears that the local population are very eager to display the effectiveness of their computing facilities, and would like us to attend a small demonstration..."
As we are jostled into a semi-circle around the Atari ST, one of the explorers at the back mutters something about our guide mentioning speed problems during the last safari. The local representative bows and speaks: "Your guide mentioned that the problems with the MSIMPL program were not due to any lack of speed in the computer. We would like to reinforce this with a short demonstration. Please watch while I load the MBUFF program. This gives a graphic display of the size of the queue of bytes in the MIDI buffer. They are stored there whilst waiting to be processed. Notice how the average value is only one or two, and how it increases only momentarily when I play on this master keyboard..."
He is correct. The MBUFF program looks at the number of bytes which are waiting in a queue to be processed, and displays a rectangle whose length represents the number of bytes — although the graphics display takes quite a time to draw the filled rectangles, the length of the buffer is less than 10 for most of the time, even with heavy use of the Pitch Bend and Modulation Wheels. How significant is this?
The maximum length of the queue is set to 256 bytes when the ST is powered up, although the size of the buffer (and thus the maximum queue size) can be changed by software. Less than 5% of the buffer is being used in this case, although for programs like MKDLY the proportion can be much higher. As a precaution, most of the programs on the disk set the buffer size to between 512 and 4k bytes, which is probably overcautious. If you are using FirST Basic, then you can remove the buffer statements and in most cases the programs should still work.
For programs which may have to deal with large numbers of MIDI bytes in continuous blocks — System Exclusive dumps, for example — then the need for a larger buffer can become very important. The last thing you need in a block of data representing a sound or a sequence is an error. Too large a buffer can also create problems. Apart from using up valuable memory space, the combination of very large buffers and slow, complex processing can produce long delays between the MIDI messages entering the ST and leaving.
The problems of buffer size and delay are apparent in the MGRAY program, which looks at the velocity levels at which the black and white notes are played, and displays the number of keys of the two colours played together with the average velocity. The counting and averaging calculations take quite some time, and when you send Note On messages to the program there may be a delay before the first set of results are displayed and subsequently updated. You may also notice a similar delay when using the MDISP program with lots of MIDI Clock or Active Sensing activity — the Note On or Off messages do not appear on the screen as you play them.
When the buffer fills up completely, the queue will overflow and bytes are inevitably lost. In the case of a sequencer or SysEx Dump librarian, this is obviously disastrous. You can experiment with the MBUFF program by adding in time delays or complex mathematical manipulations (of the note number or velocity values) and observe the effect on the buffer. You will need to scale the graphics display and be prepared for all sorts of corrupted MIDI messages when the buffer fills up!
With the buffer and speed topics covered, the time is ripe for further exploration. In the last expedition, we were faced with an uncrossable canyon. We were unable to make status changes since we needed to preserve running status. We will now build a bridge across the canyon and continue...
Looking back at the basics, one of the fundamental status changes is when a message appears which refers to a different MIDI channel. Without running status, a series of bytes such as
90 3C 70 90 40 72
provides a reinforcement of the status for each message, and status changes are no problem:
90 3C 70 91 40 72
Here, the second note is on channel 2 instead of channel 1. If running status were in effect, then the change is more interesting. The first message:
90 3C 70 40 72
has two notes on channel 1, whilst the second message:
90 3C 70 91 40 72
remains the same. In effect, the missing $90 byte has been replaced with the $91 status byte for the new channel. So in order to be able to change status we need to be able to undo running status, and then manipulate the new status bytes. This adding of redundancy by inserting status bytes which are not needed is accomplished by the MDRS program, which uses almost exactly the same program loop as before, but with a slight addition.
Part of MDRS program:
start:
n = INP(3)
retest:
a = n AND &HFF
escape$ = INKEYS
IF escapeS <>"" THEN GOTO leave
IF NOT((a = &H90) OR (a = &H80)) THEN
OUT 3, n
GOTO start
END IF
n = INP(3)
do_next:
OUT 3, a
OUT 3, n
v = INP(3)
OUT 3, v
n = INP(3)
b = n AND &H80
IF (b <> &H80) THEN GOTO do_next
GOTO retest
Two changes have been made. Firstly, instead of just looping back to the 'start' label when anything other than a Note On or Note Off status byte is detected, this program outputs the byte and then loops. This means that unlike all the previous programs, the filtering works both ways — the program outputs all bytes unchanged except the ones which start with the chosen status bytes.
The status byte is repeated inside the do_next loop, and the usual test for continued running status now results in a repetition of the status byte as the do_next loop is repeated. The extra OUT 3, a statement makes all the difference — this program now converts two byte running status messages to three byte messages, and it remembers the current status in the 'a' variable.
This program segment is the key to achieving all the manipulations which we could not do before. Make sure that you can follow exactly what is happening as the program carries out each instruction. Remember that the running status loop (the do_next loop) behaves exactly as before, except that we are adding in extra status bytes for our own purposes. Once you are confident in using this new weapon, then we can investigate some applications.
With running status active, we are restricted to a single channel. With the amended program segment we are freed from this restriction and can now change channels and status at will. For a single channel channeliser the new program makes no difference, and is not used since we are just adjusting the channel part of the status byte.
Part of MCHAN program:
retest:
a = n AND &HF0
escapeS = INKEYS
IF escapeS <>"" THEN GOTO leave
IF NOT((a = &H90) OR (a = &H80)) THEN GOTO start
OUT 3, a + (chan-1)
n = INP(3)
do_next:
Interestingly, the code for the GEM version of the channeliser program (CHAN04) is almost exactly the same.
Part of CHAN04 program:
retest:
a = n AND &HF0
escape$ = INKEYS
IF escape $<>"" THEN GOTO leave
IF NOT((a = &H90) OR (a = &H80) OR (a= &HCO) OR (a= &HB0) OR (a= &HE0)) THEN GOTO start
OUT 3, a + ch
n = INP(3)
The major difference is that this version of the loop converts everything except Pressure messages, whilst the normal program only works on Note On or Note Off messages. This example thus shows how to add in further OR terms into the filter to enable you to choose exactly which messages you want to process. For converting single channel inputs to multiple channel outputs, then the ability to add in status bytes is essential.
Part of MK2CH program:
start:
n = INP(3) AND &HFF
retest:
in = n
a = n AND &HF0
aa = a
chan = n AND &H0F
escapeS = INKEY$
IF escape$ <>"" THEN GOTO leave
IF NOT((a = &H90) OR (a = &H80) OR (a = &HB0)) THEN GOTO start
OUT 3, n
n = INP(3) AND &HFF
do_next:
OUT 3, n
v = INP(3) AND &HFF
OUT 3, v
OUT 3, aa+add
OUT 3, n
OUT 3, v
n = INP(3) AND &HFF
a = n AND &H80
IF (a <> &H80) THEN OUT 3, (in AND &HF0) + chan: GOTO do_next
GOTO retest
In case you thought that everything so far has been obvious, then this badly programmed example shows how much forethought really is needed — it's another example of how not to do things! Instead of outputting the status byte at the beginning of the 'do_next' loop, the testing and output of the status byte is done at the end of the loop, and it changes the value of variable 'a', which is used to store the basic status message type. In order to make the program work — because it does — there are two different status bytes stored as two variables: 'a' and 'aa'. These are needed because the do_next loop destroys the value of 'a' each time it tests for a status byte. Trying to work out what this program is doing may be hard, but modifying it to make it do something else is almost impossible.
Here is a return to the way that we have carried out the status byte insertion previously, with a program which outputs four channels for one.
Part of MK4CH program:
start:
n = INP(3) AND &HFF
retest:
a = n AND &HFO
chan = n AND &H0F
escape$ = INKEY$
IF escapeS <>"" THEN GOTO leave
IF NOT((a = &H90) OR (a = &H80) OR (a = &HB0)) THEN
OUT 3, n
GOTO start
END IF
n = INP(3) AND &HFF
do_next:
OUT 3, a + chan
OUT 3, n
v = INP(3) AND &HFF
OUT 3, v
OUT 3, a+(add MOD 15)
OUT 3, n
OUT 3, v
OUT 3, a+((add+1) MOD 15)
OUT 3, n
OUT 3, v
OUT 3, a+((add+2) MOD 15)
OUT 3, n
OUT 3, v
n = INP(3) AND &HFF
IF ((n AND &H80) <> &H80) THEN GOTO do_next
GOTO retest
This program adds MIDI Controllers to the Note messages as being suitable for rechannelising, and also replaces the two line test for a new status byte with a single line version. To recap, the purpose of the '((n AND &H80) <> &H80)' test is to see if the most significant bit is set, since this indicates a status byte. It does not mean that we are looking for a $8n status byte for Note Offs, but instead it will detect any byte with the status bit set.
Programs such as these can be useful with multi-timbral synthesizers like the Yamaha SY77, where the Multi mode does not allow several channels to be controlled at once from the keyboard. Assuming that four 4-Element sounds are stacked on four MIDI channels, then the MK4CH program can produce a monster 4-note polyphonic sound from an SY77!
Thinking back to the speed discussion earlier, it is interesting to notice that with this program, when you play several notes at once you can actually hear them being sent out sequentially. The 4k buffer size makes very little difference to the program's performance since the 'times four' multiplication of events really does slow things down. Remember that a 4-note chord is now a 16-note chord on four channels!
Channel changing also crops up in utilities like Keyboard Splitters, where one channel is assigned below the split point, and another is assigned above it.
Part of MKSPL program:
do_next:
IF (n AND &H7F) > where THEN
OUT 3, a
OUT 3, n
v = INP(3)
OUT 3, v
ELSE
OUT 3, a + 1
OUT 3, n
v = INP(3)
OUT 3, v
END IF
n = INP(3)
IF ((n AND &H80) <> &H80) THEN GOTO do_next
GOTO retest
The split point is set by the variable 'where', and shifts the notes below the split point up a channel — so MIDI channel 1 becomes channel 2. Note that there are two 'v = INP(3)' statements inside the IF THEN ELSE structure - how would you alter the program so that there was only one?
Even splits based on velocity, not note number, can be programmed.
Part of MVSPL program:
do_next:
v = INP(3) AND &H7F
SELECT CASE v
CASE > where
OUT 3, a
OUT 3, n
OUT 3, v
CASE <= where
IF v = 0 THEN
OUT 3, a + 1
OUT 3, n
OUT 3, v
OUT 3, a
OUT 3, n
OUT 3, v
ELSE
OUT 3, a + 1
OUT 3, n
OUT 3, v
END IF
END SELECT
n = INP(3)
IF ((n AND &H80) <> &H80) THEN GOTO do_next
GOTO retest
This program is complicated by the need to cater for the case when a zero velocity value is used as a Note Off message. Rather than try to keep track of which notes are on which channel, this program turns the note off on both channels each time it receives a zero velocity byte, even though the note is only playing on one channel.
By using a splitter with several expanders or samplers, it is possible to simulate a single multi-timbral instrument, but with the added advantage of separate outputs. (Reviewers always complain about the lack of separate outputs for multi-timbral expanders!) Taking further the idea of using velocity creatively, it is possible to use velocity to produce transpositions instead of channel changes.
Part of MKV2N program:
do_next:
v = INP(3) AND &H7F
SELECT CASE v
CASE >= add
OUT 3, n + trn
OUT 3, v
CASE 0
OUT 3, n + trn
OUT 3, 0
OUT 3, n
OUT 3,0
CASE ELSE
OUT 3, n
OUT 3, v
END SELECT
n = INP(3)
IF ((n AND &H80) <> &H80) THEN GOTO do_next
GOTO retest
This process does not need a status change at all. The actual effect of a change of pitch related to the velocity can be unusual, or even unusable (octaves and sensible intervals, please), but it serves as a very good demonstration of the power of MIDI processing.
Finally in the 'strange effects' section, sustained notes can be converted to staccato versions.
Part of MKSTC program:
do_next:
OUT 3, a + chan
OUT 3, n
v = INP(3) AND &HFF
OUT 3, v
OUT 3, &H80 + chan
OUT 3, n
OUT 3, 0
n = INP(3) AND &HFF
IF ((n AND &H80) <> &H80) GOTO do_next
GOTO retest
This program changes status with a fixed Note Off message immediately following the Note On message (what would the filter look like in the 'start' loop?). Since we are only temporarily changing status, it is easy to restore it again. Some instruments and expanders do not like very short notes like this, so you may need to experiment with time delays (in between which statements?) to obtain reliable results.
The process of undoing running status is now complete. We have beaten our deadliest enemy and can retire for a well-earned night's rest under the mosquito nets. From here on, progress should be much easier since we will simply be applying familiar tools and techniques to new applications. The next expedition takes us onto the trail of a program which accidentally escaped attention during the System Exclusive series, and found its way onto some of the accompanying disks without any explanation...
PROGRAM DISK
All the programs mentioned in this series can be found on the MIDI Land Programs disk (order code S101) which is available from SOS Software, price £7 inc postage.
SOS Software, (Contact Details).
HiSoft Power Basic can be obtained from:
HiSoft, (Contact Details).
Read the next part in this series:
Adventures In MIDILand (Part 4)
(SOS Nov 90)
All parts in this series:
Part 1 | Part 2 | Part 3 (Viewing) | Part 4 | Part 5 | Part 6
The Musical Micro - Rag Bags and Hotch Potch |
![]() Software Support - Hints, Tips & News From The World of Music Software |
Apple Notes |
![]() Software Support - Hints, tips & news from the world of Music Software |
Software Support - Hints, Tips & News From The World Of Music Software |
![]() PC Notes |
Adrift On An MTC - MIDI Time Code |
Lab Notes: Blessed are the Seque |
![]() Software Support - Hints, Tips & News From The World of Music Software |
![]() Mac Notes |
Browse by Topic:
Topic:
Series:
Part 1 | Part 2 | Part 3 (Viewing) | Part 4 | Part 5 | Part 6
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!
New issues that have been donated or scanned for us this month.
All donations and support are gratefully appreciated - thank you.
Do you have any of these magazine issues?
If so, and you can donate, lend or scan them to help complete our archive, please get in touch via the Contribute page - thanks!