Home -> Magazines -> Issues -> Articles in this issue -> View
Micromusic: Notate your Nascom | |
Article from Electronics & Music Maker, July 1981 | |
A series that focuses on using the popular microcomputers for making music.

For those who would like to know how the program was devised, here is my approach.
We start by assuming that a squarewave signal is required, i.e. the line is set high and low for equal times alternately. This uses the OUT instruction in a Nascom system. To get the required frequency, we must arrange to have a controlled time delay between the OUT's. In the absence of an external timer chip and interrupt system, this has to be done by software loops, requiring knowledge of how long each instruction takes. The OUT instruction itself takes 11 cycles of clock frequency, or 5½ microseconds.
At this stage, where we start to look at Z80 instructions, it is necessary to be aware of the range of instructions, what they will do, and the timing. I have found a Zilog booklet, giving the instructions in condensed form, immensely helpful here, but the manufacturers' programming manual gives more detail, as do several books on Z80 programming. One strange-look-ing instruction which is very useful is seen at address 0E3F of the listing: DJNZ L00P1. This decrements the B register and gives a jump if not zero. The mnemonic doesn't obviously relate to the B register - you just have to know this. The jump would take 13 cycles, but no jump, i.e. program continues, takes only 8.
To get a variable delay, we enter a number into a register and subtract 1 at regular intervals. When the result is zero, the delay is ended. So the B register is often used for this purpose. As it turns out in this case, it is better to use it as an inner timing loop with the main count-down in an outer loop, because if we increment the number initially loaded into B we get an extra 13 cycles of delay, whereas using any other register would take longer. The outer loop here counts down using the accumulator, which is loaded first with the frequency code.

Since the delay is proportional to this code, good resolution and accurate frequency generation require it to be as large a number as possible. Hence we try to use FF hex, or 255 decimal, or near to it, for the longest half-cycle period, which is at the lowest frequency we are to use. (256 is possible, but we reserve the maximum code of 00 to indicate a pause. Why does 00 give a maximum delay? I leave the reader to spot this.) My note table was chosen to span three octaves up from C at 130.8Hz, which has a corresponding periodic time of 7645 microseconds. If we now divide 7645 by 255 we get the length of time to be occupied by the counting loop. A greater length means the divisor is reduced, spoiling the resolution; but a smaller length means we can't get the full period at the lowest frequency. So 7645/255 is in fact a minimum, and it comes to almost exactly 30. We should aim, then, at getting a counting loop as near as possible to 30 microseconds per cycle; but since these will be used twice in every cycle in the countdown, we need 30 'T cycles' (Z80 clock cycles) in each half-period, with the Nascom 1's 2-MHz clock.
The loop shown between addresses 0E3D and 0E42 takes 31 cycles, as can be seen by adding the four cycle lengths for these instructions. The DJNZ line is a little luxury which enables a single change in the previous line to slow down the tune, although it also reduces the pitch. I found this very useful in checking my sample tune, which I loaded with one or two errors; changing 0E3E from 1 to 3 made it play more slowly, and I was able to spot the errors more easily. This change added 26 cycles to the delay loop.
Loading A at the beginning of DELAY, and returning from the subroutine, take an extra 7 and 10 cycles respectively, so the total delay is 17 + 31*n cycles, where n is the note frequency code.
Having got the note sounding, we need a method of deciding when to end it. One possible method is to decrement a counter by 1 after each cycle, but this would mean a different delay code for each note frequency, and would be very trying to enter. The Scamp system I mentioned earlier did this, in order to shorten and simplify a ROM program in a device not intended for flexibility.
There is a simple alternative. Each cycle lasts for 31*n microseconds, ignoring a small (we hope) extra time for loads and tests which we will check later. So let us subtract n from the duration code after every cycle; we have then subtracted effectively the length of the cycle from the code, measured in 31-microsecond units. The duration code must then be simply the number of 31-microsecond periods required. Since we need a large number, to get notes of about a second in length, the duration code is made the high-order byte 'd' in a 16-bit number with low-order byte zero. Then d*256*31 is the duration in microseconds. For example, 30 hex gives 380928, or 0.38 second. Duration is loaded into the Z80's register pair DE at programme steps 0E07 to 0E09.
The subtraction routine is done at TEST. To do a 16-bit subtraction, we must use the HL pair - but this is also used as a pointer to the tune table and we have to save its previous contents. What a beautiful instruction EX DE, HL turns out to be! It not only gets DE into HL but saves the pointer in DE until we are ready to swap back. It couldn't be more tailor-made for the job. All this takes 47 cycles, however, so we waste 47 cycles in the first half-cycle to preserve our squarewave, although we needn't really do so as square-waves aren't all that interesting.
The true half-cycle time can be calculated now, allowing for 35 cycles to output high or low and call delay; 47 for test or balance; and delay itself, 17 + 31*n. The total is 99 + 31*n, giving a full-period time of 99 + 31*n microseconds. The required values of n for the different frequencies are calculated from equating this formula to the period time. The result is about 3 less than the number of 31-microseconds loops in the period, and leads to the values in Table 2.
Pauses are as important in music as sounds. To simplify coding, it is best to use the same duration code for a pause as for a note. Since every subtraction in the note routine corresponds to n*31 microseconds, we need a 31-microsecond loop in PAUSE, i.e. 62 T-cycles, and count this down by ordinary decrements instead of subtractions. Note another quirk of the Z80: decrementing DE doesn't set any flags, so we have to test for zero by ORing D and E.
We can now check the inaccuracies caused by the load and test parts of the cycle. At the top of the musical scale, we have a large number of cycles in a given duration, so the duration is extended more than at the bottom by the fixed 99 microseconds per cycle. Taking extremes: top C, with duration 30 hex for example, will have INT (48*256/27) cycles, i.e. 455 cycles, each of which takes 99 + 27*31 = 936 microseconds, giving a total duration of 425880 microseconds. Bottom C, on the other hand, with the same duration, will have only 50 cycles of 7632 microseconds, giving a total of 381600 microseconds, which is about 10% less. The error is not noticeable for most purposes; if it proves to be, it is still easier to make a small adjustment to a duration code than to have a different one for every note.
For convenience in a first approach, I have classified code 30 as giving ⅜ second in the duration table. This is slightly low compared with the figures I have just shown, but is within about 2% at the bottom end of the range.
Finally, we may be stimulated into thinking how to alter and improve things. Can we alter speed without altering pitch? At step 0E32, the duration code is decremented. We could decrement faster by repeating this instruction, more than once if wanted, and this would speed the playing. I haven't tried it because it means reassembling the following program. And inserting a counting loop round this instruction slows the basic program. We could also write a program to multiply or divide all the duration codes in the tune table. We could experiment with pulse waveforms. We could have a sequence table, which plays several tunes or parts of tunes in the order specified. We could interact with BASIC to make loading even easier, generate random sequences, or compose. And so it goes on. Is anyone else hooked?


Electronic Drum Sequencer - Software for BBC Micro |
The Syndrom - How it Works (Part 1) |
Sample & Hold Resurrection - what to do with your analog sample and hold once you've gone digital |
The Programmable Digital Sound Generator (Part 1) |
4780 Sequencer Modification |
An Ultra VCO From The 4720 |
The Matinee Organ (Part 1) |
Keyboard Matrix Interface For EK-3 |
The Electric Drummer (Part 1) |
Test Tone Oscillator |
Adding Fine Tuning To Standard Controls |
Workbench - Impedance. What is it?! |
Browse by Topic:
Feature by Don Finlay
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!
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!