Technically Speaking (Part 3)
The third of our build-your-own-MIDI-interface-for-BBC-and-DX21.
In a specially extended Technically Speaking, Andy Honeybone persuades his BBC micro to become a voice dump for the Yamaha DX21 synth. Software, we've got it. Solutions, you've got 'em.
"What, no ROM pack!". Thus spake the critics of the budget DX21. And here, in what could only be described as the twinkling of an eye by someone whose sense of temporal relativity was well shot, is Making Music's solution.
Take a straight BBC 'B' micro with the MIDI interface as described in weeks past, two DIN to DIN leads, a word processor, Acornsoft FORTH and start typing. The result is a DX21 Voice Manager which can suck the voices from the synth, store them on disc, catalogue the voice names, recall them from disc and squirt them back from whence they came.
Now FORTH might not be too familiar to many of you, but there's no shame in that. You can either just type it in and ignore it or you could take this series as the push necessary to jolt you into learning another language. Either way, I would recommend that you equip yourselves with FORTH in ROM. Although this month's program will run on FORTH from disc (with just over 1k to spare), you are clogging up 16k of vital memory which is much needed in the realtime MIDI recorder to be featured in a later article (if you are using disc FORTH, remember to load the assembler on screen 12).
Dedicated FORTH programmers will no doubt be wincing at the lack of the 1k source code screens which I have abandoned in favour of creating the program on a word processor (VIEW) and using OS' *EXEC filename to compile the code. Any word processor capable of producing an ASCII file should suffice.
Why FORTH? In a word, portability. In two words, portability and speed. I'd be the first to admit that the BBC is dead as a computer for the second half of the eighties. However, I'm not so well off that I can just nip off and buy an Amiga or an Atari in the hope that they will be supported with professional MIDI software and not killed at birth by the IBM brigade. FORTH runs on every microprocessor and is implemented for almost every compter. Its source code can be sent down an RS232 or MIDI line from one computer to another and be running in minutes. Of course an Amiga wouldn't known what to do with BBC 6502 assembler or OSBYTE calls, but these hardware specific areas of code can be quickly skirted around by the redefinable nature of FORTH. Because FORTH is intermediate in speed between machine code and BASIC and does not obscure the underlying hardware, many routines previously coded in assembler to run with BASIC can be written directly in FORTH. I've tried to bring any 'magic numbers' to the head of the program as constants. Just changing these values should help portability not only between computers but between synthesisers.
The program should be self-explanatory in use so let's get on and trace the program flow from pushing the red function key f0. The key is programmed by the KEY' command to issue the word get_dx and send the FORTH interpreter rushing off to look for that command within its dictionary. On finding get_dx, FORTH begins executing the definition which consists of the four previously defined words:- prepare, fill_buff, cat and chksum. The name of the definitions should give a fair indication of their function.
The definition of prepare consists of further backward calls to jmp_nmi and setupbuf followed by an instruction to load a value into the MIDI interface to set the clock division rate and interrupt response to receiver buffer full. The coding of jmp_nmi consists only of directions to load the address of the interrupt handling machine code into a specific memory area and to reset the MIDI interface prior to receiving a new command. Hence as jmp_nmi makes no further backward references other than to standard keywords, it is the tip of one root if you care to think of a FORTH program in botanical terms.
Moving on, setupbuf is another root end which simply initialises a pointer to the first position of the input buffer and clears the end of file flag. Having hit all the dead ends within the definition prepare, FORTH returns to the next command in the definition get_dx which is fill_buf. A quick look at fill_buf shows that it asks the DX21 for a bulk voice dump, waits until the data fills the buffer, catalogues the voice names to the screen and finally tests the checksum to ensure that there have been no reception errors.
First off in the definition of fill_buf is dump_req which issues the system exclusive MIDI message with the Yamaha identification for 32 voice bluk (sic) data as it says in the manual (p48). The call to xmit (transmit) sends the preceding data byte to the MIDI interface. The BEGIN... UNTIL construct in xmit waits for the last byte to be sent before the new byte so that pile-up doesn't occur. Next, the program waits in a 'do nothing' loop until the end of file flag is raised by the interrupt code which, of course, has been busy collecting the data spilling from the DX21. Lastly, the routine tidy_up is called to do a belt and braces reset of the MIDI interface and restore the original code which was replaced with the jump address of our interrupt handler code.
The catalogue of the voice names is produced by the definition cat. The format of the data dump is a six byte header, 4096 data bytes and a two byte tail. The voice name appears in the dump as ten bytes starting 57 bytes from the top of the data. The header is six bytes hence the offset to the start of the first voice from the beginning of the bulk data dump is 6+57=63 which is &3F in hexadecimal. Each individual voice is padded with zeros to be 128 bytes long and so this becomes the interval between name fields.
In an attempt to dress the program up and add a degree of user friendliness, the displays banner and help have been included. The hex value &8D lurking around in mm is the Teletext control code for double height lettering.
The last definition within get_dx to be executed is chksum. The checksum is the seven-bit two's complement value of the data bytes summed ignoring overflow. As the sum of a value and its two's complement is zero, by adding all the data bytes and the checksum a value is returned which is zero for the least significant seven bits if the data is correct.
So that's traced get_dx and hopefully given you a feel for a threaded interpreted language. Rounding off, the remaining routines are concerned with the transfer of voice data from the computer to the DX21 and the disc filing system. The definition put_dx sets up the MIDI interface for operation without interrupts and steps through the buffer transmitting each byte in turn. Yamaha were smart enough to make the header of the received data the same as that required to tell the DX21 that a bulk voice dump was coming its way.
The routine >ASCII (to ASCII) takes a numeric value from the stack and replaces it with the codes for its character representation in reverse order. The load and save commands use this word to assemble a command filename start_address + length character string in reverse order on the stack. A call to load_OS_cmd reads the stack into a buffer and passes the start and length to >CLI which sends the string to the command line interpreter of the machine's operating system.
So that's the program. In use, the only pit-fall to avoid is remembering '1' to turn the memory protect off when loading voice data to the DX21.
Gear in this article:
Feature by Andy Honeybone
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!