; ;MUSIC4 ; MUSIC PLAYING PROGRAM USING STORED ;WAVEFORM AND OUTPUT TO AN 8 BIT DAC ;SEPARATE WAVEFORMS FOR EACH VOICE AT WAVE1, WAVE2 ETC. ;WAVEFORMS ARE ASSEMBLED BY A BASIC PROGRAM WHICH ;IS CALLED AWAVE. THIS PROGRAM ;OUTPUTS AN ASM FILE WHICH IS INPUT TO ASM PRODUCING ;A HEX FILE WHICH LOAD MAKES INTO A COM FILE ;TO BE USED BY MUSIC4. ;TUNES ARE PUT TOGETHER SIMILARLY BUT WITH ANOTHER ;BASIC PROGRAM CALLED NOTES. ; APORT EQU 5 ;ANALOG OUTPUT PORT INIT ORG 100H XRA A OUT 79H CMA OUT 78H MVI A,4 OUT 79H LXI SP,STACK SINON LXI H,INTRO CALL TXTYP CONTROL LXI H,PROMPT CALL TXTYP ;PUT PROMPT MSG ON CONSOLE CALL CI PUSH PSW CALL CRLF POP PSW CPI 'T' ;LOAD A TUNE FILE JZ TUNIN CPI 'W' ;LOAD A WAVE FORM JZ WAVIN CPI 'Q' ;QUIT...BACK TO CP/M JZ 0 CPI 'S' ;SET TEMPO JZ SETEM CPI 'M' ;MOVE UP OR DOWN SCALE JZ MOVE CPI 'P' ;PLAY THE TUNE JNZ SINON ;IF NOT L OR P OR Q ASK AGAIN START DB 0DDH,21H ;LD IX,TUNE DW TUNE NEXT LXI H,0 SHLD V1PT ;INITIALIZE POINTERS SHLD V2PT SHLD V3PT SHLD V4PT MVI H,NOTES/256 ;PAGE FOR NOTES TABLE DB 0DDH,7EH,0 ;LD A,(IX) ORA A JZ ENDTUN STA DUR DB 0DDH,23H ;INC IX DB 0DDH,7EH,0 ;LD A,(IX) MOV L,A MOV B,M INX H MOV C,M DB 0DDH,23H ;INC IX DB 0DDH,7EH,0 ;LD A,(IX) MOV L,A MOV D,M INX H MOV E,M DB 0D9H ;EXX DB 0DDH,23H ;INC IX DB 0DDH,7EH,0 ;LD A,(IX) MVI H,NOTES/256 ;PAGE FOR NOTES TABLE MOV L,A MOV B,M INX H MOV C,M DB 0DDH,23H ;INC IX DB 0DDH,7EH,0 ;LD A,(IX) MOV L,A MOV D,M INX H MOV E,M DB 0DDH,23H ;INC IX DB 0D9H ;EXX TON1 MVI A,64 STA TEMCT TON2 LHLD V1PT DAD B SHLD V1PT MOV L,H MVI H,WAVE1/256 MOV A,M LHLD V2PT DAD D SHLD V2PT MOV L,H MVI H,WAVE2/256 ;PAGE FOR 2ND VOICE ADD M DB 0D9H ;EXX FOR Z-80 DB 08H ;EX AF,AF' FOR Z-80 LHLD V3PT DAD B SHLD V3PT MOV L,H MVI H,WAVE3/256 ;PAGE FOR 3RD VOICE ADD M LHLD V4PT DAD D SHLD V4PT MOV L,H MVI H,WAVE4/256 ;PAGE FOR 4TH VOICE ADD M OUT APORT DB 0D9H ;EXX FOR Z-80 LXI H,TEMCT DCR M ;TEMPO COUNT JNZ TON2 LXI H,DUR DCR M ;DURATION COUNT JNZ TON1 JMP NEXT ; ENDTUN CALL CSTS ;CHECK IF ANY KB ENTRY JZ AGAIN CALL CI ;GET CHAR FROM CONSOLE CPI 3 ;CONTROL C JZ 0 ;BACK TO CP/M CPI 1BH ;"ESCAPE" JZ CONTROL AGAIN LXI B,0 ;WAIT A WHILE BEFORE AG1 DCR B ;STARTING TO PLAY JNZ AG1 ;THE TUNE AGAIN DCR C JNZ AG1 JMP START ;SET TEMPO FASTER OR SLOWER ;+ IS FASTER...- IS SLOWER..ARG. IS DECIMAL 2 DIGITS SETEM LXI H,SETMS CALL TXTYP CALL TXTIN ;USE CP/M IO TO GET LINE CALL CRLF LXI H,CONBUF+2 ;FROM CONSOLE MOV A,M CPI '+' ;FASTER JZ UPTEM CPI '-' ;SLOWER JNZ SETER ;MUST EITHER + OR - CALL DECBI ;CONVERT 2 DEC TO BINARY LXI H,TEMPO ADD M MOV M,A JMP CONTROL ;DONE...ASK FOR ANOTHER UPTEM CALL DECBI ;CONVERT DECIMAL TO BINARY LXI H,TEMPO CMA ADD M MOV M,A JMP CONTROL ;FINISHED...ASK FOR NEXT ;MOVE ALL NOTES IN TUNE UP OR DOWN THE SCALE MOVE LXI H,MOVMS CALL TXTYP CALL TXTIN CALL CRLF LXI H,CONBUF+2 MOV A,M ;FIRST CHAR OF INPUT CPI '+' ;MOVE UP JZ UP CPI '-' ;MUST BE EITHER + OR - JNZ MOVER CALL DECBI ;CONVERT INCREMENT TO BINAY RAL ;TWO BYTES PER STEP, SO *2 CMA ;MOVE DOWN, SO SUBTRACT MOV B,A ;SAVE FOR LATER USE JMP MOVAL UP CALL DECBI ;SAME AS ABOVE MOV B,A ;BUT ADDED TO MOVE UP MOVAL LXI H,TUNE MOV1 INX H ;BYPASS TIME BYTE MVI C,4 ;4 NOTES EACH LINE MOV2 MOV A,M ;GET NOTE ORA A JZ OK ;REST, SO DON'T MESS WITH IT ADD B ;ADD OR SUB INCREMENT CPI 131 ;RANGE CHECK JC OK ;MAX IS 130 XRA A ;SET TO 0 (REST) OK MOV M,A ;PUT IT BACK IN TUNE INX H DCR C ;DO 4 NOTES JNZ MOV2 MOV A,M ;NEXT TIME ORA A ;SET FLAGS JNZ MOV1 ;ZERO IS END JMP CONTROL MOVER LXI H,MVRMS CALL TXTYP JMP CONTROL ;CONVERT 2 ASCII DIGITS TO BINARY ;RETURN WITH VALUE IN A DECBI INX H MOV A,M CPI '0' JC SETER CPI '9'+1 JNC SETER SUI '0' MOV B,A INX H MOV A,M CPI '0' JC FINI CPI '9'+1 JNC FINI SUI '0' MOV C,A MOV A,B RAL MOV B,A RAL RAL ADD B ADD C RET FINI MOV A,B RET SETER LXI H,SERMS CALL TXTYP JMP CONTROL ;WAVE FORM INPUT WAVIN CALL INIR ;OPEN THE FILE LXI H,WAVE1 ;PUT IT HERE JMP FILP ;SAME AS FOR LOADING TUNE ;TUNE INPUT ROUTINE TUNIN CALL INIR ;OPEN FILE CALL GBYT ;GET FIRST BYTE FOR TEMPO STA TEMPO LXI H,TUNE FILP CALL GBYT ;GET A BYTE FROM FILE JC CONTROL MOV M,A INX H JMP FILP ;DO UNTIL EOF ;GET CHAR FROM CONSOLE CI PUSH H! PUSH D! PUSH B MVI C,1 CALL BDOS POP B! POP D! POP H RET ;OUTPUT CAR RET AND LINE FEED TO CONSOLE CRLF PUSH H LXI H,CRST CALL TXTYP POP H RET CRST DB CR,LF,'$' ;TYPE A LINE OF TEXT ON CONSOLE TXTYP PUSH H! PUSH D! PUSH B XCHG MVI C,9 CALL BDOS POP B POP D POP H RET ;INPUT A LINE OF TEXT FROM CONSOLE TXTIN PUSH H! PUSH D! PUSH B LXI D,CONBUF+65 MVI C,65 ;CLEAR BUFFER TO SPACES MVI A,' ' TXTN1 STAX D DCX D DCR C JNZ TXTN1 MVI C,10 CALL BDOS POP B! POP D! POP H RET ;OPEN FILE OPENF LXI D,INFCB MVI C,15 ;CPM FUNCTION FOR OPEN CALL BDOS CPI 255 ;FAILED TO OPEN IF = 255 CMC RNZ LXI H,NOFMS ;FILE NOT FOUND MSG CALL TXTYP STC RET NOFMS DB 'FILE NOT FOUND',CR,LF,'$' CMDMSG DB 'TYPE COMMAND',CR,LF DB 'T - LOAD TUNE',CR,LF DB 'W - LOAD WAVEFORMS',CR,LF DB 'P - PLAY TUNE',CR,LF DB 'Q - QUIT (TO CP/M)',CR,LF,'$' ;GET A CHARACTER FROM DISK FILE GBYT PUSH H CALL DISKIN ;LIB ROUTINE TO GET BYTE POP H ; FROM DISK FILE RET ;INITIALIZE TO READ DISK FILE INIR LXI H,GREET CALL TXTYP CALL TXTIN CALL CRLF LXI H,CONBUF+2 ;+2 FOR COUNTS LXI D,INFCB ; A LA CP/M FORMAT CALL MTFCB ;LIB ROUTINE TO MAKE FCB JC INIR ;ERROR, TRY AGAIN CALL OPENF ;FCB OK, OPEN IT JC INIR ;ERROR, TRY AGAIN LXI H,INBUF+128 ;INIT. FOR DISKIN SHLD INPTR RET GREET DB 'ENTER FILE NAME ',0DH,0AH,'$' ;TEST FOR ABORT (CNTRL C) ABTST CALL CI CPI 3 RNZ ;NOPE JMP RESTRT ;RETURN TO CP/M ;CONSOLE STATUS CHECK...RETURNS A NON-ZERO ; IF KEY PRESSED AT CONSOLE CSTS PUSH H! PUSH D! PUSH B MVI C,11 CALL BDOS ORA A POP B! POP D! POP H RET ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; MAKE CP/M FILE CONTROL BLOCK ; ; MAKEFCB.LIB - VERSION 0.2 - 28 OCT 77 ; ; JEFFREY W. SHOOK ; P.O. BOX 185 ; ROCKY POINT, NEW YORK 11778 ; (516) 744 7133 ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; CREATE A CP/M FILE CONTROL BLOCK FROM ; A COMMAND STRING AT THE ADDRESS IN HL ; AND PLACE IT AT THE ADDRESS IN DE. RETURN ; WITH THE CARRY SET IF AN ERROR OCCURS. ; DEFINITIONS FCBSIZ: EQU 33 FNMLEN: EQU 11 ; FILE NAME LENGTH MTFCB: PUSH H ; SAVE CMD STRING PTR PUSH D ; SAVE FCB ADDRESS LXI B,FCBSIZ; CLEAR ENTIRE FCB AREA MVI A,0 ; CALL FILLB ; POP D ; FILL FILE NAME WITH SPACES PUSH D ; INX D ; LXI B,FNMLEN; MVI A,' ' ; CALL FILLB ; POP D ; RESTORE POINTERS POP H ; CALL SKIPS ; SKIP LEADING SPACES INX H ; CHECK FOR DISK CODE MOV A,M ; DCX H ; CPI ':' ; JNZ MTFCB1 ; JUMP ON NO CODE MOV A,M ; TEST IF DISK CODE GOOD INX H ; INX H ; SBI '@' ; RC ; MAKE ERROR RETURN IF BAD CPI 'Z'+1 ; CMC ; RC ; STAX D ; STORE DISK CODE AT FCB + 0 MTFCB1: INX D ; MVI C,8 ; PROCESS FILE NAME FIELD CALL GETNAM ; MOV A,M ; TEST FOR FILE TYPE SEPARATOR INX H ; CPI '.' ; JNZ MTFCB2 ; MVI C,3 ; PROCESS FILE TYPE FIELD CALL GETNAM ; MOV A,M ; INX H ; MTFCB2: CALL TERMT ; TEST FOR CORECT TERMINATOR RET ; PROCESS NAME FIELD GETNAM: MOV A,M ; GET CHAR FROM CMD STR INX H ; CPI '?' ; ALLOW AMBIG REFERENCE CHAR JZ GETNA1 ; CPI '*' ; FILL REST WITH ? JZ GETNA2 ; CALL VALCHR ; TEST FOR ALLOWED CHAR IN NAME JC GETNA3 ; GETNA1: STAX D ; STORE CHAR IN TFCB INX D ; DCR C ; CHECK NAME SIZE JNZ GETNAM ; RET ; GETNA2: MVI A,'?' ; FILL REST OF FIELD WITH ? MVI B,0 ; JMP FILLB ; GETNA3: INX D ; MOVE FCB PTR TO END OF FIELD DCR C ; JNZ GETNA3 ; DCX H ; RET ; ; TEST FOR VALID CHAR IN NAME FIELD ; RETURN WITH CARRY SET IF INVALID. VALCHR: CPI '*' CMC RZ CPI ',' CMC RZ CPI '.' CMC RZ CPI ' ' RC CPI '^'+1 CMC RC CPI ':' CMC RNC CPI '@' RET ; TEST FOR VALID FILENAME TERMINATOR CHAR ; RETURN WITH CARRY SET IF INVALID. TERMT: CPI ' ' RZ CPI ',' RZ CPI CR RZ CPI ';' RZ STC RET ; SKIP SPACES IN CMD STRING SKIPS: MVI A,' ' SKIPS1: CMP M RNZ INX H JMP SKIPS1 ; FILL BLOCK WITH VALUE ; ENTER WITH: ; A = VALUE FOR FILL ; DE = START OF BLOCK ; BC = LENGTH OF BLOCK CLRB: MVI A,0 FILLB: INR B DCR B JNZ FILLB1 INR C DCR C RZ FILLB1: STAX D INX D DCX B JMP FILLB ;++++++++++++++++++++++++++++++++++++++++++++++ ; ; SEQUENTIAL DISK CHARACTER INPUT ; ; DISKIN.LIB - VERSION 1.0 - 18 SEP 77 ; ; J.W. SHOOK, P.O. BOX 185, ROCKY POINT, NY 11778 ; ;++++++++++++++++++++++++++++++++++++++++++++++ ; BEFORE READING A FILE SEQUENTIALLY ; THE FOLLOWING INITIAL CONDITIONS ; MUST BE ESTABLISHED. ; 1) A CP/M FILE CONTROL BLOCK ; CONTAINING THE FILE NAME MUST ; START AT LOCATION INFCB. ; 2) A 128 BYTE BUFFER AREA MUST ; START AT LOCATION INBUF. ; 3) THE FILE MUST BE SUCCESSFULLY ; OPENED. ; 4) THE NEXT RECORD POINTER IN ; THE FILE CONTROL BLOCK MUST BE ; SET TO ZERO. ; 5) THE WORD AT LOCATION INPTR ; MUST BE SET TO INBUF+128 TO ; MARK THE BUFFER AS EMPTY. ; 6) TO READ A FILE AGAIN, JUST SET ; NEXT RECORD TO ZERO, AND ; RESET INPTR. ; READ CHARACTER FROM FILE DISKIN: LHLD INPTR ; TEST BUFFER POINTER LXI D,-(INBUF+128) DAD D MOV A,H ORA L CZ RDREC ; IF EMPTY, READ NEXT RECORD RC ; RETURN ON BAD READ LHLD INPTR ; GET CHAR FROM BUFFER MOV A,M INX H ; MOVE BUFFER POINTER SHLD INPTR RET SETMS DB 'TYPE +OR-NN...+ FASTER...NN IN DECIMAL$' SERMS DB 'ERROR...TEMPO UNCHANGED',CR,LF,'$' MOVMS DB 'TYPE +OR-NN...+ UP SCALE...NN DECIMAL$' MVRMS DB 'ERROR...TUNE UNCHENGED',CR,LF,'$' INTRO DB 'MUSIC PLAYING PROGRAM COMMANDS',CR,LF DB 'W...LOAD A WAVEFORM',CR,LF DB 'T...LOAD A TUNE',CR,LF DB 'S...SET TEMPO FASTER OR SLOWER',CR,LF DB 'M...MOVE TUNE UP OR DOWN SCALE',CR,LF DB 'P...PLAY THE TUNE',CR,LF DB 'Q...QUIT-TO CP/M',CR,LF,'$' PROMPT DB 'COMMAND?...$' ; REFILL DISK INPUT BUFFER RDREC: LXI D,INBUF ; SET DMA ADDRESS MVI C,SDMA CALL BDOS LXI D,INFCB ; READ A RECORD MVI C,READ CALL BDOS RAR ; SET CARRY ON BAD READ LXI H,INBUF ; SET POINTER TO BUFFER START SHLD INPTR RET ;DEFINE VARIABLES TEMPO EQU TON1+1 ;LOADED BY TUNIN ROUTINE RESTRT EQU 0 ;CPM REBOOT BDOS EQU 5 ;CP/M ENTRY FOR I/O READ EQU 20 ;CP/M READ NEXT RECORD FUNCTION SDMA EQU 26 ;CP/M SET DMA ADDRESS FUNCTION CR EQU 13 LF EQU 10 INBUF DS 128 ;DISK FILE INPUT BUFFER INFCB DS 33 ;FILE CONTROL BLOCK CONBUF DB 64 ;CONSOLE INPUT BUFFER DB 0 DS 64 INPTR DS 2 ;POINTER FOR DISKIN0V DS 32 STACK ; V1PT DW 0 V2PT DW 0 V3PT DW 0 V4PT DW 0 DUR DS 1 INC1 DS 2 INC2 DS 2 INC3 DS 2 INC4 DS 2 TEMCT DS 1 ; ;TABLE OF INCREMENTS FOR EACH NOTE. 2 BYTE ENTRIES ; ; ID NOTE FREQ INCR NOTES ORG 256*($/256+1) ;MUST BE ON PAGE BOUNDARY DB 0,0 ;0 REST 0 0 DB 0,244 ;2 C1 32.702 .95445 DB 1,3 ;4 C1# 34.647 1.0112 DB 1,18 ;6 D1 36.647 1.07135 DB 1,35 ;8 D1# 38.891 1.13505 DB 1,52 ;10 E1 41.204 1.20255 DB 1,70 ;12 F1 43.654 1.27405 DB 1,90 ;14 F1# 46.249 1.3498 DB 1,110 ;16 G1 48.999 1.43005 DB 1,132 ;18 G1# 51.915 1.5151 DB 1,155 ;20 A1 55.000 1.6070 DB 1,179 ;22 A1# 58.270 1.70065 DB 1,205 ;24 B1 61.735 1.80175 DB 1,233 ;26 C2 65.405 1.9089 DB 2,6 ;28 C2# 69.295 2.0224 DB 2,37 ;30 D2 73.415 2.1427 DB 2,69 ;32 D2# 77.783 2.2701 DB 2,104 ;34 E2 82.408 2.4051 DB 2,140 ;36 F2 87.308 2.5481 DB 2,179 ;38 F2# 92.498 2.6996 DB 2,220 ;40 G2 97.998 2.8601 DB 3,8 ;42 G2# 103.83 3.0302 DB 3,54 ;44 A2 110.00 3.2104 DB 3,103 ;46 A2# 116.54 3.4013 DB 3,154 ;48 B2 123.47 3.6035 DB 3,209 ;50 C3 130.81 3.8178 DB 4,11 ;52 C3# 138.59 4.0448 DB 4,73 ;54 D3 146.83 4.2854 DB 4,138 ;56 D3# 155.57 4.5402 DB 4,207 ;58 E3 164.82 4.8102 DB 5,25 ;60 F3 174.62 5.0962 DB 5,102 ;62 F3# 185.00 5.3992 DB 5,184 ;64 G3 196.00 5.7203 DB 6,15 ;66 G3# 207.65 6.0604 DB 6,108 ;68 A3 220.00 6.4208 DB 6,205 ;70 A3# 233.08 6.8026 DB 7,53 ;72 B3 246.94 7.2071 DB 7,163 ;74 C4 261.62 7.6356 DB 8,23 ;76 C4# 277.18 8.0897 DB 8,146 ;78 D4 293.66 8.5707 DB 9,21 ;80 D4# 311.13 9.0804 DB 9,159 ;82 E4 329.63 9.6203 DB 10,49 ;84 F4 349.23 10.1924 DB 10,204 ;86 F4# 369.99 10.7984 DB 11,113 ;88 G4 391.99 11.4405 DB 12,13 ;90 G4# 415.30 12.1208 DB 12,215 ;92 A4 440.00 12.8416 DB 13,155 ;94 A4# 466.16 13.6052 DB 14,106 ;96 B4 493.88 14.4142 DB 15,69 ;98 C5 523.24 15.2713 DB 16,46 ;100 C5# 554.36 16.1794 DB 17,36 ;102 D5 587.32 17.1414 DB 18,41 ;104 D5# 622.26 18.1607 DB 19,62 ;106 E5 659.26 19.2406 DB 20,98 ;108 F5 698.46 20.3847 DB 21,153 ;110 F5# 739.98 21.5969 DB 22,226 ;112 G5 783.98 22.8811 DB 24,62 ;114 G5# 830.60 24.2417 DB 25,175 ;116 A5 880.00 25.6831 DB 27,54 ;118 A5# 932.32 27.2103 DB 28,212 ;120 B5 987.76 28.8283 DB 30,139 ;122 C6 1046.5 30.5426 DB 32,92 ;124 C6# 1108.7 32.3588 DB 34,72 ;126 D6 1174.6 34.2828 DB 36,82 ;128 D6# 1244.5 36.3214 DB 38,123 ;130 E6 1318.5 38.4812 ORG NOTES+100H ;MUST BE ON PAGE BOUNDARY WAVE1 DS 100H ;1ST VOICE WAVE2 DS 100H ;2ND VOICE WAVE3 DS 100H ;3RD VOICE WAVE4 DS 100H ;4TH VOICE TUNE ;SCORE CODE BEGINS HERE END 100H