.........1.........2.........3.........4.........5.........6.........7.........8

Mastering Machine Code on Your Spectrum
part 4 of 8 - from ZX Computing Apr/May'83

Following in her series, Toni Baker, author of "Mastering
Machine Code on your ZX81", transforms your Spectrum into a
musical machine.


Long, long ago in a galaxy far, far away, great battles were
waged between the humanoids and the space invaders, the
spaceships and the asteroids. This world was brought to your
attention with the coming of the video age - first in
arcades, and now in home computers like the Spectrum. In the
comfort of your own home you can gently soothe away all your
frustrations by killing untold millions of malevolent
aliens, fighting with mystical dragons to rescue beautiful
princes from evil wizards, or testing your intelligence with
maze games and mastermind puzzles. After all - what else are
computers for?

In another sector of the galaxy lay-accountants and
businessfolk ponder over the strings of figures being reeled
off by the ZX Printer telling them to the nearest penny how
much tax they can fiddle before they get caught, or staring
for hours at the bland bar-charts and friendly graphs
plotting current profit returns against the popularity of
'Crossroads'. After all, computers weren't designed for
playing games - or were they?


Strumming your Spectrum

Then one day, as I sat drinking coffee and chatting away to
my fellow compatriots, wishing I could play the guitar as
well as they, a friend introduced me to a new concept. Maybe
computers have a purpose in life beyond simple sport and
science. Surely computers like the ZX81 (for this was a long
time ago) had meaning in the fields of art and music and
culture. A program, it was suggested, could be viewed as a
work bf art, with the programmer being the artist. If this
were so then most of the programs we see around us are
functional - analogous to chairs or tables - they were not,
in general, beautiful - analogous to a painting or a piece
of music. It is to this friend that I dedicate this article
and, in particular, the program which goes with it.

This is called Cathy's Program, the original version of
which appeared in my book Mastering Machine Code On Your
ZX81 and was written for the Sinclair ZX81. This new updated
version, however, is written for the ZX Spectrum. Although
its basic structure is the same, the individual parts have
needed to be entirely rewritten.

The purpose of the program is to turn the Spectrum keyboard
into a musical one, so that each key produces a different
note, and continues to produce it for as long as the key is
held down. The diagram in Fig.2a shows which key produces
which note; there are two octaves, with the lower two rows
producing notes from middle C upwards, and the upper two
rows the next octave above this. The program is entirely in
machine code and once set in motion will continue to run
until you break out by pressing Break (Caps Shift and Space)
as normal.


New wave music

A small amount of explanation is required before the listing
will make sense, and so the first thing I ought to do is
explain the principle by which notes are produced on the
Spectrum. The most important instruction is OUT (FE),A. The
Spectrum can only produce one type of sound - that is, one
type of waveform - essentially, a square wave or a
rectangular wave. A square wave is a wave which at any
instant in time may be either at HIGH potential or at LOW
potential; it may never be at an intermediate potential.

Here's what the instruction OUT (FE),A does: suppose A
contains the (binary) number 'xxxnxgrb; (each letter
represents a binary digit). The xs are for our purposes
effectively meaningless, but the other letters: n, g, r and
b are quite important. They switch hardware devices on and
off (see Fig.1).

Bits 2, 1 and 0 then control the overall colour output to
the screen. (In practice it is only the BORDER colours which
may be changed in this way - the screen colours are
controlled by the attribute bytes).

The principle of creating music then is to create a square
wave. The procedure for doing this is 'short delay / OUT
(FE),xxx1xxxx / short delay / OUT (FE),xxx0xxxx / repeat for
as many cycles as required'. Note that doing this will
automatically change the BORDER colour. If you wish to avoid
this then you must slightly modify the procedure to 'short
delay / OUT (FE),xxx1xbbb / short delay / OUT (FE),xxx0xbbb
/ repeat for as many cycles as required' where bbb
represents the current BORDER colour number in binary.


On that note ...

Before we look at the finished program, I'd like to
introduce you to one of the subroutines in the ROM. The
subroutine is called KEY-SCAN, and its effect is to
determine which keys, if any, are currently depressed. You
can use the subroutine simply by the instruction CALL
KEY-SCAN (CD 8E02). The machine code registers will all be
wiped out by the subroutine so, if you wish to preserve
them, you must PUSH them onto the stack and then POP them on
return. Register DE will contain the final output of the
subroutine as shown in Fig.3. Also, in the case of two or
more keys being pressed simultaneously, the zero flag will
be RESET. In all other cases, the zero flag will be SET.

The key codes mentioned in the above description are in all
cases a number between 00 and 27. A different number is
returned for each key. The codes themselves are listed in
Fig.2b; you can see for yourselves that the keys are covered
in what at first glance seems to be a very strange order.

There is one final point I have to make before we can turn
the Spectrum into a musical instrument. Little things called
Interrupts. Fifty times a second, the Spectrum hardware
sends a little pulse down one of the pins connected to the
Z80 chip. When this happens, one of the following sequences
of things will happen, depending upon a previously unheard
of flag called the (IFF1 Interrupt Flip/Flop one). (The
people who name these things must have some sense of
humour!):

If IFF1 = 0 then: do nothing.

If IFF1 = 1 then: Stack all registers onto the machine
stack;
CALL 0038 is executed - this does the following:
increment the system variable FRAMES;
scan the keyboard, updating the system variables KSTATE and
LAST_K.
POP all registers from the stack and carry on as before.

The normal state of the flag IFF1 is one, so that all
programs, machine code or BASIC, are slowed down because the
subroutine at 0038 is executed 50 times a second without our
knowledge or consent. With regard to music, it means the
exact timing we require in order to produce square waves of
the right wavelength will be totally wrong since we shall
have no idea as to whether or when the interrupt routine
will be carried out in any given cycle. In order to overcome
this problem, it is necessary to reset IFF1 to zero so that
the above sequence of events will not be carried out. The
instruction DI (Disable Interrupts) is equivalent to saying
LET IFF1 =0, and so this, then, is the instruction we need.

When the Spectrum, in normal use, waits for a key to be
pressed, what is really happening is that it is waiting for
KSTATE to change. Note that this can only happen if IFF1 =
1, for otherwise the subroutine at 0038 will never be called
and the Spectrum will just sit there waiting forever, while
the poor old user can do nothing but gnash teeth and throw
bricks at the television. In order to prevent this from
happening EI, (Enable Interrupts or LET IFF1=1) must be
executed before returning to BASIC. Any machine code program
which runs while the interrupts are disabled may only scan
the keyboard by using IN r,(FE) instructions, or by CALLing
KEY-SCAN, not by examining KSTATE or LAST_K.

Figure 4, then, is the final result: Cathy's Program for the
Spectrum. Despite its lengthy appearance, it is actually
quite short and doesn't take very long to feed in at all. To
all musicians out there - behold your new instrument!

In my next article I shall continue on the theme of
creativity, but with attention turned toward the visual,
rather than the audial.


- Fig.1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

A breakdown of the individual letters of A in the instruction, OUT (FE),A

b: 0 = switch the blue  gun off, 1 = switch the blue  gun on.
r: 0 = switch the red   gun off, 1 = switch the red   gun on.
g: 0 = switch the green gun off, 1 = switch the green gun on.
n: 0 = switch the note generator to LOW  potential,
   1 = switch the note generator to HIGH potential.


- Fig.2a  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Which key on the Spectrum produces which note? There are two
octaves, the bottom two rows producing notes above middle C
and the top two rows producing the next octave above that.
(Note that the sharp (#) notes are indicated with an asterisk.)

 --    --    --    --    --    --    --    --    --    --
[  ]  [  ]  [C*]  [D*]  [  ]  [F*]  [G*]  [A*]  [  ]  [  ]
 --    --    --    --    --    --    --    --    --    --

   --    --    --    --    --    --    --    --    --    --
  [  ]  [C ]  [D ]  [E ]  [F ]  [G ]  [A ]  [B ]  [C ]  [  ]
   --    --    --    --    --    --    --    --    --    --

     --    --    --    --    --    --    --    --    --    --
    [  ]  [C*]  [D*]  [  ]  [F*]  [G*]  [A*]  [  ]  [  ]  [  ]
     --    --    --    --    --    --    --    --    --    --

 ----    --    --    --    --    --    --    --    --    ----
[    ]  [C ]  [D ]  [E ]  [F ]  [G ]  [A ]  [B ]  [C ]  [    ]
 ----    --    --    --    --    --    --    --    --    ----


- Fig.2b  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

The codes, and how they are allocated on the keys of the Spectrum.

 --    --    --    --    --    --    --    --    --    --
[24]  [1C]  [14]  [0C]  [04]  [03]  [0B]  [13]  [1B]  [23]
 --    --    --    --    --    --    --    --    --    --

   --    --    --    --    --    --    --    --    --    --
  [25]  [1D]  [15]  [0D]  [05]  [02]  [0A]  [12]  [1A]  [22]
   --    --    --    --    --    --    --    --    --    --

     --    --    --    --    --    --    --    --    --    --
    [26]  [1E]  [16]  [0E]  [06]  [01]  [09]  [11]  [19]  [21]
     --    --    --    --    --    --    --    --    --    --

 ----    --    --    --    --    --    --    --    --    ----
[ 27 ]  [1F]  [17]  [0F]  [07]  [00]  [08]  [10]  [18]  [ 20 ]
 ----    --    --    --    --    --    --    --    --    ----


- Fig.3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

The contents of the register DE.

SITUATION               VALUE OF DE
No key at all           FFFF
Caps Shift only         FF27
Symbol Shift only       FF18
Both Shifts together    2718
Any key without Shift   FFaa, where aa is the key code of the key concerned.
Any key with Caps Shift 27aa, where aa is the key code of the key concerned.
Any key with Symb Shift 18aa, where aa is the key code of the key concerned.
Any two keys together   aabb, where aa and bb are the key codes concerned.


- Fig.4 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

Cathy's program.

9E93464B  NOTES  G   G#  G+  F+#  Keys B, H, Y and 6
0050A9B4         -   F+  F#  F    Keys 5, T, G and V
8A813D42         A   A#  A+  G+#  Keys N, J, U and 7
5C5600C1         D+# E+  -   E    Keys 4, R, F and C
78003539         B   -   B+  A+#  Keys M, K, I and 8
6962CFDD         C+  D+  D#  D    Keys 3, E, D and X
70003200         C+# -   C++ -    Keys Symbol Shift, L, O and 9
0070ECFD         -   C+  C#  C    Keys 2, W, S and Z
00000000         -   -   -   -    Keys Space, Enter, P and 0
00000000         -   -   -   -    Keys 1, Q, A and Caps Shift

00        SOUND  NOP              This subroutine causes a
00               NOP              very short delay - the exact
00               NOP              timing of which is determined
10FB             DJNZ SOUND       by B, before sounding
D3FE             OUT (FE),A       a pulse.
C9               RET

call here:
3A485C    START  LD A,(BORDCR)    Bits 5, 4 and 3 contain the BORDER colour.
1F               RRA
1F               RRA
1F               RRA
E607             AND 07           A: BORDER colour
F610             OR 10            A: BORDER colour but with bit 4 set
4F               LD C,A           C: BORDER colour + bit 4 set
F3               DI               Disable Interrupts
C5        LOOP   PUSH BC          Preserve the value of C
CD8E02           CALL KEY_SCAN    Scan the keyboard
C1               POP BC           Restore the value of C
212027           LD HL,2720       HL: the key value for 'Caps Shift Space'
A7               AND A            Reset Carry flag
ED52             SBC HL,DE        Compare key pressed (if any)
                                  with 'Caps Shift Space'
281B             JR Z,EXIT        Exit program if desired
7B               LD A,E           A: key code (ignoring Shifts)
3C               INC A
28EF             JR Z,LOOP        Loop if no key pressed
AF               XOR A            A: zero
57               LD D,A           DE: key code ignoring Shifts
21????           LD HL,NOTES
19               ADD HL,DE        Point HL to note value in table
46               LD B,(HL)        B: note value
B8               CP B             Compare B with zero
28E5             JR Z,LOOP        Loop if no note on that key
79               LD A,C           A: BORDER colour (bit 4: 1)
C5               PUSH BC          Preserve the value of B
CD????           CALL SOUND       Generate first half cycle
C1               POP BC           Restore the value of B
E607             AND 07           A: BORDER colour (bit 4: 0)
CD????           CALL SOUND       Generate second half cycle
18D8             JR LOOP          Repeat sequence
FB        EXIT   EI               Enable Interrupts
C9               RET              End of routine

[In the accompanying program file ZX83044]
[these addresses have been used:         ]
[       NOTES: 60000: EA60               ]
[       SOUND: 60040: EA88               ]
[       START: 60048: EA90               ]
[The routine is 102 bytes long.       JG.]

--
Another Fine Product transcribed by:
Jim Grimwood (jimg@globalnet.co.uk), Weardale, England
--
