BeeBMIDI (Part 2)
The second part of our constructional article on building a MIDI interface for the BBC Model B home computer. There's a complete parts list and some more software to get your board up and running once you've built it.
Last month we published preliminary details on the construction of 'BeeBMIDI', a MIDI interface for the BBC Model B home computer, designed by Jay Chapman and Dave Eagle. BeeBMIDI 2 continues where that piece left off, with a full parts list and some MIDI software routines that should get your interface working even if you've only minimum of BASIC programming experience.
Last month's article certainly seemed to provoke a good deal of interest from readers, perhaps not surprisingly so in view of the fact that the BBC is one of this country's most popular home micros and that, at this stage anyway, there's only one other company producing MIDI software and hardware for said computer.
To clear up a couple of points that might have caused a little uncertainty among interested readers in the weeks ensuing last month's feature's appearance, you may have noticed that there are a number of decoupling capacitors drawn in on the PCB layout illustration that aren't included in the circuit diagram. This is normal practice and all the capacitors are in fact detailed in the parts list printed here. In addition, a gremlin in the E&MM artistry department resulted in a minor detail being omitted from the BeeBMIDI circuit diagram as printed in the June issue: the other end of R4 should be connected to the five-volt supply instead of floating around in mid-air.
Incidentally, BeeBMIDI PCBs are now available direct from E&MM, price £4.95. Cheques/postal orders should be made payable to Glidecastle Publishing Ltd., and you should allow 28 days for delivery.
More and more people are discovering, and wanting to take advantage of, the potential that MIDI offers. No doubt many E&MM readers will be building the BeeBMIDI microcomputer-to-MIDI interface described in the magazine, only to connect all the hardware together and find it will do nothing without some software!
Well, E&MM intends to be very active in this field and will in fact be marketing a comprehensive MIDI software package in a couple of months' time, as well as running a series of articles on how to write software for MIDI.
What we're going to do now is describe a few routines written in BASIC which will allow you to get something out of your MIDI set-up straight away, without diving into the complexities of assembler programming, interrupt handling, keyboard scanning and other such deep mysteries. At the end of the article some modifications, possible in BASIC, are also suggested.
Although the routines are written in BBC BASIC they can be translated to other BASICs without too many problems. The program has been tested on a Yamaha DX7 and a Roland JX3P, and should work with most other MIDI-equipped instruments.
The PROCinitialise routine relates to the 6850 Asynchronous Communications Interface Adaptor (ACIA) in the BeeBMIDI interface used to connect the BBC Microcomputer, via its 1MHz bus, to MIDI synths. The ACIA is responsible for converting the parallel bytes handled by the micro into serial bit streams over the MIDI connections and was described in detail in last month's MIDI supplement.
First, some names are set up for the ACIA register addresses and control codes. The ACIA is sent a Master Reset code in line 1330. The BBC BASIC syntax used in this line, '?address=value', corresponds to 'POKE address, value' in some other BASICS. Finally the ACIA is configured to receive and send one start, eight data and one stop bits and to divide its external receive and transmit clock frequencies by 16. Since the two frequencies input to the ACIA are both 500KHz, this gives the correct MIDI serial bit time clocking of 31.25kBaud.
This routine, or its assembly level equivalent, is required in every piece of MIDI control software using this ACIA.
The byte passed as a parameter to the PROCsend_midi(byte%) routine is transmitted over MIDI Out via the ACIA. As the ACIA's registers are 'memory mapped' - that is, they appear as normal locations in the BBC Micro's 6502 CPU memory - all we have to do is poke the byte to be transmitted into the ACIA Transmit Register (line 1490). Before doing so, we have to check that the last byte transmitted has actually gone. This is done by the REPEAT UNTIL loop (lines 1460 and 1470) from which the program exits when the expression '?status_reg% AND &02' becomes non-zero.
BBC BASIC is again unusual in that '?status_reg%' is the equivalent syntax to 'PEEK(status_reg%)' in MICROSOFT type BASICS. The 'AND&02' ('&' indicates that a hexadecimal value follows) causes all the bits in the expression result to be zero except the bit corresponding to the 1 in the binary version of &02, ie. '0000001 O'. Thus the only bit we actually see the value of in the result of '?status__reg% AND &02' is the 'Transmit Register Empty' bit. If the expression result is non-zero then this bit is on and the register is empty, so we can transmit.
Now that we have a routine to send a byte via MIDI Out, we can make the instrument(s) on the other end actually do something!
The PROCselect_voice(voice%) routine is passed a voice number in the parameter voice%, and simply sends the correct MIDI status byte (line 1570) followed by the voice number (line 1580). Note that the voice number has 1 subtracted from it. This sort of 'correction' will occur quite often when you're sending such data over MIDI, because the digital hardware implementing the MIDI control starts counting with 0, whereas you or I usually start with 1. Another example of this is the MIDI Channel Numbers, which are referred to as 1 to 16 but are coded internally as 0 to 15.
Lines 1080 to 1110 call this routine after asking the user which voice number he would like. These lines check that the voice number given is in the range 1 to 32, the possible voice numbers on the DX7 (when 'corrected' to 0 to 31). The JX3P is slightly more complex to deal with because you need to take in the bank as well as the voice number. Bank B, voices 1 to 16 are coded internally as voice numbers 16 to 31 (after 'correction'), bank C's 16 voices as 32 to 47 and bank D's as 48 to 63, so it's not too difficult to expand lines 1080 to 1110 to cope, viz:
1090 INPUT "Bank, Voice", bank$, voice%
1100 UNTIL bank$ >= "A" AND bank$ <= "D" AND voice% >= 1 AND voice% <= 16
1110 PROCselect___voice ((ASC(banks$) - ACS("A")) * 16 + voice%)
PROCplay_data is a very simple routine to get something musical sent over MIDI. The tune played should at least be recognisable, though it is played a little woodenly, I have to admit.
The method used here is to split time up into fixed length intervals. Data is read and transmitted over MIDI from the start of each interval until a marker value of -1 is read: the routine then delays for the fixed interval. This means that the read and transmission time is added to the fixed interval but this should not be noticeable. When a -2 marker value is found, the routine exits.
This routine's code should not be too difficult to understand. If you want to change the tempo you can alter the 300 in line 1760: a larger number will give you a slower tempo and vice versa.
The data actually sent over MIDI needs a little explanation.
The first byte sent (DATA on line 1860) is &90 (decimal 144), which is a status byte saying that data for 'key on' events follows. Each event needs two data bytes - the first gives the number of the key pressed and the second the key velocity. Because MIDI, allows 'running status' - that is, the status byte need not be sent on every event provided status is not to be changed - we don't need to send another status byte. Of course, we need to say when keys are released, but we are allowed to use a 'key on' event with a velocity of zero to say 'key off'.
The next two bytes sent are both 64. The first byte is the key number of the E above middle C: the key numbers increase or decrease by 1 for each semitone pitch change - middle C is key number 60. The second byte, the key velocity, is also 64. We've used a velocity of 64 for all 'key on' events as this is the centre value of the velocity data value range - it's also the value that would be sent by a non-touch-sensitive keyboard.
After waiting for two time intervals (forced by the two markers at the end of line 1870), with the E above middle C playing the program, send the data on line 1880. The note number is again 64 but the velocity value is zero, so this causes the E above middle C to stop playing. You should now be able to work out what the rest of the data does. The note numbers, with their pitches, are shown in Figure 1.
Perhaps the most obvious modification is to replace line 1800 with:
1800 UNTIL FALSE and insert the line:
1785 IF byte% = -2 THEN RESTORE
The effect of these two edits is that PROCplay_data now plays the data repeatedly - so we have a very simple sequencing facility.
You could easily make this sequencing more useful by transposing the sequence each time through. To do this you could have the amount to transpose by on each repeat held in an array. At each RESTORE, you increment an index into the array so that a new value will be used the next time around. For example, if you wanted to play the sequence once as written, transpose up by an octave and then down by a 5th, your array values would be 0, +12, -7. Line 1780 would therefore change to something like: 1780 IF byte%>=0 THEN PROCsend_midi (byte%+pitch—offset%(index%)) where pitch_offset% is the array and index% is the variable being incremented at each RESTORE.
There's nothing to stop you sending MIDI codes for events other than 'key on's, of course. You might like to try experimenting with the pitch-bend and modulation controllers, but don't forget that if you insert bytes to effect this sort of control between the 'key on' message bytes, you have to follow the MIDI rules - insert new bytes after the velocity data byte of a 'key on' event and insert another &90 'key on' status byte after the new bytes, otherwise the following 'key on' data bytes will be assumed to be pitch (or whatever) controller data!
Try changing line 2030 to:
2030 DATA 72,64,-1,-1,&E0,0,66,0,68,0,70,-1,0,68,0,66,0,64,-1,-1,&90
I know it sounds like a cat in pain, but you get the general idea.
The &E0 is the 'Pitch Wheel Change' status byte and is followed by pairs of bytes representing the wheel's position. The pairs are sent with the low order byte first - in the example above I didn't actually use the resolution offered by the low order byte, which I set to zero. The wheel's centre position is represented by the byte pair 0, 64 (&00, &40) giving the combined hexadecimal value of &4000.
Another possible modification would be to send chords rather than the simple monophonic tune given in the program. All you have to do is turn more notes on at a time - and then turn them off some time later. For example the following sequence of bytes will play a C6th chord.
If your synth is capable of touch-sensitive operation, you might like to try varying the velocity values associated with each 'key on'. Using something like 'CLAV 2' on the DX7, you should be able to get a nice 'funky' sound going.
Finally, if you're rich enough to have two MIDI synths (sorry - that should read 'if you were rich enough...') why not set them onto different channels and send different control information to each of them? Chords to one and the melody to the other, for example. Incidentally, don't buy two JX3Ps if you want to do this - I don't think you can change their channel number, so both would be on channel 1...
Anyway, what you need to do is send a status byte, incorporating the correct channel number in its least significant nibble (4 bits) followed by control information for the synth on that channel, and then send another status byte incorporating the second synth's channel number, followed by its data.
By way of an example, assume that a JX3P is on channel 1 (since it can't be on any other channel!) and a DX7 is on channel 2. Don't forget that the channel numbers need 'correcting' from the range 1 to 16 into the range 0 to 15, so a 'key on' status byte for channel 1 looks like &90 whereas for channel 2 it looks like &91.
The following sequence of bytes will cause PROCplay_data to play middle C on the JX3P and G above middle C on the DX7 simultaneously.
1885 DATA &90,60,64,&91,67,64,-1,-1,-1,-1,&90,60,0,&91,67,0,-2
Note that a byte could have been saved if we take advantage of 'running status' and code the MIDI bytes up as follows (think about it...)
1885 DATA &90,60,64,&91,67,64,-1,-1,-1,-1,67,0,&90,60,0,-2
In later articles we'll see how techniques based on this idea can give split keyboard effects where both halves (or thirds, or quarters... in fact, up to 16ths!) can be transposed into sensible ranges.
Well, I hope you'll have a lot of fun 'doodling' with these routines and that your interest will be aroused enough for you to follow some of the more technical programming articles that E&MM will be publishing in the future. And if it all seems like too much hard work, you can always buy the 'MIDI Control Software' Package that E&MM will be marketing soon.
Gear in this article:
Previous article in this issue:
Next article in this issue:
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!