#################################################################### The text following is six separate program files, three each for two separate programs. They are separated by a line of "###'s" and must be each culled out of this file before assembly or compilation. The first three files are "MPRIM.ASM", "MPU.H", and "TESTMPU.C". These comprise the beginning of an interrupt driven program using the Roland MPU-401 in its "intelligent" mode. This might be assumed to be the best mode for writing sequencer and recorder programs, especially if memory resources are limited. There is a drawback in this mode, in that any software written for it becomes chained to usage with the MPU. If you have an eye to transporting your work to such as the Arari/ST, this is not so good. Also, while the MPU is impressive, it was designed to be memory efficient when used as the foundation for a sequencer/recorder. If you are looking to set up musical phrases as, say LISP s-expressions, it might not be so great. For these two reasons, and for others I haven't thought of, you might want to put the MPU to sleep, and just use it as a dumb MIDI port. The second three program files do just that. They are "MIDI.ASM", "MIDI.H", and "TESTMIDI.C" All were written for the Microsoft Assembler version 3 or higher, and the Microsoft C compiler, version 4 (the new one). Both resulting programs do work on my Kaypro 286i (an AT-clone). They may or may not work on your machine. I have left the copyright notice intact because I wish to emphasize that these programs are suitable only for pointing other MPU programmers in the right direction. There are dead ends and (likely) errors. Used with caution as a guide to your own programs, they might be usefull. Used without thought or understanding, and I guarantee they will be more trouble than they are worth. With that cheery thought, I wish you good luck. John Dunn January, 1986 ############################################################### PAGE 60,127 TITLE MPU primitives NAME MPRIM .SALL ;============================================================== ; COPYRIGHT (C) 1986 John Dunn ;-------------------------------------------------------------- ; date: 01/02/86 ; update: 01/02/86 ; last hacker: John Dunn ;============================================================== PRIM_TEXT SEGMENT BYTE PUBLIC 'CODE' PRIM_TEXT ENDS CONST SEGMENT WORD PUBLIC 'CONST' CONST ENDS _BSS SEGMENT WORD PUBLIC 'BSS' _BSS ENDS _DATA SEGMENT WORD PUBLIC 'DATA' _DATA ENDS DGROUP GROUP CONST, _BSS, _DATA ;============================================================== _DATA SEGMENT WORD PUBLIC 'DATA' ;-------------------------------------------------------------- PUBLIC _indexp,_indext,_channel,_rtmsg,_pending PUBLIC _recording,_playing,_loading,_enderr ;-------------------------------------------------------------- _channel dw 0 ; current midi channel _rtmsg dw 0 ; real time message flag _pending dw 0 ; number of sys excl pending _recording dw 0 ; nz when recording track data _playing dw 0 ; nz when playing track data _loading dw 0 ; nz when loading para data _enderr dw 0 ; nz if put index at limit _indext dw 0 ; index track buffer _indexp dw 0 ; index param buffer startt dw 0 ; start track buffer startp dw 0 ; start param buffer endtrk dw 0 ; end track buffer endpar dw 0 ; end param buffer limitt dw tbufx-_tbuf ; track buffer limit limitp dw pbufx-_pbuf ; param buffer limit icount dw 0 ; midi msg count index rcount dw 0 ; midi msg run count pcount dw 0 ; play track count clkblp dw 0 ; clock blip count intval dw 0 ; inte data value special dw 0 ; nz = special routine sptable dw dotimev,procsm,sysexc,songsel,songp1,songp2 ;-------------------------------------------------------------- _DATA ENDS ;============================================================== PBUF_DATA SEGMENT PARA MEMORY 'BUFFER' ;-------------------------------------------------------------- PUBLIC _pbuf ;-------------------------------------------------------------- _pbuf db 17000 dup(?) ; parameter buffer pbufx db 0 ;-------------------------------------------------------------- PBUF_DATA ENDS ;============================================================== TBUF_DATA SEGMENT PARA MEMORY 'BUFFER' ;-------------------------------------------------------------- PUBLIC _tbuf ;-------------------------------------------------------------- _tbuf db 16384 dup(?) ; parameter buffer tbufx db 0 ;-------------------------------------------------------------- TBUF_DATA ENDS ;============================================================== PRIM_TEXT SEGMENT ASSUME CS: PRIM_TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP ;============================================================== bpo equ 6 ; base pointer offset ; 6 = large model; 4 = small p1 equ bpo ; single word arg 1, use [bp+@1] p2 equ bpo+2 ; single word arg 2, use [bp+@2] ;-------------------------------------------------------------- mdata equ 0330H ; mpu data port address mstat equ 0331H ; mpu status port address mcmd equ 0331H ; mpu command port address mdsr equ 80H ; mpu data set ready, active low mdrr equ 40H ; mpu data read ready, active low ;-------------------------------------------------------------- ; initialize mpu, int vectors, etc. ; must be called once only on startup ; public _initm _initm proc far push es ; save current es mov ah,35h ; get current int 2 mov al,0AH int 21H mov word ptr cs:orgint+3,es ; save it mov word ptr cs:orgint+1,bx pop es ; restore es push ds ; save current ds mov ah,25H ; set int vect mov al,0AH ; int 2 for MPU mov dx,seg mpuint mov ds,dx mov dx,offset mpuint int 21H ; set new int vect pop ds ; restore ds mov dx,mdata ; clear data port in al,dx in al,21H ; enable irq2 jmp short $+2 ; delay for AT and al,0FBH out 21H,al sti ; enable ints ret _initm endp ; end of init mpu ;-------------------------------------------------------------- ; shutdown mpu, restore int vectors, etc. ; must be called once only on exit ; public _exitm _exitm proc far in al,21H ; disable irq2 jmp short $+2 ; delay for AT or al,4 out 21H,al push ds mov ah,25h ; restore previous irq2 mov al,0AH mov dx,word ptr cs:orgint+3 mov ds,dx mov dx,word ptr cs:orgint+1 int 21h pop ds ret _exitm endp ;-------------------------------------------------------------- ; this routine is only called by int 2 ; if it was not generated by the mpu, it vectors ; to the original int address, otherwise it saves ; registers, then calls the c routine _mpuint, ; after which it restores registers, clears nmi ; and returns from int. ; mpuint proc far push ax ; save ax push dx mov dx,mstat ; read mpu status mpui0: jmp short $+2 in al,dx and al,mdsr ; generated by mpu? jz mpui1 ; yes, branch ; jmp mpui0 pop dx ; no, restore cpu pop ax iret ; return from interrupt orgint: jmp far ptr intval ; dummy vector, filled by _initm dw 0 mpui1: push bx ; save cpu state push cx push di push si push bp push ds push es mov ax,seg dgroup ; set up c seg regs mov ds,ax mov es,ax mov dx,mdata ; get mpu int data in al,dx call dompu ; do the mpu routine pop es ; restore seg regs pop ds pop bp ; restore cpu state pop si pop di pop cx pop bx pop dx mov al,20H ; send eoi to 8259 out 20H,al pop ax iret ; return from interrupt mpuint endp ;-------------------------------------------------------------- ; dompu ; process mpu inte ; local call ; dompu proc near mov byte ptr intval,al ; save as global variable mov bx,special or bx,bx ; special flag set? jz dompu1 ; no, branch dec bx ; yes, jump to special routine add bx,bx mov dx,sptable[bx] jmp dx dompu1: cmp al,0F0H ; < F0H jnb dompu2 ; no, branch jmp timev ; yes, do time value dompu2: cmp al,0F8H ; < F8H jnb dompu3 ; no, branch jmp trackd ; yes, do track data request dompu3: jnz dompu4 ; branch if not = F8H jmp timeo ; else do timing overflow dompu4: cmp al,0F9H ; = F9? jnz dompu5 ; no, branch jmp condr ; yes, do conductor request dompu5: cmp al,0FDH ; = FD? jnz dompu6 ; no, branch jmp clockh ; yes, do clock to host dompu6: cmp al,0FCH ; = FD? jnz dompu7 ; no, branch jmp allend ; yes, do all end dompu7: cmp al,0FFH ; = FF? jnz dompu8 ; no, branch jmp midism ; yes, do midi system message dompu8: ret dompu endp ;-------------------------------------------------------------- ; mpuput(data) ; send data to mpu-401 ; C call ; public _mpuput _mpuput proc far push bp mov bp,sp mov dx,mstat ; mpu status port mpup1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpup1 ; loop til ready mov dx,mdata ; mpu data port mov ax,[bp+p1] ; get the data out dx,al ; send to mpu mov sp,bp ; restore C sp pop bp ret ; exit _mpuput endp ;-------------------------------------------------------------- ; mpuput ; send data in AL to mpu-401 ; local call, AX is preserved ; mpuput proc near push ax mov dx,mstat ; mpu status port mpupa1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpupa1 ; loop til ready mov dx,mdata ; mpu data port pop ax ; get the data out dx,al ; send to mpu ret ; exit mpuput endp ;-------------------------------------------------------------- ; data=mpuget() ; get data from mpu-401 ; C call ; public _mpuget _mpuget proc far mov dx,mstat ; mpu status port mpug1: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpug1 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; get the data byte mov ah,0 ; zero out ms byte ret ; exit with ax = data _mpuget endp ;-------------------------------------------------------------- ; mpuget ; get data from mpu-401 to AX ; local call ; mpuget proc near mov dx,mstat ; mpu status port mpuga1: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpuga1 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; get the data byte mov ah,0 ; zero out ms byte ret ; exit with ax = data mpuget endp ;-------------------------------------------------------------- ; mpucmd(cmd) ; send a command to mpu-401 ; public _mpucmd _mpucmd proc far push bp mov bp,sp mov dx,mstat ; mpu status port mpuc1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpuc1 ; loop til ready cli ; disable intes mov ax,[bp+p1] ; get the command out dx,al ; send to mpu mpuc2: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpuc2 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; read it cmp al,0FEH ; acknowledge? jz mpuc3 ; yes, branch push di ; save C registers push si call dompu ; do mpu routine pop si pop di mov dx,mstat ; mpu status port jmp short mpuc2 ; check again for ack mpuc3: sti ; enable ints mov sp,bp ; restore C sp pop bp ret ; exit _mpucmd endp ;-------------------------------------------------------------- ; data = gett() ; get byte from track buffer ; C call ; public _gett _gett proc far mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endtrk ; reached end? jnz gett1 ; no, exit mov bx,startt ; yes, set index = start gett1: mov _indext,bx ; save index ret ; exit with ax = data _gett endp ;-------------------------------------------------------------- ; gett ; get byte to AX from track buffer ; local call ; gett proc near mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endtrk ; reached end? jnz getta1 ; no, exit mov bx,startt ; yes, set index = start getta1: mov _indext,bx ; save index ret ; exit with ax = data gett endp ;-------------------------------------------------------------- ; putt(track_data) ; put byte to track buffer ; C call ; public _putt _putt proc far push bp mov bp,sp mov bx,_indext ; get index mov dx,seg _tbuf mov al,[bp+p1] ; get the data push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitt ; reached limit? mov ax,1 ; flag error jz putt0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indext,bx ; store index mov endtrk,bx ; end = index putt0: mov _enderr,ax ; save in _enderr mov sp,bp ; restore C sp pop bp ret ; exit _putt endp ;-------------------------------------------------------------- ; putt ; put byte in AL to track buffer ; local call ; putt proc near mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitt ; reached limit? mov ax,1 ; flag error jz putta0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indext,bx ; store index mov endtrk,bx ; end = index putta0: mov _enderr,ax ; save in _enderr ret ; exit putt endp ;-------------------------------------------------------------- ; data = getp() ; get byte from parameter buffer ; C call ; public _getp _getp proc far mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endpar ; reached end? jnz getp1 ; no, exit mov bx,startp ; yes, set index = start getp1: mov _indexp,bx ; save index ret ; exit with ax = data _getp endp ;-------------------------------------------------------------- ; getp ; get byte to AX from param buffer ; local call ; getp proc near mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endpar ; reached end? jnz getpa1 ; no, exit mov bx,startp ; yes, set index = start getpa1: mov _indexp,bx ; save index ret ; exit with ax = data getp endp ;-------------------------------------------------------------- ; putp(param_data) ; put byte to param buffer ; C call ; public _putp _putp proc far push bp mov bp,sp mov bx,_indexp ; get index mov dx,seg _pbuf mov al,[bp+p1] ; get the data push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitp ; reached limit? mov ax,1 ; flag error jz putp0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indexp,bx ; store index mov endpar,bx ; end = index putp0: mov _enderr,ax ; save in _enderr mov sp,bp ; restore C sp pop bp ret ; exit _putp endp ;-------------------------------------------------------------- ; putp ; put byte in AL to param buffer ; local call ; putp proc near mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitp ; reached limit? mov ax,1 ; flag error jz putpa0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indexp,bx ; store index mov endpar,bx ; end = index putpa0: mov _enderr,ax ; save in _enderr ret ; exit putp endp ;-------------------------------------------------------------- ; timeo ; process timing overflow on inte ; local call with intval in AL ; timeo proc near call putt ret timeo endp ;-------------------------------------------------------------- ; condr ; process conductor request on inte ; local dummy routine, sends timing overflow byte ; condr proc near mov al,0F8H call putt ret condr endp ;-------------------------------------------------------------- ; clockh ; process clock to host on inte ; local call ; clockh proc near mov ax,clkblp ; get blip flag inc ax ; count up and ax,1 mov clkblp,ax ; put back inc ax ; 1,2 = happy face mov cx,ds mov dx,0B800H ; point to gx screen mov ds,dx mov byte ptr ds:9EH,al ; display blip mov ds,cx ret clockh endp ;-------------------------------------------------------------- ; allend ; process all end on inte ; local call, clears playing flag ; allend proc near mov ax,0 mov _playing,ax ret allend endp ;-------------------------------------------------------------- ; timev ; process time value on inte ; local call with intval in AL ; timev proc near call putt mov ax,1 ; set special = 1 mov special,ax ; dotimev on next inte ret timev endp ;-------------------------------------------------------------- ; dotimev (special = 1 ) ; next inte processing of time value ; local call with intval in AL ; dotimev proc near cmp al,0F8H ; mpu mark, no operation jz dotime1 cmp al,0F9H ; mpu mark, measure end jz dotime2 cmp al,0FCH ; mpu mark, data end jnz dotime3 mov ax,0 mov _recording,ax ; clr recording flag dotime2:call putt ; put in record buffer dotime1:mov ax,0 mov special,ax ; done, clear special ret ; exit dotime3:mov ah,al ; get a copy and ah,0F0H ; zip channel data cmp ah,0C0H ; midi msg, program change jz dotime4 cmp ah,0DH ; midi msg, channel pressure jnz dotime5 dotime4:mov dx,1 ; set to recieve 1 more byte jmp short dotime6 dotime5:cmp ah,80H ; midi msg, note off jz dotime7 cmp ah,90H ; midi msg, note on jz dotime7 cmp ah,0A0H ; midi msg, after touch jz dotime7 cmp ah,0B0H ; midi msg, control change jz dotime7 cmp ah,0E0H ; midi msg, pitch wheel jnz dotime8 dotime7:mov dx,2 ; set to recieve 2 more bytes dotime6:mov rcount,dx mov icount,dx call putt ; put in record buffer ret ; exit dotime8:and ah,80H ; < 7FH ? jz dotime9 ; yes, branch mov ax,0 ; no, is error mov special,ax ; clear special call far ptr _beep ; signal error ret ; exit dotime9:mov ah,byte ptr icount ; get current count cmp ah,0 ; new one? jnz dotim10 ; no, branch mov ah,byte ptr rcount ; yes, icount <-- rcount dotim10:push ax ; save it call putt ; save the data byte in AL pop ax ; ah = icount dec ah ; dec icount mov byte ptr icount,ah ; save it jnz dotime11 ; branch if icount not 0 mov ax,0 ; else clear special mov special,ax dotime11:ret ; exit dotimev endp ;-------------------------------------------------------------- ; trackd ; process track play request on inte ; local call with intval in AL ; trackd proc near call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port cmp al,0F8H ; midi timing overflow jnz trackd1 ret ; just exit if it was timing overfow trackd1:call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port and al,0F0H ; strip midi channel info cmp al,0F0H ; mpu mark jnz trackd2 ret trackd2:test al,80H ; <= 7FH ? jnz trackd3 ; no, branch cmp pcount,1 ; pcount = 1 ? jnz trackd4 ; no, branch ret ; yes, exit trackd3:cmp al,0C0H ; one byte needed? jz trackd5 cmp al,0D0H jnz trackd6 trackd5:mov pcount,1 ; yes, set running pcount to 1 jmp short trackd4 ; ... and get one more byte trackd6:mov pcount,2 ; else set running pcount to 2 call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port trackd4:call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port ret trackd endp ;-------------------------------------------------------------- ; midism ; process midi system message on inte ; local call ; midism proc near mov ax,2 ; flag special = 2 mov special,ax ; procsm on next inte ret midism endp ;-------------------------------------------------------------- ; procsm ( special = 2) ; continue to process midi system message in inte ; local call with intval in AL ; procsm proc near cmp al,0F0H ; midi exclusive jnz procsm1 call putp ; save in para buffer mov ax,1 ; set loading flag mov _loading,ax mov ax,3 ; set special = 3 mov special,ax ; continue on next inte ret procsm1:cmp al,0F3H ; song select jnz procsm2 mov ax,4 ; set special = 4 mov special,ax ; continue on next inte ret procsm2:cmp al,0F2H ; song position jnz procsm3 mov ax,5 ; set special = 5 mov special,ax ; continue on next inte ret procsm3:cmp al,0F6H ; tune request jnz procsm4 nop ; insert routine here jmp short procsm0 ; clr special & exit procsm4:mov byte ptr _rtmsg,al ; flag real time message procsm0:mov ax,0 ; clear special mov special,ax ret ; exit procsm endp ;-------------------------------------------------------------- ; sysexc (special = 3 ) ; inte processing of system exclusive values ; local call with intval in AL ; sysexc proc near push ax ; save inte value call putp ; save in parameter buffer pop ax cmp al,0F7H ; was it EOX jnz sysexc0 ; no, just exit mov ax,0 ; yes, mov _loading,ax ; clear loading flag mov special,ax ; clear special inc word ptr _pending ; inc pending flag sysexc0:ret ; exit sysexc endp ;-------------------------------------------------------------- ; songsel (special = 4) ; inte processing of song select ; local call with intval in AL ; songsel proc near nop ; dummy routine mov ax,0 ; clear special mov special,ax ret songsel endp ;-------------------------------------------------------------- ; songp1 (special = 5) ; inte processing of song position 1st byte ; local call with intval in AL ; songp1 proc near nop ; dummy routine mov ax,6 ; special = 6 mov special,ax ; songp2 on next int ret songp1 endp ;-------------------------------------------------------------- ; songp2 (special = 6) ; inte processing of position 2nd byte ; local call with intval in AL ; songp2 proc near nop ; dummy routine mov ax,0 ; clear special mov special,ax ret songp2 endp ;-------------------------------------------------------------- ; a little beep on the speaker ; public _beep _beep proc far mov al,0b6h out 043h,al ;write timer mode regester mov ax,1000 ;set divisor value to 1000 out 042h,al ;write timer 1 count lsb mov al,ah out 042h,al ;write timer 2 count msb in al,061h ;get current port b setting mov ah,al ;save current setting. or al,3 ;turn speaker on out 061h,al mov cx,0a48h ;10 msec delay on ibm pc 4.7mh 8088 delay: loop delay mov al,ah ;get old port b setting out 061h,al ;set it back the way you found it ret _beep endp ;-------------------------------------------------------------- ; blip(char) -- sends char to upper right corner of screen ; public _blip _blip proc far push bp mov bp,sp mov ax,[bp+p1] add ax,'0' mov cx,ds mov dx,0B800H mov ds,dx mov byte ptr ds:9EH,al mov ds,cx mov sp,bp pop bp ret _blip endp ;-------------------------------------------------------------- PRIM_TEXT ENDS END ############################################################### /************************************************************** * mpu.h * * equates for mpu & tx816 * */ /* mpu port addresses & flags */ #define MDATA 0x330 /* mpu data port address */ #define MSTAT 0x331 /* mpu status port address */ #define MCMD 0x331 /* mpu command port address */ #define MDSR 0x80 /* mpu data set ready, active low */ #define MDRR 0x40 /* mpu data read ready, active low */ /* mpu data codes */ #define NULINT 0xFA /* null interrupt code */ #define MPUACK 0xFE /* mpu acknowledge */ /* mpu command codes */ #define METRONOME_ON 0x83 /* metronome on with no accents */ #define METRONOME_ACCENT 0x85 /* metronome on with accents */ #define METRONOME_OFF 0x84 /* metronome off */ #define RESET 0xFF /* reset mpuw */ #define SEND_SYS 0xDF /* want to send system message */ #define EXCL_ON 0x97 /* exclusive to host: on */ #define EXCL_OFF 0x96 /* exclusive to host: off */ #define CLOCK_ON 0x95 /* clock to host: on */ #define CLOCK_OFF 0x94 /* clock to host: off */ /* midi codes */ #define EOX 0xF7 /* end of transmission */ /* Yamaha specific codes */ #define DUMP_1V 0 /* bulk dump 1 voice */ #define DUMP_1P 1 /* bulk dump 1 performance setup */ #define DUMP_64P 2 /* bulk dump 64 performance setups */ #define DUMP_32V 9 /* bulk dump 32 voices */ #define DUMP_CA 0 /* dump condition acknowledge */ ############################################################### /************************************************************** * testmpu.c * * test program for mpu & TX816 * */ #include "stdio.h" #include "mpu.h" /************************************************************** * global values */ extern unsigned char tbuf[]; /* track buffer */ extern unsigned char pbuf[]; /* parameter buffer */ extern unsigned int indext; /* track buf index */ extern unsigned int indexp; /* para buf index */ extern unsigned int channel; /* current midi channel */ extern unsigned int rtmsg; /* real time message flag */ extern unsigned int pending; /* number of sys excl pending */ extern unsigned int recording; /* nz when recording track data */ extern unsigned int playing; /* nz when playing track data */ extern unsigned int loading; /* nz when loading para data */ extern unsigned int enderr; /* nz if put index at limit */ main(argc, argv) int argc; char *argv[]; { int i; initm(); mpucmd(RESET); mpucmd(EXCL_ON); mpucmd(CLOCK_ON); getchar(); printf("dump in progress\n"); dump_request(DUMP_1V); for(i = 0; i < 256; ++i) printf("%x ",pbuf[i]); printf("\n\n"); mpucmd(RESET); printf("reset\n"); getchar(); mpucmd(CLOCK_OFF); exitm(); exit(0); } /************************************************************** * issue a request to dump data * specific to Yamaha */ dump_request(fmt) int fmt; { indexp = 0; mpucmd(SEND_SYS); mpuput(0xF0); mpuput(0x43); mpuput(0x20 | channel); mpuput(fmt); mpuput(EOX); while(!loading); beep(); } ############################################################### PAGE 60,127 TITLE MIDI primitives for dumb-MPU NAME MIDI .SALL ;============================================================== ; COPYRIGHT (C) 1986 John Dunn ;-------------------------------------------------------------- ; date: 01/02/86 ; update: 01/02/86 ; last hacker: John Dunn ;============================================================== PRIM_TEXT SEGMENT BYTE PUBLIC 'CODE' PRIM_TEXT ENDS CONST SEGMENT WORD PUBLIC 'CONST' CONST ENDS _BSS SEGMENT WORD PUBLIC 'BSS' _BSS ENDS _DATA SEGMENT WORD PUBLIC 'DATA' _DATA ENDS DGROUP GROUP CONST, _BSS, _DATA ;============================================================== _DATA SEGMENT WORD PUBLIC 'DATA' ;-------------------------------------------------------------- PUBLIC _indexp,_indext,_channel,_rtmsg,_pending PUBLIC _recording,_playing,_loading,_enderr ;-------------------------------------------------------------- _channel dw 0 ; current midi channel _rtmsg dw 0 ; real time message flag _pending dw 0 ; number of sys excl pending _recording dw 0 ; nz when recording track data _playing dw 0 ; nz when playing track data _loading dw 0 ; nz when loading para data _enderr dw 0 ; nz if put index at limit _indext dw 0 ; index track buffer _indexp dw 0 ; index param buffer startt dw 0 ; start track buffer startp dw 0 ; start param buffer endtrk dw 0 ; end track buffer endpar dw 0 ; end param buffer limitt dw tbufx-_tbuf ; track buffer limit limitp dw pbufx-_pbuf ; param buffer limit icount dw 0 ; midi msg count index rcount dw 0 ; midi msg run count pcount dw 0 ; play track count clkblp dw 0 ; clock blip count intval dw 0 ; inte data value special dw 0 ; nz = special routine sptable dw dotimev,procsm,sysexc,songsel,songp1,songp2 ;-------------------------------------------------------------- _DATA ENDS ;============================================================== PBUF_DATA SEGMENT PARA MEMORY 'BUFFER' ;-------------------------------------------------------------- PUBLIC _pbuf ;-------------------------------------------------------------- _pbuf db 17000 dup(?) ; parameter buffer pbufx db 0 ;-------------------------------------------------------------- PBUF_DATA ENDS ;============================================================== TBUF_DATA SEGMENT PARA MEMORY 'BUFFER' ;-------------------------------------------------------------- PUBLIC _tbuf ;-------------------------------------------------------------- _tbuf db 16384 dup(?) ; parameter buffer tbufx db 0 ;-------------------------------------------------------------- TBUF_DATA ENDS ;============================================================== PRIM_TEXT SEGMENT ASSUME CS: PRIM_TEXT, DS: DGROUP, SS: DGROUP, ES: DGROUP ;============================================================== bpo equ 6 ; base pointer offset ; 6 = large model; 4 = small p1 equ bpo ; single word arg 1, use [bp+@1] p2 equ bpo+2 ; single word arg 2, use [bp+@2] ;-------------------------------------------------------------- mdata equ 0330H ; mpu data port address mstat equ 0331H ; mpu status port address mcmd equ 0331H ; mpu command port address mdsr equ 80H ; mpu data set ready, active low mdrr equ 40H ; mpu data read ready, active low ;-------------------------------------------------------------- ; initialize mpu, int vectors, etc. ; must be called once only on startup ; public _initm _initm proc far push es ; save current es mov ah,35h ; get current int 2 mov al,0AH int 21H mov word ptr cs:orgint+3,es ; save it mov word ptr cs:orgint+1,bx pop es ; restore es push ds ; save current ds mov ah,25H ; set int vect mov al,0AH ; int 2 for MPU mov dx,seg mpuint mov ds,dx mov dx,offset mpuint int 21H ; set new int vect pop ds ; restore ds call mpurst ; reset mpu in al,21H ; enable irq2 jmp short $+2 ; delay for AT and al,0FBH out 21H,al ret _initm endp ; end of init mpu ;-------------------------------------------------------------- ; shutdown mpu, restore int vectors, etc. ; must be called once only on exit ; public _exitm _exitm proc far in al,21H ; disable irq2 jmp short $+2 ; delay for AT or al,4 out 21H,al push ds mov ah,25h ; restore previous irq2 mov al,0AH mov dx,word ptr cs:orgint+3 mov ds,dx mov dx,word ptr cs:orgint+1 int 21h pop ds ret _exitm endp ;-------------------------------------------------------------- ; mpurst ; reset the mpu ; local call ; mpurst proc near cli ; disable intes mov dx,mstat ; mpu status port mpurs1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpurs1 ; loop til ready mov ax,0FFH ; get the command out dx,al ; send to mpu mpurs2: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpurs2 ; loop til ready mov dx,mdata ; read mpu data port mov dx,mdata ; read mpu data port mov dx,mdata ; read mpu data port sti ; enable intes ret ; exit mpurst endp ;-------------------------------------------------------------- ; this routine is only called by int 2 ; if it was not generated by the mpu, it vectors ; to the original int address, otherwise it saves ; registers, then calls the c routine _mpuint, ; after which it restores registers, clears nmi ; and returns from int. ; mpuint proc far push ax ; save ax push dx mov dx,mstat ; read mpu status mpui0: jmp short $+2 in al,dx and al,mdsr ; generated by mpu? jz mpui1 ; yes, branch pop dx ; no, restore cpu pop ax iret ; return from interrupt orgint: jmp far ptr intval ; dummy vector, filled by _initm dw 0 mpui1: push bx ; save cpu state push cx push di push si push bp push ds push es mov ax,seg dgroup ; set up c seg regs mov ds,ax mov es,ax mov dx,mdata ; get mpu int data in al,dx call dompu ; do the mpu routine pop es ; restore seg regs pop ds pop bp ; restore cpu state pop si pop di pop cx pop bx pop dx mov al,20H ; send eoi to 8259 out 20H,al pop ax iret ; return from interrupt mpuint endp ;-------------------------------------------------------------- ; dompu ; process mpu inte ; local call ; dompu proc near mov byte ptr intval,al ; save as global variable mov bx,special or bx,bx ; special flag set? jz dompu1 ; no, branch dec bx ; yes, jump to special routine add bx,bx mov dx,sptable[bx] jmp dx dompu1: cmp al,0F0H ; < F0H jnb dompu2 ; no, branch jmp timev ; yes, do time value dompu2: cmp al,0F8H ; < F8H jnb dompu3 ; no, branch jmp trackd ; yes, do track data request dompu3: jnz dompu4 ; branch if not = F8H jmp timeo ; else do timing overflow dompu4: cmp al,0F9H ; = F9? jnz dompu5 ; no, branch jmp condr ; yes, do conductor request dompu5: cmp al,0FDH ; = FD? jnz dompu6 ; no, branch jmp clockh ; yes, do clock to host dompu6: cmp al,0FCH ; = FD? jnz dompu7 ; no, branch jmp allend ; yes, do all end dompu7: cmp al,0FFH ; = FF? jnz dompu8 ; no, branch jmp midism ; yes, do midi system message dompu8: ret dompu endp ;-------------------------------------------------------------- ; mpuput(data) ; send data to mpu-401 ; C call ; public _mpuput _mpuput proc far push bp mov bp,sp mov dx,mstat ; mpu status port mpup1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpup1 ; loop til ready mov dx,mdata ; mpu data port mov ax,[bp+p1] ; get the data out dx,al ; send to mpu mov sp,bp ; restore C sp pop bp ret ; exit _mpuput endp ;-------------------------------------------------------------- ; mpuput ; send data in AL to mpu-401 ; local call, AX is preserved ; mpuput proc near push ax mov dx,mstat ; mpu status port mpupa1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpupa1 ; loop til ready mov dx,mdata ; mpu data port pop ax ; get the data out dx,al ; send to mpu ret ; exit mpuput endp ;-------------------------------------------------------------- ; data=mpuget() ; get data from mpu-401 ; C call ; public _mpuget _mpuget proc far mov dx,mstat ; mpu status port mpug1: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpug1 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; get the data byte mov ah,0 ; zero out ms byte ret ; exit with ax = data _mpuget endp ;-------------------------------------------------------------- ; mpuget ; get data from mpu-401 to AX ; local call ; mpuget proc near mov dx,mstat ; mpu status port mpuga1: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpuga1 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; get the data byte mov ah,0 ; zero out ms byte ret ; exit with ax = data mpuget endp ;-------------------------------------------------------------- ; mpucmd(cmd) ; send a command to mpu-401 ; public _mpucmd _mpucmd proc far push bp mov bp,sp mov dx,mstat ; mpu status port mpuc1: in al,dx ; get the status and al,mdrr ; test for Data Recieve Ready jnz mpuc1 ; loop til ready cli ; disable intes mov ax,[bp+p1] ; get the command out dx,al ; send to mpu mpuc2: in al,dx ; get the status and al,mdsr ; test for Data Set Ready jnz mpuc2 ; loop til ready mov dx,mdata ; mpu data port in al,dx ; read it cmp al,0FEH ; acknowledge? jz mpuc3 ; yes, branch push di ; save C registers push si call dompu ; do mpu routine pop si pop di mov dx,mstat ; mpu status port jmp short mpuc2 ; check again for ack mpuc3: sti ; enable ints mov sp,bp ; restore C sp pop bp ret ; exit _mpucmd endp ;-------------------------------------------------------------- ; data = gett() ; get byte from track buffer ; C call ; public _gett _gett proc far mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endtrk ; reached end? jnz gett1 ; no, exit mov bx,startt ; yes, set index = start gett1: mov _indext,bx ; save index ret ; exit with ax = data _gett endp ;-------------------------------------------------------------- ; gett ; get byte to AX from track buffer ; local call ; gett proc near mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endtrk ; reached end? jnz getta1 ; no, exit mov bx,startt ; yes, set index = start getta1: mov _indext,bx ; save index ret ; exit with ax = data gett endp ;-------------------------------------------------------------- ; putt(track_data) ; put byte to track buffer ; C call ; public _putt _putt proc far push bp mov bp,sp mov bx,_indext ; get index mov dx,seg _tbuf mov al,[bp+p1] ; get the data push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitt ; reached limit? mov ax,1 ; flag error jz putt0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indext,bx ; store index mov endtrk,bx ; end = index putt0: mov _enderr,ax ; save in _enderr mov sp,bp ; restore C sp pop bp ret ; exit _putt endp ;-------------------------------------------------------------- ; putt ; put byte in AL to track buffer ; local call ; putt proc near mov bx,_indext ; get index mov dx,seg _tbuf push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitt ; reached limit? mov ax,1 ; flag error jz putta0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indext,bx ; store index mov endtrk,bx ; end = index putta0: mov _enderr,ax ; save in _enderr ret ; exit putt endp ;-------------------------------------------------------------- ; data = getp() ; get byte from parameter buffer ; C call ; public _getp _getp proc far mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endpar ; reached end? jnz getp1 ; no, exit mov bx,startp ; yes, set index = start getp1: mov _indexp,bx ; save index ret ; exit with ax = data _getp endp ;-------------------------------------------------------------- ; getp ; get byte to AX from param buffer ; local call ; getp proc near mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; fetch the data mov al,ds:[bx] xor ah,ah ; ax = data pop ds inc bx ; inc index cmp bx,endpar ; reached end? jnz getpa1 ; no, exit mov bx,startp ; yes, set index = start getpa1: mov _indexp,bx ; save index ret ; exit with ax = data getp endp ;-------------------------------------------------------------- ; putp(param_data) ; put byte to param buffer ; C call ; public _putp _putp proc far push bp mov bp,sp mov bx,_indexp ; get index mov dx,seg _pbuf mov al,[bp+p1] ; get the data push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitp ; reached limit? mov ax,1 ; flag error jz putp0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indexp,bx ; store index mov endpar,bx ; end = index putp0: mov _enderr,ax ; save in _enderr mov sp,bp ; restore C sp pop bp ret ; exit _putp endp ;-------------------------------------------------------------- ; putp ; put byte in AL to param buffer ; local call ; putp proc near mov bx,_indexp ; get index mov dx,seg _pbuf push ds mov ds,dx ; store the data mov ds:[bx],al pop ds inc bx ; inc index cmp bx,limitp ; reached limit? mov ax,1 ; flag error jz putpa0 ; yes, branch with err mov ax,0 ; no, flag no-error mov _indexp,bx ; store index mov endpar,bx ; end = index putpa0: mov _enderr,ax ; save in _enderr ret ; exit putp endp ;-------------------------------------------------------------- ; timeo ; process timing overflow on inte ; local call with intval in AL ; timeo proc near call putt ret timeo endp ;-------------------------------------------------------------- ; condr ; process conductor request on inte ; local dummy routine, sends timing overflow byte ; condr proc near mov al,0F8H call putt ret condr endp ;-------------------------------------------------------------- ; clockh ; process clock to host on inte ; local call ; clockh proc near mov ax,clkblp ; get blip flag inc ax ; count up and ax,1 mov clkblp,ax ; put back inc ax ; 1,2 = happy face mov cx,ds mov dx,0B800H ; point to gx screen mov ds,dx mov byte ptr ds:9EH,al ; display blip mov ds,cx ret clockh endp ;-------------------------------------------------------------- ; allend ; process all end on inte ; local call, clears playing flag ; allend proc near mov ax,0 mov _playing,ax ret allend endp ;-------------------------------------------------------------- ; timev ; process time value on inte ; local call with intval in AL ; timev proc near call putt mov ax,1 ; set special = 1 mov special,ax ; dotimev on next inte ret timev endp ;-------------------------------------------------------------- ; dotimev (special = 1 ) ; next inte processing of time value ; local call with intval in AL ; dotimev proc near cmp al,0F8H ; mpu mark, no operation jz dotime1 cmp al,0F9H ; mpu mark, measure end jz dotime2 cmp al,0FCH ; mpu mark, data end jnz dotime3 mov ax,0 mov _recording,ax ; clr recording flag dotime2:call putt ; put in record buffer dotime1:mov ax,0 mov special,ax ; done, clear special ret ; exit dotime3:mov ah,al ; get a copy and ah,0F0H ; zip channel data cmp ah,0C0H ; midi msg, program change jz dotime4 cmp ah,0DH ; midi msg, channel pressure jnz dotime5 dotime4:mov dx,1 ; set to recieve 1 more byte jmp short dotime6 dotime5:cmp ah,80H ; midi msg, note off jz dotime7 cmp ah,90H ; midi msg, note on jz dotime7 cmp ah,0A0H ; midi msg, after touch jz dotime7 cmp ah,0B0H ; midi msg, control change jz dotime7 cmp ah,0E0H ; midi msg, pitch wheel jnz dotime8 dotime7:mov dx,2 ; set to recieve 2 more bytes dotime6:mov rcount,dx mov icount,dx call putt ; put in record buffer ret ; exit dotime8:and ah,80H ; < 7FH ? jz dotime9 ; yes, branch mov ax,0 ; no, is error mov special,ax ; clear special call far ptr _beep ; signal error ret ; exit dotime9:mov ah,byte ptr icount ; get current count cmp ah,0 ; new one? jnz dotim10 ; no, branch mov ah,byte ptr rcount ; yes, icount <-- rcount dotim10:push ax ; save it call putt ; save the data byte in AL pop ax ; ah = icount dec ah ; dec icount mov byte ptr icount,ah ; save it jnz dotime11 ; branch if icount not 0 mov ax,0 ; else clear special mov special,ax dotime11:ret ; exit dotimev endp ;-------------------------------------------------------------- ; trackd ; process track play request on inte ; local call with intval in AL ; trackd proc near call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port cmp al,0F8H ; midi timing overflow jnz trackd1 ret ; just exit if it was timing overfow trackd1:call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port and al,0F0H ; strip midi channel info cmp al,0F0H ; mpu mark jnz trackd2 ret trackd2:test al,80H ; <= 7FH ? jnz trackd3 ; no, branch cmp pcount,1 ; pcount = 1 ? jnz trackd4 ; no, branch ret ; yes, exit trackd3:cmp al,0C0H ; one byte needed? jz trackd5 cmp al,0D0H jnz trackd6 trackd5:mov pcount,1 ; yes, set running pcount to 1 jmp short trackd4 ; ... and get one more byte trackd6:mov pcount,2 ; else set running pcount to 2 call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port trackd4:call gett ; get next track buffer byte nop ; fix midi channel call mpuput ; send it to mpu data port ret trackd endp ;-------------------------------------------------------------- ; midism ; process midi system message on inte ; local call ; midism proc near mov ax,2 ; flag special = 2 mov special,ax ; procsm on next inte ret midism endp ;-------------------------------------------------------------- ; procsm ( special = 2) ; continue to process midi system message in inte ; local call with intval in AL ; procsm proc near cmp al,0F0H ; midi exclusive jnz procsm1 call putp ; save in para buffer mov ax,1 ; set loading flag mov _loading,ax mov ax,3 ; set special = 3 mov special,ax ; continue on next inte ret procsm1:cmp al,0F3H ; song select jnz procsm2 mov ax,4 ; set special = 4 mov special,ax ; continue on next inte ret procsm2:cmp al,0F2H ; song position jnz procsm3 mov ax,5 ; set special = 5 mov special,ax ; continue on next inte ret procsm3:cmp al,0F6H ; tune request jnz procsm4 nop ; insert routine here jmp short procsm0 ; clr special & exit procsm4:mov byte ptr _rtmsg,al ; flag real time message procsm0:mov ax,0 ; clear special mov special,ax ret ; exit procsm endp ;-------------------------------------------------------------- ; sysexc (special = 3 ) ; inte processing of system exclusive values ; local call with intval in AL ; sysexc proc near push ax ; save inte value call putp ; save in parameter buffer pop ax cmp al,0F7H ; was it EOX jnz sysexc0 ; no, just exit mov ax,0 ; yes, mov _loading,ax ; clear loading flag mov special,ax ; clear special inc word ptr _pending ; inc pending flag sysexc0:ret ; exit sysexc endp ;-------------------------------------------------------------- ; songsel (special = 4) ; inte processing of song select ; local call with intval in AL ; songsel proc near nop ; dummy routine mov ax,0 ; clear special mov special,ax ret songsel endp ;-------------------------------------------------------------- ; songp1 (special = 5) ; inte processing of song position 1st byte ; local call with intval in AL ; songp1 proc near nop ; dummy routine mov ax,6 ; special = 6 mov special,ax ; songp2 on next int ret songp1 endp ;-------------------------------------------------------------- ; songp2 (special = 6) ; inte processing of position 2nd byte ; local call with intval in AL ; songp2 proc near nop ; dummy routine mov ax,0 ; clear special mov special,ax ret songp2 endp ;-------------------------------------------------------------- ; a little beep on the speaker ; public _beep _beep proc far mov al,0b6h out 043h,al ;write timer mode regester mov ax,1000 ;set divisor value to 1000 out 042h,al ;write timer 1 count lsb mov al,ah out 042h,al ;write timer 2 count msb in al,061h ;get current port b setting mov ah,al ;save current setting. or al,3 ;turn speaker on out 061h,al mov cx,0a48h ;10 msec delay on ibm pc 4.7mh 8088 delay: loop delay mov al,ah ;get old port b setting out 061h,al ;set it back the way you found it ret _beep endp ;-------------------------------------------------------------- ; blip(char) -- sends char to upper right corner of screen ; public _blip _blip proc far push bp mov bp,sp mov ax,[bp+p1] add ax,'0' mov cx,ds mov dx,0B800H mov ds,dx mov byte ptr ds:9EH,al mov ds,cx mov sp,bp pop bp ret _blip endp ;-------------------------------------------------------------- PRIM_TEXT ENDS END ############################################################### /************************************************************** * midi.h * * equates for MPU-401 & MIDI * */ /* mpu port addresses & flags */ #define MDATA 0x330 /* mpu data port address */ #define MSTAT 0x331 /* mpu status port address */ #define MCMD 0x331 /* mpu command port address */ #define MDSR 0x80 /* mpu data set ready, active low */ #define MDRR 0x40 /* mpu data read ready, active low */ /* general equates */ #define TRUE 1 #define FALSE 0 /* midi codes */ #define KEY_ON 0x90 /* +2, turn note on/off */ #define KEY_OFF 0x80 /* +2, turn note off */ #define EOX 0xF7 /* +0, end of transmission */ /* Yamaha specific codes */ #define DUMP_1V 0 /* bulk dump 1 voice */ #define DUMP_1P 1 /* bulk dump 1 performance setup */ #define DUMP_64P 2 /* bulk dump 64 performance setups */ #define DUMP_32V 9 /* bulk dump 32 voices */ #define DUMP_CA 125 /* dump condition acknowledge */ ############################################################### /************************************************************** * testmidi.c 1/4/86 Copyright (c) 1986, John Dunn * * test program for MPU/MIDI and TX816 * */ #include "stdio.h" #include "midi.h" /************************************************************** * global values */ extern unsigned char pbuf[]; /* play buffer */ extern unsigned char rbuf[]; /* recording buffer */ extern unsigned char sbuf[]; /* sysexc dump buffer */ extern unsigned int indexp; /* play buf index */ extern unsigned int indexr; /* recording buf index */ extern unsigned int indexs; /* sysexc dump buf index */ extern unsigned int channel; /* current midi channel */ extern unsigned int pending; /* number of sys excl pending */ extern unsigned int recording; /* nz when recording track data */ extern unsigned int playing; /* nz when playing track data */ extern unsigned int looping; /* nz when playing a loop */ extern unsigned int loading; /* nz when loading sysexc dump data */ extern unsigned int enderr; /* nz if put index at limit */ extern unsigned long ticks; /* clock tick count */ extern unsigned long nextt; /* timer tick count */ extern unsigned char tocks[]; /* midi string tick representation */ extern unsigned char packet[]; /* midi output packet */ unsigned int gv = 64; /* global note velocity */ main(argc, argv) int argc; char *argv[]; { int i; initm(); printf("starting\n"); getchar(); channel = 0; startt(); dump_request(DUMP_1V); for(i = 0; i < 166; ++i) printf("%x ",sbuf[i]); printf("\n\n"); for(i = 145+6; i < 155+6; ++i) printf("%c",sbuf[i]); printf("\n\n"); dump_request(DUMP_1P); for(i = 0; i < 110; ++i) printf("%x ",sbuf[i]); printf("\n\n"); for(i = 64+6; i < 94+6; ++i) printf("%c",sbuf[i]); printf("\n"); foo(); nextt = 0; ticks = 0; indexp = 0; playing = TRUE; getchar(); looping = TRUE; playing = TRUE; getchar(); while(!packet[2]); printf("ready to record\n"); indexr = 0; recording = 1; getchar(); indexr = 0; for(i = 0; i < 256; ++i) printf("%x ",rbuf[i]); printf("\n\n"); stopt(); exitm(); getchar(); exit(0); } /************************************************************** * issue a request to dump data * specific to Yamaha */ dump_request(fmt) int fmt; { indexs = 0; midio(0xF0); midio(0x43); midio(0x20 | channel); midio(fmt); midio(EOX); while(!loading); } /************************************************************** * xlates(notes) * translate a character string to midi data in the play buffer * valid characters: * T,S,I,Q,H,W = notes * 0,1,2,3,4,5,6,7,8,9 = octaves * A,B,C,D,E,F,G = pitch * +,- = sharp, flat */ xlate(notes) char *notes; { int time,oct,val; char c; playing = 0; /* disable playing */ indexp = 0; /* reset play index */ ticks = 0; /* reset clock */ while (c = toupper(*notes++)) { if(c > 'G') { switch(c) { case 'T': time = 1; break; /* 32nd note */ case 'S': time = 2; break; /* 16th note */ case 'I': time = 4; break; /* Eighth note */ case 'Q': time = 8; break; /* quarter note */ case 'H': time = 16; break; /* half note */ case 'W': time = 32; break; /* whole note */ } putp(KEY_ON); /* send MIDI note on */ putptok(); /* send current time */ ticks = ticks+time; /* add note time/2 */ putp(oct+val); /* send note value */ putp(gv); /* send global velocity */ putp(KEY_ON); /* send MIDI note off */ putptok(); ticks = ticks+time; /* add note time/2 */ putp(oct+val); /* send note value */ putp(0); /* send velocity = 0 */ } else if(c >= 'A') { switch(c) { case 'C': val = 0; break; /* key of C */ case 'D': val = 2; break; case 'E': val = 4; break; case 'F': val = 5; break; case 'G': val = 7; break; case 'A': val = 9; break; case 'B': val = 11; break; } } else if(c >= '0') oct = 12*(c-'0'); else switch(c) { case '+': val++; break; /* sharp */ case '-': val--; break; /* flat */ } } indexp = 0; /* reset play index */ ticks = 0; /* reset clock */ } /* translate ticks to tocks, then put tocks into the play buffer */ putptok() { tictoc(); /* ticks --> tocks */ putp(tocks[0]); putp(tocks[1]); putp(tocks[2]); putp(tocks[3]); } foo() { static char *this = "3CIESGS4CIESGS5CIESGS6CIESGS7CH"; xlate(this); }