| Routines

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'.
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