home *** CD-ROM | disk | FTP | other *** search
/ Outlet 51 / outlet-51.mgt / b1 < prev    next >
Text File  |  2021-04-18  |  20KB  |  1 lines

  1.         Only used to execute the BEEP command; can be called    from m/c, but it is simpler to call 03B5 BEEPER direct.                 This routine is concerned only with calculating, from   the pitch P, as defined in the Spectrum Manual, Chapter or Part 19, and the duration t in seconds, the parameters for BEEPER:          the number of complete loudspeaker on/loudspeaker off    cycles required, f * t, where f is the frequency in hertz, and         the length of the timing loop in units of four T states; this takes the form of a delay counter for the sound generation loop.                                                                   P and t are of course input as part of the BASIC        command, and are therefore found on the calculator stack. The   routine checks that P and t are within acceptable limits.               P as input in BASIC is zero for middle C, plus or minus one for each semitone above or below middle C; P must be between-60d and +69d inclusive, but needn't be a whole number. There   are twelve semitones in an octave; doubling the frequency       increases the pitch by an octave, so the increase in frequency  for one semitone is an increase by a factor 1 + K where                         (1 + K)**12d = 2, ie                                            K = twelfth root of 2 minus one                  (badly printed in the notes).                                          Thus, since 261.63d hertz is the frequency of middle C,                     f = 261.63d * (1 + K)**P.                           The routine first calculates f in several stages:              - separate P into an integer part and a fractional part, i and p                                                                - multiply the fractional part p by the constant K as    described above; actually a slightly lower value is used, to    allow for a slight "overhead" in the timing loops. This gives anadjustment factor to increase the frequency allowing for the    fraction-of-a-semitone increase in pitch required                      - reject i if it is below -60d or above 69d                     - reduce i by twelve till it is less than twelve, keepingcount; the count indicates the octave within which the pitch    falls, the reduced i indicates the nearest semitone below the   pitch P = i + p                                                        - index with the reduced i into a table which gives the  correct pitch for each semitone of the middle C octave, as a    list of twelve constants                                               - increment this semitone frequency by 1 + pK, the       fractional adjustment                                                  - double the frequency once for each octave recorded in  the count.                                                              The calculation is organised in such a way as to producecorrect results for either negative or positive i.                      Next it checks t; eleven-second beeps aren't allowed.           Now f * t is calculated and stacked; this is the first  of the two parameters for BEEP.                                         Now the counter for the timing loop is calculated.              Each delay is four T states, and the delay is used twicein each cycle; one second on the Spectrum is 3,500,000d T       states; and the operation of the loops takes a total of 241d T  states: so the value of the counter should be                           (3,500,000d/f - 241d)/8 = 437,500d/f - 30.125d                  This is the second parameter for BEEP; rejected if it   comes out too big, indicating that P was more than +69d.                [By my calculations this parameter is slightly          incorrect; see under 0385 BEEPER below.]                                A last check is made of f * t; if it is zero no beep is made, but no error reported, allowing for BEEP x,y commands     where y may be zero.                                                   Input parameters: The last number on the calculator stackis read as P, the next as t. They must be on the calculator     stack even for direct calls from m/c.                                  Action: use the calculator to split P into a fractional  and integer part                                                        - get pK + 1; the fraction-of-a-semitone adjustment for the eventual frequency, see above                                       - get the exponent of the integer part i; now in mem-0          - if it isn't zero report "Integer out of range"; i mustbe in small integer form                                                - get its sign byte; 00 for positive, FF for negative           - get its lo byte and shift its hi bit into carry; therewill be carry if the byte is more than 7Fh/127d - but if the    sign is negative this means carry for -80h/128d or more                 - now SBC A,A; giving zero if there was no carry, FF if there was                                                               - if the result doesn't match the sign byte report      "Integer out of range"; a positive byte more than 7F or a       negative one less than -80h                                             - get the hi byte                                               - if this doesn't match the sign byte report "Integer   out of range"; the hi byte should be 00 for positive, FF for    negative too                                                            - add 3Ch/60d to the lo byte                                    - if the result is "positive" jump on to BE i OK;       "positive" means the hi bit is zero, so the jump is only made   for positive i of 43h/67d or less                                       - (i is negative, or positive > 43h/67d) if the additiondidn't produce a change in parity report "Integer out of range";this rejects negative values of i from -80h/128d to -3Bh/59d, ieany negative value is now correct, but incorrect positive values46h/70d to 7Fh/127d have still passed - they will be rejected   when FIND INT2 is called later to get 437,500d/f - 30.125 as a  small integer.                                                         _0425_BE_i_OK: make an octave counter FAh/minus 6               _0427_BE_OCTAVE (the entry value for the pitch is now theresult of the last addition, the integer part i of the pitch    plus 3Ch/60d, and ranges from one to BBh/187d. Values from one  to 3Bh/59d represent negative i, below middle C; 3Ch/60d is     middle C itself, zero; values from 3Dh/61d upwards represent    positive values, some of which are incorrect): increment the    counter                                                                 - take 0Ch/12d from the pitch value                             - if it is still positive or zero loop back to BE OCTAVE        - add back 0C/12h; now i is a semitone value within the octave, ie between one and twelve, the octave count is between  minus six and plus eleven                                               - call 3406 LOC MEM with the semitone value to index    into the table at 046E                                                  - call 33B4 STACK NUM to put the FP number from the     table on the calculator stack; the frequency of the             corresponding semitone in the octave of middle C, call it C             - use the calculator to multiply C by the fractional    pitch adjustment still on the stack                                     - add the octave count to the exponent of C; this       doubles the frequency once for each count of the octaves                - use the calculator and call 1E94 FIND INT1 to get INT t into a register; t is the length of the BEEP in seconds as    originally input from BASIC                                             - if INT t exceeds ten seconds report "Integer out of   range"                                                                  - use the calculator to figure f * t; the first BEEP    parameter                                                               - figure 437,500d/f - 30.125; the second BEEP parameter         - call 1E99 FIND INT2 to put the 2nd parameter in a 2-  byte register; if it won't go, because the pitch P was too high,this reports "Integer out of range"                                     - call 1E99 FIND INT2 to get the first BEEP parameter           - move the parameters into the registers where BEEPER   expects to find them                                                    - check the first BEEP parameter for zero                       - if it was zero return without going through BEEPER            - decrement it; because BEEPER counts from zero.               Exit: into 03B5 BEEPER, but RET if the BEEP is zero.            Output parameters: DE holds the number of cycles                 - HL holds the length of the timing loop in T states/4          - P and t have been removed from the calculator stack           - mem-0 is corrupted.                                          Rems:                                                            03B5 BEEPER controlled by this command routine                  03D6 BE H&L LP timing loop controlled by parameter              03F6 BE END completed                                           33B4 STACK NUM called by                                                                                                    BEEPER subroutine 03B5                                              Activates the loudspeaker for a given number P of pulseseach of given duration D, half sound and half silence; D is in  units of four T states, see timing.                                     In the execution of the BEEP command from BASIC, P and Dare calculated by the subroutine BEEP from the BASIC input of   pitch and total duration, but the subroutine is also called     direct from 0F38 ED LOOP to make the keyboard "click", and from 107F ED ERROR and 1167 ED FULL to make a "rasp", with preset    values of P and D.                                                      It can similarly be called from m/c programs, with P andD calculated in the program or outside it, or determined by goodold trial and error!                                                    The interrupt is disabled during BEEPER, since the      irregular length of the interrupt routines would otherwise      disturb the pitch.                                                      For simplicity, decimal numbers are used unless         otherwise indicated throughout the rest of this description:            The hi byte and the lo byte of the duration D are used  as separate delay counters for the delay loop BE H&L LP. The hi byte H is used as it stands but the lo byte is divided by 4,    giving L = INT (lo byte/4) and a remainder byte r; the value    used for r is 3 minus the remainder on dividing the lo byte by  four, so that D = 256 * H + 4 * L + 3 - r.                              The delay loop BE H&L LP is in two parts. The first parttakes 16 T states each time its counter X, say, doesn't reach   zero, and 11 when it does; a total of 16 * (X - 1) + 11 = 16 * X- 5 T states. The second part adds 21 T states to the total     delay of the first; resets the counter for the first to 63; and loops back with a second counter Y, say, to repeat. Thus the    first turn through the whole loop takes 16 * X - 5 + 21 = 16 *  (X + 1) T states, and the other Y - 1 turns take 16 * (63 + 1) =16 * 64 each; so the total delay of the loop is                                 16 * (X + 1) + 16 * 64 * (Y - 1)                 T states.                                                              When the speaker is turned off, X and Y are given the   values L + 1 and H + 1, so the delay works out at                   16 * L + 32 + 16 * 64 * H = [256 * H + 4 * L + 3] * 4 + 20   T states. The expression in [] is equal to the duration        parameter D, plus r.                                                    When the speaker is on, L is incremented, adding 16 T   states; so the delay is 4 * (D + r) + 20 for speaker off and 4 *(D + r) + 36 for speaker on.                                            For each cycle of the on/off loop after the first,      starting when the speaker is turned on by OUT (FE),A:                  - reset the hi counter, jump on to BE AGAIN where the lo counter is incremented, and loop; this takes 44 T states               - delay by 3 - r NOPs, ie 4(3 - r) T states, plus 8 T    states to increment the counters, 4 * (D + r) + 36 in the delay loop, 7 to flop the OUT byte, and 11 for the OUT itself: total  from OUT "on" to OUT "off",                                            44 + 4 * (3 - r) + 8 + 4 * (D + r) + 36 + 7 + 11 =                                 4 * D + 118                                  - now reset the hi and lo counters, check and decrement  the pulse counter, and loop; 60 T states this time                     - again delay by 3 - r NOPs, 8 T states to increment the counters, only 4 * (D - r) + 20 in the delay loop this time, 7  to flop the OUT byte, and 11 for the OUT itself: total from OUT "off" to OUT "on",                                                     60 + 4 * (3 - r) + 8 + 4 * (D + r) + 20 + 7 + 11 =                              4 * D + 118 again.                               Thus the whole loop takes 8 * D + 236 T states: however D is calculated on the assumption it takes 8 * D + 241. Either  my calculations are incorrect or the Spectrum BEEP is slightly  out of tune!                                                            The OUT to port FE on each half loop is a code with the present border colour in the three lo bits so that the border   colour isn't changed by the output, and either one in bit 4 to  turn the loudspeaker on, or zero to turn it off. See "ports".          Input parameters: DE holds the number of pulses P                - HL holds the duration D of each pulse.                       Action: disable the interrupt                                    - halve the lo byte of the duration twice; making L = lobyte/4, so the loop counter is now 256 * H + L                          - reverse the original value of L; ie subtract it from  100h, 100h - L                                                          - AND this with 3; this gives the remainder on dividing 100h - L by 4, so it neatly finds r, 3 minus the remainder              - add r to the address of BE IX+3 in IX; thus adding r  NOPs to the loop starting at BE IX+0                                    - get the present border colour from 5C48 BORDCR                - AND it with 00111000b/38h; isolating the PAPER colour         - shift it 3 times right; making the PAPER number               - AND it with 00001000b/08; this is now the OUT byte,   with the BORDER colour, bit 3 set for "MIC off", and bit 4 zero for "speaker off"                                                      _03D1_BE_IX+3, etc: delay by up to 3 NOPS.                      _03D4_BE_IX+0 (on the first entry, the delay counter     holds the small number 3 - r, and the loudspeaker is off):      increment each byte of the delay counter                               _03D6_BE_H&L_LP: decrement the lo counter                        - if it hasn't gone to zero loop back to BE H&L LP              - put 63d in the lo counter                                     - decrement the hi counter                                      - if it hasn't gone to zero loop back to BE H&L LP              - XOR the OUT byte with 00010000b/10h to flop the       speaker on/off bit 4; on the first loop it is now "on"                  - OUTput it to port FE                                          - restore the hi byte of the delay counter to its       original value H                                                        - if bit 4 of the OUT byte is set jump on to BE AGAIN;  the speaker is on                                                       - (speaker off) if the pulse counter has reached zero,  jump on to BE END                                                       - (more pulses to come) restore the lo byte of the delaycounter to its original value L                                         - decrement the pulse loop counter                              - jump back to the start of the delay loop IX; one of BEIX+3 to BE IX+0 depending on the remainder byte r.                     _03F2_BE_AGAIN (speaker on): restore the lo byte of the  delay counter to its original value L                                   - increment L once; to compensate for the absence of thepulse counter check                                                     - jump back to IX.                                             _03F6_BE_END (the pulse counter has gone to zero) re-    enable the interrupt and finish.                                       Exit: RET.                                                      Output parameters: none                                          - interrupt is re-enabled.                                     Called from:                                                     0F38 ED LOOP                                                    107F ED ERROR                                                   1167 ED FULL                                                   Exit from:                                                       0427 BE OCTAVE (03F8 BEEP)                                                                                                  BE H&L LP 03D6 (03B5 BEEPER)                                       Jumps from:                                                      auto (twice)                                                                                                                BE i OK 0425 (03F8 BEEP)                                           Jumps from:                                                      03F8 BEEP                                                                                                                   BE IX+0 03D4, BE IX+1 03D3, BE IX+2 03D2, BE IX+3 03D1 (03B5BEEPER)                                                                Jumps from:                                                      03D6 BE H&L LP (a jump to IX calculated in 03B5 BEEPER)                                                                     BE OCTAVE 0427 (03F8 BEEP)                                         Jumps from:                                                      auto                                                                                                                        BIN key (C4) see also commands, functions and operators,    KEYBOARD SCANNING, 022C extended mode table (b)                         The B key in E mode without shift produces the function BIN; not strictly a function, it must be followed by a string ofzeros and ones which are to be read as a binary number. On      execution, 24FB SCANNING indexes into the scanning function     table at 2596 to find the executive routine 268D S BIN. This    doesn't actually convert the binary number to 5-byte FP form: itis done by 2C9B DEC TO FP, study of which will show that            (a) the binary form may not include a fractional point          (b) it can have no more than 16 binary digits - up to FFFFh/65535d.                                                                 These limitations aren't mentioned in the handbooks!                                                                        binary format of numbers see BIN key                                                                                            binary operation see also "+" (2B) after end of alphabet            This term is used in the notes to refer to operations   which have two arguments placed one before and one after the    operator, as opposed to_unary_operations which have only one    placed after the operator. Addition is a binary operation;      "unary minus" as in -12 is a unary operation. Nothing to do withoperating with binary numbers!