home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols100 / vol120 / composer.asm < prev    next >
Encoding:
Assembly Source File  |  1985-02-09  |  32.0 KB  |  1,592 lines

  1.  
  2.  
  3.  
  4. ;    COMPOSER.ASM    A MUSICIAL PROGRAM BY C. W. CHATHAM
  5. ;            Copyright  Nov 1, 1982
  6. ;
  7. ;     Permission is hereby granted for the non-commercial rep-
  8. ; roduction of this program.  All other rights reserved.
  9. ;
  10. ;    This program is designed to operate with AY-3-8910/8912 
  11. ; sound chips.  It requires a 2ms counter at memory location
  12. ; TICK (000Bh) as defined in the first equate.  This is used for
  13. ; all tempo regulation.  
  14. ;
  15. ;
  16. ;    Definitions:    PSGRx
  17. ;            0    Ch A Tone Period  8 bit LSB
  18. ;            1    "       "      4 bit    MSB
  19. ;            2    Ch B Tone Period  8 bit LSB
  20. ;            3              4 bit MSB
  21. ;            4    Ch C Tone Period  8 bit LSB
  22. ;            5              4 bit MSB
  23. ;            6    Noise Period      5 bits
  24. ;            7    N/Enable  port/noise/tone
  25. ;            8    Ch A Amplitude      M +4 bits
  26. ;            9    Ch B Amp
  27. ;            10    Ch C Amp
  28. ;            11    Envelope Period   Fine (LSB)
  29. ;            12      "        "      Coarse (MSB)
  30. ;            13    Envelope Shape/Cycle 4 bits     
  31. ; end of registers    14    CH 'A' ON TIME      Fine (LSB)
  32. ;            15              Coarse (MSB)
  33. ;            16        Tied?        1 bit
  34. ;            17    CH 'B' ON TIME      Fine (LSB)
  35. ;            18              Coarse (MSB)
  36. ;            19        Tied?        1 bit
  37. ;            20    CH 'C' ON TIME      Fine (LSB)
  38. ;            21              Coarse (MSB)
  39. ;            22        Tied?        1 bit
  40. ;            23
  41. ;            24
  42. ;            30
  43. ;-----------------------------------------------------------
  44. TICK    EQU    0BH      ;MEMORY LOCATION OF 2ms TICK COUNTER
  45. BDOS    EQU    5H
  46. CONIN    EQU    1
  47. CONOUT    EQU    2
  48. PSTRING    EQU    9
  49. RSTRING    EQU    10
  50. OPENF    EQU    15
  51. CLOSEF    EQU    16
  52. FCB    EQU    5CH
  53. CR    EQU    0DH    ;CARRIAGE RTN
  54. LF    EQU    0AH    ;LINE FEED
  55. HT    EQU    09H    ;HOR TAB
  56. BS    EQU    08H    ;BACKSPACE
  57. DEL    EQU    7FH    ;DELETE
  58. SPC    EQU    20H    ;SPACE
  59. ES    EQU    24H    ;END STRING
  60. ;------------------------------è    ORG    100H
  61.     LXI    SP,STACK    ;LOCAL STACK
  62.     MVI    A,'1'    ;GET PORT #1 ADDRESS
  63.     CALL    GTPRT
  64. CLGTFL    CALL    CLS    ;CLEAR THE SCREEN
  65.     CALL    NAME    ;PRINT OPENING STATEMENT
  66.     CALL    GETFIL    ;GET THE STARTING MUSIC
  67.     CALL    LOADFIL    ;
  68. NEWTMP    CALL    TEMPO
  69.     CALL    BEAT0
  70. STRTHR    CALL    START
  71.     CALL    BEGIN
  72.     CALL    0000H    ;PAUSE
  73. PSTAT    DB    0
  74. MSURE    DS    4    ;0000-9999 MEASURE #
  75. BNOTE    DB    '4'    ;NOTE TO GET ONE BEAT
  76. BMSUR    DB    '4'    ;# BEATS PER MEASURE
  77. IMSUR    DS    2    ;# INTERUPTS PER MEASURE
  78. TIME1    DS    2    ;# INTERUPTS PER WHOLE NOTE
  79. BEAT    DS    2    ;# INTERUPTS PER BEAT
  80. FILPT    DS    2    ;FILE POINTER
  81. NDBUF    DS    2    ;TOP OF MUSIC BUFFER SET BY LDFIL
  82. TMPO    DB    120,49,50,48    ;SET BY TEMPO
  83. PSGN    DB    01H    ;PSG IN USE
  84.         ;FOLLOWING SET BY GTPORT
  85. PORT    DB    320Q    ;BASE PORT FOR CURRENT USE
  86. PORT2    DB    322Q    ;PORT + 2
  87. REGIS    DW    PSGR1    ;BASE FOR CURRENT PSG REGISTERS
  88.         ;CHNL SET BY NOTE3
  89. CHNL    DB    'A'    ;CURRENT PSG CHANNEL
  90. PSGB1    DB    322Q    ;PSGA1-1  (PORT2)
  91. PSGA1    DB    320Q    ;PSGA1+0
  92. PSGR1    DS    1EH
  93. PSGB2    DB    0    ;
  94. PSGA2    DB    0    ;PSGA1+20H
  95. PSGR2    DS    1EH
  96. PSGB3    DB    0
  97. PSGA3    DB    0    ;PSGA1+40H
  98. PSGR3    DS    1EH
  99. PSGB4    DB    0
  100. PSGA4    DB    0    ;PSGA1+60H
  101. PSGR4    DS    1EH
  102. PSGB5    DB    0
  103. PSGA5    DB    0    ;PSGA1+80H
  104. PSGR5    DS    1EH
  105. PSGB6    DB    0
  106. PSGA6    DB    0    ;PSGA1+A0H 
  107. PSGR6    DS    1EH
  108. ;
  109. ;
  110. SVOICE    DB    '1','A'    ;START VOICE
  111. ;VOICE TABLE  1st Byte=R6 (N Freq)  2nd Byte=R7 (Not Enable)
  112. ; 3rd & 4th=R11 & R12 (Envelope period LSB & MSB)
  113. ;    5th Byte=R15 (Envelope Shape/Cycle)
  114. VOICEA    DB    000Q,370Q,00H,90H,09    ;SINGLE STRIKE DECAYèVOICEB    DB    000Q,370Q,000,60H,09
  115. VOICEC    DB    000Q,370Q,000,38H,09
  116. VOICED    DB    000Q,370Q,000,20H,09
  117. VOICEE    DB    000Q,370Q,000,14H,09
  118. VOICEF    DB    000Q,370Q,000,0AH,09
  119. VOICEG    DB    000Q,370Q,000,06H,09
  120. VOICEH    DB    000Q,370Q,000,03H,09
  121.  
  122. VOICEI    DB    000Q,370Q,000,0AH,08    ;MULT STRIKE DECAY
  123. VOICEJ    DB    000Q,370Q,000,07H,08
  124. VOICEK    DB    000Q,370Q,000,05H,08
  125. VOICEL    DB    000Q,370Q,000,03H,08
  126. VOICEM    DB    000Q,370Q,000,02H,08
  127.  
  128. VOICEN    DB    000Q,370Q,000,18H,0EH    ;WARBLE
  129. VOICEO    DB    000Q,370Q,000,0AH,0EH
  130. VOICEP    DB    000Q,370Q,000,08H,0EH
  131. VOICEQ    DB    000Q,370Q,000,06H,0EH
  132. VOICER    DB    000Q,370Q,000,04H,0EH
  133. VOICES    DB    000Q,370Q,000,03H,0EH
  134. VOICET    DB    000Q,370Q,000,02H,0EH
  135. VOICEU    DB    000Q,370Q,000,02H,0DH    ;RAPID ATTACK 
  136.     ;SPECIAL EFFECTS IN CHANNEL A ONLY
  137. VOICEV    DB    001Q,361Q,000,60H,09H    ;DRUM 1
  138. VOICEW    DB    377Q,361Q,000,14H,09H    ;DRUM 2
  139. VOICEX    DB    377Q,360Q,000,06H,0DH    ;BREATHY WHISTLE
  140. VOICEY    DB    017Q,361Q,000,020Q,00H    ;GUNSHOT
  141. VOICEZ    DB    001Q,361Q,000,070Q,00H    ;EXPLOSION
  142.  
  143. ZERO    DB    '0'
  144. TIMER    DB    0
  145. ;
  146. NAME    MVI    C,09H    ;PRINT STRING FCN
  147.     LXI    D,NAME1
  148.     CALL    BDOS
  149.     RET
  150. NAME1    DB    LF,HT,HT,HT,HT,'COMPOSER.ASM',CR,LF,LF
  151.     DB    HT,HT,'By C.W. Chatham    '
  152.     DB    ' Copyright 1 Nov 1982',CR,LF
  153.     DB    LF,HT,HT,'A musical program using the AY 3-8910'
  154.     DB    ' PSG.',CR,LF,HT,LF,LF,LF,'$'
  155.  
  156. ;------------------------
  157. BEGIN    ;START HERE FOR MUSIC PLAYING
  158.     ;JUMPS TO HERE UPON DETECTION OF CLOCK CHANGE
  159.     ;AT LOCATION TICK -- 000BH
  160.     LXI    H,TICK
  161.     MOV    A,M
  162.     LXI    H,TIMER
  163.     MOV    M,A    ;PUT CURRENT TICK COUNT IN 
  164.             ;TIMER
  165.     MVI    B,00H    ;SET CHANNEL AVAIL TO ZERO
  166. ;-----------------------    
  167. PRTCAL    LXI    H,PSGB1è    CALL    PRTCLA
  168.     NOP        ;IS PORT ZERO?
  169.     JZ    BEGIN4    ;IF SO FINISHED
  170.     CALL    BEGIN0
  171.     LXI    H,PSGB2
  172.     CALL    PRTCLA
  173.     NOP
  174.     JZ    BEGIN4
  175.     CALL    BEGIN0
  176.     LXI    H,PSGB3
  177.     CALL    PRTCLA
  178.     NOP
  179.     JZ    BEGIN4
  180.     CALL    BEGIN0
  181.     LXI    H,PSGB4
  182.     CALL    PRTCLA
  183.             ;ORA    A
  184.     JZ    BEGIN4
  185.     CALL    BEGIN0
  186.     LXI    H,PSGB5
  187.     CALL    PRTCLA
  188.             ;ORA    A
  189.     JZ    BEGIN4
  190.     CALL    BEGIN0
  191.     LXI    H,PSGB6
  192.     CALL    PRTCLA
  193.             ;ORA    A
  194.     JZ    BEGIN4
  195.     CALL    BEGIN0
  196.     JMP    BEGIN4
  197. ;------------------------
  198. PRTCLA    MOV    A,M
  199.     ORA    A    ;IS A PORT AVAIL?
  200.     RZ        ;NO PORT#
  201.     LXI    D,PORT2    ;POINT TO PORT2
  202.     STAX    D    ;STORE PORT2#
  203.     INX    H    ;LOAD PORT#
  204.     MOV    A,M
  205.     DCX    D    ;POINT TO PORT
  206.     STAX    D    ;STORE PORT#
  207.     RET
  208. ;------------------------
  209. BEGIN0    MVI    C,0FH    ;STEP TO PSGRx+14
  210.     DAD    B    ;ADD THE 15 TO HL
  211.     MVI    C,03H    ;PUT COUNTER IN C
  212. BEGIN1    MOV    A,M    ;CHECK FOR ZERO IN PSGRx 14/17/20
  213.     MOV    E,A
  214.     INX    H    ;POINT TO COARSE BYTE
  215.     MOV    D,M
  216.     ORA    D    ;IS THE TIME UP?
  217.     JNZ    BEGIN3
  218.     MVI    B,1    ;SET B TO INDICATE AVAIL CH
  219.     JMP    BEGIN2
  220. BEGIN3    DCX    D    ;DEC COUNT AND RETURN
  221.     MOV    M,D    ;IT TO MEMORYè    DCX    H    ;SEND FINE BYTE
  222.     MOV    M,E
  223.     INX    H    ;POINT TO COARSE BYTE
  224.     MOV    A,E
  225.     ORA    D
  226.     JNZ    BEGIN2    ;NO CHANGE NECESSARY
  227.         ;CHECK FOR TIE BYTE
  228.     INX    H    ;POINT TO TIE BYTE
  229.     MOV    A,M
  230.     DCX    H
  231.     ORA    A    ;IS IT ZERO?
  232.     JNZ    BEGIN2    ;IF NOT, PLAY ON
  233.     
  234.         ;SEND 0 TO THIS CHANNEL AMPLITUDE
  235.     MVI    A,11    ;CH A AMP REGISTER + 3
  236.     SUB    C    ;SUBTRACT COUNTER
  237.     PUSH    B
  238.     PUSH    H
  239.     LXI    H,PORT
  240.     MOV    C,M
  241.     CALL    OUTC    ;Z80 OP OUT A,(C)
  242.     XRA    A    ;CLEAR A
  243.     LXI    H,PORT2
  244.     MOV    C,M
  245.     CALL    OUTC    ;SEND ZERO
  246.     POP    H
  247.     POP    B
  248. BEGIN2    DCR    C
  249.     RZ        ;FINISHED THIS PSG
  250.     INX    H
  251.     INX    H    ;POINT TO NEXT CHANNEL
  252.     JMP    BEGIN1    ;DO IT AGAIN
  253. BEGIN4    DCR    B    ;CHECK FOR 1 IN B (CH AVAIL)
  254.     JM    BEGIN5
  255.     CALL    RDFIL
  256. BEGIN5    MVI    C,0BH
  257.     CALL    BDOS    ;IS CONSOLE READY?
  258.     ORA    A
  259.     JZ    BEGIN6    ;NO CHARACTER READY
  260.     MVI    C,01H
  261.     CALL    BDOS
  262.     CPI    'Q'    ;PRESS Q TO QUIT
  263.     JZ    NDPLA    ;WRITE 0 AMP TO PSGS AND END
  264.     CPI    'P'
  265.     JZ    STRTHR
  266.     CPI    'T'
  267.     JZ    NEWTMP
  268.     CPI    'S'
  269.     JZ    CLGTFL
  270. BEGIN6    LXI    H,TICK
  271.     MOV    A,M    ;CHECK FOR TIMER CHANGE
  272.     LXI    H,TIMER
  273.     CMP    M
  274.     JZ    BEGIN5    ;NO CHANGE SO WAIT
  275.     JMP    BEGINè;-----------------------
  276. START    CALL    SETUP    
  277.     ;SET UP PSG REGISTERS FOR PLAYING
  278.     MVI    A,7    ;PSG ENABLE
  279.     CALL    OUTP
  280.     MVI    A,370Q    ;ENABLE TONES ONLY
  281.     CALL    OUTP2
  282.     MVI    A,11    ;ENVELOPE PERIOD
  283.     CALL    OUTP
  284.     MVI    A,00    ;FILL FINE VALUE
  285.     CALL    OUTP2
  286.     MVI    A,14
  287.     CALL    OUTP    ;COARSE VALUE
  288.     MVI    A,35H
  289.     CALL    OUTP2    ;
  290.     MVI    A,13    ;ENVELOPE REGIS
  291.     CALL    OUTP    
  292.     MVI    A,09    ;ENVELOPE SHAPE
  293.     CALL    OUTP2
  294.         ;SET FILE POINTER (FILPT)
  295.     LXI    H,MUSICB-1
  296.     CALL    SVFLPT
  297.     CALL    CLS
  298.     CALL    CURS
  299.     LXI    D,INSTR1
  300.     MVI    C,PSTRING
  301.     CALL    BDOS
  302.     CALL    GTFLPT
  303.     CALL    PRNT
  304.     RET
  305. ;------------------------
  306. OPTION    
  307.     RET
  308. ;--------------------------
  309. PLAY    LXI    H,CHNL    ;GET CHANNEL A,B,OR C
  310.     MOV    A,M
  311.     LXI    H,REGIS    ;GET BASE OF REGISTER IN HL
  312.     MOV    E,M
  313.     INX    H
  314.     MOV    D,M
  315.     XCHG
  316.     SUI    'A'    ;CHANGE TO BINARY CHANNEL
  317.     ;    PLAY NOTE WITH HL POINT TO PSGR#
  318.     ;    CHANEL IN E IN FORM OF A=0H, B=1H, C=2H
  319.     PUSH     H
  320.     MOV    E,A    ;SAVE CHANEL IN E
  321.     ORA    A    ;CLEAR CARRY BIT
  322.     RAL        ;MULTIPLY BY TWO
  323.     CALL    OUTP    ;SEND REGISTER FOR FINE TUNE
  324.     PUSH    PSW    ;SAVE REGISTER POINTER
  325. PLAY1    DCR    A    ;CHECK CHANEL
  326.     JM    PLAY2    ;CHANEL SET
  327.     INX    H    ;IF NOT INCREMENT HL
  328.     JMP    PLAY1    ;CHECK IF FINISHED
  329. PLAY2    MOV    A,M    ;PUT FINE TUNE IN ACUMè    CALL    OUTP2    ;SEND IT
  330.     POP    PSW    ;GET FINE TUNE POINTER
  331.     INR    A
  332.     CALL    OUTP    ;SEND IT TO PSG
  333.     INX    H
  334.     MOV    A,M    ;GET COARSE BYTE
  335.     CALL    OUTP2    ;SEND TO PSG
  336.     MOV    A,E    ;PUT CHANEL IN A
  337.     ADI    8    ;POINT TO AMPLITUDE REGISTER
  338.     CALL    OUTP    
  339.     POP    H
  340. ;-------
  341.     PUSH    H    ;FOR SENDING ENVELOPE
  342. ;-------
  343.     ADD    L
  344.     MOV    L,A
  345.     JNC    PLAY3
  346.     INR    H
  347. PLAY3    MOV    A,M
  348.     CALL    OUTP2
  349. ;-------------------------------
  350.     ORI    10H    ;SEND UPDATE TO PSG ENVELOPE
  351.             ;IF MODE CTL SELECTED AND
  352.             ;CH #A BEING PLAYED
  353.     POP    H    ;RESTORE PSGRx POINTER
  354.     RZ        ;RTN IF MODE CONTROL NOT USED
  355.  
  356.     XCHG        ;SAVE H
  357.     LXI    H,CHNL
  358.     MVI    A,'A'
  359.     CMP    M    ;CHECK FOR ZERO    (CH #A)
  360.     RNZ        ;IF NOT (CH #A) RETURN
  361.     XCHG    
  362.     MVI    A,13    ;SET FOR ENVELOPE CONT
  363.     CALL    OUTP
  364.     CALL    ADD6
  365.     CALL    ADD6
  366.     INX    H    ;POINT TO PSGRx+13
  367.     MOV    A,M    ;GET MODE
  368.     CALL    OUTP2    ;SEND TO PORT2
  369. ;--------------------------------
  370.     RET
  371. ;-----------------------------------
  372. NDPLA            ;END PLAY AND QUIT
  373.     LXI    H,NDMSG
  374.     CALL    SVFLPT
  375.     JMP    BEGIN
  376. NDMSG    DB    '\A,R,3,0\B,R,3,0\C,R,3,0\$'
  377.     DB    '2A,R,3,0\2B,R,3,0\2C,R,3,0\'
  378.     DB    '3A,R,3,0\3B,R,3,0\3C,R,3,0\'
  379.     DB    '4A,R,3,0\4B,R,3,0\4C,R,3,0\'
  380.     DB    '5A,R,3,0\5B,R,3,0\5C,R,3,0\'
  381.     DB    '6A,R,3,0\6B,R,3,0\6C,R,3,0\$'
  382. ;-----------------------------------
  383. OUTP    PUSH    Hè    PUSH    B
  384.     LXI    H,PORT    ;LOAD ADDRESS OF PORT
  385.     MOV    C,M    ;GET PORT ADDRESS INTO C
  386.     CALL    OUTC    ;SEND TO PORT
  387.     POP    B
  388.     POP    H
  389.     RET
  390. OUTP2    PUSH    H
  391.     PUSH    B
  392.     LXI    H,PORT2
  393.     MOV    C,M
  394.     CALL    OUTC
  395.     POP    B
  396.     POP    H
  397.     RET
  398.     DS    1BH
  399. ;------------------------
  400. GTPRT            ;GET PORTS @ PUT INTO PORT AND PORT2
  401.             ;PSG# IN A IN FORM OF "1, 2, 3" ETC.
  402.     PUSH    H
  403.     PUSH    D
  404.     SUI    '1'
  405.     INR    A
  406.     JM    GTPRT4
  407.     CPI    7
  408.     JP    GTPRT4
  409.     LXI    H,PSGA1
  410.     LXI    D,20H
  411. GTPRT1    DCR    A    ;POINT TO PSGAx ADDRESS
  412.     JZ    GTPRT3
  413.     DAD    D
  414.     JMP    GTPRT1
  415. GTPRT3    MOV    A,M
  416.     PUSH    H    ;SAVE PSGAx ADDRESS
  417.     LXI    H,PORT    
  418.     MOV    M,A    ;PUT PORT# IN "PORT"
  419.     POP    H
  420.     PUSH    H    ;GET PSGAx ADDRESS
  421.     DCX    H    ;PSGBx ADDRESS
  422.     MOV    A,M
  423.     LXI    H,PORT2
  424.     MOV    M,A    ;PUT PORT+2 IN PORT2
  425.     POP    D    ;ADDRESS OF PORT2
  426.     INX    D    ;ADDRESS OF PSGR#
  427.     LXI    H,REGIS    ;BASE OF PSG REGISTER
  428.     MOV    M,E
  429.     INX    H
  430.     MOV    M,D
  431.     POP    D
  432.     POP    H
  433.     RET
  434. GTPRT4    POP    D
  435.     POP    H
  436.     JMP    RDFIL1
  437. ;èERROR    CALL    CLS    ;CLEAR THE SCREEN
  438.     LXI    D,ERR
  439.     CALL    PRINT
  440.     JMP    00H
  441. ERR    DB    CR,LF,HT,'You have encountered a non-recoverable'
  442.     DB    ' program error.',CR,LF,'$'
  443. ;
  444. ;
  445. GETFIL    LXI    D,GETP    ;MUSIC INPUT
  446.     MVI    C,PSTRING    ;PRINT STRING
  447.     CALL    BDOS
  448.  
  449.     CALL    GTFIL8    ;LOAD BUFFER WITH SPACES
  450.     LXI    H,MUSICB
  451.     LXI    D,FCB
  452.     LXI    B,12
  453.     CALL    LDIR
  454.     LXI    D,MUSICB
  455. GTFIL0    MVI    A,0EH    ;14 IS MAX NUMBER CHAR
  456.     STAX    D
  457.     MVI    C,0AH
  458.     CALL    BDOS
  459. MAKCAP    LXI    H,MUSICB+1    ;CONVERT TO CAPS
  460.     MVI    C,0EH
  461.     MVI    B,'a'
  462. MKCAP1    MOV    A,M    ;GET BYTE
  463.     CMP    B    ;IS IT LESS THAN A?
  464.     JC    MKCAP2
  465.     SUI    20H    ;CONVERT TO UP CASE
  466.     MOV    M,A    ;SAVE IT
  467. MKCAP2    INX    H
  468.     DCR    C
  469.     JNZ    MKCAP1
  470. GTFILA    LXI    H,MUSICB+3    ;POINT TO 2ND BYTE
  471.     LXI    D,FCB    ;POINT TO FCB DESTINATION
  472.     MOV    A,M
  473.     CPI    ':'    ;IS THE 1ST BYTE DISK DRIVE
  474.     JNZ    GTFIL1
  475.     DCX    H    ;POINT TO DISK IN BUFFER
  476.     MOV    A,M    ;PUT IN A
  477.     SUI    40H
  478.     CPI    1
  479.     JM    ERROR    ;CANT BE LESS THAN THIS
  480.     XCHG        ;POINT TO FCB WITH HL
  481.     MOV    M,A    ;LOAD DISK DRIVE
  482.     XCHG
  483.     INX    D    ;POINT TO FCB+1 (BEGIN NAME)
  484.     LXI    H,MUSICB+4    ;POINT TO NAME IN BUFF
  485.     JMP    GTFIL2
  486. GTFIL1    LXI    H,FCB    ;1ST BYTE NOT DISK NAME
  487.     MVI    A,0
  488.     MOV    M,A    ;PUT 0 IN FCB+0
  489.     XCHG        ;POINT TO FCB WITH DE
  490.     INX    D    ;POINT TO FCB+1
  491.     LXI    H,MUSICB+2    ;POINT TO NAME IN BUFFèGTFIL2    LXI    B,08H    ;COUNT FOR XFR
  492.     MOV    A,M
  493.     CPI    '.'
  494.     JZ    GTFIL7
  495.     CPI    SPC
  496.     JZ    GTFILB
  497.     CALL    LDI
  498.     MOV    A,C
  499.     ORA    A
  500.     JNZ    GTFIL2+2
  501. GTFIL5    LXI    B,03H    ;COUNTER
  502.     MOV    A,M
  503.     CPI    '.'
  504.     JZ    GTFIL7
  505. GTFIL6        ;
  506.     CALL    LDI    ;SEND IT
  507.     MOV    A,C
  508.     ORA    A    ;CHECK FOR 0
  509.     JNZ    GTFIL6    ;PLAY IT AGAIN SAM
  510.     XCHG
  511. GTFILB    LXI    H,FCB+12    ;POINT TO FCB+12
  512.     MVI    M,0    ;SEND ZEROS TO 
  513.     INX    H    ;FCB+12,13, AND 14
  514.     MVI    M,0
  515.     INX    H
  516.     MVI    M,0
  517.     RET        ;FINISHED
  518.  
  519. GTFIL7    INX    H    ;POINT TO 1 PAST '.'
  520.     LXI    D,FCB+9    ;POINT TO 1ST EXT BYTE
  521.     ;GET IST EXT CHR IN A
  522.     JMP    GTFIL5
  523. GTFIL8    LXI    H,MUSICB+11H    ;FILL BUFF WITH SPACES
  524.     MVI    C,0FH
  525. GTFIL9    MVI    M,SPC    ;LOAD SPACE IN BUFF
  526.     DCX    H
  527.     DCR    C    ;COUNTER
  528.     JNZ    GTFIL9
  529.     XCHG        ;POINT TO BUFF WITH DE
  530.     RET
  531. GETP    DB    CR,LF,HT,HT,'Type the name of the music file.'
  532.     DB    CR,LF,LF,LF,HT,HT,HT,HT,'$'
  533. ;--------------------------
  534. LOADFIL        ;OPEN THE FILE IN FCB AND LOAD IT INTO
  535.         ;MEMORY BUFFER AT ADDRESS MUSICB.
  536.     LXI    D,OPSTR
  537.     CALL    PRINT
  538.     LXI    D,FCB
  539.     MVI    C,15    ;OPEN FILE FCN
  540.     CALL    BDOS
  541.     ADI    0FH    ;CHECK IF A=255
  542.     JC    OPNER    ;CAN NOT OPEN
  543.     LXI    H,FCB+32    ;CURRENT RECORD#
  544.     MVI    M,0    ;SET TO ZERO
  545.     CALL    CLSè    CALL    CURS
  546.     LXI    D,LDSTR
  547.     CALL    PRINT
  548.     JMP    LDFIL1
  549. OPSTR    DB    HT,HT,'Opening file.',CR,LF,'$'
  550. LDSTR    DB    HT,HT,'Loading music program.',CR,LF,'$'
  551. OPNERS    DB    HT,HT,'UNABLE TO OPEN FILE AS ENTERED.',CR,LF,'$'
  552. CLSTR    DB    HT,HT,'Closing file.',CR,LF,ES
  553. OPNER    LXI    D,OPNERS
  554.     CALL    PRINT
  555.     POP    H    ;RETURN INST TO 'CALL LOADFIL'
  556.     JMP    CLGTFL    ;GO TRY AGAIN (GETFIL)
  557. LDFIL1    LXI    D,MUSICB    ;SET DMA ADDRESS
  558.     MVI    C,1AH
  559.     CALL    BDOS
  560. LDFIL2    LXI    D,FCB    ;READ SEQUENTIAL INTO BUFF
  561.     MVI    C,14H    ;20
  562.     CALL    BDOS
  563.     ORA    A    ;IS A 0 RETURNED IN A?
  564.     JZ    LDFIL3    ;AINT FINISHED YET
  565.     LXI    H,LDFIL1+1    ;PREP FOR NEXT TIME
  566.     LXI    D,MUSICB    ;DMA ADDRESS
  567.     MOV    M,E
  568.     INX    H
  569.     MOV    M,D
  570.     CALL    CLS
  571.     CALL    CURS
  572.     LXI    D,CLSTR
  573.     CALL    PRINT
  574.     LXI    D,FCB    ;CLOSE FILE
  575.     MVI    C,16
  576.     CALL    BDOS
  577.     CALL    CLS
  578.     CALL    CURS
  579.     RET        ;FINISHED
  580. LDFIL3    LXI    H,LDFIL1+1    ;GET LAST DMA ADDRESS
  581.     MOV    A,M
  582.     INX    H
  583.     MOV    D,M
  584.     ADI    128    ;ADD SECTOR READ LENGTH TO DMA
  585.     MOV    E,A
  586.     JNC    LDFIL4
  587.     INR    D    ;ADD CARRY TO HIGH BIT
  588. LDFIL4    LXI    H,NDBUF    ;TOP OF BUFFER
  589.     MOV    M,E
  590.     INX    H
  591.     MOV    M,D
  592.     LXI    H,LDFIL1+1    ;DMA ADDRESS
  593.     MOV    M,E
  594.     INX    H
  595.     MOV    M,D
  596.     JMP    LDFIL1    ;SET DMA ADDRESS @ GO AGAIN
  597. ;---------------------------
  598. ;
  599. TEMPO            ;CALL FOR AND SET TEMPO COUNTERè            ;FOR ONE BEAT
  600.     CALL    CLS
  601.     CALL    CURS             
  602. ;TEMPO+6
  603.     LXI    D,TEMP1    ;ADDRESS OF PROMPT STRING
  604.     MVI    C,09H    
  605.     CALL    BDOS    ;PRINT IT
  606. TEMPO1    LXI    H,TMPO+1    ;POINT TO STORE AREA
  607.     LXI    B,03H
  608. TEMPO2    MOV    A,M
  609.     CALL    PUTCHR    ;PRINT IT
  610.     INX    H
  611.     DCR    C    ;PRINTED 3?
  612.     JNZ    TEMPO2
  613.     LXI    H,TMPO+1    ;POINT TO 1ST CHAR
  614.     MVI    C,3    ;3 TIMES
  615. TEMPO3    MVI    A,BS    ;BACKSPACE
  616.     CALL    PUTCHR    ;SEND BACKSPACE
  617.     DCR    C
  618.     JNZ    TEMPO3    ;3 TIMES?
  619. ;SETS CURSOR AT HUNDREDS POSITION
  620.     MVI    C,3
  621. TEMPO4    CALL    GETNUM
  622.     ORA    A    ;IS IT A ZERO?
  623.     JZ    TEMPO5    ;FINISHED INPUT?
  624.     MOV    M,A
  625.     INX    H
  626.     DCR    C
  627.     JNZ    TEMPO4    ;GET ANOTHER CHAR
  628. ;FINISHED INPUT - CALCULATE @ PUT IN TMPO
  629. TEMPO5    LXI    H,TMPO+1
  630.     CALL    TEMPOA
  631.     XRA    A
  632. TEMPO6    DCR    C
  633.     JM    TEMPO7
  634.     ADI    100
  635.     JC    TMPOER    ;MAX VAL=256
  636.     JMP    TEMPO6
  637. TEMPO7    INX    H    ;POINT TO TENS
  638.     CALL    TEMPOA
  639. TEMPO8    DCR    C
  640.     JM    TEMPO9
  641.     ADI    10
  642.     JC    TMPOER    ;MAX VAL=256
  643.     JMP    TEMPO8
  644. TEMPO9    INX    H    ;POINT TO ONES
  645.     CALL    TEMPOA
  646. TMPO10    DCR    C
  647.     JM    TMPO11    ;VALUE COMPLETE
  648.     INR    A
  649.     CPI    255
  650.     JZ    TMPO11    ;VALUE = 255
  651.     JMP    TMPO10
  652. TMPO11 LXI    H,TMPO
  653.     MOV    M,A    ;STORE ITè    RET
  654. TEMPOA    PUSH    PSW
  655.     MOV    A,M    ;GET NUMBER
  656.     SUI    30H    ;CONVERT TO BINARY
  657.     JM    ERROR    ;NOT ASCII NUMBER
  658.     MOV    C,A
  659.     POP    PSW
  660.     RET
  661. TMPOER    LXI    H,PSTAT    ;PROGRAM STATUS
  662.     MOV    A,M
  663.     ANI    80H    ;CHECK BIT 7
  664.     RNZ        ;DO NOTHING DURING PLAY
  665.     CALL    CLS    ;CLEAR SCREEN
  666.     LXI    D,TERMSG
  667.     MVI    C,PSTRING
  668.     CALL    BDOS
  669.     JMP    TEMPO+3
  670. TERMSG    DB    CR,LF,LF,LF,HT,HT,'The tempo must be a '
  671.     DB    'number between 30 and 255.',CR,LF
  672.     DB    HT,HT,'Try one more time.$'  
  673. TEMP1    DB    HT,HT,'Enter the tempo of the desired song.'
  674.     DB    CR,LF,HT,HT,HT,HT,ES
  675. ;
  676. BEAT0    LXI    H,TMPO    ;GET TEMPO
  677.     MOV    A,M
  678.     CPI    30H
  679.     JNC    BEAT1
  680.     MVI    A,30H
  681. BEAT1    LXI    H,7530H    ;2MS INT/MIN (30000)
  682.     LXI    D,0000H    ;ZERO THE COUNTER
  683.     MVI    B,0    ;CLEAR D
  684.     MOV    C,A    ;SUBTRACTOR IN DE
  685. BEAT2        ;DEVIDE BY SUCCESSIVE SUBTRACTION
  686.     CALL    SBCHB    ;Z80 16BIT SBC HL,BC
  687.     JC    BEAT3    ;HL<0
  688.     INX    D    ;SUBTRACTED (BC) TIMES
  689.             ;WITHOUT CARRY
  690.     JMP    BEAT2    ;DO AGAIN
  691. BEAT3    LXI    H,BEAT    ;# INTERRUPTS/BEAT LOADED
  692.     MOV    M,E
  693.     INX    H
  694.     MOV    M,D
  695.     CALL    HOLNOT
  696.     RET
  697. ;
  698. GETNUM            ;GET A NUMBER
  699.     CALL    GETCHR
  700.     CPI    08H    ;DONT ACCEPT BACKSPACE
  701.     JZ    GTNUM3
  702.     CPI    127    ;DONT ACCEPT DELETE
  703.     JZ    GTNUM3
  704.     CPI    48    ;IS IT LESS THAN A NUMBER?
  705.     JM    GTNUM1
  706.     CPI    58    ;IS IT GREATER THAN A NUMBER?
  707.     JP    GTNUM1è    RET
  708. GTNUM1    CPI    CR
  709.     JZ    GTNUM2
  710.     MVI    A,127    ;SEND A DELETE CHARACTER
  711.     CALL    PUTCHR    ;SEND IT TO CONSOLE
  712.     JMP    GETNUM    ;TRY AGAIN
  713. GTNUM2    MVI    A,0
  714.     RET
  715. GTNUM3    MVI    A,20H    ;SEND SPACE
  716.     CALL    PUTCHR
  717.     JMP    GETNUM
  718. ;----------------
  719. TRIAD    ;START WITH VALUE IN DE FOR BEAT TIME 
  720.     ;RETURN 2/3 VALUE IN DE FOR TRIAD NOTES
  721.     CALL    SVFLPT
  722.     XCHG    ;HL=DE
  723.     XRA    A    ;CLEAR PSW
  724.     MOV    D,A
  725.     MOV    E,A    ;CLEAR DE
  726.     MOV    A,L    ;HL=HL*2
  727.     RAL
  728.     MOV    L,A
  729.     MOV    A,H
  730.     RAL
  731.     MOV    H,A
  732.     LXI    B,03H    ;DEVIDE BY 3
  733. TRIAD1    CALL    SBCHB    ;16 BIT SUBTRACT
  734.     RC        ;QUIT HL<0
  735.     INX    D    ;ADD 1 TO DE
  736.     JMP    TRIAD1    ;DO AGAIN
  737. ;---------------
  738. ;PUT HOLE NOTE VALUE IN TIME1
  739. HOLNOT    LXI    H,BEAT    ;GET 1 BEAT COUNT
  740.     MOV    E,M    ;PUT IN DE
  741.     INX    H
  742.     MOV    D,M
  743.     LXI    H,BNOTE    ;GET BEAT NOTE
  744.     MOV    B,M    ;PUT IN B
  745.     MOV    A,M
  746.     CPI    '1'
  747.     JZ    HLNT1    ;DONE
  748.     CALL    SHFTDL    ;SHIFT DE LEFT
  749.     CPI    '2'
  750.     JZ    HLNT1
  751.     CALL    SHFTDL    ;NOT HALF NOTE
  752.     CPI    '4'
  753.     JZ    HLNT1
  754.     CALL    SHFTDL    ;NOT QUARTER NOTE
  755.     CPI    '8'
  756.     JZ    HLNT1
  757.     CALL    SHFTDL    ;NOT EIGHTH NOTE
  758.     CPI    '6'
  759.     JZ    HLNT1
  760.     CALL    SHFTDL    ;NOT SIXTEENTH
  761.     CPI    '3'è    JZ    HLNT1
  762.     JMP    ERROR
  763. HLNT1    ;PUT VALUE IN TIME1
  764.     LXI    H,TIME1
  765.     MOV    M,E
  766.     INX    H
  767.     MOV    M,D
  768.     RET
  769. ;------------------
  770. SHFTDL    ;SHIFT DE LEFT 1 BIT
  771.     PUSH    PSW
  772.     XRA    A    ;CLEAR CARRY
  773.     MOV    A,E
  774.     RAL
  775.     MOV    E,A
  776.     MOV    A,D
  777.     RAL
  778.     MOV    D,A
  779.     POP    PSW
  780.     RET
  781. ;----------------
  782. NOTTIM    ;GET SIXTEEN BIT COUNT FOR NOTE
  783.     ;NOTE VALUE IN 'A' RTN VAL IN DE
  784.     LXI    H,TIME1
  785.     MOV    B,A    ;SAVE ASCII NOTE
  786.     MOV    E,M    ;GET WHOLE NOTE VAL
  787.     INX    H
  788.     MOV    D,M
  789.     CPI    '1'
  790.     RZ    ;NO CHANGE NECESSARY
  791.     CALL    SHFTDR    ;SHIFT DE RIGHT
  792.     CPI    '2'
  793.     RZ
  794.     CALL    SHFTDR
  795.     CPI    '4'
  796.     RZ
  797.     CALL    SHFTDR
  798.     CPI    '8'
  799.     RZ
  800.     CALL    SHFTDR
  801.     CPI    '6'
  802.     RZ
  803.     CALL    SHFTDR
  804.     RET
  805. ;-------------------------
  806. RDFIL    ;READS NEXT FILE ENTRY BEGINNING AT
  807.     ;LOCATION OF FILE POINTER 'FILPT'
  808.     CALL    GTFLPT
  809.     MOV    A,M
  810.     CPI    CR
  811.     JNZ    RDFIL0
  812.     INX    H
  813.     INX    H
  814.     MOV    A,M
  815. RDFIL0    CPI    '$'    ;END?è    JZ    QUIT
  816.     CPI    ','    ;IF ',' THEN SET PSG=1
  817.     JZ    NOTE0    ;AND CHANNEL=A
  818.     CPI    27H    ;IS IT QUOTE?
  819.     JZ    PRNT    ;PRINT IT
  820.     CPI    '\'
  821.     JZ    RDFIL2
  822.     CPI    '1'    ;IS IT AS LARGE AS A NUMBER?
  823.     JM    RDFIL2
  824.     CPI    '6'+1    ;6 OR LESS?
  825.     JM    NOTE1    ;SET CHIP=(A)
  826.             ;PLAY NOTE
  827.     CPI    'A'
  828.     JM    RDFIL2
  829.     CPI    'C'+1    ;C OR LESS?
  830.     JM    NOTE0    ;SET CHIP=1
  831.             ;PLAY NOTE
  832.     CPI    'R'
  833.     JZ    REST0    ;REST
  834.     CPI    'V'
  835.     JZ    VOICE0    ;PSG VOICE
  836.     CPI    'M'
  837.     JZ    MSUR0    ;MEASURE
  838.     CPI    'T'
  839.     JZ    TMP0    ;TEMPO
  840.     CPI    'J'
  841.     JZ    JUMP0    ;JUMP TO MEASURE#
  842.     CPI    'K'
  843.     JZ    JUMP8
  844.     CPI    'L'
  845.     JZ    JUMP9
  846.     CPI    'N'
  847.     JZ    JUMP10
  848. RDFIL1    CALL    GTFLPT
  849. RDFIL2    MOV    A,M
  850.     CPI    '\'
  851.     JZ    RDFIL3
  852.     INX    H
  853.     JMP    RDFIL2    ;THROW AWAY ALL TO '\'
  854. RDFIL3    INX    H
  855.     MOV    A,M
  856.     CPI    '\'
  857.     JZ    RDFIL4
  858.     CALL    SVFLPT
  859.     RET    ;GO BACK TO MAIN PROGRAM
  860. RDFIL4    
  861.     DCX    H
  862.     CALL    SVFLPT
  863.     RET
  864. ;--------------------------
  865. TMP0    ;SETS NEW TEMPO WRITTEN INTO
  866.     ;MUSIC WITH HL POINTING TO THE
  867.     ;'T' FOLLOWING A '\'
  868.     INX    H
  869.     MOV    A,Mè    CPI    ' '
  870.     JZ    TMP0
  871.     CPI    ','
  872.     JZ    TMP0
  873.     CPI    '\'
  874.     JZ    RDFIL1    ;GO TO NEXT FILE ENTRY
  875.     XCHG
  876.     LXI    H,TMPO+1    ;POINT TO BUFFER
  877.     MOV    M,A
  878.     XCHG
  879.     INX    H
  880.     MOV    A,M    ;GET 2ND BYTE
  881.     CPI    '\'
  882.     JZ    RDFIL1    ;ABORT 
  883.     XCHG    
  884.     INX    H    ;LOAD 2ND BYTE
  885.     MOV    M,A
  886.     XCHG
  887.     INX    H
  888.     MOV    A,M    ;GET 3RD BYTE
  889.     CPI    '\'
  890.     CZ    TMP1    ;LESS THAN 100
  891.     XCHG
  892.     INX    H
  893.     MOV    M,A    ;LOAD LAST BYTE
  894.     CALL    TEMPO5    ;COMPUTE 'TEMPO'
  895.     CALL    BEAT0    ;COMPUTE # INT/BEAT
  896.             ;LOAD INTO BEAT
  897.             ;PUT WHOLE NOTE
  898.             ;VALUE INTO TIME1
  899.     JMP    RDFIL1    ;FINISHED
  900.     DS    20H
  901. TMP1    XCHG        ;POINT TO TMPO+2 (TENS)
  902.     INX    H    ;POINT TO TMPO+3 (ONES)
  903.     MOV    M,A    ;LOAD TENS
  904.     LXI    H,TMPO+1    ;GET 1ST BYTE (TENS)
  905.     MOV    A,M
  906.     INX    H    ;PUT IT IN TENS POSITION
  907.     MOV    M,A    ;WHERE IT BELONGS
  908.     MVI    A,'0'    ;
  909.     DCX    H
  910.     MOV    M,A    ;PUT ZERO IN TMPO+1 (HUNDREDS)
  911.     INX    H    ;POINT TO TENS
  912.     XCHG        ;CONFIGUR FOR RETURN
  913.     RET
  914. ;----------------------
  915. GTFLPT    ;GET FILE POINTER (FILPT) WITH HL
  916.     ;RETURNED WITH VALUE OF POINTER
  917.     PUSH    D
  918.     LXI    H,FILPT
  919.     MOV    E,M
  920.     INX    H
  921.     MOV    D,M
  922.     XCHG
  923.     POP    Dè    RET
  924. ;-----------------------
  925. SVFLPT    ;SAVE FILE POINTER (FILPT) WITH HL
  926.     ;POINTING TO LOCATION TO BE SAVED
  927.     PUSH    PSW
  928.     PUSH    B
  929.     PUSH    D
  930.     XCHG
  931.     LXI    H,FILPT
  932.     MOV    M,E
  933.     INX    H
  934.     MOV    M,D
  935.     XCHG
  936.     POP    D
  937.     POP    B
  938.     POP    PSW
  939.     RET
  940. ;--------------------------
  941.     DS    30H
  942. NOTE0    ;CHIP = #1
  943.     DCX    H    ;SET HL AT ONE
  944.         ;PRIOR TO CHANNEL #
  945.     MVI    A,'1'    ;PSG #1
  946. NOTE1    CALL    SVFLPT    ;SAVE FILE POINTER
  947.     CALL    GTPRT    ;SET PORT NUMBER
  948.     CALL    GTFLPT    ;POINT TO CHANNEL #
  949.     INX    H
  950.     MOV    A,M
  951.     CPI    ','
  952.     JNZ    NOTE3
  953. NOTE2    DCX    H    ;SET POINTER JUST PRIOR
  954.             ;TO NOTE VALUE
  955.     MVI    A,'A'    ;LOAD DEFAULT CHANNEL #
  956. NOTE3    XCHG
  957.     JMP    TIMEUP    ;CHECK IF CURRENT NOTE
  958.             ;IS FINISHED
  959. NOTE3A    MOV    M,A
  960.     XCHG
  961. NOTE4    INX    H    ;POINT TO CHANNEL# +1
  962.     MVI    C,0
  963.     MOV    A,M
  964.     CPI    ','    ;IS IT NOTE VALUE?
  965.     JZ    NOTE4
  966.     ;GET AND PROGRAM CURRENT PSG CHANNEL
  967.     ;FOR TONE COUNT
  968.     CPI    '\'
  969.     JZ    RDFIL1    ;ABORT
  970.     CPI    '0'
  971.     JM    RDFIL1    ;ABORT
  972.     CPI    '8'
  973.     JP    NOTE6    ;NOT A NUMBER
  974.     SUI    '0'    ;CONVERT TO BINARY
  975.     MOV    C,A    ;OCTAVE COUNTER IN C
  976. NOTE5    INX    H    ;LOOK AT NOTE
  977.     MOV    A,MèNOTE6    CALL    SVFLPT
  978.     CPI    'R'    ;IS IT A REST?
  979.     JZ    NOTER
  980.     CPI    'A'
  981.     JM    RDFIL1    ;ABORT-NOT NOTE
  982.     LXI    H,CNOTE    ;POINT TO "C" VALUE
  983.     CPI    'C'
  984.     JZ    NOTE7    ;LOAD VALUE
  985.     CALL    ADD6    ;INX H 6 TIMES
  986.     CPI    'D'
  987.     JZ    NOTE7
  988.     CALL    ADD6
  989.     CPI    'E'
  990.     JZ    NOTE7
  991.     CALL    ADD6
  992.     CPI    'F'
  993.     JZ    NOTE7
  994.     CALL    ADD6
  995.     CPI    'G'
  996.     JZ    NOTE7
  997.     CALL    ADD6
  998.     CPI    'A'
  999.     JZ    NOTE7
  1000.     CALL    ADD6
  1001.     CPI    'B'
  1002.     JZ    NOTE7
  1003.     JMP    RDFIL1    ;ABORT NOT NOTE
  1004. NOTE7    ;CHECK IF SHARP OR FLAT
  1005.     XCHG    ;SAVE NOTE ADDRESS IN DE
  1006.     CALL    GTFLPT
  1007.     INX    H    ;POINT TO NOTE + 1
  1008.     MOV    A,M
  1009.     CPI    '#'    ;CHECK IF SHARP
  1010.     JZ    SHARP
  1011.     CPI    '+'
  1012.     JZ    SHARP
  1013.     CPI    'S'
  1014.     JZ    SHARP
  1015.     CPI    'F'    ;CHECK IF FLAT
  1016.     JZ    FLAT
  1017.     CPI    '-'
  1018.     JZ    FLAT
  1019.     CPI    'B'
  1020.     JZ    FLAT
  1021.     DCX    H    ;POINT TO NOTE
  1022. NOTE8    ;GET TONE VAL AND CONVERT
  1023.     ;FOR PROPER OCTAVE
  1024.     CALL    SVFLPT    ;SAVE FILE POINTER
  1025.     XCHG    ;POINT TO NOTE TABLE
  1026.     MOV    E,M    ;LOAD VAL IN DE
  1027.     INX    H
  1028.     MOV    D,M
  1029. NOTE9    DCR    C    ;DEC OCTAVE COUNTER
  1030.     JM    NOTE10
  1031.     MOV    A,E    ;SAVE LSBè    CALL    SHFTDR    ;SHIFT DE RIGHT
  1032.     JMP    NOTE9    ;
  1033. NOTE10    ANI    01H    ;IS RT BIT A '1'?
  1034.     JZ    NOTE11
  1035.     INX    D    ;IF SO ADD 1 TO TONE
  1036. NOTE11        ;PUT TONE VAL IN PSG FILE
  1037.     LXI    H,CHNL
  1038.     MOV    A,M    ;PUT CHANNEL IN A
  1039.     PUSH    D
  1040.     LXI    H,REGIS
  1041.     MOV    E,M
  1042.     INX    H
  1043.     MOV    D,M
  1044.     XCHG
  1045.     POP    D
  1046.     CPI    'A'    ;IS IT 'A' CHANNEL?
  1047.     JZ    NOTE12    
  1048.     INX    H    ;IF NOT POINT TO B
  1049.     INX    H
  1050.     CPI    'B'    ;'B' CHANNEL?
  1051.     JZ    NOTE12
  1052.     INX    H    ;IF NOT POINT TO C
  1053.     INX    H
  1054. NOTE12    MOV    M,E    ;STORE LOW ORDER BYTE
  1055.     INX    H
  1056.     MOV    M,D    ;STORE HIGH ORDER BYTE
  1057. NOTET    ;GET NOTE TIME VALUE AND SET IN PSG FILE AS
  1058.     ;A 16 BIT VALUE AT PSGRx+
  1059.     ;A CHANNEL    14
  1060.     ;B CHANNEL    17
  1061.     ;C CHANNEL    20
  1062.     CALL    GTFLPT    ;GET FILE POINTER
  1063.     INX    H    ;POINT TO TIMEVALUE
  1064.     MOV    A,M
  1065.     CPI    ','
  1066.     JNZ    NOTT1    ;
  1067.     INX    H
  1068. NOTT1    MOV    A,M
  1069.     CPI    ','    ;IS IT SEPERATOR?
  1070.     JZ    NOTETA
  1071.     CPI    '/'    ;IS IT SEPERATOR?
  1072.     JNZ    NOTET0
  1073. NOTETA    MVI    A,'4'    ;DEFAULT TO QTR NOTE
  1074.     DCX    H    ;POINT BACK ONE
  1075.     CALL    SVFLPT
  1076.     JMP    NOTET1
  1077. NOTET0    CPI    '1'
  1078.     JM    RDFIL1    ;ERROR-ABORT
  1079.     CPI    '9'
  1080.     JP    RDFIL1    ;ERROR
  1081.     CPI    '5'
  1082.     JZ    RDFIL1    ;ERROR
  1083.     CPI    '7'
  1084.     JZ    RDFIL1    ;ERROR
  1085. NOTET1    CALL    SVFLPT    ;VALID NOTE DESIGNATOR IN A    è    CALL    NOTTIM    ;GET NOTE TIME
  1086.     CALL    GTFLPT    ;GET FILE POINTER
  1087.     INX    H
  1088.     MOV    A,M
  1089.     CPI    ','
  1090.     JZ    NOTETB
  1091.     CALL    SVFLPT    ;SAVE POINTER
  1092.     CPI    '.'    ;DOTTED NOTE
  1093.     CZ    DOTNOT    ;DE=DE*1.5
  1094.     CPI    'T'    ;TRIAD
  1095.     CZ    TRIAD    ;DE=DE*2/3
  1096.     ;PUT NOTE VALUE IN DE INTO REGISTER 
  1097. NOTETB    LXI    H,CHNL    ;GET CHANNEL 
  1098.     PUSH    D    ;SAVE NOTE DWELL
  1099.     MOV    C,M    ;GET CHANNEL COUNTER
  1100.     LXI    H,REGIS    ;POINT TO REGISTER
  1101.     MOV    E,M
  1102.     INX    H
  1103.     MOV    D,M
  1104.     XCHG    ;POINTING TO PSGRx
  1105.     LXI    D,14    ;ADD OFFSET TO CHANNEL A
  1106.     DAD    D    ;POINTING TO PSGRx+14
  1107.     POP    D    ;RESTORE VALUE
  1108.     MOV    A,C
  1109.     CPI    'A'    ;IS IT CHANNEL 'A'
  1110.     JZ    NOTET2
  1111.     CALL    ADD3
  1112.     CPI    'B'
  1113.     JZ    NOTET2
  1114.     CALL    ADD3
  1115. NOTET2    MOV    M,E    ;PUT LOW BIT INTO
  1116.     INX    H    ;REGISTER FILE
  1117.     MOV    M,D    ;PUT HI BIT
  1118.     PUSH    H    ;SAVE PSGRx+ LOCATION
  1119.         ;CHECK FOR AND SET TIE BYTE
  1120.     CALL    GTFLPT
  1121.     INX    H    ;LOOK AT NEXT BYTE
  1122.     MOV    A,M    ;FOR TIE '-'
  1123.     CPI    '-'
  1124.     MVI    A,1
  1125.     JZ    NOTTA
  1126.     DCX    H
  1127.     XRA    A    ;SEND 0 TO TIE BYTE
  1128. NOTTA    CALL    SVFLPT
  1129.     POP    H
  1130.     INX    H
  1131.     MOV    M,A    ;SEND IT
  1132.     CALL    GTFLPT
  1133.     JMP    NOTE13
  1134. NOTER    CALL    SVFLPT    ;REST - CONTINUE
  1135.     JMP    NOTET
  1136.         ;GET AND STORE AMPLITUDE VALUE
  1137. NOTE13    INX    H    ;POINT TO NOTE+1
  1138.     MOV    A,M
  1139.     CPI    ','è    JZ    NOTE13    ;STEP AHEAD ONE
  1140.     CPI    '\'
  1141.     JZ    NOTE15    ;USE MODE CONTROL
  1142.     CPI    '0'    ;LESS THAN ZERO?
  1143.     JM    NOTE16    ;USE DEFAULT
  1144.     CPI    '9'+1    ;IS IT NUMBER?
  1145.     JM    NOTE14    ;USE THE NUMBER
  1146.     CPI    'A'    ;LESS THAN LETTER?
  1147.     JM    NOTE16    ;WRONG, USE DEFAULT
  1148.     CPI    'F'+1
  1149.     JP    NOTE15    ;>F SO SET MODE CONTROL
  1150.     SUI    55    ;CONVERT ASCII A-F
  1151.             ;TO HEX
  1152.     JMP    NOTE18
  1153. NOTE14        ;SET NUMBER VALUE IN A
  1154.     SUI    '0'    ;30H
  1155.     JMP    NOTE18
  1156. NOTE15    MVI    A,1FH    ;SET MODE CONTROL
  1157.     JMP    NOTE18
  1158. NOTE16    MVI    A,08H    ;USE DEFAULT VALUE
  1159.  
  1160. NOTE18            ;PUT VALUE IN A INTO PSG CHANNEL
  1161.     PUSH    PSW    ;SAVE VALUE
  1162.     LXI    H,CHNL
  1163.     MOV    A,M    ;GET CHANNEL NUMBER
  1164.     SUI    'A'    ;CONVERT TO BINARY
  1165.     MOV    C,A    ;STORE IN COUNTER
  1166.     LXI    H,REGIS
  1167.     MOV    E,M    ;GET LOW BYTE
  1168.     INX    H
  1169.     MOV    D,M    ;GET HI BYTE
  1170.     XCHG        ;POINT TO REG #
  1171.     CALL    ADD6    ;POINT TO REG # +6
  1172.     INX    H
  1173. NOTE17    INX    H    ;POINT TO REG # +8
  1174.     DCR    C
  1175.     JP    NOTE17
  1176.     POP    PSW
  1177.     MOV    M,A    ;PUT IT IN REG
  1178.     CALL    PLAY    ;PLAY THE NOTE
  1179.     JMP    RDFIL1    ;
  1180. ;-------------------------
  1181. TIMEUP    PUSH    PSW    ;SAVE ENVIRONMENT
  1182.     PUSH    D
  1183.     LXI    H,CHNL    ;GET CHANNEL
  1184.     PUSH    H    ;SAVE FOR LATER
  1185.     MOV    M,A    ;PUT CHANNEL IN A
  1186.     LXI    H,REGIS    ;LOAD PSGRx IN DE
  1187.     MOV    E,M
  1188.     INX    H
  1189.     MOV    D,M
  1190.     LXI    H,14    ;ADD OFFSET TO 1ST CHAN
  1191.     DAD    D    ;TIME @ STORE IN HL
  1192.     SUI    'A'-1    ;CONVERT TO BINARY 1,2,3
  1193. TMUP1    DCR    Aè    JZ    TMUP2
  1194.     CALL    ADD3    ;POINT TO NEXT CHAN TIME
  1195.     JMP    TMUP1
  1196. TMUP2    MOV    A,M    ;GET FINE TIME TO GO
  1197.     INX    H
  1198.     MOV    D,M    ;COARSE TIME TO GO
  1199.     ORA    D    ;LAST NOTE FINISHED?
  1200.     JNZ    TMUP3    ;NOT FINISHED
  1201.     POP    H
  1202.     POP    D
  1203.     POP    PSW
  1204.     JMP    NOTE3A    ;GO BACK AND PLAY
  1205. TMUP3    POP    H
  1206.     POP    D
  1207.     POP    PSW
  1208.     CALL    GTFLPT
  1209. TMUP4    MOV    A,M    ;SET FILPT AT '\' AND RTN
  1210.     CPI    '\'
  1211.     JZ    RDFIL2
  1212.     DCX    H
  1213.     JMP    TMUP4    ;DO AGAIN
  1214. ;------------------------
  1215. SETUP    ;ZEROS PSG WORKING REGISTER
  1216.     LXI    H,PSGR1
  1217.     CALL    SETUP0
  1218.     LXI    H,PSGR2
  1219.     CALL    SETUP0
  1220.     LXI    H,PSGR3
  1221.     CALL    SETUP0
  1222.     LXI    H,PSGR4
  1223.     CALL    SETUP0
  1224.     LXI    H,PSGR5
  1225.     CALL    SETUP0
  1226.     LXI    H,PSGR6
  1227.     CALL    SETUP0
  1228.     RET
  1229. SETUP0    XRA    A    ;CLEAR A
  1230.     MVI    C,1EH
  1231. SETUP1    MOV    M,A
  1232.     INX    H
  1233.     DCR    C
  1234.     JNZ    SETUP1
  1235.     RET
  1236. ;------------------------
  1237. DOTNOT    ;START WITH 16 BIT TIME VALUE IN DE
  1238.     ;RETURN DE*1.5 IN DE
  1239.     CALL    SVFLPT
  1240.     PUSH    PSW
  1241.     PUSH    D    ;SAVE VALUE
  1242.     CALL    SHFTDR    ;DEVIDE BY TWO
  1243.     POP    H    
  1244.     MOV    A,L
  1245.     ADD    E
  1246.     MOV    E,A    ;RESULT IN E
  1247.     MOV    A,Hè    ADC    D    ;ADD WITH CARRY
  1248.     MOV    D,A
  1249.     POP    PSW    ;RESTORE A
  1250.     RET
  1251. ;------------------------
  1252. ADD6    CALL    ADD3
  1253.     CALL    ADD3
  1254.     RET
  1255. ADD3    INX    H
  1256.     INX    H
  1257.     INX    H
  1258.     RET
  1259. ;---------------------------
  1260. CFNOTE    DW    4146    ;PSG TONE TABLE
  1261. CNOTE    DW    3914
  1262. CSNOTE    DW    3694
  1263. DFNOTE    DW    3694
  1264. DNOTE    DW    3487
  1265. DSNOTE    DW    3291
  1266. EFNOTE    DW    3291
  1267. ENOTE    DW    3107
  1268. ESNOTE    DW    2932    
  1269. FFNOTE    DW    3107
  1270. FNOTE    DW    2932
  1271. FSNOTE    DW    2768
  1272. GFNOTE    DW    2768
  1273. GNOTE    DW    2612
  1274. GSNOTE    DW    2466
  1275. AFNOTE    DW    2466
  1276. ANOTE    DW    2327
  1277. ASNOTE    DW    2197
  1278. BFNOTE    DW    2197
  1279. BNOTEE    DW    2073
  1280. BSNOTE    DW    1957    
  1281. ;--------------------------
  1282. REST0    
  1283.     JMP    RDFIL1    
  1284. MSUR0    
  1285.     JMP    RDFIL1
  1286. ;------------------------------
  1287. SHARP
  1288.     INX    D
  1289.     INX    D
  1290.     JMP    NOTE8
  1291. FLAT
  1292.     DCX    D
  1293.     DCX    D
  1294.     JMP    NOTE8
  1295. ;------------------------------
  1296. VOICE0        ;SEND UPDATE TO PSGRx VOICING 
  1297.     INX    H    ;POINT TO PSG# IN FILE
  1298.     MOV    A,M
  1299.     CALL    SVFLPT
  1300.     CALL    GTPRT    ;GET THE PORT #
  1301.     LXI    H,PORTè    MVI    A,0
  1302.     CMP    M
  1303.     JZ    RDFIL1    ;THROW AWAY IF PORT=0
  1304.     CALL    GTFLPT
  1305.     INX    H    ;POINT TO VOICE
  1306.     MOV    A,M
  1307.     SUI    'A'
  1308.     JM    RDFIL2    ;WRONG VOICE SELCTED
  1309.     MOV    C,A    ;AND PUT IN C
  1310.     INR    C
  1311. ;---------------------------
  1312. ;NUMBER OF VOICES AVAILABLE IN PROGRAM SET HERE
  1313.     CPI    26    ;# OF OPTIONS AVAILABLE    
  1314. ;---------------------------------
  1315.     JP    RDFIL2
  1316.     INR    A
  1317.     LXI    D,0005H    ;# OF BYTES IN VOICEx
  1318.     LXI    H,VOICEA
  1319. VOICE1    DCR    C    ;ADD TO SELECTED VOICE
  1320.     JZ    VOICE2
  1321.     DAD    D    ;POINT TO NEXT VOICE
  1322.     JMP    VOICE1
  1323. VOICE2    ;HL=VOICEx ADDRESS  SEND VOICING
  1324.     ;TO PSGRx AND TO PORT
  1325.     PUSH    H    ;SAVE VOICE ADDRESS
  1326.     LXI    H,REGIS    ;GET PSGRx INTO DE
  1327.     MOV    E,M
  1328.     INX    H
  1329.     MOV    D,M
  1330.     XCHG        ;POINT WITH HL    
  1331.     CALL    ADD6    ;POINT TO PSGRx+6
  1332.     POP    D    ;GET VOICEx ADD
  1333.     XCHG        ;POINT TO VOICEx IN HL
  1334.     MVI    A,6
  1335.     CALL    VOICE3
  1336.     CALL    LDI
  1337.     MVI    A,7    ;SEND TO REG #7
  1338.     CALL    VOICE3
  1339.     CALL    LDI
  1340.     INX    D
  1341.     INX    D
  1342.     INX    D    ;POINT TO PSGRx+11
  1343.     MVI    A,11    ;SEND TO REG #11
  1344.     CALL    VOICE3
  1345.     CALL    LDI
  1346.     MVI    A,12    ;SEND TO REG #12
  1347.     CALL    VOICE3
  1348.     CALL    LDI
  1349.     MVI    A,13    ;SEND TO REG #13
  1350.     CALL    VOICE3
  1351.     CALL    LDI
  1352.     JMP    RDFIL1
  1353. VOICE3    CALL    OUTP    ;SET UP PORT
  1354.     MOV    A,M    ;GET VAL FROM VOICEx+REG #
  1355.     CALL    OUTP2    ;SEND ITè    RET
  1356. ;-----------------------------
  1357.     DS    1FH
  1358. JUMP    ;MOVES FILE POINTER TO MEASURE MARKED AS THE 
  1359.     ;JUMP NUMBER TO REPLAY PORTIONS ACCORDING TO
  1360.     ;THE FOLLOWING  J=JUMP EACH TIME  
  1361.     ;K=JUMP ONE TIME (CHANGE K TO O)
  1362.     ;L=JUMP ALTERNATE TIMES (CHANGE L TO N)
  1363.     ;N=DONT JUMP  (CHANGE N TO L)
  1364. JUMP0    INX    H    ;POINT TO ONE PAST LETTER
  1365.     MOV    A,M
  1366.     CPI    '\'    ;IS IT SEPERATOR
  1367.     JZ    RDFIL1    ;ABORT
  1368.     CPI    '0'    ;IS IT LESS THAN 0?
  1369.     JM    JUMP0    ;TRY NEXT ONE
  1370.     CPI    '9'+1    ;IS IT > 9?
  1371.     JP    RDFIL2    ;NOT NUMBER OR SEPERATOR
  1372.     CALL    SVFLPT    ;POINT TO FIRST NUMBER
  1373.     LXI    H,MUSICB
  1374. JUMP1    MVI    A,'\'    ;FIND FIRST SEPERATOR
  1375.     CMP    M
  1376.     JZ    JUMP2
  1377.     INX    H
  1378.     JMP    JUMP1+2
  1379. JUMP2    INX    H    ;FIRST AFTER \
  1380.     MVI    A,'M'    ;FIND MEASURE MARKER
  1381. JUMP2A    CMP    M
  1382.     JZ    JUMP3
  1383.     INX    H
  1384.     JMP    JUMP2A
  1385. JUMP3    INX    H    ;POINT TO FIRST NUMBER
  1386.     MOV    A,M    ;IS IT LESS THAN 0?
  1387.     CPI    '0'
  1388.     JM    JUMP2+1
  1389.     CPI    '9'+1    ;IS IT > A NUMBER
  1390.     JP    JUMP2+1    ;1; 
  1391.     ;NOW POINTING TO FIRST NUMBER AFTER 'M'
  1392.     XCHG    ;POINT TO MUSIC BUFFER WITH D
  1393. JUMP4    CALL    GTFLPT    ;BEGIN TO MATCH NUMBER
  1394.         
  1395. JUMP5    ;POINT TO 1ST NUMBER
  1396.     LDAX    D    ;GET BUFFER NUMBER
  1397.     CMP    M    ;COMPARE WITH MEASURE #
  1398.     JZ    JUMP6
  1399.     XCHG
  1400.     JMP    JUMP2
  1401. JUMP5A    INX    H
  1402.     INX    D
  1403.     JMP    JUMP5    ;CHECK NEXT NUMBER FOR MATCH
  1404. JUMP6    MVI    A,'\'    ;IS IT PAST NUMBER?
  1405.     CMP    M
  1406.     JZ    JUMP7
  1407.     JMP    JUMP5A
  1408.     ;LOOK FOR NEXT 'M'
  1409. JUMP7    XCHG    ;POINT TO NEW FILPT WITH Hè    CALL    SVFLPT    ;PUT NEW-FOUND MEASURE 
  1410.             ;INTO FILE POINTER
  1411.     JMP    RDFIL2    ;RETURN
  1412. JUMP8    MVI    M,'O'
  1413.     JMP    JUMP0
  1414. JUMP9    MVI    M,'N'
  1415.     JMP    JUMP0
  1416. JUMP10    MVI    M,'L'
  1417.     JMP    RDFIL2
  1418. ;-------------------------
  1419. QUIT    ;END OF MUSIC FILE.
  1420.     CALL    CLS
  1421.     LXI    D,QTMSG
  1422.     MVI    C,PSTRING
  1423.     CALL    BDOS
  1424.     JMP    0000H
  1425. QTMSG    DB    LF,LF,HT,HT,'END OF MUSIC FILE',LF,LF,ES
  1426. ;------------------------
  1427. SHFTDR    ;SHIFT DE RIGHT 1 BIT
  1428.     PUSH    PSW
  1429.     XRA    A    ;CLEAR CARRY
  1430.     MOV    A,D
  1431.     RAR
  1432.     MOV    D,A
  1433.     MOV    A,E
  1434.     RAR
  1435.     MOV    E,A
  1436.     POP    PSW
  1437.     RET
  1438.  
  1439. ;----------------
  1440. GETCHR    PUSH    H    ;READ NEXT CONSOLE CHARACTER TO A
  1441.     PUSH    D
  1442.     PUSH    B
  1443.     MVI    C,CONIN
  1444.     CALL    BDOS
  1445.     POP    B
  1446.     POP    D
  1447.     POP    H
  1448.     RET
  1449. ;-------------------
  1450. PUTCHR    PUSH    H    ;WRITE NEXT CONSOLE CHARACTER TO A
  1451.     PUSH    D
  1452.     PUSH    B
  1453.     MVI    C,CONOUT
  1454.     MOV    E,A    ;CHARACTER TO SEND
  1455.     CALL    BDOS
  1456.     POP    B
  1457.     POP    D
  1458.     POP    H
  1459.     RET
  1460. CRLF        ;SEND CARRIAGE RETURN LINE FEED
  1461.     MVI    A,CR    ;CARRIAGE RETURN
  1462.     CALL    PUTCHR
  1463.     MVI    A,LF    ;LINE FEEDè    CALL    PUTCHR
  1464.     RET
  1465. PRINT        ;PRINT THE BUFFER ADDRESSED BY DE UNTIL $
  1466.     PUSH    D
  1467.     CALL    CRLF
  1468.     POP    D    ;NEW LINE
  1469.     MVI    C,PSTRING
  1470.     CALL    BDOS    ;PRINT THE STRING
  1471.     RET
  1472. READ        ;READ THE CONSOLE STRING
  1473.     MVI    C,RSTRING
  1474.     CALL    BDOS    ;GET THE STRING
  1475.     RET
  1476. ;------------------------
  1477. UCCV        ;UPPER CASE CONVERSION
  1478.     CPI    97    ;COMPARE WITH "a"
  1479.     RM        ;NOT LOWER CASE
  1480.     CPI    123    ;COMPARE WITH ("z"+1)
  1481.     RP        ;NOT LOWER CASE
  1482.     SUI    32    ;CONVERT TO UPPER CASE
  1483.     RET
  1484. ;-----------------------
  1485. CLS            ;H19 CLEAR SCREEN
  1486.     PUSH    H    ;SAVE ENVIRONMENT
  1487.     PUSH    B
  1488.     PUSH    D
  1489.     LXI    D,CSI    ;SET ADDRESS OF CLEAR STRING
  1490.     MVI    C,09H    ;PRINT STRING
  1491.     CALL    BDOS
  1492.     POP    D
  1493.     POP    B
  1494.     POP    H
  1495.     RET
  1496. CSI    DB    27,'E$'    ;MSG TO CLEAR SCREEN
  1497. ;-------------------------
  1498. CURS    LXI    D,STCUR    ;SET CURSOR TO CENTER SCREEN 
  1499.     MVI    C,09H    ;PRINT STRING FCN
  1500.     CALL    BDOS
  1501.     RET
  1502. STCUR    DB    27,'Y',40,32,'$'
  1503.     DS    40    ;20 LEVEL STACK
  1504. STACK
  1505. ;----------------------------------------------------------
  1506.  
  1507. LDI    ;    MEMORY TO MEMORY TRANSFER WITH AUTO INCREMENT
  1508.     ;    OF MEMORY POINTER REGISTERS AND AUTO DECREMENT
  1509.     ;    OF A BYTE COUNT REGISTER PAIR (AS Z80 OP CODE)
  1510.     DI
  1511.     MOV    A,M
  1512.         STAX    D    ;MEMORY TRANSFER COMPLETE 
  1513.     INX    H
  1514.     INX    D
  1515.     DCX    B
  1516.     EI
  1517.     RETè
  1518. ;--------------------------------------------------
  1519. SBCHB        ;16 BIT SUBTRACT W CARRY (SBC HL,BC)
  1520.     XRA    A
  1521.     MOV    A,L
  1522.     SUB    C    ;SUB C FROM L
  1523.     MOV    L,A
  1524.     MOV    A,H
  1525.     SBB    B    ;SUBTRACT WITH BORROW
  1526.             ;B FROM H
  1527.     MOV    H,A
  1528.     RET
  1529. ;------------------------------------------------
  1530.     ;SAME AS Z80 OP CODE OF SAME NAME (SEE LDI)
  1531. LDIR    CALL    LDI
  1532.     MOV    A,C
  1533.     ORA    B
  1534.     RZ
  1535.     JMP    LDIR
  1536.  
  1537. ;--------------------------------------------------
  1538.  
  1539. LDD    DI        ;(Z80 OP CODE EQUIVALENT)
  1540.     MOV    A,M
  1541.     STAX    D
  1542.     DCX    H
  1543.     DCX    D
  1544.     DCX    B
  1545.     EI
  1546.     RET
  1547. ;
  1548. LDDR    CALL    LDD    ;(Z80 OP CODE EQUIVALENT)
  1549.     MOV    A,C
  1550.     ORA    B
  1551.     RZ
  1552.     JMP    LDDR
  1553. ;---------------------------------------------
  1554. OUTC            ;Z80 OP ( OUT  A,(C)  )  SENDS 
  1555.             ;CONTENTS OF A TO PORT SPECIFIED
  1556.             ;IN REGISTER C
  1557.     PUSH    H
  1558.     LXI    H,OUTC+6    ;SELF-MODIFYING CODE
  1559.     MOV    M,C
  1560.     OUT    00H    ;PORT MODIFIED
  1561.     POP    H
  1562.     RET
  1563. ;------------------------
  1564. PAUSE    LXI    D,PAUS1    ;STOP FOR A WHILE
  1565.     CALL    PRINT
  1566.     LXI    D,PAUS2
  1567.     CALL    READ
  1568.     RET
  1569. PAUS1    DB    CR,LF,'Enter RETURN to continue.',CR,LF,'$'
  1570. PAUS2    DS    0FH
  1571. ;-------------------------èINSTR1    DB    HT,HT,'Press the following keys for the function desired.'
  1572.     DB    CR,LF,LF,HT,HT,'P',HT,HT,'Play again',CR,LF
  1573.     DB    HT,HT,'T',HT,HT,'Change tempo and play again',CR,LF
  1574.     DB    HT,HT,'S',HT,HT,'Play another song',CR,LF
  1575.     DB    HT,HT,'Q',HT,HT,'Quit',CR,LF,LF,HT,HT,'**************'
  1576.     DB    '*******************',CR,LF,LF,'$'
  1577. ;_________________________
  1578. PRNT    INX    H    ;PRINT WORDS TO TERMINAL
  1579.     MOV    A,M
  1580.     CPI    '\'    ;FINISHED?
  1581.     JNZ    PRNT1
  1582.     JMP    RDFIL2
  1583. PRNT1    MVI    C,2
  1584.     MOV    E,A
  1585.     PUSH    H
  1586.     CALL    BDOS
  1587.     POP    H
  1588.     JMP    PRNT
  1589. ;-------------------------
  1590. MUSICB    DS    0FH
  1591.     END