COMMENT * DX-7 Voice Troll Copyright (c) 1986 Steve Rimmer May also be suitable for use as a speadsheet, although it's not likely. * MIDI_PORT EQU 0330H ;BASE OF MPU-401 PORTS STATUS_PORT EQU MIDI_PORT+1 COMMAND_PORT EQU MIDI_PORT+1 DATA_PORT EQU MIDI_PORT SEND_READY EQU 80H ;BIT FOR DATA WAITING DATA_READY EQU 40H ;BIT FOR CLEAR TO SEND MPU_RESET EQU 0FFH ;COMMAND TO RESET MPU401 MPU_UART EQU 03FH ;COMMAND TO SET UART MODE MPU_VERSION EQU 0ACH ;COMMAND TO REQUEST VERSION MPU_REVISION EQU 0ADH ;COMMAND TO REQUEST REVISION CODEX SEGMENT ASSUME CS:CODEX, DS:CODEX, ES:CODEX MAIN PROC FAR ORG 100H MAIN ENDP START: CALL CLRSCRN ;CLEAR THE TUBE START00: MOV AL,MPU_RESET CALL PUT_MPU ;RESET THE MPU-401 CALL ILPRT ;SAY HELLO DB 16 DUP(205) DB ' DX Voice Troll Copyright (c) 1986 Steve Rimmer ' DB 16 DUP(205),0 MOV DX,011EH;SHOW CALL GOTOXY ;... MPU-401 VERSION CALL ILPRT DB 'MPU-401 version ',0 CALL GET_VERSION MOV AL,MPU_UART CALL PUT_MPU ;PUT MPU-401 IN UART MODE CALL BLANK CALL ILPRT ;SHOW MENU DB 'S= send, R= receive, Q= get lost ',0 START0:CALL GETCH ;GET CHOICE CALL TOUPPER CMP AL,'S' ;REQUEST TO SEND? JNE START1 ;IF NOT, TRY RECEIVE CALL LOAD_NAME ;LOAD FILE NAME JC ACCESS_DENIED ;IF CARRY, BAD LOAD CALL CHECKSUM;SEE IF IT'S A GOOD FILE JNE CHECKSUM_ERROR CALL SEE_DX ;SEE THE VOICES CALL PUT_DX ;SEND THEM TO THE DX JMP GET_LOST;WANDER AWAY START1:CMP AL,'R' ;REQUEST TO RECEIVE? JNE START2 ;IF NOT, TRY RECEIVE CALL SAVE_NAME ;GET NAME OF FILE JC ACCESS_DENIED ;CARRY SAYS SOMETHING'S AMISS CALL GET_DX ;GET VOICES CALL CHECKSUM;SEE IF IT'S A GOOD FILE JNE CHECKSUM_ERROR CALL SEE_DX ;SEE THE VOICES CALL SAVE_DX ;SAVE THEM TO THE FILE JMP GET_LOST;ABSCOND START2:CMP AL,'Q' ;REQUEST TO SCRAM? JNE START0 ;IF NOT, TRY AGAIN GET_LOST: MOV AL,MPU_RESET ;CLOSE UP SHOP CALL PUT_MPU CALL CLRSCRN ;CLEAR TUBE INT 20H ;VAPOURIZE CHECKSUM_ERROR:CALL BLANK ;SAY BAD CHECKSUM CALL ILPRT DB 'Checksum error - zap any key',0 CALL GETCH JMP GET_LOST ACCESS_DENIED: CALL BLANK ;SAY BAD FILE CALL ILPRT DB 'File error - zap any key',0 CALL GETCH JMP GET_LOST STUFF PROC NEAR ;THIS ROUTINE SENDS VOICES TO DX-7 PUT_DX:CALL BLANK ;SAY WHAT WE'RE UP TO CALL ILPRT DB 'Sending voices',0 MOV SI,OFFSET CODE_END ;POINT TO VOICES PUT_DX1: MOV AL,[SI] ;GET BYTE PUSH AX CALL PUT_MIDI;SEND IT POP AX INC SI ;POINT TO NEXT BYTE CMP AL,0F7H ;CHECK FOR END OF VOICES JNE PUT_DX1 ;LOOP 'TIL DONE CALL BLANK ;SAY ALL DONE CALL ILPRT DB 'All done - Zap STORE on the DX-7',0 RET ;THIS ROUTINE GETS A FILE NAME TO SAVE TO SAVE_NAME: CALL BLANK ;SHOW PROMPT CALL ILPRT DB 'File name to save to: ',0 MOV BYTE PTR [CODE_END],64 ;MAXIMUM OF 64 CHARACTERS MOV AH,0AH ;GET STRING THROUGH DOS MOV DX,OFFSET CODE_END INT 21H SUB AX,AX ;PUT TERMINATING NULL MOV AL,BYTE PTR [CODE_END+1] MOV SI,OFFSET CODE_END+2 ;...AT END OF STRING ADD SI,AX MOV BYTE PTR [SI],0 MOV DX,OFFSET CODE_END+2 MOV CX,0 MOV AH,3CH INT 21H ;CREATE THE FILE MOV WORD PTR [FILE_HANDLE],AX ;AND SAVE THE FILE HANDLE RET ;THIS ROUTINE SAVES THE VOICE FILE SAVE_DX: CALL BLANK ;SAY WHAT CALL ILPRT DB 'Saving voices',0 MOV AH,40H ;WRITE FILE TO DISK MOV DX,OFFSET HEADER MOV CX,4200 MOV BX,WORD PTR [FILE_HANDLE] INT 21H MOV AH,3EH ;CLOSE FILE MOV BX,WORD PTR [FILE_HANDLE] INT 21H RET ;THIS ROUTINE LOADS A VOICE FILE LOAD_NAME: CALL BLANK ;SPEAK CALL ILPRT DB 'File name to load: ',0 MOV BYTE PTR [CODE_END],64 MOV AH,0AH ;GET THE NAME MOV DX,OFFSET CODE_END INT 21H SUB AX,AX MOV AL,BYTE PTR [CODE_END+1] MOV SI,OFFSET CODE_END+2 ADD SI,AX ;PLACE TERMINATING NULL MOV BYTE PTR [SI],0 MOV DX,OFFSET CODE_END+2 MOV AX,3D00H INT 21H ;OPEN FILE JC LOAD_NAME1 MOV WORD PTR [FILE_HANDLE],AX CALL BLANK ;SAY WHAT'S HAPPENING CALL ILPRT DB 'Loading voices',0 MOV AH,3FH ;INHALE VOICES MOV DX,OFFSET HEADER MOV CX,4200 MOV BX,WORD PTR [FILE_HANDLE] INT 21H JC LOAD_NAME1 MOV AH,3EH ;CLOSE FILE INT 21H LOAD_NAME1: RET ;THIS ROUTINE GETS VOICE DUMP INTO MEMORY GET_DX:CALL BLANK ;VERBALIZE CALL ILPRT DB 'Awaiting voice dump',0 MOV SI,OFFSET CODE_END ;POINT TO FREE SPACE GET_DX0: CALL GET_MIDI;GET A BYTE CMP AL,0F0H ;CHECK FOR START OF JNE GET_DX0 ;... VOICE DUMP MOV [SI],AL ;SAVE THE BYTE INC SI ;BUMP THE POINTER GET_DX1: CALL GET_MIDI;GET A BYTE MOV [SI],AL ;SAVE IT INC SI ;BUMP THE POINTER CMP AL,0F7H ;SEE IF IT'S END OF DUMP JNE GET_DX1 RET ;THIS ROUTINE FIGURES THE CHECKSUM FOR THE VOICES CHECKSUM: MOV CX,4096 ;NUMBER OF BYTES IN DUMP SUB AX,AX ;NULL ACCUMULATOR MOV SI,OFFSET CODE_END+6 ;POINT TO FIRST VOICE CHECKSUM1: ADD AL,[SI] ;ADD BYTE INC SI ;BUMP POINTER LOOP CHECKSUM1 ;AND LOOP NOT AL ;DO TWOS COMPLIMENT ADD AL,1 AND AL,7FH ;...SORT OF MOV AH,[SI] ;GET CHECKSUM FROM MEMORY CMP AH,AL ;SET FLAG RET ;THIS ROUTINE SHOWS THE VOICE NAMES SEE_DX:MOV BX,OFFSET CODE_END+6 ;POINT TO FIRST VOICE MOV DH,4 ;SET VERTICAL LINE SEE_DX1: MOV DL,28 ;SET LEFT VOICE POSITION CALL GOTOXY ;MOVE CURSOR CALL SEE_NAME;SHOW NAME ADD BX,80H ;POINT TO NEXT VOICE MOV DL,42 ;SET RIGHT VOICE POSITION CALL GOTOXY ;MOVE CURSOR CALL SEE_NAME;SHOW NAME ADD BX,80H ;POINT TO NEXT VOICE INC DH ;NEW LINE CMP DH,20 ;SEE IF WE'RE DONE JL SEE_DX1 CALL BLANK ;SAY WE' DONE CALL ILPRT DB 'Zap any key to continue',0 CALL GETCH RET ;THIS ROUTINE SHOWS ONE VOICE NAME SEE_NAME: PUSH BX ;SAVE POINTER ADD BX,76H ;POINT PAST OPERATORS MOV CX,10 ;TEN BYTES IN A VOICE SEE_NAME1: MOV AL,[BX] ;GET A BYTE CALL PUTCH ;POINT IT INC BX ;BUMP POINTER LOOP SEE_NAME1 ;AND LOOP POP BX ;RESTORE POINTER RET ;THIS ROUTINE CLEARS THE MESSAGE LINE BLANK: MOV DX,1800H;POSITION AT BOTTOM CALL GOTOXY ;...OF TUBE MOV CX,79 ;AND PRINT MOV AL,32 ;...A LINE OF SPACES BLANK1:CALL PUTCH LOOP BLANK1 MOV DX,1800H;POSITION CURSOR AGAIN CALL GOTOXY RET ;THIS ROUTINE GETS ONE BYTE FROM THE MIDI PORT GET_MIDI: SUB CX,CX ;RESET TIMEOUT COUNTER GET_MIDI1: MOV DX,STATUS_PORT ;GET STATUS PORT VALUE IN AL,DX AND AL,SEND_READY ;SEE IF DATA'S A'WAITIN' CMP AL,SEND_READY JNE GET_MIDI2 ;LOOP 'TIL IT IS LOOP GET_MIDI1 GET_MIDI2: MOV DX,DATA_PORT ;WRANGLE THAT THAR DATA IN AL,DX CMP AL,0FEH ;IGNORE TIMERS JE GET_MIDI RET ;THIS ROUTINE SENDS THE BYTE IN AL TO THE MIDI PORT PUT_MIDI: PUSH AX ;SAVE THE BYTE PUT_MIDI1: MOV DX,STATUS_PORT ;WAIT FOR CLEAR IN AL,DX ;... SIGNAL FROM BUS AND AL,DATA_READY CMP AL,DATA_READY JE PUT_MIDI1 POP AX ;RESTORE THE BYTE MOV DX,DATA_PORT ;AND SEND IT OUT OUT DX,AL IN AL,DX ;I DON'T KNOW WHY IT RET ;... WANTS THIS BUT IT DOES ;THIS ROUTINE SENDS A COMMAND TO THE MPU-401 PUT_MPU: PUSH AX ;SAVE COMMAND SUB CX,CX ;RESET TIMEOUT COUNTER PUT_MPU1: MOV DX,STATUS_PORT ;WAIT FOR FREE PORT IN AL,DX AND AL,DATA_READY CMP AL,DATA_READY JNE PUT_MPU2 LOOP PUT_MPU1 PUT_MPU2: POP AX ;RESTORE BYTE MOV DX,COMMAND_PORT ;AND SEND IT OUT DX,AL SUB CX,CX ;RESET TIMOUT COUNTER PUT_MPU3: MOV DX,STATUS_PORT ;WAIT FOR BYTE TO COME BACK IN AL,DX AND AL,SEND_READY CMP AL,SEND_READY JNE PUT_MPU4 LOOP PUT_MPU3 PUT_MPU4: MOV DX,DATA_PORT ;GET THE BYTE IN AL,DX CMP AL,0FEH ;CHECK FOR ACK RET ;THIS ROUTINE GETS THE VERSION AND REVISION NUMBERS OF THE MPU-401 GET_VERSION: MOV AL,MPU_VERSION CALL PUT_MPU ;ASK FOR VERSION CALL GET_MIDI;GET THE BYTE PUSH AX ;SAVE IT AND AL,0F0H ;ISOLATE HIGH NYBBLE MOV CL,4 SHR AL,CL ADD AL,'0' ;ADD ASCII CALL PUTCH ;AND SHOW IT MOV AL,'.' ;PRINT A DOT CALL PUTCH POP AX ;RESTORE BYTE AND AL,0FH ;ISOLATE LOW NYBBLE ADD AL,'0' ;ADD ASCII CALL PUTCH ;AND SHOW IT MOV AL,MPU_REVISION ;ASK FOR REVISION CALL PUT_MPU CALL GET_MIDI;GET BYTE ADD AL,64 ;ADD ASCII CALL PUTCH ;AND SHOW IT RET ;THIS ROUTINE TRASNLATES AL TO UPPER CASE TOUPPER: CMP AL,'a' JL TOUPPER1 CMP AL,'z' JG TOUPPER1 SUB AL,'a'-'A' TOUPPER1: RET ;THIS ROUTINE DOES IN LINE PRINTING ILPRT: POP BX ILPLP: MOV AL,[BX] CMP AL,0 JE ILPRET CALL PUTCH INC BX JMP ILPLP ILPRET:INC BX PUSH BX RET ;THIS ROUTINE PRINTS ONE CHARACTER PUTCH: PUSH DX PUSH CX PUSH BX PUSH AX MOV AH,15 INT 10H POP AX PUSH AX MOV AH,14 INT 10H POP AX POP BX POP CX POP DX RET ;THIS ROUTINE GETS ONE CHARACTER FROM THE KEYBOARD GETCH: PUSH BX PUSH CX PUSH DX MOV AH,0 INT 16H POP DX POP CX POP BX RET ;THIS ROUTINE POSITIONS THE CURSOR AT (DL,DH) GOTOXY:PUSH AX PUSH BX PUSH CX PUSH DX MOV AH,15 INT 10H POP DX PUSH DX MOV AH,2 INT 10H POP DX POP CX POP BX POP AX RET CLRSCRN: MOV AX,0600H MOV BX,0700H MOV CX,0000H MOV DX,184FH INT 10H SUB DX,DX CALL GOTOXY RET FILE_HANDLE: DW 0 HEADER: DB 'DX-Archive Voice File ' DB 'Copyright (c) 1985 Steve Rimmer ' CODE_END: DB 0 STUFF ENDP CODEX ENDS END START