Micromusic (Part 3)
Polyphonic Sequencing with the ZX81
In the January issue we described an 8-bit output port; whilst this is fine for those synthesisers with a digital input, most operate with a one volt per octave control voltage. Figure 1 shows a digital to analogue converter (DAC) to provide this voltage from a digital input. IC1 is the converter IC itself; although this is an 8-bit device, only the six most significant bits are used to give a little over five octaves range. Bit seven is the gate signal, and in many cases this can be connected direct to the output port; or via a simple amplifier if 15 volt gates are required.
IC3 is a voltage regulator (pin connections are given for the DIL version of the 723) which feeds a stable reference current into pin 14 of IC1 via the 5k1 resistor. The 5k0 preset allows adjustment of this current to give an accurate one volt per octave output. IC1 actually gives a current output of 417uA per octave, and IC2 converts this to the required voltage swing.
Temperature stability is important in a circuit such as this, and metal oxide or metal film resistors should be used for best drift characteristics; the preset should be a cermet type for the same reasons, preferably of the multi-turn variety to make setting up easy. The 15V supply rails can often be derived from the synthesiser to be driven.
With the converter connected to the lower six bits of the ZX81s output port, monitor the voltage output with a digital voltmeter. The simple BASIC program below causes the output code to change by one octave every time NEWLINE is pressed; simply adjust the preset until the output voltage changes by exactly one volt when this is done.
10 POKE 16351,1
20 INPUT N$
30 POKE 16351,13
40 INPUT N$
50 GOTO 10
Note that this program uses port address 16351; i.e. the one shown in Figure 1 last month, with links 'A' being connected to put the port in memory address space.
We are now in a position to create a sequencer program using all topics we have covered so far. This program is in machine code for speed, and can drive up to seven synthesisers if you have them. The port circuitry given last month is used, but with links 'B' connected. An extra latch will be required for every synthesiser output; if more than four output ports are used, an additional 74LS02 will be needed as well. The program addresses the first port at 1F (hex) and so the first latch should be selected by IC1 pin 15, the second by pin 14, and so on. The input port is still situated at DF, and is therefore selected by pin nine as in the original circuit.
The note codes are stored in string array A$, which needs to be dimensioned beforehand in the form A$ (N, V). V is the number of voices, and should always be included even if it's one. To avoid complexity in the machine code, the music is split up into 'events' of equal time duration. If a semiquaver is the shortest note in the piece to be played, this will be one event; in this example, a crochet would occupy four events, a minim eight and so on. Thus N in the array dimension is the number of events; the program simply steps through the array from one to N, outputting each line of V 'voices' to the ports. The speed at which this happens is governed by pulses applied to bit seven of input port DF, so the music can be synchronised to a drum machine or 'click track' recorded on tape.
If the array is dimensioned A$ (10,3) for example, the sequence of events would be as follows: when the input pulse goes low, the code corresponding to character A$ (1,1) will appear on port 1F; A$ (1,2) will appear on port 3F and A$ (1,3) will be sent to port 5F. When the pulse goes high, A$ (2,1), A$ (2,2) and A$ (2,3) will be output from the ports in the same order, and so on.
It should be evident by now that an efficient method of filling up A$ is going to be necessary, and a BASIC program to do this will be discussed later (although no claims are made for its efficiency!).
The complete machine code listing is given in Table 1, and should be entered using the 'machine code monitor' given in December. Note that the program starts at location 16524, so there will be some blank bytes at the beginning; nearly 180 bytes are used, so make sure your REM statement has sufficient characters in it. Once the program is entered, save it on tape to avoid disaster.
The program consists of six subroutines, as follows:
This looks at the BREAK key, and returns with the carry flag reset if it is pressed.
Register C is used to hold the current port address; this routine adds 20 (hex) to the value of C to get the next address.
This routine is an aid to tuning up, and sends the code for middle A to all the ports (with bit seven set) so that the synthesisers may be tuned together. When the BREAK key is pressed, all the gate bits are reset to turn off the sound.
Machine code programs do not have access to BASIC variables, and this segment locates A$ in the variable memory space.
This is a subroutine used by the final program segment, and in fact does most of the work of outputting each voice in a particular time event to its respective port.
The final part is the actual playback routine itself; this uses all the other subroutines, except the tune routine, monitors the sync, input and detects the end of the piece. This is indicated by A$ (N,1) being either STOP (code 227) or GOTO (code 236). As you might expect, GOTO causes the sequence to start again from the beginning, whilst STOP returns the BASIC and ends the piece.
The only machine code routines that would normally be called from BASIC would be 16536 (to tune up) and 16640 (to start playing the piece); type PRINT USR (16536) or (16640).
Next month we will cover ways of programming the music; for the time being, it should be possible to develop short sequences by entering the note codes into A$ by hand. Remember that the numbers need to be converted into their corresponding characters first.
My apologies for a couple of mistakes that somehow crept in last month. Firstly, in Figure 1, the lower output pin of IC1 was shown as pin eight; this should be pin seven to correspond with the address table. Second, line 210 of the sequencer program may have puzzled those of you who couldn't find the function TEN on your ZX81; that should have been LEN of course.
Feature by Peter Maydew
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!