world of sound Spectrum - Chapter 4.5: Programming sound effects - Polyphonic ringtones (polyphonic).

ZX Forum #04
        4.5. Polyphonic ringtones


   While in the previous chapter, I carefully
You proved the futility of attempts to music programming in 
assembler, you still should know the basic principles of this 
activity. 

   Now I will describe the creation of polyphonic
music, ie music which can
sound two or more notes simultaneously.

   The first example is a subroutine,
Two-simulating sound:
1415.
 10 DI; ban interrupt
 20 LD D, 200; D = Frequency 1
 30 LD E, 50; E = Frequency 2
 40 LD H, 150; H = duration
 50 XOR A; A = border for voice 1 (0)
 60 EX AF, AF '; shift registers A and F on

                                    Alternative
 70 XOR A; A = border for voice 2 (0)
 80 LD C, E; C = Counter 1
 90 LD B, D; B = Counter 2
100 BEEP EX AF, AF '; shift registers A and F

                                    (Changing voice)
110 DEC C; C = C-1
120 JR NZ, CONT; if C <> 0 then go to

                                    CONT
130 LD C, E; restore counter 1
140 XOR 16; invert the bits D4 to vote

                                    1
150 CONT OUT (254), A; bring A to port 254
160 EX AF, AF '; shift registers A and F

                                    (Changing voice)
170 DEC B; B = B-1
180 JR NZ, CONT2; if B <> 0 then go to

                                    CONT2
190 LD B, D; restore Counter 2
200 XOR 16; invert the bits D4 to vote

                                    2
210 CONT2 OUT (254), A; bring A to port 254
220 INC L; L = L +1
230 JR NZ, BEEP; if L <> 0 then go to

                                    BEEP
240 NOP; reserve
250 NOP; reserve
260 DEC H; H = H-1
270 JR NZ, BEEP; if H <> 0 then go to

                                    BEEP
280 EI; permission to interrupt
290 RET; Returns
2
Now I will explain some details.

   Two alternative register A is used first and second votes 
for the storage Border color and condition of the speaker.


   Countries of operations to register before L
completion of the cycle is designed to "stretch" length. If you 
remove it, then the sound of this subprogramme will be so short 
that you can get it do not even hear.


   Two-byte transfer (operation NOP) you can use to change the 
frequency Both votes during playback.

To do this, instead of "NOP" to insert INC
DEC D or D for the first vote and INC E or
DEC E for the second.

   This routine can be used to
assembly (see previous chapter), or
BASIC (in this case, the parameters should be entered by the 
operator in the following POKE 

cell: ADDR +2 - Frequency 1, ADDR +4 - frequency 2, ADDR +6 - 
duration, where ADDR - the address of the subroutine in memory).


   The next two polyphonic routines very similar to each other, 
but the first sounds much quieter and cleaner than a few

second.

   Here they are:
1415.
 10 DI; ban interrupt
 20 LD HL, 2000; HL = length
 30 LOOP1 LD IX, FRQS; IX = address of frequency tables
 40 LD B, 5; B = number of votes
 50 LOOP2 DEC (IX +0); byte at IX +0

                                    decrease 1
 60 JR NZ, NOSIGN; if not 0, then go to

                                    NOSIGN
 70 LD A, 24; A = Border color + 24
 80 OUT (254), A; output to port A 254
 90 LD A, (IX +5); update counter
100 LD (IX +0), A; current channel
110 XOR A; A = color of the border (0)
120 OUT (254), A; output to port A 254
130 NOSIGN INC IX; IX = IX +1
140 DJNZ LOOP2; cycle
150 DEC HL; HL = HL-1
160 LD A, H; HL =
170 OR L; 0?
180 JR NZ, LOOP1; if not, then the cycle
190 EI; permission to interrupt
200 RET; Returns
210 FRQS DEFB 1,1,1,1,1; counters for 5 channels
220 DEFB 10,20,30; frequency
230 DEFB 40,50; 5 channels

 10 DI; ban interrupt
 20 LD HL, 2000; HL = length
 30 LOOP1 LD IX, FRQS; IX = address of frequency tables
 40 LD B, 5; B = number of votes
 50 LOOP2 DEC (IX +0); byte at IX +0

                                    decrease 1
 60 JR NZ, NOSIGN; if not 0, then go to

                                    NOSIGN
 70 LD A, (IX +5); A = IX +5 contents
 80 XOR 1; invert bit D0
 90 LD (IX +5), A; contents IX +5 = A
100 LD A, 0; A = Border color
110 JR Z, NOSIGN; if D0 contains. IX +5 = 0, then

                                    go to NOSIGN
120 OR 24; set to 1 bits D3 and

                                    D4 register A
130 OUT (254), A; output to port A 254
140 LD A, (IX +10); update counter
150 LD (IX +0), A; current channel
160 NOSIGN INC IX; IX = IX +1
170 DJNZ LOOP2; cycle
180 DEC HL; HL = HL-1
190 LD A, H; HL =
200 OR L; 0?
210 JR NZ, LOOP1; if not, then the cycle
220 EI; permission to interrupt
230 RET; Returns
240 FRQS DEFB 1,1,1,1,1; counters for 5 channels
250 DEFB 0,0,0,0,0; buffers for 5 channels
260 DEFB 10,20,30; frequency
270 DEFB 40,50; 5 channels
2

   These routines give birth counters
each channel and subsequently their
reduced. If any of the counters
becomes 0, the speaker output
signal, and at the counter recorded the frequency of the table.

   In these examples, routines reproduce by five votes, but you 
can easily change their number, modifying values ​​in lines 40 
and 90 for the first subprogram, or 40,70,90 and 140 (line 140 
need to insert the number of votes multiplied by 2) - for the 
second. It should also adjust the frequency table. 

   While the vote may be quite a lot (85), to get involved in 
their number is not worth it, because more of them, the worse 
the quality. However, there is hardly a genius able to write a 
song by 85 votes. 

   If you want to use polyphony, but at any given time you
want to play a lesser number of votes
What is given, then the unused voices need to assign 
frequencies, which coincide with the frequencies used by the 
votes.