home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sound
/
midi
/
mbm.asm
< prev
next >
Wrap
Assembly Source File
|
1988-03-20
|
24KB
|
598 lines
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