0000-                  4       ;
0000-                  5       ; MUSIC PLAYER FOR THE KIM-1 USING '6502 GAMES' HARDWARE. BOARD SHOULD BE
0000-                  6       ; JUMPERED WITH VIA CHIPS AT THE ADDRESSES SPECIFIED BELOW. OTHER THAN THAT
0000-                  7       ; THE CODE IS UNCHANGED FROM THE BOOK.
0000-                  8       ;
C000-                  9       VIA1    .EQ     $C000
CC00-                 10       VIA3    .EQ     $CC00
0350-                 11       TABEG   .EQ     $0350       ; TABLE TO STORE MUSIC
0000-                 12
0200-                 13               .OR     $0200
0200-                 14               .TA     $0200
0200-20 06 03         15 (  6) RCONE   JSR     INITKEY
0203-                 16               .IN     ../../common/CH02-Music/player.asm
0203-            I     1       ;   MUSIC PLAYER PROGRAM
0203-            I     2       ;   USES 16-KEY KEYBOARD AND BUFFERED SPEAKER
0203-            I     3       ; PROGRAM PLAYS STORED MUSICAL NOTES. THERE ARE TWO MODES OF OPERATION: INPUT
0203-            I     4       ; AND PLAY. INPUT MODE IS THE DEFAULT, AND ALL NON-COMMAND KEYS PRESSED PRESSED
0203-            I     5       ; (0-D) ARE STORED FOR REPLAY. IF AN OVERFLOW OCCURS, THE USER IS WARNED WITH
0203-            I     6       ; A THREE-TONE WARNING. THE SAME WARBLING TONE IS ALSO USED TO SIGNAL A RESTART
0203-            I     7       ; OF THE PROGRAM.
0203-            I     8       ;
0000-            I     9       PILEN   .EQ     $00         ; LENGTH OF NOTE LIST
0001-            I    10       TEMP    .EQ     $01         ; TEMPORARY STORAGE
0002-            I    11       PTR     .EQ     $02         ; CURRENT LOCATION IN LIST
0003-            I    12       FREQ    .EQ     $03         ; TEMPORARY STORAGE FOR FREQUENCY
0004-            I    13       DUR     .EQ     $04         ; TEMP STORAGE FOR DURATION
CC00-            I    14       PORT3B  .EQ     VIA3        ; VIA OUTPUT PORT B
CC02-            I    15       DDR3B   .EQ     VIA3+2      ; VIA PORT B DIRECTION REGISTER
CC03-            I    16       DDR3A   .EQ     VIA3+3
CC01-            I    17       PORT3A  .EQ     VIA3+1
CC00-            I    18       PORT3B  .EQ     VIA3
0203-            I    19
0203-            I    20       ;
0203-            I    21       ; COMMAND LINE INTERPRETER
0203-            I    22       ;  $F AS INPUT MEANS RESET POINTERS, START OVER.
0203-            I    23       ;  $E MEANS PLAY CURRENTLY STORED NOTES
0203-            I    24       ;  ANYTHING ELSE IS STORED FOR REPLAY.
0203-            I    25       ;
0203-A9 00       I    26 (  2) START   LDA     #0          ; CLEAR NOTE LIST LENGTH
0205-85 00       I    27 (  2)         STA     PILEN
0207-18          I    28 (  2)         CLC                 ; CLEAR NIBBLE MARKER
0208-20 E1 02    I    29 (  6) NXKEY   JSR     GETKEY
020B-C9 0F       I    30 (  2)         CMP     #15         ; IS KEY #15?
020D-D0 05       I    31 (2**)         BNE     NXTST       ; NO, DO NEXT TEST
020F-20 8A 02    I    32 (  6)         JSR     BEEP3       ; TELL USER OF CLEARING
0212-90 EF       I    33 (2**)         BCC     START       ; CLEAR POINTERS AND START OVER
0214-C9 0E       I    34 (  2) NXTST   CMP     #14         ; IS KEY #14?
0216-D0 06       I    35 (2**)         BNE     NUMKEY      ; NO, KEY IS NOTE NUMBER
0218-20 4B 02    I    36 (  6)         JSR     PLAYEM      ; PLAY NOTES
021B-18          I    37 (  2)         CLC
021C-90 EA       I    38 (2**)         BCC     NXKEY       ; GET NEXT COMMAND
021E-            I    39       ;
021E-            I    40       ; ROUTINE TO LOAD NOT LIST WITH NOTES
021E-            I    41       ;
021E-85 01       I    42 (  2) NUMKEY  STA     TEMP        ; SAVE KEY, FREE A
0220-20 73 02    I    43 (  6)         JSR     PLAYIT      ; PLAY NOTE
0223-A5 00       I    44 (  3)         LDA     PILEN       ; GET LIST LENGTH
0225-C9 FF       I    45 (  2)         CMP     #$FF        ; OVERFLOW?
0227-D0 05       I    46 (2**)         BNE     OK          ; NO, ADD NOTE TO LIST
0229-20 8A 02    I    47 (  6)         JSR     BEEP3       ; YES, WARN USER
022C-90 DA       I    48 (2**)         BCC     NXKEY       ; RETURN TO INPUT MODE
022E-4A          I    49 (  2) OK      LSR     A           ; SHIFT LOW BIT INTO NIBBLE POINTER
022F-A8          I    50 (  2)         TAY                 ; USE SHIFTED NIBBLE POINTER AS BYTE INDEX
0230-A5 01       I    51 (  3)         LDA     TEMP        ; RESTORE KEY#
0232-B0 09       I    52 (2**)         BCS     FINBYT      ; IF BYTE ALREADY HAS A NIBBLE, FINISH IT AND STORE
0234-29 0F       I    53 (  2)         AND     #%00001111  ;  1ST NIBBLE. MASK HIGH NIBBLE
0236-99 50 03    I    54 (  5)         STA     TABEG,Y     ; SAVE UNFINISHED 1/2 BYTE
0239-E6 00       I    55 (  5)         INC     PILEN       ; POINT TO NEXT NIBBLE
023B-90 CB       I    56 (2**)         BCC     NXKEY       ; GET NEXT KEYSTROKE
023D-0A          I    57 (  2) FINBYT  ASL     A           ; SHIFT NIBBLE 2 TO HIGH ORDER
023E-0A          I    58 (  2)         ASL     A
023F-0A          I    59 (  2)         ASL     A
0240-0A          I    60 (  2)         ASL     A
0241-19 50 03    I    61 ( 4*)         ORA     TABEG,Y     ; JOIN 2 NIBBLES AS BYTE
0244-99 50 03    I    62 (  5)         STA     TABEG,Y     ; ... AND STORE.
0247-E6 00       I    63 (  5)         INC     PILEN       ; POINT TO NEXT NIBBLE IN NEXT BYTE
0249-90 BD       I    64 (2**)         BCC     NXKEY       ; RETURN
024B-            I    65       ;
024B-            I    66       ; ROUTINE TO PLAY NOTES
024B-            I    67       ;
024B-A2 00       I    68 (  2) PLAYEM  LDX     #0          ; CLEAR POINTER
024D-86 02       I    69 (  3)         STX     PTR
024F-A5 02       I    70 (  3)         LDA     PTR         ; LOAD ACCUMULATOR WITH CURRENT POINTER VALUE
0251-4A          I    71 (  2) LOOP    LSR     A           ; SHIFT NIBBLE INDICATOR INTO CARRY
0252-AA          I    72 (  2)         TAX                 ; USE SHIFTED NIBBLE POINTER AS BYTE POINTER
0253-BD 50 03    I    73 ( 4*)         LDA     TABEG,X     ; LOAD NOTE TO PLAY
0256-B0 04       I    74 (2**)         BCS     ENDBYT      ; LOW NIBBLE USED, GET HIGH
0258-29 0F       I    75 (  2)         AND     #%00001111  ; MASK OUT HIGH BITS
025A-90 06       I    76 (2**)         BCC     FINISH      ; PLAY NOTE
025C-29 F0       I    77 (  2) ENDBYT  AND     #%11110000  ; THROW AWAY LOW NIBBLE
025E-4A          I    78 (  2)         LSR     A           ; SHIFT INTO LOW
025F-4A          I    79 (  2)         LSR     A
0260-4A          I    80 (  2)         LSR     A
0261-4A          I    81 (  2)         LSR     A
0262-20 73 02    I    82 (  6) FINISH  JSR     PLAYIT      ; CALCULATE CONSTANTS & PLAY
0265-A2 20       I    83 (  2)         LDX     #$20        ; BETWEEN-NOTE DELAY
0267-20 9F 02    I    84 (  6)         JSR     DELAY
026A-E6 02       I    85 (  5)         INC     PTR         ; ONE NIBBLE USED
026C-A5 02       I    86 (  3)         LDA     PTR
026E-C5 00       I    87 (  3)         CMP     PILEN       ; END OF LIST?
0270-90 DF       I    88 (2**)         BCC     LOOP        ; NO, GET NEXT NOTE
0272-60          I    89 (  6)         RTS                 ; DONE
0273-            I    90       ;
0273-            I    91       ; ROUTINE TO DO TABLE LOOK UP, SEPARATE REST
0273-            I    92       ;
0273-C9 0D       I    93 (  2) PLAYIT  CMP     #13         ; REST?
0275-D0 06       I    94 (2**)         BNE     SOUND       ; NO.
0277-A2 54       I    95 (  2)         LDX     #$54        ; DELAY = NOTE LENGTH = .21SEC
0279-20 9F 02    I    96 (  6)         JSR     DELAY
027C-60          I    97 (  6)         RTS
027D-AA          I    98 (  2) SOUND   TAX                 ; USE KEYS AS INDEX..
027E-BD D4 02    I    99 ( 4*)         LDA     DURTAB,X    ;  ... TO FIND DURATION.
0281-85 04       I   100 (  2)         STA     DUR         ; STORE DURATION FOR USE
0283-BD C7 02    I   101 ( 4*)         LDA     NOTAB,X     ; LOAD NOTE VALUE
0286-20 AB 02    I   102 (  6)         JSR     TONE
0289-60          I   103 (  6)         RTS
028A-            I   104       ;
028A-            I   105       ; ROUTINE TO MAKE 3 TONE SIGNAL
028A-            I   106       ;
028A-A9 FF       I   107 (  2) BEEP3   LDA     #$FF        ; DURATION FOR BEEPS
028C-85 04       I   108 (  2)         STA     DUR
028E-A9 4B       I   109 (  2)         LDA     #$4B        ; CODE FOR E2
0290-20 AB 02    I   110 (  6)         JSR     TONE        ; 1ST NOTE
0293-A9 38       I   111 (  2)         LDA     #$38        ; CODE FOR D2
0295-20 AB 02    I   112 (  6)         JSR     TONE
0298-A9 4B       I   113 (  2)         LDA     #$4B
029A-20 AB 02    I   114 (  6)         JSR     TONE
029D-18          I   115 (  2)         CLC
029E-60          I   116 (  6)         RTS
029F-            I   117       ;
029F-            I   118       ; VARIABLE-LENGTH DELAY
029F-            I   119       ;
029F-A0 FF       I   120 (  2) DELAY   LDY     #$FF
02A1-EA          I   121 (  2) DLY     NOP
02A2-D0 00       I   122 (2**)         BNE     DL0         ; (.+2 IN BOOK)
02A4-88          I   123 (  2) DL0     DEY
02A5-D0 FA       I   124 (2**)         BNE     DLY         ; 10 US. LOOP
02A7-CA          I   125 (  2)         DEX
02A8-D0 F5       I   126 (2**)         BNE     DELAY       ; LOOP TIME = 2556*[X]
02AA-60          I   127 (  6)         RTS
02AB-            I   128       ;
02AB-            I   129       ; ROUTINE TO MAKE TONE: # OF 1/2 CYCLES IS IN 'DUR', AND 1/2 CYCLE TIME IS IN
02AB-            I   130       ; ACCUMULATOR. LOOP TIME = 20*[A]+26 US SINCE TWO RUNS THROUGH THE OUTER LOOP
02AB-            I   131       ; MAKES ONE CYCLE OF THE TONE.
02AB-            I   132       ;
02AB-85 03       I   133 (  2) TONE    STA     FREQ        ; FREQ IS TEMP FOR # OF CYCLES
02AD-A9 FF       I   134 (  2)         LDA     #$FF        ; SET UP DATA DIRECTION REGISTER
02AF-8D 02 CC    I   135 (  4)         STA     DDR3B
02B2-A9 00       I   136 (  2)         LDA     #$00        ; A IS SENT TO PORT, START HI
02B4-A6 04       I   137 (  3)         LDX     DUR
02B6-A4 03       I   138 (  3) FL2     LDY     FREQ
02B8-88          I   139 (  2) FL1     DEY
02B9-18          I   140 (  2)         CLC
02BA-90 00       I   141 (2**)         BCC     FL0         ; (.+2 IN BOOK)
02BC-D0 FA       I   142 (2**) FL0     BNE     FL1         ; INNER, 10 US LOOP.
02BE-49 FF       I   143 (  2)         EOR     #$FF        ; COMPLEMENT I/O PORT
02C0-8D 00 CC    I   144 (  4)         STA     PORT3B      ; ... AND SET IT
02C3-CA          I   145 (  2)         DEX
02C4-D0 F0       I   146 (2**)         BNE     FL2         ; OUTER LOOP
02C6-60          I   147 (  6)         RTS
02C7-            I   148       ;
02C7-            I   149       ; TABLE OF NOTE CONSTANTS
02C7-            I   150       ; CONTAINS:
02C7-            I   151       ; [OCTAVE BELOW MIDDLE C] : G,A,BCC
02C7-            I   152       ; [OCTAVE OF MIDDLE C] : C,D,E,F,F#,G,G#,A,B
02C7-            I   153       ; [OCTAVE ABOVE MIDDLE C] : C
02C7-            I   154       ;
02C7-FE E2 C9 BE 
     A9 96 8E 86 
     7E 77 70 64 
     5E          I   155       NOTAB   .HS     FE.E2.C9.BE.A9.96.8E.86.7E.77.70.64.5E
02D4-            I   156       ;
02D4-            I   157       ; TABLE OF NOTE DURATIONS IN # OF 1/2 CYCLES SET FOR A NOTE LENGTH OF
02D4-            I   158       ; ABOUT .21 SEC.
02D4-            I   159       ;
02D4-55 60 6B 72 
     80 8F 94 A1 
     AA B5 BF D7 
     E4          I   160       DURTAB  .HS     55.60.6B.72.80.8F.94.A1.AA.B5.BF.D7.E4
02E1-                 17               .IN     ../../common/CH01-Getkey/getkey_routine.asm
02E1-            I     1       ; 'GETKEY' KEYBOARD INPUT ROUTINE READS AND DEBOUNCES KEYBOARD. RETURNS WITH
02E1-            I     2       ; KEY NUMBER IN ACCUMULATOR IF KEY DOWN. OPERATION: SENDS NUMBERS 0-F TO 74154
02E1-            I     3       ; (4 TO 16 LINE DECODER), WHICH GROUNDS ONE SIDE OF KEYSWITCHES ONE AT A TIME.
02E1-            I     4       ; IF A KEY IS DOWN, PA7 OF VIA #3 WILL BE GROUNDED, AND THE CURRENT VALUE
02E1-            I     5       ; APPLIED TO THE 74154 BE THE KEY NUMBER. WHEN THE PROGRAM DETECTS A KEY CLOSE
02E1-            I     6       ; CHECKS FOR KEY CLOSURE FOR 50 MS. TO ELIMINATE BOUNCE.
02E1-            I     7       ; NOTE: IF NO KEY IS PRESSED, GETKEY WILL WAIT.
02E1-            I     8       ;
02E1-2C 01 CC    I     9 (  4) GETKEY  BIT     PORT3A      ; SEE IF KEY IS STILL DOWN FROM LAST KEY CLOSURE:
02E4-            I    10                                   ;  KEYSTROBE IN 'N' STATUS BIT.
02E4-10 FB       I    11 (2**)         BPL     GETKEY      ; IF YES, WAIT FOR KEY RELEASE
02E6-A2 0F       I    12 (  2) RSTART  LDX     #15         ; SET KEY COUNTER TO 15
02E8-8E 00 CC    I    13 (  4) NXTKEY  STX     PORT3B      ; OUTPUT KEY # TO 74154
02EB-2C 01 CC    I    14 (  4)         BIT     PORT3A      ; SEE IF KEY DOWN: STROBE IN 'N'
02EE-10 05       I    15 (2**)         BPL     BOUNCE      ;  IF YES, GO DEBOUNCE
02F0-CA          I    16 (  2)         DEX                 ;   DECREMENT KEY #
02F1-10 F5       I    17 (2**)         BPL     NXTKEY      ;  NO, DO NEXT KEY
02F3-30 F1       I    18 (2**)         BMI     RSTART      ; START OVER
02F5-8A          I    19 (  2) BOUNCE  TXA                 ; SAVE KEY NUMBER IN A
02F6-A0 12       I    20 (  2)         LDY     #$12        ; OUTER LOOP CNT LOAD FOR DELAY OF 50 MS.
02F8-A2 FF       I    21 (  2) LP1     LDX     #$FF        ; INNER 11 US. LOOP
02FA-2C 01 CC    I    22 (  4) LP2     BIT     PORT3A      ; SEE IF KEY STILL DOWN
02FD-30 E7       I    23 (2**)         BMI     RSTART      ; IF NOT, KEY NOT VALID, RESTART
02FF-CA          I    24 (  2)         DEX
0300-D0 F8       I    25 (2**)         BNE     LP2         ; THIS LOOP USES 2115*5 US.
0302-88          I    26 (  2)         DEY
0303-D0 F3       I    27 (2**)         BNE     LP1         ; OUTER LOOP: TOTAL IS 50 MS.
0305-60          I    28 (  6)         RTS                 ; DONE: KEY IN A.
0306-            I    29       ;
0306-            I    30       ; SUBROUTINE 'INITKEY'
0306-            I    31       ; TAKES CARE OF INITIALIZING VIA #3 FOR USING WITH THE GETKEY ROUTINE FROM
0306-            I    32       ; THE CODE.
0306-            I    33       ;
0306-A9 00       I    34 (  2) INITKEY LDA     #0
0308-8D 03 CC    I    35 (  4)         STA     DDR3A       ; SET KEY STROBE PORT FOR INPUT
030B-A9 FF       I    36 (  2)         LDA     #$FF
030D-8D 02 CC    I    37 (  4)         STA     DDR3B       ; SET KEYS FOR OUTPUT
0310-60          I    38 (  6)         RTS
