Prev: 0333 Up: Map Next: 03F8
03B5: THE 'BEEPER' SUBROUTINE
Used by the routines at BEEP, EDITOR, ED_ERROR and ED_COPY.
The loudspeaker is activated by having D4 low during an 'OUT' instruction that is using port +FE. When D4 is high in a similar situation the loudspeaker is deactivated. A 'beep' can therefore be produced by regularly changing the level of D4.
Consider now the note 'middle C' which has the frequency 261.63 Hz. In order to get this note the loudspeaker will have to be alternately activated and deactivated every 1/523.26th of a second. In the Spectrum the system clock is set to run at 3.5 MHz. and the note of 'middle C' will require that the requisite 'OUT' instruction be executed as close as possible to every 6689 T states. This last value, when reduced slightly for unavoidable overheads, represents the 'length of the timing loop' in this subroutine.
This subroutine is entered with the DE register pair holding the value 'f*t', where a note of given frequency 'f' is to have a duration of 't' seconds, and the HL register pair holding a value equal to the number of T states in the 'timing loop' divided by 4, i.e. for the note 'middle C' to be produced for one second DE holds +0105 (INT(261.3*1)) and HL holds +066A (derived from 6689/4-30.125).
Input
DE Number of passes to make through the sound generation loop
HL Loop delay parameter
BEEPER 03B5 DI Disable the interrupt for the duration of a 'beep'.
03B6 LD A,L Save L temporarily.
03B7 SRL L Each '1' in the L register is to count 4 T states, but take INT (L/4) and count 16 T states instead.
03B9 SRL L
03BB CPL Go back to the original value in L and find how many were lost by taking 3-(A mod 4).
03BC AND $03
03BE LD C,A
03BF LD B,$00
03C1 LD IX,$03D1 The base address of the timing loop.
03C5 ADD IX,BC Alter the length of the timing loop. Use an earlier starting point for each '1' lost by taking INT (L/4).
03C7 LD A,($5C48) Fetch the present border colour from BORDCR and move it to bits 2, 1 and 0 of the A register.
03CA AND $38
03CC RRCA
03CD RRCA
03CE RRCA
03CF OR $08 Ensure the MIC output is 'off'.
Now enter the sound generation loop. DE complete passes are made, i.e. a pass for each cycle of the note.
The HL register holds the 'length of the timing loop' with 16 T states being used for each '1' in the L register and 1024 T states for each '1' in the H register.
03D1 NOP Add 4 T states for each earlier entry point that is used.
03D2 NOP
03D3 NOP
03D4 INC B The values in the B and C registers will come from the H and L registers - see below.
03D5 INC C
BE_H_L_LP 03D6 DEC C The 'timing loop', i.e. BC*4 T states. (But note that at the half-cycle point, C will be equal to L+1.)
03D7 JR NZ,BE_H_L_LP
03D9 LD C,$3F
03DB DEC B
03DC JP NZ,BE_H_L_LP
The loudspeaker is now alternately activated and deactivated.
03DF XOR $10 Flip bit 4.
03E1 OUT ($FE),A Perform the 'OUT' operation, leaving the border unchanged.
03E3 LD B,H Reset the B register.
03E4 LD C,A Save the A register.
03E5 BIT 4,A Jump if at the half-cycle point.
03E7 JR NZ,BE_AGAIN
After a full cycle the DE register pair is tested.
03E9 LD A,D Jump forward if the last complete pass has been made already.
03EA OR E
03EB JR Z,BE_END
03ED LD A,C Fetch the saved value.
03EE LD C,L Reset the C register.
03EF DEC DE Decrease the pass counter.
03F0 JP (IX) Jump back to the required starting location of the loop.
The parameters for the second half-cycle are set up.
BE_AGAIN 03F2 LD C,L Reset the C register.
03F3 INC C Add 16 T states as this path is shorter.
03F4 JP (IX) Jump back.
Upon completion of the 'beep' the maskable interrupt has to be enabled.
BE_END 03F6 EI Enable interrupt.
03F7 RET Finally return.
Prev: 0333 Up: Map Next: 03F8