Prev: 03B5 Up: Map Next: 046E
03F8: THE 'BEEP' COMMAND ROUTINE
The address of this routine is found in the parameter table.
The subroutine is entered with two numbers on the calculator stack. The topmost number (P) represents the 'pitch' of the note and the number underneath it (t) represents the 'duration'.
Input
Output
BEEP 03F8 RST $28 The floating-point calculator is used to manipulate the two values: t, P.
03F9 DEFB $31 duplicate: t, P, P
03FA DEFB $27 int: t, P, i (where i=INT P)
03FB DEFB $C0 st_mem_0: t, P, i (mem-0 holds i)
03FC DEFB $03 subtract: t, p (where p is the fractional part of P)
03FD DEFB $34 stk_data: Stack the decimal value K=0.0577622606 (which is a little below 12*(2↑0.5)-1)
03FE DEFB $EC,$6C,$98,$1F,$F5
0403 DEFB $04 multiply: t, pK
0404 DEFB $A1 stk_one: t, pK, 1
0405 DEFB $0F addition: t, pK+1
0406 DEFB $38 end_calc
Now perform several tests on i, the integer part of the 'pitch'.
0407 LD HL,$5C92 This is 'mem-0-1st' (MEMBOT).
040A LD A,(HL) Fetch the exponent of i.
040B AND A Give an error if i is not in the integral (short) form.
040C JR NZ,REPORT_B
040E INC HL Copy the sign byte to the C register.
040F LD C,(HL)
0410 INC HL Copy the low-byte to the B register, and to the A register.
0411 LD B,(HL)
0412 LD A,B
0413 RLA Again give report B if i does not satisfy the test: -128<=i<=+127.
0414 SBC A,A
0415 CP C
0416 JR NZ,REPORT_B
0418 INC HL
0419 CP (HL)
041A JR NZ,REPORT_B
041C LD A,B Fetch the low-byte and test it further.
041D ADD A,$3C
041F JP P,BE_i_OK Accept -60<=i<=67.
0422 JP PO,REPORT_B Reject -128 to -61.
Note: the range 70 to 127 will be rejected later on.
The correct frequency for the 'pitch' i can now be found.
BE_i_OK 0425 LD B,$FA Start '6' octaves below middle C.
BE_OCTAVE 0427 INC B Repeatedly reduce i in order to find the correct octave.
0428 SUB $0C
042A JR NC,BE_OCTAVE
042C ADD A,$0C Add back the last subtraction.
042E PUSH BC Save the octave number.
042F LD HL,$046E The base address of the 'semitone table'.
0432 CALL LOC_MEM Consider the table and pass the 'A th.' value to the calculator stack. (Call it C.)
0435 CALL STACK_NUM
Now the fractional part of the 'pitch' can be taken into consideration.
0438 RST $28 t, pK+1, C
0439 DEFB $04 multiply: t, C(pK+1)
043A DEFB $38 end_calc
The final frequency f is found by modifying the 'last value' according to the octave number.
043B POP AF Fetch the octave number.
043C ADD A,(HL) Multiply the 'last value' by 2 to the power of the octave number.
043D LD (HL),A
043E RST $28 t, f
043F DEFB $C0 st_mem_0: Copy the frequency (f) to mem-0
0440 DEFB $02 delete: t
Attention is now turned to the 'duration'.
0441 DEFB $31 duplicate: t, t
0442 DEFB $38 end_calc
0443 CALL FIND_INT1 The value 'INT t' must be in the range +00 to +0A.
0446 CP $0B
0448 JR NC,REPORT_B
The number of complete cycles in the 'beep' is given by f*t so this value is now found.
044A RST $28 t
044B DEFB $E0 get_mem_0: t, f
044C DEFB $04 multiply: f*t
The result is left on the calculator stack whilst the length of the 'timing loop' required for the 'beep' is computed.
044D DEFB $E0 get_mem_0: f*t, f
044E DEFB $34 stk_data: Stack the value (3.5*10↑6)/8=437500
044F DEFB $80,$43,$55,$9F,$80
0454 DEFB $01 exchange: f*t, 437500, f
0455 DEFB $05 division: f*t, 437500/f
0456 DEFB $34 stk_data: f*t, 437500/f, 30.125
0457 DEFB $35,$71
0459 DEFB $03 subtract: f*t, 437500/f-30.125
045A DEFB $38 end_calc
Note: the value 437500/f gives the 'half-cycle' length of the note and reducing it by 30.125 allows for 120.5 T states in which to actually produce the note and adjust the counters etc.
The values can now be transferred to the required registers.
045B CALL FIND_INT2 The 'timing loop' value is compressed into the BC register pair and saved.
045E PUSH BC
Note: if the timing loop value is too large then an error will occur (returning via ERROR_1), thereby excluding 'pitch' values of 70 to 127.
045F CALL FIND_INT2 The f*t value is compressed into the BC register pair.
0462 POP HL Move the 'timing loop' value to the HL register pair.
0463 LD D,B Move the f*t value to the DE register pair.
0464 LD E,C
However before making the 'beep' test the value f*t.
0465 LD A,D Return if f*t has given the result of 'no cycles' required.
0466 OR E
0467 RET Z
0468 DEC DE Decrease the cycle number and jump to BEEPER (making at least one pass).
0469 JP BEEPER
Report B - integer out of range.
REPORT_B 046C RST $08 Call the error handling routine.
046D DEFB $0A
Prev: 03B5 Up: Map Next: 046E