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