6.2. Programming
All sound effects and music programmed by the constant
change of values registers with appropriate delays. Realize
this may, for example, such a subroutine: 1415.
10 LD HL, 60000; HL = address of data
20 LOOP LD A, (HL); A = data bytes
30 INC HL; HL = HL +1
40 CP 255; A = 255?
50 RET Z; if so, return
60 CP 16; A = 16?
70 JR NZ, REG; if not, go to the REG
80 LD B, (HL); B = pause duration
90 PAUSE HALT; interrupt latency
100 DJNZ PAUSE; cycle
110 JR CONT; go to the CONT
120 REG LD BC, 65533; BC = port address register
130 OUT (C), A; write register number
140 LD B, 191; BC = address data port
150 LD A, (HL); A = register value
160 OUT (C), A; write data to register
170 CONT INC HL; HL = HL +1
180 JR LOOP; go to top
2
This software is quite primitive, and
to play the music does not really fit, but to create simple
effects - in most times. Before its launch do not forget
prepare a data block at 60000,
consisting of pairs of data and ending
number 255. The first value in each pair must be a register
number and the second - number to be written in the register.
In addition, if the first value equals 16, the second is
interpreted as delay (in the fifties of a second).
For music, use much more complex routines like
usually employed in the second interrupt mode. Data for these
routines are usually stored in a much more comfortable form
separately for each of the three channels. Result in completely
even the simplest example of such routines in this book is not
possible because of its complexity, but if you are familiar with
assembler, you should not write anything
a routine, and I can tell,
how to do it.
First, consider the format of the data. I
propose the following system: a melody will be given three (the
number of votes) the basic building blocks of data. Since
practically any melody consists of identical fragments repeated
in different orders, it would be logical in the main unit
itself does not define a melody, and the addresses of such
fragments. These fragments are usually called patterns (pattern
- a stencil, template).
So, in the main unit may contain the following byte values:
65,535 (# FFFF) - end of melodies
0 (# 0000) - the beginning of the cycle
addr (# XXXX) - address of the next pattern
Code "start cycle" (0) marks the spot
from which begins playing the melody with repetition.
Now for patterns. Without going into the theory, give me
developed Format:
128 (# 80) - end of pattern
129, n (# 81, # XX) - set the duration of n
130, n (# 82, # XX) - noise with a frequency of n (0 ... 31)
131, n1, n2 (# 83, # XX, # XX) - noise with a frequency of n
(0 ... 31) +
note (0 ... 100)
132, n1, n2 (# 84, # XX, # XX) - a direct frequency reference
tone
(0 ... 4095)
133, addr (# 85, # XXXX) - a task unit frequency change
tone
134, addr (# 86, # XXXX) - a task unit frequency change
noise
135, addr (# 87, # XXXX) - a task block changes
Volume
136, n1, n2, n3 (# 88, # XX, # XXXX) - generator control
envelope
0 ... 100 (# 00 ... # 64) - Notes from the LA subkontroktavy
Let me explain some of the codes:
129 - As you probably noticed, when a
Denmark notes its duration does not indicate
is called. The fact that it uses
Xia duration, set wages
it with this command. Length
sensitivity is measured in the Fifties
fractions of seconds.
131 - With this code, you may one
simultaneously reproduce the tone and noise.
133,134,135 - These codes specify additional
blocks of data are positive, indicating
how to change the tone frequency, time
quency noise and the volume for
Playing music. If, after the code 133
or 134 instead of the address block is
Xia 0, then change the frequency off
Xia. A number from 0 to 15 after the code 135
indicates the need for maintaining
of constant volume,
corresponding to this number.
136 - This code controls the generator envelope
envelope. After him, should we find
ditsya-byte integer from 0 to 7,
indicating the shape of the envelope in
According to Table 5 and dvuhbay
tovoe number specifying the period of change
of the envelope.
0 ... 100 - These codes define notes. Code 0
corresponds to the note LA subkontrokta
you, 1 - LA # 2 - SR, etc.
The unit, which describes the change in frequency
tone, use the following values:
128 (# 80) - end of block
-127 ... 127 (# 81 ... # 79) - the frequency shift
Block frequency noise will be given in the following format:
128 (# 80) - end of block
-31 ... 31 (# E1 ... # 1F) - the frequency shift
A unit volume changes let defined as follows:
128 (# 80) - end of block
0 ... 15 (# 00 ... # 0F) - meaning the volume
It is quite logical to make this procedure works in the
second interrupt mode. Based on this, as well as from the
proposed format of the data, we can see that for each channel
will need an array of variables. I suggest the following format:
offset size value
0 2 start address of the main block of data
February 2 current address in the main block of data
February 4 starting block address changes tone frequency
June 2 current address in the block frequency tone
Aug. 2 starting address block frequency noise
February 10 current address in the block frequency noise
Feb. 12 start address unit volume changes
February 14 current address in the block volume changes
February 16 current address in the current pattern
18 January value of the current duration
January 19 meter length
January 20 the number of remaining repetitions
In addition, it will take another three bytes for each
channel for storing tempo count rate and the flag resolution
sound.
The package will include the following
Procedure:
SINIT - Initializing tables, connection
second mode interrupts.
SSTOP - Off coprocessor, restore
resistivity standard mode interrupt
vany.
SNEW - Run all three channels. If you
call of this subroutine in Regis
fuck HL, DE and BC should be Adre
sa major blocks of data for the channel
crystals A, B and C, respectively. As a result
Giustra A should be the number of
repetitions tunes from 1 to 254 or
255 if you want to chalk
Diya was repeated endlessly.
SNEWA - Starting channel A. In the register HL
should be addressed to the data block and
in case A - the number of repetitions
(Similarly SNEW). Working channels
B and C, this procedure without affecting
em.
SNEWB - Starting channel B. All the same
SNEWA.
SNEWC - Starting channel C. All the same
SNEWA.
MUTE - ban / permit work. In Regis
A triangle should be the channel number of
0 to 2 or 3, if you are applying
to all channels. In case B USD
wives to be code modes: 0 -
stop, 1 - noiseless,
2 - playing.
STATUS - Getting the state of the channel. As a result
Giustra A should be the channel number
from 0 to 2. On return from space
A procedure STATUS register contains
code mode selected channel
la (similar to B in MUTE).
TEMPO - Setting the pace. In case A USD
wives to be the channel number from 0 to 2
or 3, if you are applying to all
channels. In case B should we find
ditsya tempo.
Thus, the beginning of the package might look like:
1415.
10 ORG 60000
20 JP SINIT
30 JP SSTOP
40 JP SNEW
50 JP SNEWA
60 JP SNEWB
70 JP SNEWC
80 JP MUTE
90 JP STATUS
2
TEMPO procedure might look like:
1415.
100 TEMPO DI
110 PUSH HL
120 PUSH AF
130 LD HL, TEMPS; HL = pointer to the pace
140 CP A, 3
150 JR Z, TEMP3
160 ADD A, L
170 LD L, A
180 JR NC, TEMP1
190 INC H
200 TEMP1 LD (HL), B
210 INC HL
220 INC HL
230 INC HL
240 LD (HL), B
250 TEMP2 POP AF
260 POP HL
270 EI
280 RET
290 TEMP3 PUSH DE
300 LD D, 6
310 TEMP4 LD (HL), B
320 INC HL
330 DEC D
340 JR NZ, TEMP4
350 POP DE
360 JR TEMP2
2
Since I went to data access, it is necessary
result in line with their description:
1415.
370 CHAN_A DEFS 21; array of variables for channel A
380 CHAN_B DEFS 21; array of variables for channel B
390 CHAN_C DEFS 21; array of variables for the channel C
400 MUTS DEFS 3; flags permit sound
410 TEMPS DEFS 3; rate
420 CURTS DEFS 3; counters rates
430 AYREGS DEFS 14; copies of registers of a coprocessor
440 ENVS DEFB 0,4,11,13,8,12,14,10; the envelope
450 SVOLS DEFW # 8000, # 8001, # 8002; table changes 460 DEFW
# 8003, # 8004 # 8005; of volume 470 DEFW # 8006, # 8007, #
8008; standard 480 DEFW # 8009, # 800A, # 800B; values
490 DEFW # 800C, # 800D, # 800E
500 DEFW # 800F
510 NOTES DEFW ... ; Here to write all the values
; Of Table 9 from the upper left
; Angle in order from top - down,
which is valid ; Islands - left
2
Line 430 contains the domain data that is used for audio
output. First, it formed the values of all registers of a
coprocessor with the following subprograms:
1415.
520 SETAY PUSH HL
530 PUSH AF
540 LD AL, AYREGS
550 ADD A, L
560 LD L, A
570 JR NC, SETAY1
580 INC HL
590 SETAY1 LD (HL), B
600 POP AF
610 POP HL
620 RET
2
She needed to pass the register number in A and
its value in B.
The contents of this field is copied in real coprocessor
registers another subroutine:
1415.
630 AYOUT PUSH HL
640 PUSH DE
650 PUSH BC
660 LD HL, AYREGS +13
670 LD D, 13
680 AYOUT1 LD BC, 65533
690 OUT (C), D
700 LD B, 191
710 LD E, (HL)
720 OUT (C), E
730 DEC HL
740 DEC D
750 JP P, AYOUT1; if D> = 0, then go to
AYOUT1
760 POP BC
770 POP DE
780 POP HL
790 RET
2
Any of the registers in this area
also read:
1415.
800 GETAY PUSH HL
810 PUSH AF
820 LD HL, AYREGS
830 ADD A, L
840 LD L, A
850 JR NC, GETAY1
860 INC H
870 GETAY1 LD B, (HL)
880 POP AF
890 POP HL
900 RET
2
This routine must pass number
required to register A and she will return it
value B.
Line 440 needed to decrypt
package envelope. If any number of tables 5 added to the label
ENVS and upon receipt of the address read one byte, you get a
value that should be written in R13.
Line 450 will need to decrypt
standard volume levels. For this
be a number from 0 to 15 multiplied by 2 (you can use the SLA)
and add to label SVOLS. The value obtained should be used as
the address block change the volume.
Line 510 will be useful for deciphering the music. If the
code notes (from 0 to 100) multiplied by 2 (team SLA) and added
to the label of NOTES, and on the resulting address is
considered two-byte number, you get the value
junior and senior registers frequency.
Now for the main procedures:
1415.
910 STATUS PUSH HL
920 LD HL, MUTS
930 ADD A, L
940 LD L, A
950 JR NC, STAT1
960 INC H
970 STAT1 LD A, (HL)
980 POP HL
990 RET
2
This small but useful procedure
help the programmer to know in what state is this or that
channel. For example, to find which of them is free.
The following procedure - MUTE:
1415.
1000 MUTE DI
1010 PUSH HL
1020 PUSH AF
1030 LD HL, MUTS
1040 CP A, 3
1050 JR Z, MUT2
1060 ADD A, L
1070 LD L, A
1080 JR NC, MUT1
1090 INC H
1100 MUT1 LD (HL), B
1110 POP AF
1120 POP HL
1130 EI
1140 RET
1150 MUT2 LD (HL), B
1160 INC HL
1170 LD (HL), B
1180 INC HL
1190 JR MUT1
2
This procedure is necessary, for example,
to temporarily stop the work of one of
channels.
Now - the initialization of channels:
1415.
1200 SNEWC PUSH IX
1210 LD IX, CHAN_C
1220 PUSH BC
1230 LD B, 2
1240 JR SNEW1
1250 SNEWB PUSH IX
1260 LD IX, CHAN_B
1270 PUSH BC
1280 LD B, 1
1290 JR SNEW1
1300 SNEWA PUSH IX
1310 LD IX, CHAN_A
1320 PUSH BC
1330 LD B, 0
1340 SNEW1 DI
1350 PUSH BC
1360 PUSH DE
1370 PUSH HL
1380 PUSH IX
1390 POP HL
1400 PUSH HL
1410 POP DE
1420 INC DE
1430 LD BC, 20
1440 LD (HL), B
1450 LDIR
1460 POP HL
1470 PUSH HL
1480 LD (IX +20), A
1490 LD (IX +0), L
1500 LD (IX +1), H
1510 LD (IX +19), 0
1520 LD E, (HL)
1530 INC HL
1540 LD D, (HL)
1550 INC HL
1560 LD (IX +2), L
1570 LD (IX +3), H
1580 LD (IX +16), E
1590 LD (IX +17), D
1600 LD HL, SVOLS +30
1610 LD (IX +12), L
1620 LD (IX +13), H
1630 LD (IX +14), L
1640 LD (IX +15), H
1650 LD (IX +18), 13; the duration of the default
= 1 / 4
1660 POP HL
1670 POP DE
1680 POP BC
1690 LD A, B
1700 LD B, 2
1710 CALL MUTE
1720 LD B, 1
1730 CALL TEMPO
1740 POP BC
1750 POP IX
1760 EI
1770 RET
2
And finally, initialize all three channels:
1415.
1780 SNEW PUSH HL
1790 CALL SNEWA
1800 PUSH DE
1810 POP HL
1820 CALL SNEWB
1830 PUSH BC
1840 POP HL
1850 CALL SNEWC
1860 POP HL
1870 RET
2
Initialization routines to prepare the arrays of variables
necessary for the data. They set block addresses frequency
tones and noise in the "not used" (will wear they 0). Choose a
constant level volume (15). And also set the duration of notes
by default equal to 1 / 4 seconds.
That routine connect a second
Interrupt mode:
1415.
1880 SINIT LD A, 24
1890 LD (65535), A
1900 LD A, 195
1910 LD (65524), A
1920 LD HL, INTR; HL = address of handler
1930 LD (65525), HL
1940 LD HL, 65024
1950 LD DE, 65025
1960 LD BC, 256
1970 LD (HL), 255
1980 LD A, H
1990 LDIR
2000 DI
2010 LD I, A
2020 IM 2
2030 LD HL, MUTS; ban
2040 XOR A
2050 LD (HL), A; work
2060 INC HL
2070 LD (HL), A; all
2080 INC HL
2090 LD (HL), A; channels
2100 EI
2110 RET
2
This subroutine returns the standard mode interrupts on and
off coprocessor:
1415.
2120 SSTOP DI
2130 LD A, 63
2140 LD I, A
2150 IM 1
2160 EI
2170 LD HL, AYREGS
2180 LD DE, AYREGS +1
2190 LD BC, 13
2200 LD (HL), B; B = 0
2210 LDIR; cleaning of registers
2220 LD A, 7
2230 DEC B; B = 255
2240 CALL SETAY; R7 = 255 (off mixer)
2250 JP AYOUT; output registers in the coprocessor
2
Now let us interrupt handler. Since he must serve three
channels, and arrays of variables is most easily addressed
registers IX, we can propose this routine:
1415.
2260 INTR PUSH AF; preservation registers
2270 PUSH HL
2280 PUSH DE
2290 PUSH BC
2300 PUSH IX
2310 LD IX, CHAN_A; training registers
2320 XOR A
2330 CALL DISPAT; coprocessor
2340 LD IX, CHAN_B
2350 LD A, 1 for all channels
2360 CALL DISPAT
2370 LD IX, CHAN_C
2380 LD A, 2
2390 CALL DISPAT
2400 CALL AYOUT; output registers in the coprocessor
2410 POP IX; restore registers
2420 POP BC
2430 POP DE
2440 POP HL
2450 POP AF
2460 RST 56; standard call handler
2470 RET
2
This handler for each channel
calls the dispatcher (DISPAT), holding up to register A channel
number, and register IX - the array address of its variables.
Role DISPAT procedure is to process variables TEMPS, CURTS
and MUTS for specified channel, as well as to call the main
subroutine creation of sound - GETSND.
Here is the text of procedure DISPAT:
1415.
2480 DISPAT PUSH AF
2490 LD E, A
2500 LD D, 0
2510 CALL STATUS
2520 OR A; channel stopped?
2530 JR NZ, DISP1
2540 POP AF
2550 LD B, A
2560 JR DISP3
2570 DISP1 LD HL, CURTS
2580 ADD HL, DE
2590 LD A, (HL)
2600 OR A
2610 JR Z, DISP2
2620 DEC (HL); reduction in the rate meter
2630 POP AF
2640 RET
2650 DISP2 DEC HL; update
2660 DEC HL
2670 DEC HL; counter
2680 LD A, (HL)
2690 INC HL; rate
2700 INC HL
2710 INC HL
2720 LD (HL), A
2730 POP AF
2740 CALL GETSND; challenge the basic procedure
2750 LD B, A
2760 CALL STATUS
2770 CP 1; should "drown out"?
2780 RET NZ
2790 DISP3 LD C, B; "mute"
2800 LD HL, AYREGS +6
2810 LD A, 9; channel
2820 DISP4 SLA A
2830 DJNZ DISP4
2840 OR (HL)
2850 LD (HL), A
2860 INC HL
2870 ADD HL, BC
2880 LD (HL), 0
2890 RET
2
So, all service procedures are given. Only one left - GETSND:
1415.
2900 GETSND ...
2
That is what I propose to write to you.
But do not worry - I'll explain everything in detail.
Most likely, the procedure will GETSND
is sufficiently large. Perhaps even more
of all these procedures together.
But there is nothing difficult in it does not, and its volume
due to the rather complex format
data.
The task procedure GETSND reduces the formation of certain
cells of AYREGS data of one channel for subsequent copying into
registers coprocessor.
The details of this procedure
transferred to the channel number in register A (that she knew
of any place cells data for the frequency, volume, etc.) and
address of an array of variables in the register IX.
Note that it is obliged to preserve the value of the register
A! You may even have to make an additional variable to store it.
Thus, the procedure in the procedure
GETSND the following:
1. Check if there is zero counter
duration (IX +19).
2. If not, then continue playback
of the current note.
3. If equal, then select a new note and
start its playback.
The term "resume playback
current notes "includes the following:
1. Reduce the length of the counter.
2. If the address of one of the additional
blocks is 0, items 3 ... 5 for
this unit perform is not necessary.
3. Choose the next value of the blocks
Frequency and volume, using
Using variables IX +6 / IX +7, IX +10 / IX +11
and IX +14 / IX +15.
4. In accordance with the selected values
mi and the channel number with the update on the
aid procedures and GETAY SETAY Region
AYREGS (note that the bias
the frequencies may be negative
mi).
5. Update variables to addresses IX +6 /
IX +7, IX +10 / IX +11 and IX +14 / IX +15 in with
correspondence with paragraph 3.
Start playback of music "includes
in itself is only one item:
1. Rewrite the variables to addresses IX +4 /
IX +5, IX +8 / IX +9, IX +12 / IX +13 and IX +18 in
their counters - doubles (IX +6 / IX +7, IX +10 /
IX +11, IX +14 / IX +15 and IX +19).
But the point to choose a new note - a little more
complicated:
1. Choose the next byte from the current
pattern (e - IX +16 / IX +17).
2. If it is not equal to 0 ... 100, 130, 131 and
132 - treat as appropriate
control code and go to Step 1.
3. Accordingly, a byte or a couple
meters and the channel number of the update
AYREGS region and a variable IX +16 / IX +17.
Now, the processing control codes:
Code 128:
1. Choose the address of the next pattern of
the main unit (addressed mostly to block
Ke contained in IX +2 / IX +3).
2. Update variable IX +2 / IX +3.
3. If the address pattern is zero, Skopje
rovat variable IX +2 / IX +3 in IX +0 / IX +
1 and go to Step 1.
4. If the address is 65535, copy
variable IX +0 / IX +1 in IX +2 / IX +3 and
reduce the repeat count (IX +20).
If the repeat count is zero,
set the channel state to stop
Flax "by the procedure of MUTE. Continue
to step 1.
5. Record the selected address in IX +16 / IX +17
and select a new note. "
Code 129:
1. Get byte, followed by this code, and
recorded in the IX +18. Select a new note. "
Code 133 (134):
1. Get address, followed by this code,
and put it in the IX +4 / IX +5 (IX +8 / IX +
9). Select a new note. "
Code 135:
1. Get address, followed by this code.
2. If it is less than 16, calculate the corresponding
corresponding address in the table SVOLS.
3. Put the probe in IX +12 / IX +
13.
4. Select a new note. "
Code 136:
1. Set in the register of the volume set
of the channel to 16.
2. Write to IX +14 / IX +15 zero.
3. Get byte, followed by this code.
4. Calculate the table ENVS value R13
and renew the domain AYREGS.
5. Take the two bytes following the code
forms and bring them into the cells 11 and 12
area AYREGS.
6. Select a new note. "
Now how can calculate the number of registers for a given
channel. To calculate the number of the register of frequency,
rather channel number multiplied by 2 (ADD A, A). Resulting
number is the number register Low Byte frequency. To get the
register number of the byte in the frequency, the value should
be increased by 1 (INC A).
To calculate the volume number of the register, it is
necessary to add the channel number 8 (ADD A, 8).
If you write a procedure GETSND, in
Your hands will be quite a powerful program, suitable for
writing both music and effects.
And at the end of the description of this program - tips on
compiling the data blocks for her.
To raise or lower the note one octave, its value must be
correspondingly increased or decreased by 12. Note BEFORE the
first octave corresponds to the number 39.
The values of the durations you can take
Table 11.
Now, some tips on programming a coprocessor. For the
formation of new sounds you can use the generator envelope that
is configured to periodically change the volume and greater
frequency. Particularly good results can be achieved by
configuring it at multiples frequency of the main signal.
To mute the music co-processor is often used prohibition
all functions of the mixer (output byte 255
R7), but this method is not very reliable.
If the envelope generator is configured to periodically change
the volume, then this the trick will not work: will be audible
click. For a complete silencing of a coprocessor can recommend
a routine: 1415.
10 LD HL, DATA; HL = address of data
20 LD E, 10; E = number of first register
30 LOOP LD BC, 65533; BC = port address register
40 OUT (C), E; output port E in BC
50 LD A, (HL); A = value of the next
Register
60 LD B, 191; BC = address data port
70 OUT (C), A; output to port A BC
80 INC HL; HL = HL +1
90 DEC E; E = E-1
100 LD A, E; E =
110 CP; 6 6?
120 JR NZ, LOOP; if not, then the cycle
130 RET; Returns
140 DATA DEFB 0,0,0,255; data registers AY
2
In many cases, required to determine
whether there is a coprocessor to the computer. Some do it by
checking the type of computer (48K/128K), but this method does
not quite fair, since AY can stand and
the good old Spectrum. Here is a subroutine, which determines
the presence of a coprocessor more reliably: 1415.
10 LD BC, 65533; BC = port address register
20 XOR A; A = 0
30 OUT (C), A; selection register 0
40 LD B, 191; BC = address data port
50 OUT (C), A; output 0 in the selected case
60 LD B, 255; BC = port address register
70 IN A, (C); input values from the selected
Register
80 OR A; A = 0?
90 RET; Returns
2
If after calling this subroutine
Z flag is cleared, then the coprocessor is present. Otherwise -
no.
And finally I want to tell you about one
very interesting technique. It is often used in many programs.
Reading data from the registers are up and converting them
appropriately in graphical information along with music
playback, you can make soundlights or peak signal level.