home *** CD-ROM | disk | FTP | other *** search
- TITLE MPU/MIDI primitives for Modular Sequencer
- NAME MBM
- .SALL
- ;==============================================================
- ; MusicBox Modular Sequencer, Version 2
- ; midi and clock interface
- ;--------------------------------------------------------------
- ; author: John Dunn
- ; date: 03/07/86
- ; update: 03/20/88
- ;--------------------------------------------------------------
- ; COPYRIGHT (C) 1986 John Dunn, All Rights Reserved
- ; Entered into the Public Domain, March 20, 1988
- ;
- ; Use and copying of this software and preparation of derivative works
- ; based upon this software are permitted. Any distribution of this
- ; software or derivative works must comply with all applicable United
- ; States export control laws.
- ;
- ; This software is made available AS IS, and the author makes no warranty
- ; about the software, its performance, or its conformity to any specification.
- ;
- ; Any person obtaining a copy of this software is requested to send their
- ; name and address address to:
- ;
- ; John Dunn, Senior Research Fellow
- ; Time Arts Inc.
- ; 3436 Mendocino Ave.
- ; Santa Rosa, CA 95401
- ;
- ;==============================================================
- include order.asm
- ;--------------------------------------------------------------
- include equates.asm
- ;==============================================================
- _DATA SEGMENT
- ASSUME DS:DGROUP, CS:_TEXT
- ;--------------------------------------------------------------
- public midip
- ;--------------------------------------------------------------
- extrn midiok:byte
- ;--------------------------------------------------------------
- moboix0 dw 0 ; MIDI Out Buffer Index
- mobiix0 dw 0 ; MIDI In Buffer Index
- ;--------------------------------------------------------------
- moboix1 dw 0 ; MIDI Out Buffer Index
- mobiix1 dw 0 ; MIDI In Buffer Index
- ;--------------------------------------------------------------
- midip db 0 ; midi port number 0/1
- mpuis db 0 ; nz if mpu intes happening
- savint0 db 0 ; saved int byte from 8259A
- ;--------------------------------------------------------------
- _DATA ENDS
- ;==============================================================
- _TEXT SEGMENT
- ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: NOTHING
- ;==============================================================
- extrn _dummy:far
- extrn loops:word
- ;==============================================================
- ; basic midi port routines
- ;--------------------------------------------------------------
- ; words declared in the CS for faster interrupt service
- public midixs,mstop,mstart,mcont,midata,miflag,midatix,misend
- public _mpuinf,_mpuinm
- ;--------------------------------------------------------------
- midixs db 0 ; midi extrnal sync tick
- mstop db 0 ; midi stop tick
- mstart db 0 ; midi start tick
- mcont db 0 ; midi continue tick
- midata db 0 ; midi input data byte
- miflag db 0 ; midi input data flag
- misysx db 0 ; midi sys exclusive flag
- midatix db 0 ; midi data index
- misend db 0 ; midi send data flag
- _mpuinf db 0 ; mpu input from 1=1, 2=2, 0=none
- _mpuinm db 3 ; mpu input mask
- nottrue db 'install patch area',0,1,3,7,0
- mobuf1 db 8192+105 dup(?) ; MIDI Out Buffer
- mobuf0 db 8192+128 dup(?) ; MIDI Out Buffer
- ;--------------------------------------------------------------
- ; initialize mpu, int vectors, etc.
- ; must be called once only on startup
- ; sets direct MIDI mode, with interrupt on input
- ; sets interrupt vector 0AH at 0000:0028, for
- ; hardware interrupt 2.
- ;
- public startm
- startm proc near
- test mpuis,1 ; already done it?
- jnz initmx ; yes, split
- 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,offset mpuint
- mov cx,seg mpuint
- mov ds,cx
- int 21H ; set new int vect
- pop ds ; restore ds
-
- cli
- call mpurst ; reset mpu
- in al,21H ; enable irq2
- mov savint0,al ; save it
- and al,0FBH
- out 21H,al
- mov mpuis,1 ; flag = active
- sti
- initmx: ret
- startm endp ; end of init mpu
- ;--------------------------------------------------------------
- ; shutdown mpu, restore int vectors, etc.
- ; must be called once only on exit
- ;
- public stopm
- stopm proc near
- test mpuis,1 ; already done it?
- jz exitmx ; yes, split
- cli
- mov al,0FFH ; issue mpu reset
- mov dx,mpucmd
- out dx,al
- add dx,2 ; do 2nd port
- out dx,al
- mov al,savint0 ; get original irq masks
- out 21H,al ; restore them
- mov mpuis,0 ; flag = inactive
- ;
- push ds
- mov ah,25h ; restore previous irq2
- mov al,0AH
- mov dx,word ptr cs:orgint+1
- mov cx,word ptr cs:orgint+3
- mov ds,cx
- int 21h
- pop ds
- ;
- exitmx: ret
- stopm 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
- cli ; disable interupts
- push ax ; save ax
- push dx
-
- mov ah,1 ; set mpu in flag to mpu#1
- mov dx,mpstat ; read mpu status
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
- add dx,2 ; no, check other port
- mov ah,2 ; set mpu in flag to mpu#1
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
-
- mov ah,1 ; set mpu in flag to mpu#1
- mov dx,mpstat ; read mpu status
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
- add dx,2 ; no, check other port
- mov ah,2 ; set mpu in flag to mpu#1
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
-
- mov ah,1 ; set mpu in flag to mpu#1
- mov dx,mpstat ; read mpu status
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
- add dx,2 ; no, check other port
- mov ah,2 ; set mpu in flag to mpu#1
- in al,dx
- and al,mpdsr ; generated by mpu?
- jz mpui1 ; yes, branch
-
- mov al,20H
- out 20H,al
-
- pop dx ; restore cpu
- pop ax
- sti ; enable interupts
- iret
- orgint: jmp far ptr _dummy ; dummy vector, filled by _initm
-
- mpui1:
- push bx ; save cpu state
- push cx
- push di
- push si
- push bp
- push ds
- push es
-
- mov cx,cs ; set up seg regs
- mov ds,cx
-
- dec dx ; get mpu int data
- in al,dx ; /
-
- mov _mpuinf,ah ; save flag status
- test ah,_mpuinm ; check against mask
- jz mpuiz ; exit if masked out
-
- cmp al,0feh ; Active Sensing
- jz mpuiz ; yes, exit
- cmp al,0f8H ; Midi Sync?
- jnz mpui2 ; no, branch
- inc midixs ; yes, inc the flag
- jmp short mpuiz ; .. and on to work
- mpui2: cmp al,0fah ; Midi Start?
- jnz mpui3 ; no, branch
- inc mstart ; yes, inc the flag
- jmp short mpuiz ; .. and on to work
- mpui3: cmp al,0fbh ; Midi Continue
- jnz mpui4 ; no, branch
- inc mcont ; yes, inc the flag
- jmp short mpuiz ; .. and on to work
- mpui4: cmp al,0fch ; Midi stop?
- jnz mpui5 ; no, branch
- inc mstop ; yes, inc the flag
- jmp short mpuiz ; .. and on to work
- mpui5: mov midata,al ; put the data byte away
- mov miflag,1 ; set the data-in flag
- cmp al,0f0h ; system exclusive
- jnz mpui6 ; no, branch
- mov misysx,1 ; yes, set the flag
- jmp short mpuiz ; exit
- mpui6: cmp al,0f7h ; EOX?
- jnz mpui7 ; no, branch
- mov misysx,0 ; yes, clear the flag
- jmp short mpuiz ; exit
- mpui7: test misysx,-1 ; sys exclusive happening?
- jnz mpuiz ; yes, branch
- test misend,-1 ; want to send data?
- jz mpui8 ; no, branch
- mov dx,seg bufsp ; yes get the buffer
- mov es,dx ; /
- mov bl,midatix ; get the index
- mov bh,0FH ; put in bank "F"
- mov es:[bx],al ; put the byte away
- mpui8: inc midatix ; inc the index
- mpuiz: ;
- 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
- out 20H,al
- pop ax
- sti ; enable interrupts
- iret ; return from interrupt
- mpuint endp
- ;--------------------------------------------------------------
- ; mpurst
- ; clear out the mpu, and set for direct MIDI i/o
- ;
- public mpurst
- mpurst proc near
- cli ; disable intes
- mov dx,mpdata ; read mpu data port
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- mov dx,mpstat ; mpu status port
- mpurs1: in al,dx ; get the status
- and al,mpdrr ; test for Data Recieve Ready
- jnz mpurs1 ; loop til ready
- mov ax,03FH ; MPU UART command
- out dx,al ; send to mpu
- mov cx,800H ; delay
- mpurs2: loop mpurs2 ; /
- mov dx,mpdata ; read mpu data port
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- ;
- ; do 2nd MPU
- ;
- test midiok,2 ; 2nd MPU online?
- jz mpursx ; no, just exit
- ;
- mov dx,mpdata+2 ; read mpu data port
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- jmp short $+2 ; wait
- mov dx,mpstat+2 ; mpu status port
- mpurs3: in al,dx ; get the status
- and al,mpdrr ; test for Data Recieve Ready
- jnz mpurs3 ; loop til ready
- mov ax,03FH ; MPU UART command
- out dx,al ; send to mpu
- mov cx,800H ; delay
- mpurs4: loop mpurs4 ; /
- mov dx,mpdata+2 ; read mpu data port
- in al,dx ; get the data
- jmp short $+2 ; wait
- in al,dx ; get the data
- ;
- mpursx: sti ; enable interrupts
- ret ; exit
- mpurst endp
- ;--------------------------------------------------------------
- ; send a byte in AL to MIDI Out Buffer
- ;
- public tomidi
- tomidi proc near
- test midip,10H ; test midi port
- jnz tomidi1 ; branch if port 1
- ;
- mov bx,mobiix0 ; get midi out buffer out index
- mov cs:mobuf0[bx],al; put next byte
- inc bx ; bump index
- and bx,8191 ; wrap-around
- mov mobiix0,bx ; store new mob out index
- ret
- ;
- tomidi1:mov bx,mobiix1 ; get midi out buffer out index
- mov cs:mobuf1[bx],al; put next byte
- inc bx ; bump index
- and bx,8191 ; wrap-around
- mov mobiix1,bx ; store new mob out index
- ret
- tomidi endp
- ;--------------------------------------------------------------
- ; send a byte in AL to all MIDI Out Buffers
- ;
- public allmidi
- allmidi proc near
- ;
- mov bx,mobiix0 ; get midi out buffer out index
- mov cs:mobuf0[bx],al; put next byte
- inc bx ; bump index
- and bx,8191 ; wrap-around
- mov mobiix0,bx ; store new mob out index
- ;
- mov bx,mobiix1 ; get midi out buffer out index
- mov cs:mobuf1[bx],al; put next byte
- inc bx ; bump index
- and bx,8191 ; wrap-around
- mov mobiix1,bx ; store new mob out index
- ret
- allmidi endp
- ;--------------------------------------------------------------
- ; get next byte from pass buffer and send to midi
- ; does nothing if midi output port is busy
- ; or if the buffer is empty
- ;
- public sendm
- sendm proc near
- mov bx,moboix0 ; get midi out buffer out index
- cmp bx,mobiix0 ; same as midi out buffer in index?
- jz sendm1 ; yes, exit
- ;
- test midiok,1 ; ok to do it?
- jz sendm2 ; no, then fake it
- ;
- mov dx,mpstat ; mpu status port
- in al,dx ; get the status
- and al,mpdrr ; test for Data Recieve Ready
- jnz sendm1 ; exit if midi out port is busy
- ;
- mov al,cs:mobuf0[bx]; get next byte
- mov dx,mpdata ; mpu data port
- out dx,al ; send to mpu
- sendm2: inc bx ; bump index
- and bx,8191 ; wrap-around
- mov moboix0,bx ; store new mob out index
- ;
- ; do 2nd buffer
- ;
- sendm1: mov bx,moboix1 ; get midi out buffer out index
- cmp bx,mobiix1 ; same as midi out buffer in index?
- jz sendm3 ; yes, exit
- ;
- test midiok,2 ; ok to do it?
- jz sendm4 ; no, then fake it
- ;
- mov dx,mpstat+2 ; mpu status port
- in al,dx ; get the status
- and al,mpdrr ; test for Data Recieve Ready
- jnz sendm3 ; exit if midi out port is busy
- ;
- mov al,cs:mobuf1[bx]; get next byte
- mov dx,mpdata+2 ; mpu data port
- out dx,al ; send to mpu
- sendm4: inc bx ; bump index
- and bx,8191 ; wrap-around
- mov moboix1,bx ; store new mob out index
- sendm3: ret
- sendm endp
- ;--------------------------------------------------------------
- ; Clear all MIDI channels
- ;
- public allclr
- allclr proc near
- allclr1:mov midip,0 ; set midi port 0
- call sendm ; now really do it
- allclr2:mov midip,10H ; set midi port 1
- call sendm ; now really do it
- mov bx,moboix0 ; get midi out buffer out index
- cmp bx,mobiix0 ; same as midi in buffer in index?
- jnz allclr1 ; no, keep sending
- mov bx,moboix1 ; get midi out buffer out index
- cmp bx,mobiix1 ; same as midi in buffer in index?
- jnz allclr2 ; no, keep sending
- ret
- allclr endp
-
- ;--------------------------------------------------------------
- ; test for midi output buffers empty
- ; returns al bits 0,1 set if buffers are not empty
- ;
- public tstmob
- tstmob: xor al,al ; clear flag
- mov bx,moboix0 ; get midi out buffer out index
- cmp bx,mobiix0 ; same as midi in buffer in index?
- jz tstmob1 ; yes, branch
- inc al ; no, set the bit
- tstmob1:mov bx,moboix1 ; get midi out buffer out index
- cmp bx,mobiix1 ; same as midi in buffer in index?
- jz tstmob2 ; yes, branch
- or al,2 ; no, set the bit
- tstmob2:ret ; exit w result in AL
- ;--------------------------------------------------------------
- ; Turn off all MIDI modules
- ;
- public alloff
- alloff proc near
- ;
- mov dh,0 ; for channels
- mov cl,dh ; dummy data byte
- workh1c:mov ah,0B0H ; MIDI Channel message
- or ah,dh ; add channel info
- ;
- mov al,ah ; midi channel msg
- call allmidi ; /
- mov al,7CH ; omni off
- call allmidi ; send
- mov al,cl ; send dummy
- call allmidi ; /
- ;
- mov al,ah ; midi channel msg
- call allmidi ; /
- mov al,7FH ; poly, ano
- call allmidi ; /
- mov al,cl ; send dummy
- call allmidi ; /
- ;
- inc dh ; next channel
- test dh,16 ; 16 channels
- jz workh1c ; /
- ;
- call allclr ; clear the channels
- ret
- alloff endp
- ;--------------------------------------------------------------
- ; TIMER ROUTINES
- ;--------------------------------------------------------------
- ; words declared in the CS for faster interrupt service
- public ticks,ticks1,timer,seconds,secondf
- ;--------------------------------------------------------------
- timeis db 0 ; nz if timer inte is happening
- times0 dw 0 ; storage for dos timer vector
- times1 dw 0 ; saa
- ticks dw 0 ; lsw of tick count
- ticks1 dw 0 ; msw of tick count
- timer dw 0 ; system timer count
- second0 dw 582 ; real time clk ticker
- seconds dw 0 ; running seconds count
- secondf db 0 ; nz if seconds was incremented
- ;--------------------------------------------------------------
- ; startt ( sets timer int to vector to dotime )
- ;
- public startt
- startt proc near
- test cs:timeis,1 ; already done it?
- jnz starttx ; yes, split
- push es
- mov ah,35H ; get current int 8
- mov al,8 ; /
- int 21H ; /
- mov cs:times1,es ; save it
- mov cs:times0,bx
- pop es
- ;
- push ds ; save data seg
- mov ah,25H ; set int vect
- mov al,8 ; int 8 for MS timer
- mov dx,offset dotime;
- mov cx,seg dotime ;
- mov ds,cx ;
- int 21H ; set new int vect
- pop ds ; restore data seg
- mov cs:timeis,1 ; flag = active
- ;
- cli
- ; mov ax,00fffh ; set new timing
- mov ax,007ffh ; set new timing
- out 40H,al
- jmp short $+2
- mov al,ah
- out 40H,al
- sti
- starttx:ret
- startt endp
- ;--------------------------------------------------------------
- ; stopt ( restores oringinal dos int )
- ;
- public stopt
- stopt proc near
- test cs:timeis,1 ; already done it?
- jz stoptx ; yes, split
- push ds ; save current data seg
- mov ah,25h ; restore previous irq
- mov al,8 ; /
- mov dx,cs:times0 ; /
- mov cx,cs:times1 ; /
- mov ds,cx ; /
- int 21h ; /
- pop ds ; restore data seg
- mov cs:timeis,0 ; flag = inactive
- ;
- cli ; restore original timing
- mov ax,0ffffh
- out 40H,al
- jmp short $+2
- mov al,ah
- out 40H,al
- sti
- stoptx: ret
- stopt endp
-
- ;--------------------------------------------------------------
- ; DOTIME interrupt routine called every clock tick
- ;
- dotime proc far
- dec cs:second0 ; count down second timer
- jnz dotim2 ; branch if not time
- inc cs:seconds ; else bump seconds count
- mov cs:second0,582 ; 582.4 ticks/sec
- mov cs:secondf,1 ; set the flag
- dotim2:
- test cs:timer,-1 ; timer zero
- jz dotim1 ; yes, branch
- dec cs:timer ; no, count down
- dotim1: inc cs:ticks ; inc ls word
- jnz dotim0 ; branch if not overflow
- inc cs:ticks1 ; else inc ms word
- ;dotim0: test cs:ticks,15 ; bump system stuff every 16th clock
- dotim0: test cs:ticks,31 ; bump system stuff every 32th clock
- jz dotimx ; branch if time to doit
- push ax
- mov al,20h
- out 20h,al
- pop ax
- iret ; else just return from interrupt
- dotimx: push cs:times1 ; on to the original inte
- push cs:times0 ; /
- ret ; /
- dotime endp
- ;--------------------------------------------------------------
- _TEXT ENDS
- END
-
-