Category : A Collection of Games for DOS and Windows
Archive   : MUSICBOX.ZIP
Filename : MBM.ASM

 
Output of file : MBM.ASM contained in archive : MUSICBOX.ZIP
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



  3 Responses to “Category : A Collection of Games for DOS and Windows
Archive   : MUSICBOX.ZIP
Filename : MBM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/