home *** CD-ROM | disk | FTP | other *** search
-
-
-
- ; COMPOSER.ASM A MUSICIAL PROGRAM BY C. W. CHATHAM
- ; Copyright Nov 1, 1982
- ;
- ; Permission is hereby granted for the non-commercial rep-
- ; roduction of this program. All other rights reserved.
- ;
- ; This program is designed to operate with AY-3-8910/8912
- ; sound chips. It requires a 2ms counter at memory location
- ; TICK (000Bh) as defined in the first equate. This is used for
- ; all tempo regulation.
- ;
- ;
- ; Definitions: PSGRx
- ; 0 Ch A Tone Period 8 bit LSB
- ; 1 " " 4 bit MSB
- ; 2 Ch B Tone Period 8 bit LSB
- ; 3 4 bit MSB
- ; 4 Ch C Tone Period 8 bit LSB
- ; 5 4 bit MSB
- ; 6 Noise Period 5 bits
- ; 7 N/Enable port/noise/tone
- ; 8 Ch A Amplitude M +4 bits
- ; 9 Ch B Amp
- ; 10 Ch C Amp
- ; 11 Envelope Period Fine (LSB)
- ; 12 " " Coarse (MSB)
- ; 13 Envelope Shape/Cycle 4 bits
- ; end of registers 14 CH 'A' ON TIME Fine (LSB)
- ; 15 Coarse (MSB)
- ; 16 Tied? 1 bit
- ; 17 CH 'B' ON TIME Fine (LSB)
- ; 18 Coarse (MSB)
- ; 19 Tied? 1 bit
- ; 20 CH 'C' ON TIME Fine (LSB)
- ; 21 Coarse (MSB)
- ; 22 Tied? 1 bit
- ; 23
- ; 24
- ; 30
- ;-----------------------------------------------------------
- TICK EQU 0BH ;MEMORY LOCATION OF 2ms TICK COUNTER
- BDOS EQU 5H
- CONIN EQU 1
- CONOUT EQU 2
- PSTRING EQU 9
- RSTRING EQU 10
- OPENF EQU 15
- CLOSEF EQU 16
- FCB EQU 5CH
- CR EQU 0DH ;CARRIAGE RTN
- LF EQU 0AH ;LINE FEED
- HT EQU 09H ;HOR TAB
- BS EQU 08H ;BACKSPACE
- DEL EQU 7FH ;DELETE
- SPC EQU 20H ;SPACE
- ES EQU 24H ;END STRING
- ;------------------------------è ORG 100H
- LXI SP,STACK ;LOCAL STACK
- MVI A,'1' ;GET PORT #1 ADDRESS
- CALL GTPRT
- CLGTFL CALL CLS ;CLEAR THE SCREEN
- CALL NAME ;PRINT OPENING STATEMENT
- CALL GETFIL ;GET THE STARTING MUSIC
- CALL LOADFIL ;
- NEWTMP CALL TEMPO
- CALL BEAT0
- STRTHR CALL START
- CALL BEGIN
- CALL 0000H ;PAUSE
- PSTAT DB 0
- MSURE DS 4 ;0000-9999 MEASURE #
- BNOTE DB '4' ;NOTE TO GET ONE BEAT
- BMSUR DB '4' ;# BEATS PER MEASURE
- IMSUR DS 2 ;# INTERUPTS PER MEASURE
- TIME1 DS 2 ;# INTERUPTS PER WHOLE NOTE
- BEAT DS 2 ;# INTERUPTS PER BEAT
- FILPT DS 2 ;FILE POINTER
- NDBUF DS 2 ;TOP OF MUSIC BUFFER SET BY LDFIL
- TMPO DB 120,49,50,48 ;SET BY TEMPO
- PSGN DB 01H ;PSG IN USE
- ;FOLLOWING SET BY GTPORT
- PORT DB 320Q ;BASE PORT FOR CURRENT USE
- PORT2 DB 322Q ;PORT + 2
- REGIS DW PSGR1 ;BASE FOR CURRENT PSG REGISTERS
- ;CHNL SET BY NOTE3
- CHNL DB 'A' ;CURRENT PSG CHANNEL
- PSGB1 DB 322Q ;PSGA1-1 (PORT2)
- PSGA1 DB 320Q ;PSGA1+0
- PSGR1 DS 1EH
- PSGB2 DB 0 ;
- PSGA2 DB 0 ;PSGA1+20H
- PSGR2 DS 1EH
- PSGB3 DB 0
- PSGA3 DB 0 ;PSGA1+40H
- PSGR3 DS 1EH
- PSGB4 DB 0
- PSGA4 DB 0 ;PSGA1+60H
- PSGR4 DS 1EH
- PSGB5 DB 0
- PSGA5 DB 0 ;PSGA1+80H
- PSGR5 DS 1EH
- PSGB6 DB 0
- PSGA6 DB 0 ;PSGA1+A0H
- PSGR6 DS 1EH
- ;
- ;
- SVOICE DB '1','A' ;START VOICE
- ;VOICE TABLE 1st Byte=R6 (N Freq) 2nd Byte=R7 (Not Enable)
- ; 3rd & 4th=R11 & R12 (Envelope period LSB & MSB)
- ; 5th Byte=R15 (Envelope Shape/Cycle)
- VOICEA DB 000Q,370Q,00H,90H,09 ;SINGLE STRIKE DECAYèVOICEB DB 000Q,370Q,000,60H,09
- VOICEC DB 000Q,370Q,000,38H,09
- VOICED DB 000Q,370Q,000,20H,09
- VOICEE DB 000Q,370Q,000,14H,09
- VOICEF DB 000Q,370Q,000,0AH,09
- VOICEG DB 000Q,370Q,000,06H,09
- VOICEH DB 000Q,370Q,000,03H,09
-
- VOICEI DB 000Q,370Q,000,0AH,08 ;MULT STRIKE DECAY
- VOICEJ DB 000Q,370Q,000,07H,08
- VOICEK DB 000Q,370Q,000,05H,08
- VOICEL DB 000Q,370Q,000,03H,08
- VOICEM DB 000Q,370Q,000,02H,08
-
- VOICEN DB 000Q,370Q,000,18H,0EH ;WARBLE
- VOICEO DB 000Q,370Q,000,0AH,0EH
- VOICEP DB 000Q,370Q,000,08H,0EH
- VOICEQ DB 000Q,370Q,000,06H,0EH
- VOICER DB 000Q,370Q,000,04H,0EH
- VOICES DB 000Q,370Q,000,03H,0EH
- VOICET DB 000Q,370Q,000,02H,0EH
- VOICEU DB 000Q,370Q,000,02H,0DH ;RAPID ATTACK
- ;SPECIAL EFFECTS IN CHANNEL A ONLY
- VOICEV DB 001Q,361Q,000,60H,09H ;DRUM 1
- VOICEW DB 377Q,361Q,000,14H,09H ;DRUM 2
- VOICEX DB 377Q,360Q,000,06H,0DH ;BREATHY WHISTLE
- VOICEY DB 017Q,361Q,000,020Q,00H ;GUNSHOT
- VOICEZ DB 001Q,361Q,000,070Q,00H ;EXPLOSION
-
- ZERO DB '0'
- TIMER DB 0
- ;
- ;
- NAME MVI C,09H ;PRINT STRING FCN
- LXI D,NAME1
- CALL BDOS
- RET
- NAME1 DB LF,HT,HT,HT,HT,'COMPOSER.ASM',CR,LF,LF
- DB HT,HT,'By C.W. Chatham '
- DB ' Copyright 1 Nov 1982',CR,LF
- DB LF,HT,HT,'A musical program using the AY 3-8910'
- DB ' PSG.',CR,LF,HT,LF,LF,LF,'$'
-
- ;------------------------
- BEGIN ;START HERE FOR MUSIC PLAYING
- ;JUMPS TO HERE UPON DETECTION OF CLOCK CHANGE
- ;AT LOCATION TICK -- 000BH
- LXI H,TICK
- MOV A,M
- LXI H,TIMER
- MOV M,A ;PUT CURRENT TICK COUNT IN
- ;TIMER
- MVI B,00H ;SET CHANNEL AVAIL TO ZERO
- ;-----------------------
- PRTCAL LXI H,PSGB1è CALL PRTCLA
- NOP ;IS PORT ZERO?
- JZ BEGIN4 ;IF SO FINISHED
- CALL BEGIN0
- LXI H,PSGB2
- CALL PRTCLA
- NOP
- JZ BEGIN4
- CALL BEGIN0
- LXI H,PSGB3
- CALL PRTCLA
- NOP
- JZ BEGIN4
- CALL BEGIN0
- LXI H,PSGB4
- CALL PRTCLA
- ;ORA A
- JZ BEGIN4
- CALL BEGIN0
- LXI H,PSGB5
- CALL PRTCLA
- ;ORA A
- JZ BEGIN4
- CALL BEGIN0
- LXI H,PSGB6
- CALL PRTCLA
- ;ORA A
- JZ BEGIN4
- CALL BEGIN0
- JMP BEGIN4
- ;------------------------
- PRTCLA MOV A,M
- ORA A ;IS A PORT AVAIL?
- RZ ;NO PORT#
- LXI D,PORT2 ;POINT TO PORT2
- STAX D ;STORE PORT2#
- INX H ;LOAD PORT#
- MOV A,M
- DCX D ;POINT TO PORT
- STAX D ;STORE PORT#
- RET
- ;------------------------
- BEGIN0 MVI C,0FH ;STEP TO PSGRx+14
- DAD B ;ADD THE 15 TO HL
- MVI C,03H ;PUT COUNTER IN C
- BEGIN1 MOV A,M ;CHECK FOR ZERO IN PSGRx 14/17/20
- MOV E,A
- INX H ;POINT TO COARSE BYTE
- MOV D,M
- ORA D ;IS THE TIME UP?
- JNZ BEGIN3
- MVI B,1 ;SET B TO INDICATE AVAIL CH
- JMP BEGIN2
- BEGIN3 DCX D ;DEC COUNT AND RETURN
- MOV M,D ;IT TO MEMORYè DCX H ;SEND FINE BYTE
- MOV M,E
- INX H ;POINT TO COARSE BYTE
- MOV A,E
- ORA D
- JNZ BEGIN2 ;NO CHANGE NECESSARY
- ;CHECK FOR TIE BYTE
- INX H ;POINT TO TIE BYTE
- MOV A,M
- DCX H
- ORA A ;IS IT ZERO?
- JNZ BEGIN2 ;IF NOT, PLAY ON
-
- ;SEND 0 TO THIS CHANNEL AMPLITUDE
- MVI A,11 ;CH A AMP REGISTER + 3
- SUB C ;SUBTRACT COUNTER
- PUSH B
- PUSH H
- LXI H,PORT
- MOV C,M
- CALL OUTC ;Z80 OP OUT A,(C)
- XRA A ;CLEAR A
- LXI H,PORT2
- MOV C,M
- CALL OUTC ;SEND ZERO
- POP H
- POP B
- BEGIN2 DCR C
- RZ ;FINISHED THIS PSG
- INX H
- INX H ;POINT TO NEXT CHANNEL
- JMP BEGIN1 ;DO IT AGAIN
- BEGIN4 DCR B ;CHECK FOR 1 IN B (CH AVAIL)
- JM BEGIN5
- CALL RDFIL
- BEGIN5 MVI C,0BH
- CALL BDOS ;IS CONSOLE READY?
- ORA A
- JZ BEGIN6 ;NO CHARACTER READY
- MVI C,01H
- CALL BDOS
- CPI 'Q' ;PRESS Q TO QUIT
- JZ NDPLA ;WRITE 0 AMP TO PSGS AND END
- CPI 'P'
- JZ STRTHR
- CPI 'T'
- JZ NEWTMP
- CPI 'S'
- JZ CLGTFL
- BEGIN6 LXI H,TICK
- MOV A,M ;CHECK FOR TIMER CHANGE
- LXI H,TIMER
- CMP M
- JZ BEGIN5 ;NO CHANGE SO WAIT
- JMP BEGINè;-----------------------
- START CALL SETUP
- ;SET UP PSG REGISTERS FOR PLAYING
- MVI A,7 ;PSG ENABLE
- CALL OUTP
- MVI A,370Q ;ENABLE TONES ONLY
- CALL OUTP2
- MVI A,11 ;ENVELOPE PERIOD
- CALL OUTP
- MVI A,00 ;FILL FINE VALUE
- CALL OUTP2
- MVI A,14
- CALL OUTP ;COARSE VALUE
- MVI A,35H
- CALL OUTP2 ;
- MVI A,13 ;ENVELOPE REGIS
- CALL OUTP
- MVI A,09 ;ENVELOPE SHAPE
- CALL OUTP2
- ;SET FILE POINTER (FILPT)
- LXI H,MUSICB-1
- CALL SVFLPT
- CALL CLS
- CALL CURS
- LXI D,INSTR1
- MVI C,PSTRING
- CALL BDOS
- CALL GTFLPT
- CALL PRNT
- RET
- ;------------------------
- OPTION
- RET
- ;--------------------------
- PLAY LXI H,CHNL ;GET CHANNEL A,B,OR C
- MOV A,M
- LXI H,REGIS ;GET BASE OF REGISTER IN HL
- MOV E,M
- INX H
- MOV D,M
- XCHG
- SUI 'A' ;CHANGE TO BINARY CHANNEL
- ; PLAY NOTE WITH HL POINT TO PSGR#
- ; CHANEL IN E IN FORM OF A=0H, B=1H, C=2H
- PUSH H
- MOV E,A ;SAVE CHANEL IN E
- ORA A ;CLEAR CARRY BIT
- RAL ;MULTIPLY BY TWO
- CALL OUTP ;SEND REGISTER FOR FINE TUNE
- PUSH PSW ;SAVE REGISTER POINTER
- PLAY1 DCR A ;CHECK CHANEL
- JM PLAY2 ;CHANEL SET
- INX H ;IF NOT INCREMENT HL
- JMP PLAY1 ;CHECK IF FINISHED
- PLAY2 MOV A,M ;PUT FINE TUNE IN ACUMè CALL OUTP2 ;SEND IT
- POP PSW ;GET FINE TUNE POINTER
- INR A
- CALL OUTP ;SEND IT TO PSG
- INX H
- MOV A,M ;GET COARSE BYTE
- CALL OUTP2 ;SEND TO PSG
- MOV A,E ;PUT CHANEL IN A
- ADI 8 ;POINT TO AMPLITUDE REGISTER
- CALL OUTP
- POP H
- ;-------
- PUSH H ;FOR SENDING ENVELOPE
- ;-------
- ADD L
- MOV L,A
- JNC PLAY3
- INR H
- PLAY3 MOV A,M
- CALL OUTP2
- ;-------------------------------
- ORI 10H ;SEND UPDATE TO PSG ENVELOPE
- ;IF MODE CTL SELECTED AND
- ;CH #A BEING PLAYED
- POP H ;RESTORE PSGRx POINTER
- RZ ;RTN IF MODE CONTROL NOT USED
-
- XCHG ;SAVE H
- LXI H,CHNL
- MVI A,'A'
- CMP M ;CHECK FOR ZERO (CH #A)
- RNZ ;IF NOT (CH #A) RETURN
- XCHG
- MVI A,13 ;SET FOR ENVELOPE CONT
- CALL OUTP
- CALL ADD6
- CALL ADD6
- INX H ;POINT TO PSGRx+13
- MOV A,M ;GET MODE
- CALL OUTP2 ;SEND TO PORT2
- ;--------------------------------
- RET
- ;-----------------------------------
- NDPLA ;END PLAY AND QUIT
- LXI H,NDMSG
- CALL SVFLPT
- JMP BEGIN
- NDMSG DB '\A,R,3,0\B,R,3,0\C,R,3,0\$'
- DB '2A,R,3,0\2B,R,3,0\2C,R,3,0\'
- DB '3A,R,3,0\3B,R,3,0\3C,R,3,0\'
- DB '4A,R,3,0\4B,R,3,0\4C,R,3,0\'
- DB '5A,R,3,0\5B,R,3,0\5C,R,3,0\'
- DB '6A,R,3,0\6B,R,3,0\6C,R,3,0\$'
- ;-----------------------------------
- OUTP PUSH Hè PUSH B
- LXI H,PORT ;LOAD ADDRESS OF PORT
- MOV C,M ;GET PORT ADDRESS INTO C
- CALL OUTC ;SEND TO PORT
- POP B
- POP H
- RET
- OUTP2 PUSH H
- PUSH B
- LXI H,PORT2
- MOV C,M
- CALL OUTC
- POP B
- POP H
- RET
- DS 1BH
- ;------------------------
- GTPRT ;GET PORTS @ PUT INTO PORT AND PORT2
- ;PSG# IN A IN FORM OF "1, 2, 3" ETC.
- PUSH H
- PUSH D
- SUI '1'
- INR A
- JM GTPRT4
- CPI 7
- JP GTPRT4
- LXI H,PSGA1
- LXI D,20H
- GTPRT1 DCR A ;POINT TO PSGAx ADDRESS
- JZ GTPRT3
- DAD D
- JMP GTPRT1
- GTPRT3 MOV A,M
- PUSH H ;SAVE PSGAx ADDRESS
- LXI H,PORT
- MOV M,A ;PUT PORT# IN "PORT"
- POP H
- PUSH H ;GET PSGAx ADDRESS
- DCX H ;PSGBx ADDRESS
- MOV A,M
- LXI H,PORT2
- MOV M,A ;PUT PORT+2 IN PORT2
- POP D ;ADDRESS OF PORT2
- INX D ;ADDRESS OF PSGR#
- LXI H,REGIS ;BASE OF PSG REGISTER
- MOV M,E
- INX H
- MOV M,D
- POP D
- POP H
- RET
- GTPRT4 POP D
- POP H
- JMP RDFIL1
- ;èERROR CALL CLS ;CLEAR THE SCREEN
- LXI D,ERR
- CALL PRINT
- JMP 00H
- ERR DB CR,LF,HT,'You have encountered a non-recoverable'
- DB ' program error.',CR,LF,'$'
- ;
- ;
- GETFIL LXI D,GETP ;MUSIC INPUT
- MVI C,PSTRING ;PRINT STRING
- CALL BDOS
-
- CALL GTFIL8 ;LOAD BUFFER WITH SPACES
- LXI H,MUSICB
- LXI D,FCB
- LXI B,12
- CALL LDIR
- LXI D,MUSICB
- GTFIL0 MVI A,0EH ;14 IS MAX NUMBER CHAR
- STAX D
- MVI C,0AH
- CALL BDOS
- MAKCAP LXI H,MUSICB+1 ;CONVERT TO CAPS
- MVI C,0EH
- MVI B,'a'
- MKCAP1 MOV A,M ;GET BYTE
- CMP B ;IS IT LESS THAN A?
- JC MKCAP2
- SUI 20H ;CONVERT TO UP CASE
- MOV M,A ;SAVE IT
- MKCAP2 INX H
- DCR C
- JNZ MKCAP1
- GTFILA LXI H,MUSICB+3 ;POINT TO 2ND BYTE
- LXI D,FCB ;POINT TO FCB DESTINATION
- MOV A,M
- CPI ':' ;IS THE 1ST BYTE DISK DRIVE
- JNZ GTFIL1
- DCX H ;POINT TO DISK IN BUFFER
- MOV A,M ;PUT IN A
- SUI 40H
- CPI 1
- JM ERROR ;CANT BE LESS THAN THIS
- XCHG ;POINT TO FCB WITH HL
- MOV M,A ;LOAD DISK DRIVE
- XCHG
- INX D ;POINT TO FCB+1 (BEGIN NAME)
- LXI H,MUSICB+4 ;POINT TO NAME IN BUFF
- JMP GTFIL2
- GTFIL1 LXI H,FCB ;1ST BYTE NOT DISK NAME
- MVI A,0
- MOV M,A ;PUT 0 IN FCB+0
- XCHG ;POINT TO FCB WITH DE
- INX D ;POINT TO FCB+1
- LXI H,MUSICB+2 ;POINT TO NAME IN BUFFèGTFIL2 LXI B,08H ;COUNT FOR XFR
- MOV A,M
- CPI '.'
- JZ GTFIL7
- CPI SPC
- JZ GTFILB
- CALL LDI
- MOV A,C
- ORA A
- JNZ GTFIL2+2
- GTFIL5 LXI B,03H ;COUNTER
- MOV A,M
- CPI '.'
- JZ GTFIL7
- GTFIL6 ;
- CALL LDI ;SEND IT
- MOV A,C
- ORA A ;CHECK FOR 0
- JNZ GTFIL6 ;PLAY IT AGAIN SAM
- XCHG
- GTFILB LXI H,FCB+12 ;POINT TO FCB+12
- MVI M,0 ;SEND ZEROS TO
- INX H ;FCB+12,13, AND 14
- MVI M,0
- INX H
- MVI M,0
- RET ;FINISHED
-
- GTFIL7 INX H ;POINT TO 1 PAST '.'
- LXI D,FCB+9 ;POINT TO 1ST EXT BYTE
- ;GET IST EXT CHR IN A
- JMP GTFIL5
- GTFIL8 LXI H,MUSICB+11H ;FILL BUFF WITH SPACES
- MVI C,0FH
- GTFIL9 MVI M,SPC ;LOAD SPACE IN BUFF
- DCX H
- DCR C ;COUNTER
- JNZ GTFIL9
- XCHG ;POINT TO BUFF WITH DE
- RET
- GETP DB CR,LF,HT,HT,'Type the name of the music file.'
- DB CR,LF,LF,LF,HT,HT,HT,HT,'$'
- ;--------------------------
- LOADFIL ;OPEN THE FILE IN FCB AND LOAD IT INTO
- ;MEMORY BUFFER AT ADDRESS MUSICB.
- LXI D,OPSTR
- CALL PRINT
- LXI D,FCB
- MVI C,15 ;OPEN FILE FCN
- CALL BDOS
- ADI 0FH ;CHECK IF A=255
- JC OPNER ;CAN NOT OPEN
- LXI H,FCB+32 ;CURRENT RECORD#
- MVI M,0 ;SET TO ZERO
- CALL CLSè CALL CURS
- LXI D,LDSTR
- CALL PRINT
- JMP LDFIL1
- OPSTR DB HT,HT,'Opening file.',CR,LF,'$'
- LDSTR DB HT,HT,'Loading music program.',CR,LF,'$'
- OPNERS DB HT,HT,'UNABLE TO OPEN FILE AS ENTERED.',CR,LF,'$'
- CLSTR DB HT,HT,'Closing file.',CR,LF,ES
- OPNER LXI D,OPNERS
- CALL PRINT
- POP H ;RETURN INST TO 'CALL LOADFIL'
- JMP CLGTFL ;GO TRY AGAIN (GETFIL)
- LDFIL1 LXI D,MUSICB ;SET DMA ADDRESS
- MVI C,1AH
- CALL BDOS
- LDFIL2 LXI D,FCB ;READ SEQUENTIAL INTO BUFF
- MVI C,14H ;20
- CALL BDOS
- ORA A ;IS A 0 RETURNED IN A?
- JZ LDFIL3 ;AINT FINISHED YET
- LXI H,LDFIL1+1 ;PREP FOR NEXT TIME
- LXI D,MUSICB ;DMA ADDRESS
- MOV M,E
- INX H
- MOV M,D
- CALL CLS
- CALL CURS
- LXI D,CLSTR
- CALL PRINT
- LXI D,FCB ;CLOSE FILE
- MVI C,16
- CALL BDOS
- CALL CLS
- CALL CURS
- RET ;FINISHED
- LDFIL3 LXI H,LDFIL1+1 ;GET LAST DMA ADDRESS
- MOV A,M
- INX H
- MOV D,M
- ADI 128 ;ADD SECTOR READ LENGTH TO DMA
- MOV E,A
- JNC LDFIL4
- INR D ;ADD CARRY TO HIGH BIT
- LDFIL4 LXI H,NDBUF ;TOP OF BUFFER
- MOV M,E
- INX H
- MOV M,D
- LXI H,LDFIL1+1 ;DMA ADDRESS
- MOV M,E
- INX H
- MOV M,D
- JMP LDFIL1 ;SET DMA ADDRESS @ GO AGAIN
- ;---------------------------
- ;
- TEMPO ;CALL FOR AND SET TEMPO COUNTERè ;FOR ONE BEAT
- CALL CLS
- CALL CURS
- ;TEMPO+6
- LXI D,TEMP1 ;ADDRESS OF PROMPT STRING
- MVI C,09H
- CALL BDOS ;PRINT IT
- TEMPO1 LXI H,TMPO+1 ;POINT TO STORE AREA
- LXI B,03H
- TEMPO2 MOV A,M
- CALL PUTCHR ;PRINT IT
- INX H
- DCR C ;PRINTED 3?
- JNZ TEMPO2
- LXI H,TMPO+1 ;POINT TO 1ST CHAR
- MVI C,3 ;3 TIMES
- TEMPO3 MVI A,BS ;BACKSPACE
- CALL PUTCHR ;SEND BACKSPACE
- DCR C
- JNZ TEMPO3 ;3 TIMES?
- ;SETS CURSOR AT HUNDREDS POSITION
- MVI C,3
- TEMPO4 CALL GETNUM
- ORA A ;IS IT A ZERO?
- JZ TEMPO5 ;FINISHED INPUT?
- MOV M,A
- INX H
- DCR C
- JNZ TEMPO4 ;GET ANOTHER CHAR
- ;FINISHED INPUT - CALCULATE @ PUT IN TMPO
- TEMPO5 LXI H,TMPO+1
- CALL TEMPOA
- XRA A
- TEMPO6 DCR C
- JM TEMPO7
- ADI 100
- JC TMPOER ;MAX VAL=256
- JMP TEMPO6
- TEMPO7 INX H ;POINT TO TENS
- CALL TEMPOA
- TEMPO8 DCR C
- JM TEMPO9
- ADI 10
- JC TMPOER ;MAX VAL=256
- JMP TEMPO8
- TEMPO9 INX H ;POINT TO ONES
- CALL TEMPOA
- TMPO10 DCR C
- JM TMPO11 ;VALUE COMPLETE
- INR A
- CPI 255
- JZ TMPO11 ;VALUE = 255
- JMP TMPO10
- TMPO11 LXI H,TMPO
- MOV M,A ;STORE ITè RET
- TEMPOA PUSH PSW
- MOV A,M ;GET NUMBER
- SUI 30H ;CONVERT TO BINARY
- JM ERROR ;NOT ASCII NUMBER
- MOV C,A
- POP PSW
- RET
- TMPOER LXI H,PSTAT ;PROGRAM STATUS
- MOV A,M
- ANI 80H ;CHECK BIT 7
- RNZ ;DO NOTHING DURING PLAY
- CALL CLS ;CLEAR SCREEN
- LXI D,TERMSG
- MVI C,PSTRING
- CALL BDOS
- JMP TEMPO+3
- TERMSG DB CR,LF,LF,LF,HT,HT,'The tempo must be a '
- DB 'number between 30 and 255.',CR,LF
- DB HT,HT,'Try one more time.$'
- TEMP1 DB HT,HT,'Enter the tempo of the desired song.'
- DB CR,LF,HT,HT,HT,HT,ES
- ;
- BEAT0 LXI H,TMPO ;GET TEMPO
- MOV A,M
- CPI 30H
- JNC BEAT1
- MVI A,30H
- BEAT1 LXI H,7530H ;2MS INT/MIN (30000)
- LXI D,0000H ;ZERO THE COUNTER
- MVI B,0 ;CLEAR D
- MOV C,A ;SUBTRACTOR IN DE
- BEAT2 ;DEVIDE BY SUCCESSIVE SUBTRACTION
- CALL SBCHB ;Z80 16BIT SBC HL,BC
- JC BEAT3 ;HL<0
- INX D ;SUBTRACTED (BC) TIMES
- ;WITHOUT CARRY
- JMP BEAT2 ;DO AGAIN
- BEAT3 LXI H,BEAT ;# INTERRUPTS/BEAT LOADED
- MOV M,E
- INX H
- MOV M,D
- CALL HOLNOT
- RET
- ;
- GETNUM ;GET A NUMBER
- CALL GETCHR
- CPI 08H ;DONT ACCEPT BACKSPACE
- JZ GTNUM3
- CPI 127 ;DONT ACCEPT DELETE
- JZ GTNUM3
- CPI 48 ;IS IT LESS THAN A NUMBER?
- JM GTNUM1
- CPI 58 ;IS IT GREATER THAN A NUMBER?
- JP GTNUM1è RET
- GTNUM1 CPI CR
- JZ GTNUM2
- MVI A,127 ;SEND A DELETE CHARACTER
- CALL PUTCHR ;SEND IT TO CONSOLE
- JMP GETNUM ;TRY AGAIN
- GTNUM2 MVI A,0
- RET
- GTNUM3 MVI A,20H ;SEND SPACE
- CALL PUTCHR
- JMP GETNUM
- ;----------------
- TRIAD ;START WITH VALUE IN DE FOR BEAT TIME
- ;RETURN 2/3 VALUE IN DE FOR TRIAD NOTES
- CALL SVFLPT
- XCHG ;HL=DE
- XRA A ;CLEAR PSW
- MOV D,A
- MOV E,A ;CLEAR DE
- MOV A,L ;HL=HL*2
- RAL
- MOV L,A
- MOV A,H
- RAL
- MOV H,A
- LXI B,03H ;DEVIDE BY 3
- TRIAD1 CALL SBCHB ;16 BIT SUBTRACT
- RC ;QUIT HL<0
- INX D ;ADD 1 TO DE
- JMP TRIAD1 ;DO AGAIN
- ;---------------
- ;PUT HOLE NOTE VALUE IN TIME1
- HOLNOT LXI H,BEAT ;GET 1 BEAT COUNT
- MOV E,M ;PUT IN DE
- INX H
- MOV D,M
- LXI H,BNOTE ;GET BEAT NOTE
- MOV B,M ;PUT IN B
- MOV A,M
- CPI '1'
- JZ HLNT1 ;DONE
- CALL SHFTDL ;SHIFT DE LEFT
- CPI '2'
- JZ HLNT1
- CALL SHFTDL ;NOT HALF NOTE
- CPI '4'
- JZ HLNT1
- CALL SHFTDL ;NOT QUARTER NOTE
- CPI '8'
- JZ HLNT1
- CALL SHFTDL ;NOT EIGHTH NOTE
- CPI '6'
- JZ HLNT1
- CALL SHFTDL ;NOT SIXTEENTH
- CPI '3'è JZ HLNT1
- JMP ERROR
- HLNT1 ;PUT VALUE IN TIME1
- LXI H,TIME1
- MOV M,E
- INX H
- MOV M,D
- RET
- ;------------------
- SHFTDL ;SHIFT DE LEFT 1 BIT
- PUSH PSW
- XRA A ;CLEAR CARRY
- MOV A,E
- RAL
- MOV E,A
- MOV A,D
- RAL
- MOV D,A
- POP PSW
- RET
- ;----------------
- NOTTIM ;GET SIXTEEN BIT COUNT FOR NOTE
- ;NOTE VALUE IN 'A' RTN VAL IN DE
- LXI H,TIME1
- MOV B,A ;SAVE ASCII NOTE
- MOV E,M ;GET WHOLE NOTE VAL
- INX H
- MOV D,M
- CPI '1'
- RZ ;NO CHANGE NECESSARY
- CALL SHFTDR ;SHIFT DE RIGHT
- CPI '2'
- RZ
- CALL SHFTDR
- CPI '4'
- RZ
- CALL SHFTDR
- CPI '8'
- RZ
- CALL SHFTDR
- CPI '6'
- RZ
- CALL SHFTDR
- RET
- ;-------------------------
- RDFIL ;READS NEXT FILE ENTRY BEGINNING AT
- ;LOCATION OF FILE POINTER 'FILPT'
- CALL GTFLPT
- MOV A,M
- CPI CR
- JNZ RDFIL0
- INX H
- INX H
- MOV A,M
- RDFIL0 CPI '$' ;END?è JZ QUIT
- CPI ',' ;IF ',' THEN SET PSG=1
- JZ NOTE0 ;AND CHANNEL=A
- CPI 27H ;IS IT QUOTE?
- JZ PRNT ;PRINT IT
- CPI '\'
- JZ RDFIL2
- CPI '1' ;IS IT AS LARGE AS A NUMBER?
- JM RDFIL2
- CPI '6'+1 ;6 OR LESS?
- JM NOTE1 ;SET CHIP=(A)
- ;PLAY NOTE
- CPI 'A'
- JM RDFIL2
- CPI 'C'+1 ;C OR LESS?
- JM NOTE0 ;SET CHIP=1
- ;PLAY NOTE
- CPI 'R'
- JZ REST0 ;REST
- CPI 'V'
- JZ VOICE0 ;PSG VOICE
- CPI 'M'
- JZ MSUR0 ;MEASURE
- CPI 'T'
- JZ TMP0 ;TEMPO
- CPI 'J'
- JZ JUMP0 ;JUMP TO MEASURE#
- CPI 'K'
- JZ JUMP8
- CPI 'L'
- JZ JUMP9
- CPI 'N'
- JZ JUMP10
- RDFIL1 CALL GTFLPT
- RDFIL2 MOV A,M
- CPI '\'
- JZ RDFIL3
- INX H
- JMP RDFIL2 ;THROW AWAY ALL TO '\'
- RDFIL3 INX H
- MOV A,M
- CPI '\'
- JZ RDFIL4
- CALL SVFLPT
- RET ;GO BACK TO MAIN PROGRAM
- RDFIL4
- DCX H
- CALL SVFLPT
- RET
- ;--------------------------
- TMP0 ;SETS NEW TEMPO WRITTEN INTO
- ;MUSIC WITH HL POINTING TO THE
- ;'T' FOLLOWING A '\'
- INX H
- MOV A,Mè CPI ' '
- JZ TMP0
- CPI ','
- JZ TMP0
- CPI '\'
- JZ RDFIL1 ;GO TO NEXT FILE ENTRY
- XCHG
- LXI H,TMPO+1 ;POINT TO BUFFER
- MOV M,A
- XCHG
- INX H
- MOV A,M ;GET 2ND BYTE
- CPI '\'
- JZ RDFIL1 ;ABORT
- XCHG
- INX H ;LOAD 2ND BYTE
- MOV M,A
- XCHG
- INX H
- MOV A,M ;GET 3RD BYTE
- CPI '\'
- CZ TMP1 ;LESS THAN 100
- XCHG
- INX H
- MOV M,A ;LOAD LAST BYTE
- CALL TEMPO5 ;COMPUTE 'TEMPO'
- CALL BEAT0 ;COMPUTE # INT/BEAT
- ;LOAD INTO BEAT
- ;PUT WHOLE NOTE
- ;VALUE INTO TIME1
- JMP RDFIL1 ;FINISHED
- DS 20H
- TMP1 XCHG ;POINT TO TMPO+2 (TENS)
- INX H ;POINT TO TMPO+3 (ONES)
- MOV M,A ;LOAD TENS
- LXI H,TMPO+1 ;GET 1ST BYTE (TENS)
- MOV A,M
- INX H ;PUT IT IN TENS POSITION
- MOV M,A ;WHERE IT BELONGS
- MVI A,'0' ;
- DCX H
- MOV M,A ;PUT ZERO IN TMPO+1 (HUNDREDS)
- INX H ;POINT TO TENS
- XCHG ;CONFIGUR FOR RETURN
- RET
- ;----------------------
- GTFLPT ;GET FILE POINTER (FILPT) WITH HL
- ;RETURNED WITH VALUE OF POINTER
- PUSH D
- LXI H,FILPT
- MOV E,M
- INX H
- MOV D,M
- XCHG
- POP Dè RET
- ;-----------------------
- SVFLPT ;SAVE FILE POINTER (FILPT) WITH HL
- ;POINTING TO LOCATION TO BE SAVED
- PUSH PSW
- PUSH B
- PUSH D
- XCHG
- LXI H,FILPT
- MOV M,E
- INX H
- MOV M,D
- XCHG
- POP D
- POP B
- POP PSW
- RET
- ;--------------------------
- DS 30H
- NOTE0 ;CHIP = #1
- DCX H ;SET HL AT ONE
- ;PRIOR TO CHANNEL #
- MVI A,'1' ;PSG #1
- NOTE1 CALL SVFLPT ;SAVE FILE POINTER
- CALL GTPRT ;SET PORT NUMBER
- CALL GTFLPT ;POINT TO CHANNEL #
- INX H
- MOV A,M
- CPI ','
- JNZ NOTE3
- NOTE2 DCX H ;SET POINTER JUST PRIOR
- ;TO NOTE VALUE
- MVI A,'A' ;LOAD DEFAULT CHANNEL #
- NOTE3 XCHG
- JMP TIMEUP ;CHECK IF CURRENT NOTE
- ;IS FINISHED
- NOTE3A MOV M,A
- XCHG
- NOTE4 INX H ;POINT TO CHANNEL# +1
- MVI C,0
- MOV A,M
- CPI ',' ;IS IT NOTE VALUE?
- JZ NOTE4
- ;GET AND PROGRAM CURRENT PSG CHANNEL
- ;FOR TONE COUNT
- CPI '\'
- JZ RDFIL1 ;ABORT
- CPI '0'
- JM RDFIL1 ;ABORT
- CPI '8'
- JP NOTE6 ;NOT A NUMBER
- SUI '0' ;CONVERT TO BINARY
- MOV C,A ;OCTAVE COUNTER IN C
- NOTE5 INX H ;LOOK AT NOTE
- MOV A,MèNOTE6 CALL SVFLPT
- CPI 'R' ;IS IT A REST?
- JZ NOTER
- CPI 'A'
- JM RDFIL1 ;ABORT-NOT NOTE
- LXI H,CNOTE ;POINT TO "C" VALUE
- CPI 'C'
- JZ NOTE7 ;LOAD VALUE
- CALL ADD6 ;INX H 6 TIMES
- CPI 'D'
- JZ NOTE7
- CALL ADD6
- CPI 'E'
- JZ NOTE7
- CALL ADD6
- CPI 'F'
- JZ NOTE7
- CALL ADD6
- CPI 'G'
- JZ NOTE7
- CALL ADD6
- CPI 'A'
- JZ NOTE7
- CALL ADD6
- CPI 'B'
- JZ NOTE7
- JMP RDFIL1 ;ABORT NOT NOTE
- NOTE7 ;CHECK IF SHARP OR FLAT
- XCHG ;SAVE NOTE ADDRESS IN DE
- CALL GTFLPT
- INX H ;POINT TO NOTE + 1
- MOV A,M
- CPI '#' ;CHECK IF SHARP
- JZ SHARP
- CPI '+'
- JZ SHARP
- CPI 'S'
- JZ SHARP
- CPI 'F' ;CHECK IF FLAT
- JZ FLAT
- CPI '-'
- JZ FLAT
- CPI 'B'
- JZ FLAT
- DCX H ;POINT TO NOTE
- NOTE8 ;GET TONE VAL AND CONVERT
- ;FOR PROPER OCTAVE
- CALL SVFLPT ;SAVE FILE POINTER
- XCHG ;POINT TO NOTE TABLE
- MOV E,M ;LOAD VAL IN DE
- INX H
- MOV D,M
- NOTE9 DCR C ;DEC OCTAVE COUNTER
- JM NOTE10
- MOV A,E ;SAVE LSBè CALL SHFTDR ;SHIFT DE RIGHT
- JMP NOTE9 ;
- NOTE10 ANI 01H ;IS RT BIT A '1'?
- JZ NOTE11
- INX D ;IF SO ADD 1 TO TONE
- NOTE11 ;PUT TONE VAL IN PSG FILE
- LXI H,CHNL
- MOV A,M ;PUT CHANNEL IN A
- PUSH D
- LXI H,REGIS
- MOV E,M
- INX H
- MOV D,M
- XCHG
- POP D
- CPI 'A' ;IS IT 'A' CHANNEL?
- JZ NOTE12
- INX H ;IF NOT POINT TO B
- INX H
- CPI 'B' ;'B' CHANNEL?
- JZ NOTE12
- INX H ;IF NOT POINT TO C
- INX H
- NOTE12 MOV M,E ;STORE LOW ORDER BYTE
- INX H
- MOV M,D ;STORE HIGH ORDER BYTE
- NOTET ;GET NOTE TIME VALUE AND SET IN PSG FILE AS
- ;A 16 BIT VALUE AT PSGRx+
- ;A CHANNEL 14
- ;B CHANNEL 17
- ;C CHANNEL 20
- CALL GTFLPT ;GET FILE POINTER
- INX H ;POINT TO TIMEVALUE
- MOV A,M
- CPI ','
- JNZ NOTT1 ;
- INX H
- NOTT1 MOV A,M
- CPI ',' ;IS IT SEPERATOR?
- JZ NOTETA
- CPI '/' ;IS IT SEPERATOR?
- JNZ NOTET0
- NOTETA MVI A,'4' ;DEFAULT TO QTR NOTE
- DCX H ;POINT BACK ONE
- CALL SVFLPT
- JMP NOTET1
- NOTET0 CPI '1'
- JM RDFIL1 ;ERROR-ABORT
- CPI '9'
- JP RDFIL1 ;ERROR
- CPI '5'
- JZ RDFIL1 ;ERROR
- CPI '7'
- JZ RDFIL1 ;ERROR
- NOTET1 CALL SVFLPT ;VALID NOTE DESIGNATOR IN A è CALL NOTTIM ;GET NOTE TIME
- CALL GTFLPT ;GET FILE POINTER
- INX H
- MOV A,M
- CPI ','
- JZ NOTETB
- CALL SVFLPT ;SAVE POINTER
- CPI '.' ;DOTTED NOTE
- CZ DOTNOT ;DE=DE*1.5
- CPI 'T' ;TRIAD
- CZ TRIAD ;DE=DE*2/3
- ;PUT NOTE VALUE IN DE INTO REGISTER
- NOTETB LXI H,CHNL ;GET CHANNEL
- PUSH D ;SAVE NOTE DWELL
- MOV C,M ;GET CHANNEL COUNTER
- LXI H,REGIS ;POINT TO REGISTER
- MOV E,M
- INX H
- MOV D,M
- XCHG ;POINTING TO PSGRx
- LXI D,14 ;ADD OFFSET TO CHANNEL A
- DAD D ;POINTING TO PSGRx+14
- POP D ;RESTORE VALUE
- MOV A,C
- CPI 'A' ;IS IT CHANNEL 'A'
- JZ NOTET2
- CALL ADD3
- CPI 'B'
- JZ NOTET2
- CALL ADD3
- NOTET2 MOV M,E ;PUT LOW BIT INTO
- INX H ;REGISTER FILE
- MOV M,D ;PUT HI BIT
- PUSH H ;SAVE PSGRx+ LOCATION
- ;CHECK FOR AND SET TIE BYTE
- CALL GTFLPT
- INX H ;LOOK AT NEXT BYTE
- MOV A,M ;FOR TIE '-'
- CPI '-'
- MVI A,1
- JZ NOTTA
- DCX H
- XRA A ;SEND 0 TO TIE BYTE
- NOTTA CALL SVFLPT
- POP H
- INX H
- MOV M,A ;SEND IT
- CALL GTFLPT
- JMP NOTE13
- NOTER CALL SVFLPT ;REST - CONTINUE
- JMP NOTET
- ;GET AND STORE AMPLITUDE VALUE
- NOTE13 INX H ;POINT TO NOTE+1
- MOV A,M
- CPI ','è JZ NOTE13 ;STEP AHEAD ONE
- CPI '\'
- JZ NOTE15 ;USE MODE CONTROL
- CPI '0' ;LESS THAN ZERO?
- JM NOTE16 ;USE DEFAULT
- CPI '9'+1 ;IS IT NUMBER?
- JM NOTE14 ;USE THE NUMBER
- CPI 'A' ;LESS THAN LETTER?
- JM NOTE16 ;WRONG, USE DEFAULT
- CPI 'F'+1
- JP NOTE15 ;>F SO SET MODE CONTROL
- SUI 55 ;CONVERT ASCII A-F
- ;TO HEX
- JMP NOTE18
- NOTE14 ;SET NUMBER VALUE IN A
- SUI '0' ;30H
- JMP NOTE18
- NOTE15 MVI A,1FH ;SET MODE CONTROL
- JMP NOTE18
- NOTE16 MVI A,08H ;USE DEFAULT VALUE
-
- NOTE18 ;PUT VALUE IN A INTO PSG CHANNEL
- PUSH PSW ;SAVE VALUE
- LXI H,CHNL
- MOV A,M ;GET CHANNEL NUMBER
- SUI 'A' ;CONVERT TO BINARY
- MOV C,A ;STORE IN COUNTER
- LXI H,REGIS
- MOV E,M ;GET LOW BYTE
- INX H
- MOV D,M ;GET HI BYTE
- XCHG ;POINT TO REG #
- CALL ADD6 ;POINT TO REG # +6
- INX H
- NOTE17 INX H ;POINT TO REG # +8
- DCR C
- JP NOTE17
- POP PSW
- MOV M,A ;PUT IT IN REG
- CALL PLAY ;PLAY THE NOTE
- JMP RDFIL1 ;
- ;-------------------------
- TIMEUP PUSH PSW ;SAVE ENVIRONMENT
- PUSH D
- LXI H,CHNL ;GET CHANNEL
- PUSH H ;SAVE FOR LATER
- MOV M,A ;PUT CHANNEL IN A
- LXI H,REGIS ;LOAD PSGRx IN DE
- MOV E,M
- INX H
- MOV D,M
- LXI H,14 ;ADD OFFSET TO 1ST CHAN
- DAD D ;TIME @ STORE IN HL
- SUI 'A'-1 ;CONVERT TO BINARY 1,2,3
- TMUP1 DCR Aè JZ TMUP2
- CALL ADD3 ;POINT TO NEXT CHAN TIME
- JMP TMUP1
- TMUP2 MOV A,M ;GET FINE TIME TO GO
- INX H
- MOV D,M ;COARSE TIME TO GO
- ORA D ;LAST NOTE FINISHED?
- JNZ TMUP3 ;NOT FINISHED
- POP H
- POP D
- POP PSW
- JMP NOTE3A ;GO BACK AND PLAY
- TMUP3 POP H
- POP D
- POP PSW
- CALL GTFLPT
- TMUP4 MOV A,M ;SET FILPT AT '\' AND RTN
- CPI '\'
- JZ RDFIL2
- DCX H
- JMP TMUP4 ;DO AGAIN
- ;------------------------
- SETUP ;ZEROS PSG WORKING REGISTER
- LXI H,PSGR1
- CALL SETUP0
- LXI H,PSGR2
- CALL SETUP0
- LXI H,PSGR3
- CALL SETUP0
- LXI H,PSGR4
- CALL SETUP0
- LXI H,PSGR5
- CALL SETUP0
- LXI H,PSGR6
- CALL SETUP0
- RET
- SETUP0 XRA A ;CLEAR A
- MVI C,1EH
- SETUP1 MOV M,A
- INX H
- DCR C
- JNZ SETUP1
- RET
- ;------------------------
- DOTNOT ;START WITH 16 BIT TIME VALUE IN DE
- ;RETURN DE*1.5 IN DE
- CALL SVFLPT
- PUSH PSW
- PUSH D ;SAVE VALUE
- CALL SHFTDR ;DEVIDE BY TWO
- POP H
- MOV A,L
- ADD E
- MOV E,A ;RESULT IN E
- MOV A,Hè ADC D ;ADD WITH CARRY
- MOV D,A
- POP PSW ;RESTORE A
- RET
- ;------------------------
- ADD6 CALL ADD3
- CALL ADD3
- RET
- ADD3 INX H
- INX H
- INX H
- RET
- ;---------------------------
- CFNOTE DW 4146 ;PSG TONE TABLE
- CNOTE DW 3914
- CSNOTE DW 3694
- DFNOTE DW 3694
- DNOTE DW 3487
- DSNOTE DW 3291
- EFNOTE DW 3291
- ENOTE DW 3107
- ESNOTE DW 2932
- FFNOTE DW 3107
- FNOTE DW 2932
- FSNOTE DW 2768
- GFNOTE DW 2768
- GNOTE DW 2612
- GSNOTE DW 2466
- AFNOTE DW 2466
- ANOTE DW 2327
- ASNOTE DW 2197
- BFNOTE DW 2197
- BNOTEE DW 2073
- BSNOTE DW 1957
- ;--------------------------
- REST0
- JMP RDFIL1
- MSUR0
- JMP RDFIL1
- ;------------------------------
- SHARP
- INX D
- INX D
- JMP NOTE8
- FLAT
- DCX D
- DCX D
- JMP NOTE8
- ;------------------------------
- VOICE0 ;SEND UPDATE TO PSGRx VOICING
- INX H ;POINT TO PSG# IN FILE
- MOV A,M
- CALL SVFLPT
- CALL GTPRT ;GET THE PORT #
- LXI H,PORTè MVI A,0
- CMP M
- JZ RDFIL1 ;THROW AWAY IF PORT=0
- CALL GTFLPT
- INX H ;POINT TO VOICE
- MOV A,M
- SUI 'A'
- JM RDFIL2 ;WRONG VOICE SELCTED
- MOV C,A ;AND PUT IN C
- INR C
- ;---------------------------
- ;NUMBER OF VOICES AVAILABLE IN PROGRAM SET HERE
- CPI 26 ;# OF OPTIONS AVAILABLE
- ;---------------------------------
- JP RDFIL2
- INR A
- LXI D,0005H ;# OF BYTES IN VOICEx
- LXI H,VOICEA
- VOICE1 DCR C ;ADD TO SELECTED VOICE
- JZ VOICE2
- DAD D ;POINT TO NEXT VOICE
- JMP VOICE1
- VOICE2 ;HL=VOICEx ADDRESS SEND VOICING
- ;TO PSGRx AND TO PORT
- PUSH H ;SAVE VOICE ADDRESS
- LXI H,REGIS ;GET PSGRx INTO DE
- MOV E,M
- INX H
- MOV D,M
- XCHG ;POINT WITH HL
- CALL ADD6 ;POINT TO PSGRx+6
- POP D ;GET VOICEx ADD
- XCHG ;POINT TO VOICEx IN HL
- MVI A,6
- CALL VOICE3
- CALL LDI
- MVI A,7 ;SEND TO REG #7
- CALL VOICE3
- CALL LDI
- INX D
- INX D
- INX D ;POINT TO PSGRx+11
- MVI A,11 ;SEND TO REG #11
- CALL VOICE3
- CALL LDI
- MVI A,12 ;SEND TO REG #12
- CALL VOICE3
- CALL LDI
- MVI A,13 ;SEND TO REG #13
- CALL VOICE3
- CALL LDI
- JMP RDFIL1
- VOICE3 CALL OUTP ;SET UP PORT
- MOV A,M ;GET VAL FROM VOICEx+REG #
- CALL OUTP2 ;SEND ITè RET
- ;-----------------------------
- DS 1FH
- JUMP ;MOVES FILE POINTER TO MEASURE MARKED AS THE
- ;JUMP NUMBER TO REPLAY PORTIONS ACCORDING TO
- ;THE FOLLOWING J=JUMP EACH TIME
- ;K=JUMP ONE TIME (CHANGE K TO O)
- ;L=JUMP ALTERNATE TIMES (CHANGE L TO N)
- ;N=DONT JUMP (CHANGE N TO L)
- JUMP0 INX H ;POINT TO ONE PAST LETTER
- MOV A,M
- CPI '\' ;IS IT SEPERATOR
- JZ RDFIL1 ;ABORT
- CPI '0' ;IS IT LESS THAN 0?
- JM JUMP0 ;TRY NEXT ONE
- CPI '9'+1 ;IS IT > 9?
- JP RDFIL2 ;NOT NUMBER OR SEPERATOR
- CALL SVFLPT ;POINT TO FIRST NUMBER
- LXI H,MUSICB
- JUMP1 MVI A,'\' ;FIND FIRST SEPERATOR
- CMP M
- JZ JUMP2
- INX H
- JMP JUMP1+2
- JUMP2 INX H ;FIRST AFTER \
- MVI A,'M' ;FIND MEASURE MARKER
- JUMP2A CMP M
- JZ JUMP3
- INX H
- JMP JUMP2A
- JUMP3 INX H ;POINT TO FIRST NUMBER
- MOV A,M ;IS IT LESS THAN 0?
- CPI '0'
- JM JUMP2+1
- CPI '9'+1 ;IS IT > A NUMBER
- JP JUMP2+1 ;1;
- ;NOW POINTING TO FIRST NUMBER AFTER 'M'
- XCHG ;POINT TO MUSIC BUFFER WITH D
- JUMP4 CALL GTFLPT ;BEGIN TO MATCH NUMBER
-
- JUMP5 ;POINT TO 1ST NUMBER
- LDAX D ;GET BUFFER NUMBER
- CMP M ;COMPARE WITH MEASURE #
- JZ JUMP6
- XCHG
- JMP JUMP2
- JUMP5A INX H
- INX D
- JMP JUMP5 ;CHECK NEXT NUMBER FOR MATCH
- JUMP6 MVI A,'\' ;IS IT PAST NUMBER?
- CMP M
- JZ JUMP7
- JMP JUMP5A
- ;LOOK FOR NEXT 'M'
- JUMP7 XCHG ;POINT TO NEW FILPT WITH Hè CALL SVFLPT ;PUT NEW-FOUND MEASURE
- ;INTO FILE POINTER
- JMP RDFIL2 ;RETURN
- JUMP8 MVI M,'O'
- JMP JUMP0
- JUMP9 MVI M,'N'
- JMP JUMP0
- JUMP10 MVI M,'L'
- JMP RDFIL2
- ;-------------------------
- QUIT ;END OF MUSIC FILE.
- CALL CLS
- LXI D,QTMSG
- MVI C,PSTRING
- CALL BDOS
- JMP 0000H
- QTMSG DB LF,LF,HT,HT,'END OF MUSIC FILE',LF,LF,ES
- ;------------------------
- SHFTDR ;SHIFT DE RIGHT 1 BIT
- PUSH PSW
- XRA A ;CLEAR CARRY
- MOV A,D
- RAR
- MOV D,A
- MOV A,E
- RAR
- MOV E,A
- POP PSW
- RET
-
- ;----------------
- GETCHR PUSH H ;READ NEXT CONSOLE CHARACTER TO A
- PUSH D
- PUSH B
- MVI C,CONIN
- CALL BDOS
- POP B
- POP D
- POP H
- RET
- ;-------------------
- PUTCHR PUSH H ;WRITE NEXT CONSOLE CHARACTER TO A
- PUSH D
- PUSH B
- MVI C,CONOUT
- MOV E,A ;CHARACTER TO SEND
- CALL BDOS
- POP B
- POP D
- POP H
- RET
- CRLF ;SEND CARRIAGE RETURN LINE FEED
- MVI A,CR ;CARRIAGE RETURN
- CALL PUTCHR
- MVI A,LF ;LINE FEEDè CALL PUTCHR
- RET
- PRINT ;PRINT THE BUFFER ADDRESSED BY DE UNTIL $
- PUSH D
- CALL CRLF
- POP D ;NEW LINE
- MVI C,PSTRING
- CALL BDOS ;PRINT THE STRING
- RET
- READ ;READ THE CONSOLE STRING
- MVI C,RSTRING
- CALL BDOS ;GET THE STRING
- RET
- ;------------------------
- UCCV ;UPPER CASE CONVERSION
- CPI 97 ;COMPARE WITH "a"
- RM ;NOT LOWER CASE
- CPI 123 ;COMPARE WITH ("z"+1)
- RP ;NOT LOWER CASE
- SUI 32 ;CONVERT TO UPPER CASE
- RET
- ;-----------------------
- CLS ;H19 CLEAR SCREEN
- PUSH H ;SAVE ENVIRONMENT
- PUSH B
- PUSH D
- LXI D,CSI ;SET ADDRESS OF CLEAR STRING
- MVI C,09H ;PRINT STRING
- CALL BDOS
- POP D
- POP B
- POP H
- RET
- CSI DB 27,'E$' ;MSG TO CLEAR SCREEN
- ;-------------------------
- CURS LXI D,STCUR ;SET CURSOR TO CENTER SCREEN
- MVI C,09H ;PRINT STRING FCN
- CALL BDOS
- RET
- STCUR DB 27,'Y',40,32,'$'
- DS 40 ;20 LEVEL STACK
- STACK
- ;----------------------------------------------------------
-
- LDI ; MEMORY TO MEMORY TRANSFER WITH AUTO INCREMENT
- ; OF MEMORY POINTER REGISTERS AND AUTO DECREMENT
- ; OF A BYTE COUNT REGISTER PAIR (AS Z80 OP CODE)
- DI
- MOV A,M
- STAX D ;MEMORY TRANSFER COMPLETE
- INX H
- INX D
- DCX B
- EI
- RETè
- ;--------------------------------------------------
- SBCHB ;16 BIT SUBTRACT W CARRY (SBC HL,BC)
- XRA A
- MOV A,L
- SUB C ;SUB C FROM L
- MOV L,A
- MOV A,H
- SBB B ;SUBTRACT WITH BORROW
- ;B FROM H
- MOV H,A
- RET
- ;------------------------------------------------
- ;SAME AS Z80 OP CODE OF SAME NAME (SEE LDI)
- LDIR CALL LDI
- MOV A,C
- ORA B
- RZ
- JMP LDIR
-
- ;--------------------------------------------------
-
- LDD DI ;(Z80 OP CODE EQUIVALENT)
- MOV A,M
- STAX D
- DCX H
- DCX D
- DCX B
- EI
- RET
- ;
- LDDR CALL LDD ;(Z80 OP CODE EQUIVALENT)
- MOV A,C
- ORA B
- RZ
- JMP LDDR
- ;---------------------------------------------
- OUTC ;Z80 OP ( OUT A,(C) ) SENDS
- ;CONTENTS OF A TO PORT SPECIFIED
- ;IN REGISTER C
- PUSH H
- LXI H,OUTC+6 ;SELF-MODIFYING CODE
- MOV M,C
- OUT 00H ;PORT MODIFIED
- POP H
- RET
- ;------------------------
- PAUSE LXI D,PAUS1 ;STOP FOR A WHILE
- CALL PRINT
- LXI D,PAUS2
- CALL READ
- RET
- PAUS1 DB CR,LF,'Enter RETURN to continue.',CR,LF,'$'
- PAUS2 DS 0FH
- ;-------------------------èINSTR1 DB HT,HT,'Press the following keys for the function desired.'
- DB CR,LF,LF,HT,HT,'P',HT,HT,'Play again',CR,LF
- DB HT,HT,'T',HT,HT,'Change tempo and play again',CR,LF
- DB HT,HT,'S',HT,HT,'Play another song',CR,LF
- DB HT,HT,'Q',HT,HT,'Quit',CR,LF,LF,HT,HT,'**************'
- DB '*******************',CR,LF,LF,'$'
- ;_________________________
- PRNT INX H ;PRINT WORDS TO TERMINAL
- MOV A,M
- CPI '\' ;FINISHED?
- JNZ PRNT1
- JMP RDFIL2
- PRNT1 MVI C,2
- MOV E,A
- PUSH H
- CALL BDOS
- POP H
- JMP PRNT
- ;-------------------------
- MUSICB DS 0FH
- END