home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
sound
/
midi
/
mba.asm
< prev
next >
Wrap
Assembly Source File
|
1988-03-20
|
179KB
|
3,938 lines
TITLE Modules for Modular Sequencer
NAME MBA
.SALL
;==============================================================
; MusicBox Modular Sequencer, Version 2
; modules code
;--------------------------------------------------------------
; 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
;==============================================================
BUFPA SEGMENT
if debug
db 7fffh dup (?)
db 7fffh dup (?)
else
db 7fffh dup (0)
db 7fffh dup (0)
endif
BUFPA ENDS
;--------------------------------------------------------------
BUFSP SEGMENT
if debug
db 4096 dup (?)
else
db 4096 dup (0)
endif
BUFSP ENDS
;--------------------------------------------------------------
BUFFS SEGMENT
if debug
db 7fffh dup (?)
db 7fffh dup (?)
else
db 7fffh dup (0)
db 7fffh dup (0)
endif
BUFFS ENDS
;--------------------------------------------------------------
BUFTU SEGMENT
if debug
db 4096 dup (?)
else
db 4096 dup (0)
endif
BUFTU ENDS
;==============================================================
_DATA SEGMENT
ASSUME DS:DGROUP, CS:_TEXT
;--------------------------------------------------------------
extrn ticka:byte,tickis:byte,fastflg:byte
extrn _header:byte
extrn varsav:word,cmdflg:byte,special:word,cmdcnt:byte
extrn locsav:word,cmdloc:word,vpage:word,curadr:word
extrn midip:byte,valflg:byte,asensf:byte
extrn @zero:near,magflg:byte,usrflg:byte,holdv:word
extrn colr:byte,lodflg:byte
extrn modnum:byte,doesc:word,clrchf:byte,curonf:byte
;--------------------------------------------------------------
if debug
extrn show0:word,show1:word,show2:word,show3:word
endif
;--------------------------------------------------------------
public midisf,midixsf,mpmodf,mpadrf,mpadr
public mmcount,mmtick,mmreset,mmstart
;--------------------------------------------------------------
midisf db 0 ; 0=no sync, 1=send sync
midixsf db 0 ; 0=not xtrn sync, NZ=is
mpmodf db 1 ; master program mode flag
mpadrf db 0 ; nz if change in prog address
mpadr db 0 ; master program address
mmcount dw 0 ; master measure count
mmtick dw 1 ; ticks left in current measure
mmreset db 1 ; master measure reset flag
mmstart db 1 ; master measurd start flag
;--------------------------------------------------------------
public rseed,rhold,notetbl,notes
public xcax,xcbx,xccx,xcdx
public temp0,temp1,temp2,temp3
;--------------------------------------------------------------
rseed dw 0 ; random number seed
rhold db 0 ; nz = holding
notes dw 4186,4435,4699,4978,5274,5588,5920,6272,6645,7040,7459,7902
;
;--------------------------------------------------------------
; notes --> clocks
;
; nv = 0 1 2 3 4 5 6 7
;
notetbl db 192, 96, 48, 24, 12, 6, 3, 2 ; normal
db 128, 64, 32, 16, 8, 4, 2, 2 ; dotted
db 255,144, 72, 36, 18, 9, 5, 3 ; tripplett
;--------------------------------------------------------------
;
xcax dw 0 ; register storage, used by xcall
xcbx dw 0
xccx dw 0
xcdx dw 0
;
temp0 db 0 ; temp storage, use within module
temp1 db 0
temp2 db 0
temp3 db 0
;--------------------------------------------------------------
; the following are saved/loaded
;--------------------------------------------------------------
public interv,mvlsav,mvlnum,mute,mutef,mprstf
public mbeat,mnote,mtempo,mclocks
public ctrlmap,pcva,pcvb,pcvc,pcvd,pcve,pcvf
;--------------------------------------------------------------
mvlsav equ $ ; start of mod values to save
interv db 64 dup(0) ; intervals for modulation
;
mprstf db 0 ; master program reset flag
mute dw -1 ; channel mute flags
mutef db 1 ; 1=mute, 0=solo flag
;
mbeat db 4 ; master beats/measure
mnote db 24 ; master note value
mtempo db 78H ; master tempo
mclocks dw 96 ; master clocks/measure
;
pcva db 16 dup (0) ; values sent to controller
pcvb db 16 dup (0) ; values sent to controller
pcvc db 16 dup (0) ; values sent to controller
pcvd db 16 dup (0) ; values sent to controller
pcve db 16 dup (0) ; values sent to controller
pcvf db 16 dup (0) ; values sent to controller
pcvg db 16 dup (0) ; values sent to controller
pcvh db 16 dup (0) ; values sent to controller
pcvx db 16 dup (0) ; values sent to controller
pcvy db 16 dup (0) ; values sent to controller
pcvz db 16 dup (0) ; values sent to controller
;
ctrlmap db 7,1,2,3,4,5,64,65 ; midi controller map
ctrlmpp db 7,1,2,3,4,5,64,65 ; midi controller map
;
mvlnum equ $-mvlsav ; number of mod values to save
;--------------------------------------------------------------
_DATA ENDS
;==============================================================
; Module Execution Code
; All inputs are word pointers to output word values.
; All outputs are binary words, with only the ls byte output.
;==============================================================
; EQUATES for modules
;
vseg equ 4 ; offset to video seg addr
vaddr equ 6 ; offset to video page addr
outn equ 8 ; offset to output
numvar equ 10 ; number of input variables
var0 equ 12 ; offset to variable 0
var1 equ var0+2 ; offset to variable 1
var2 equ var1+2 ; etc.
var3 equ var2+2 ; etc.
var4 equ var3+2 ; etc.
var5 equ var4+2 ; etc.
var6 equ var5+2 ; etc.
var7 equ var6+2 ; etc.
var8 equ var7+2 ; etc.
var9 equ var8+2 ; etc.
var10 equ var9+2 ; etc.
var11 equ var10+2 ; etc.
var12 equ var11+2 ; etc.
var13 equ var12+2 ; etc.
var14 equ var13+2 ; etc.
var15 equ var14+2 ; etc.
var16 equ var15+2 ; etc.
var17 equ var16+2 ; etc.
var18 equ var17+2 ; etc.
var19 equ var18+2 ; etc.
var20 equ var19+2 ; etc.
var21 equ var20+2 ; etc.
var22 equ var21+2 ; etc.
slewe equ var22 ; programmer slew buffer
slewf equ slewe+6 ; etc.
slewg equ slewf+6 ; etc.
slewh equ slewg+6 ; etc.
pubuf equ slewh+6 ; programmer undo buffer
psbuf equ pubuf+16 ; programmer save buffer
;
onflg equ 1 ; bit mask for note-on
offlg equ 2 ; bit mask for note-off
sentf equ 4 ; bit mask for note-sent
;--------------------------------------------------------------
_TEXT SEGMENT
ASSUME CS: _TEXT, DS: DGROUP, SS: DGROUP, ES: NOTHING
;--------------------------------------------------------------
extrn ticks:word,loops:word,seconds:word,secondf:byte
extrn todec:near,tonote:near,startm:near
extrn midatix:byte,misend:byte
extrn _cancel:near,workx:near,split:near
extrn turnon:near,turnoff:near,noop:near,curon:near,curoff:near
extrn mstart:byte,mstop:byte,mcont:byte,midata:byte,miflag:byte
extrn sendm:near,alloff:near,tomidi:near,allmidi:near,allclr:near
extrn tstmob:near,allclr:near,_mpuinf:byte,_mpuinm:byte
;==============================================================
include macros.asm
;==============================================================
; THE MODULES
;==============================================================
;==============================================================
; Global Parameter Module
; (only one copy available)
; Output: Stop flag (is high for 1 cycle prior to HLT)
; Inputs:
; 0: NZ Sets master programmer reset flag
; 1: value --> master programmer address
; 2: NZ sets menu for solo, 0 sets mute
; 3: NZ sets Program-mode flag to Program, Z sets to Play
; 4: Beats Per measure, change recaluclates tick-count "ticka"
; 5: Note value for above, change recaluclates tick-count
; 6: Tempo, change reclalculates tick-count
; 7: Reset RNG. Any change sets seed to new value
; 8: bit 0 set MIDI output sync, bit 1 sets input sync
; 9: NZ transition causes HLT, if FF then BYE
; 10 : initialized flag
; 10+:
; 11 : Copy of ticks remaining
; 11+: Transition (tick) flags
;--------------------------------------------------------------
public _alpha
_alpha: cmp byte ptr var10[di],0ABh ; initialized yet?
jz alphaz ; yes, go on
mov byte ptr var10[di],0ABh ; no, set init values
initv var3,1 ; prog <-- 1
initv var4,4 ; beats <-- 4
initv var5,3 ; note <-- 3
initv var6,78h ; tempo <-- 78h
alphaz:
;--------------------------------------------------------------
; 0: NZ Sets master programmer reset flag, Z releases
;
mov al,mprstf ; get master reset flag
and al,0FEH ; clear alpha reset bit
testv var0,-1 ; check for Z/NZ
jz alpha0a ; branch if Z
or al,1 ; ...if NZ
mov mmcount,0 ; clear measure count
mov cs:seconds,0 ; reset clock
mov cs:secondf,2 ; flag to show it
mov mmtick,1 ; reset to 1st note in measure
alpha0a:mov mprstf,al ; set/reset the flag
;--------------------------------------------------------------
; 1: value --> master programmer address
;
getv al,var1 ; get the value
cmp al,mpadr ; any change
mov ah,0 ; setup to clear change flag
jz alpha1a ; no, branch
mov ah,1 ; yes, set change flag
mov mpadr,al ; set new address
alpha1a:mov mpadrf,ah ; flag change/no change
;--------------------------------------------------------------
; 2: NZ sets menu for solo, 0 sets mute
;
mov al,1 ; set for mute
testv var2,-1 ; get the flag
jz alpha2a ; branch if solo
mov al,0 ; else set for solo
alpha2a:mov mutef,al ; set it
;--------------------------------------------------------------
; 3: NZ sets Program-mode flag to Program, Z sets to Play
;
testv var3,-1 ; check for Z/NZ
mov al,0 ; ...if Z
jz alpha3a ; branch if Z
inc al ; ...if NZ
alpha3a:mov mpmodf,al ; set/reset the flag
;--------------------------------------------------------------
; 4: Beats Per measure, change recaluclates
;
getv al,var4 ; get beats per measure
cmp mbeat,al ; compare with master beats/measure
jz alpha4z ; boogie if no change
or al,al ; don't allow 0 either
jz alpha4z ; /
mov mbeat,al ; else set new beats/measure
mov ah,mnote ; get clocks per note
mul ah ; ax = clocks/measure
mov mclocks,ax ; put away
alpha4z:
;--------------------------------------------------------------
; 5: Note value for above, change recaluclates
;
getv bl,var5 ; get note value
cmp mnote,bl ; compare with master note value
jz alpha5z ; boogie if no change
cmp bl,5 ; 0-5 allowed
ja alpha5z ; do nothing if > 6
mov bh,0 ; else xlate to clocks
add bx,offset dgroup:notetbl; /
mov al,[bx] ; al = clocks
mov mnote,al ; set new clocks/note
mov ah,mbeat ; get beats/measure
mul ah ; ax = clocks/measure
mov mclocks,ax ; put away
alpha5z:
;--------------------------------------------------------------
; 6: Tempo, change reclalculates tick-count
;
getv dl,var6 ; get beats per measure
mov fastflg,0 ; clear fast flag
cmp dl,0ffh ; fast as possible?
jnz alpha6b ; no, branch
mov fastflg,1 ; yes, set flag
alpha6b:cmp mtempo,dl ; compare with master tempo
jz alpha6z ; boogie if no change
mov mtempo,dl ; else set new value
cmp dl,5 ; must be > 5
ja alpha6a ; branch if ok
mov dl,6 ; else make it 6
alpha6a:mov ax,1456 ; calculate loop ticks
div dl ; /
mov ticka,al ; put it in the timer
alpha6z:
;--------------------------------------------------------------
; 7: Reset RNG. Any change sets seed to new value
;
getv al,var7 ; get rng seed
or al,al ; is zero?
jz alpha7z ; yes, don't set new seed
ror al,1 ; 1 --> 80H, etc.
mov ah,al ; 255 possible seeds
mov rseed,ax ; set the new seed
alpha7z:mov rhold,al ; set/clear hold flag
;--------------------------------------------------------------
; 8: bit 0 sets output sync, bit 1 sets input sync
;
test valflg,-1 ; inputting values now?
jnz alpha8d ; yes, don't do nothin
getv dl,var8 ; get the flag
mov ax,0 ; clear sync flags
test dl,1 ; output sync?
jz alpha8a ; no, branch
mov al,1 ; yes, set out sync flag
alpha8a:test dl,2 ; input sync?
jz alpha8b ; no, branch
mov ah,1 ; yes, set input sync flag
alpha8b:mov midisf,al ; set sync out flag
mov midixsf,ah ; set external sync flag
test dl,6 ; defeat active sensing?
mov al,1 ; ...setup for no defeat
jz alpha8c ; no, branch
mov al,0 ; yes, clear active sensing flag
alpha8c:mov asensf,al ; set the flag
alpha8d:
;--------------------------------------------------------------
; 9: NZ transition causes HLT.
; Value of FF causes BYE.
;
tick var9,var11+1 ; clock tick
jc alpha9c ; /
jmp alpha9z ; boogie if no tick
alpha9c:
getv al,var9 ; check for FF (split)
cmp al,0ffh ; wanna split?
jz alpha9e ; yes, do it
jmp alpha9a ; no, branch to HLT
alpha9e:
call alloff ; process all notes off
jmp split ; become history
alpha9a: ; HLT
mov bx,6E0H ; menu text offset
call turnon ; turn on the menu text
or mprstf,2 ; set HLT flag
mov al,0fch ; send MIDI STOP command
call allmidi ; /
alpha9z:
;--------------------------------------------------------------
; display number of calculation clocks available
;
alpha11:mov al,tickis ; get ticks remaining
cmp al,var11[di] ; same as before?
jz alpha11z ; yes, boogie
mov var11[di],al ; no, save new value
gettag ; es:bx = screen addr of tag
or al,al ; test for bottoming out
jz alpha11a ; branch if Z
and byte ptr es:(160*13-1)[bx],0F7H; lowlight if NZ
jmp short alpha11b ; then branch around highlight
alpha11a:or byte ptr es:(160*13-1)[bx],8; highlight if Z
alpha11b:tohex ; convert to hex word
mov es:(160*13)[bx],ah; put to the screen
mov es:(160*13+2)[bx],al; /
alpha11z:
;--------------------------------------------------------------
; shunt stop flag to output
;
alphax: mov al,mprstf ; get the flag
shr al,1 ; HLT is bit 2
putn al ; send it out
nextl ; show it
;==============================================================
; absolute time counter
; output: ticks count AND input0
; input: 0: hold, 1: period, 2: AND mask
;
;--------------------------------------------------------------
public _beta
_beta: hold var0 ; hold?
jz beta0 ; no, branch
mov al,0 ; yes, clear clock
jmp short betax ; exit
;
beta0: mov ax,cs:ticks ; get timer value
getv cl,var1 ; get period
shr ax,cl ; bump
getv ah,var2 ; get AND mask
and al,ah ; AND them
betax: putn al ; send to output
nextl
;==============================================================
; seconds counter
; output: seconds count AND input0
; input: 0: hold/reset
; 1: nz = minutes
; 2: offset
;
;--------------------------------------------------------------
public _secs
_secs: hold var0 ; hold?
jz secs0 ; no, branch
mov ax,cs:seconds ; yes, get current second count
mov var2[di],ax ; set new time offset
jmp short secsz ; exit
;
secs0: mov ax,cs:seconds ; get timer value
sub ax,var2[di] ; subtract offset
mov dx,0 ; double word
getv ch,var1 ; get clock flag
test ch,-1 ; leave free count?
jz secsx ; yes, branch
mov bx,60 ; no,/60
div bx ; /
cmp ch,1 ; want seconds?
jnz secsx ; no, do minutes
mov al,dl ; yes, mod for secs
secsx: putn al ; send to output
mov colr,yellow ; set color to yellow
mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
add bx,478 ; point to readout
call todec ; do it
mov colr,green ; fix it back to green
;
cmp ch,1 ; want seconds?
jnz secsz ; no, branch
mov byte ptr es:[bx],':'; yes, print ':'
secsz: nextv
;==============================================================
; simple loop counter
; output: loop count AND input0
; input: 0: hold, 1: period, 2: AND mask
;
;--------------------------------------------------------------
public _lambda
_lambda:hold var0 ; hold?
jz lambda0 ; no, branch
mov al,0 ; yes, clear clock
jmp short lambdax ; exit
;
lambda0:mov ax,cs:loops ; get count
getv cl,var1 ; get period
shr ax,cl ; bump
getv ah,var2 ; get AND mask
and al,ah ; AND them
lambdax:putn al ; send to output
nextl
;==============================================================
; measure clock
; output: measure start strobe, with delay
; input:
; 0: Hold
; 1: delay value
; 2x: countdown
; 2z: trip flag
;--------------------------------------------------------------
public _mclk
_mclk: mov byte ptr outn[di],0; clear output
hold var0 ; hold?
jnz mclkx ; yes, exit
;
mov al,var2+1[di] ; trip flag on?
or al,mmstart ; or measure start?
jz mclkx ; no, exit
;
test byte ptr var2+1[di],1; trip flag?
jnz mclk0 ; yes, go countdown
getv al,var1 ; no, get delay value
inc al ; 0 --> 1
mov var2[di],al ; set new countdown
mov byte ptr var2+1[di],1; set trip flag
;
mclk0: dec byte ptr var2[di] ; count down
jnz mclkx ; exit if not end of count
mov byte ptr var2+1[di],0; else clear trip flag
mov byte ptr outn[di],1 ; set output
;
mclkx: nextl ; exit
;==============================================================
; measure clock
; output: clock strobe
; input: 0: reset, 1: count, 2x:countdown timer, 2z: copy of count
;
;--------------------------------------------------------------
public _mclock
_mclock:hold var0 ; hold?
jz mclock2 ; no, branch
getv al,var1 ; yes, reset
mov ah,al ; /
mov var2[di],ax ; /
jmp short mclockz ; exit with output=0
;
mclock2:test mmstart,1 ; measure start?
jz mclockz ; no, exit
mov ah,1 ; yes, set output=1
;
getv al,var1 ; get current count
cmp al,var2+1[di] ; same as before?
jz mclock1 ; yes, branch
mov var2+1[di],al ; no, set new count
;
mclock0:mov al,var2+1[di] ; reset timer
mov var2[di],al ; /
jmp short mclockx ; exit
;
mclock1:dec byte ptr var2[di]; tick
jz mclock0 ; branch if end of count
mclockz:mov ah,0 ; else set output=0
;
mclockx:mov outn[di],ah ; send output
nextl ; exit
;==============================================================
; simple loop counter
; output: clock strobe
; input: 0: reset, 1: count, 2: offset
; 3x:countdown timer, 3z: copy of count
;--------------------------------------------------------------
public _gamma
_gamma: testv var1,-1 ; clock = 0
jz gammaz ; yes, just exit
hold var0 ; hold?
jz gamma0 ; no, branch
mov al,byte ptr cs:loops; get count
and al,1 ; /
mov var3[di],al ; reset clock counters
jmp short gammaz ; split
;
gamma0: getv ah,var1 ; get current count
cmp ah,var3+1[di] ; same as before?
jz gamma1 ; yes, branch
cmp ah,1 ; set to 1?
jnz gamma3 ; no, branch
mov ah,2 ; yes, set to 2
gamma3: mov al,byte ptr cs:loops; get count
and al,1 ; /
mov var3[di],ax ; /
;
gamma1: getv al,var2 ; get offset trigger
cmp al,ah ; out of range?
jb gamma4 ; no, branch
mov al,0 ; yes, zip it
gamma4: cmp al,var3[di] ; same as count?
jnz gamma2 ; no, branch
mov byte ptr outn[di],1; yes, set output flag
;
gamma2: inc byte ptr var3[di]; tick
cmp ah,var3[di] ; reached count?
jnz gammaz ; no, exit
mov byte ptr var3[di],0; yes, reset timer
gammaz: nextt ; exit
;==============================================================
; simple loop counter
; output: clock strobe
; input: 0: reset, 1: count
; 2x:countdown timer
;--------------------------------------------------------------
public _muclk
_muclk: testv var1,-1 ; clock = 0
jz muclkz ; yes, just exit
hold var0 ; hold?
jnz muclk0 ; yes, reset & exit
;
dec byte ptr var2[di]; count down
jnz muclkz ; exit if not 0
mov byte ptr outn[di],1; set output
muclk0: getv al,var1 ; else get count
mov var2[di],al ; put it away
muclkz: nextt ; exit
;==============================================================
; Note Clock
; output: 0/Veloc input value
; inputs:
; 0: Reset & hold
; 1: Sync pulse
; 2: Note value 0-7, +10H tripplett, +20H dotted
; 3: Sustain value 0-255
; 4: Clock offset value
; 5: Velocity value
; 6x: note countdown
; 6+: nz = wait for sync with measure
; 7x: note-on clocks
; 7+: AB = has been initialized
; 8x: nz = sync countdown flag
; 8+: offset value changed flag
;--------------------------------------------------------------
public _clock,_klock
_klock: nop ; same routine, different address
_clock:
cmp byte ptr var7+1[di],0ABH; initialized yet?
jz clock00 ; yes, branch
mov byte ptr var7+1[di],0ABH; no, initialize
;
initv var1,1 ; sync
initv var2,3 ; note
initv var5,1 ; velocity
mov word ptr var6[di],0 ; flags
mov byte ptr var7[di],0 ; flags
;
clock00:hold var0 ; hold?
jnz clock01 ; yes, go do it
getv al,var4 ; change in offset value?
cmp al,var8+1[di] ; /
jz clock0 ; no, branch
;
clock01:getv al,var4 ; get sync offset
mov var8+1[di],al ; clear change flag
inc al ; bump sync count so 0 --> 1
mov var6+1[di],al ; set up sync offset count
mov byte ptr outn[di],0 ; clear output
mov byte ptr var6[di],0 ; clear note count
jmp clockx ; exit
;
clock0: test byte ptr var6+1[di],-1 ; waiting for sync?
jz clock1 ; no, branch
getv al,var1 ; sync start?
or al,byte ptr var8[di] ; or countdown?
jnz clock0a ; yes, branch
jmp clockx ; no, exit
;
clock0a:mov byte ptr var8[di],1 ; set offset flag
dec byte ptr var6+1[di] ; countdown sync
jz clock0b ; branch on if 0
jmp clockx ; else exit
clock0b:mov byte ptr var8[di],0 ; clear offset flag
;
clock1: cmp byte ptr var6[di],0 ; at end of note?
jz clock1b ; yes, branch
jmp clock2 ; no, countdown
;
clock1b:getv bl,var2 ; get note value
mov dl,bl ; save in dl for dot/tripplet
and bl,7 ; mask
mov bh,0 ; else xlate to clocks
add bx,offset dgroup:notetbl; /
test dl,10h ; triplett?
jz clock1c ; no, branch
add bx,8 ; yes, bump table addr
jmp short clock1d ; branch around dot
clock1c:test dl,20h ; dot?
jz clock1d ; no, branch
add bx,16 ; yes, bump table addr
clock1d:;
mov cl,[bx] ; cl = clocks
getv dl,var3 ; dl = sustain value
;
mov al,1 ; al = 1 clock
cmp dl,0 ; sustain = min
jz clock1e ; yse, exit sust.
;
mov al,cl ; al = nv (clocks)
cmp dl,0ffh ; sustain = max
jz clock1e ; yes, exit legato
;
mul dl ; ax = nv * sust
mov al,ah ; al = nv * sust / 256
or al,al ; /
jnz clock1e ; go if > 0
inc al ; else make 1
;
clock1e:mov var6[di],cl ; set new note value
sub cl,al ; off = nv - on
mov var7[di],cl ; set new off-time
jmp short clock2a ; send out the note
;
clock2: dec byte ptr var6[di] ; count down note
jnz clock2a ; branch if not eon
jmp clock1b ; if end of note, do a new one
clock2a:mov al,0 ; setup for note-off
mov ah,var6[di] ; get note clock countdown
cmp ah,var7[di] ; > note-off time?
jbe clock2b ; no, send note off
getv al,var5 ; yes, send velocity
clock2b:putn al ; send to output
clockx: nextl ; exit
;==============================================================
; Loop Timer
; output: delayed pulse
; inputs: 0: strobe, 1: delay, 2: hold
; 3x: strobe clock, 4x: delay count, 4z: hold count
;--------------------------------------------------------------
public _ltimer
_ltimer:
test byte ptr var4[di],-1 ; delay high?
jz ltimer1 ; no, branch
dec byte ptr var4[di] ; yes, count down
jnz ltimerz ; exit if not finished
ltimer0:mov byte ptr outn[di],1 ; else set output
jmp short ltimerz ; then exit
;
ltimer1:test byte ptr var4+1[di],-1 ; hold high?
jz ltimer2 ; no, branch
dec byte ptr var4+1[di] ; yes, count down
jnz ltimerz ; exit if not finished
mov byte ptr outn[di],0 ; else clear output
jmp short ltimerz ; then exit
;
ltimer2:tick var0,var3 ; strobe tick?
jnc ltimerz ; no, just exit
getv al,var1 ; yes, get delay
getv ah,var2 ; ...get hold
or ah,mprstf ; /
mov var4[di],ax ; set them up
or al,al ; delay = 0?
jz ltimer0 ; yes, go set
mov byte ptr outn[di],0 ; else clear output
ltimerz:nextl ; exit
;==============================================================
; Clock Timer
; output: delayed pulse
; inputs: 0: clock, 1: strobe, 2: delay, 3: hold
; 4x: strobe clock, 5x: delay count, 5z: hold count
;--------------------------------------------------------------
public _ctimer
_ctimer:
tickb1 var1,var4 ; strobe tick?
jnc ctimer2 ; no, go on
getv al,var2 ; yes, get delay
getv ah,var3 ; ...get hold
or ah,mprstf ; /
mov var5[di],ax ; set them up
or al,al ; delay = 0?
jz ctimer0 ; yes, go set
mov byte ptr outn[di],0 ; clear output
jmp short ctimerz ; exit
;
ctimer2:tick var0,var4 ; clock tick?
jnc ctimerz ; no, branch
;
test byte ptr var5[di],-1 ; delay high?
jz ctimer1 ; no, branch
dec byte ptr var5[di] ; yes, count down
jnz ctimerz ; exit if not finished
ctimer0:mov byte ptr outn[di],1 ; else set output
jmp short ctimerz ; then exit
;
ctimer1:test byte ptr var5+1[di],-1 ; hold high?
jz ctimerz ; no, branch
dec byte ptr var5+1[di] ; yes, count down
jnz ctimerz ; exit if not finished
mov byte ptr outn[di],0 ; else clear output
;
ctimerz:nextl ; exit
;==============================================================
; Abs Timer
; output: delayed pulse
; inputs: 0: strobe, 1: delay, 2: hold, 3: period
; 4: timer value
; 5x: b0=delay flag, b1=hold flag
; 5z: clock
;--------------------------------------------------------------
public _atimer
_atimer:
test byte ptr var5[di],1 ; delay high?
jz atimer1 ; no, branch
mov ax,cs:ticks ; yes, get timer value
sub ax,var4[di] ; get lapsed time
getv dl,var1 ; get delay time
mov dh,0 ; /
getv cl,var3 ; get period
shl dx,cl ; bump
cmp dx,ax ; out of gas?
jnb atimerz ; no, exit
mov ax,cs:ticks ; get current ticks
mov var4[di],ax ; save it
atimer0:mov byte ptr outn[di],1 ; set output
hold var2 ; hold?
jz atimer3 ; no, clear flag & exit
mov byte ptr var5[di],2 ; yes, set hold flag
jmp short atimerz ; then exit
;
atimer1:test byte ptr var5[di],2 ; hold high?
jz atimer2 ; no, branch
mov ax,cs:ticks ; yes, get timer value
sub ax,var4[di] ; get lapsed time
getv dl,var2 ; get hold time
mov dh,0 ; /
getv cl,var3 ; get period
shl dx,cl ; bump
cmp dx,ax ; out of gas?
jnb atimerz ; no, exit
mov byte ptr outn[di],0 ; ...clear output
atimer3:mov byte ptr var5[di],0 ; yes, clear flags
jmp short atimerz ; then exit
;
atimer2:tick var0,var5+1 ; strobe tick?
jnc atimerz ; no, just exit
mov ax,cs:ticks ; get current ticks
mov var4[di],ax ; save it
testv var1,-1 ; delay = 0
jz atimer0 ; yes, go set
mov byte ptr var5[di],1 ; else flag delay
mov byte ptr outn[di],0 ; ...clear output
atimerz:nextl ; exit
;==============================================================
; Seconds Timer
; output: delayed pulse
; inputs: 0: strobe, 1: delay, 2: hold, 3: period
; 4: timer value
; 5x: b0=delay flag, b1=hold flag
; 5z: clock
;--------------------------------------------------------------
public _stimer
_stimer:
test byte ptr var5[di],1 ; delay high?
jz stimer1 ; no, branch
mov ax,cs:seconds ; yes, get timer value
sub ax,var4[di] ; get lapsed time
getv dl,var1 ; get delay time
mov dh,0 ; /
getv cl,var3 ; get period
shl dx,cl ; bump
cmp dx,ax ; out of gas?
jnb stimerz ; no, exit
mov ax,cs:seconds ; get current ticks
mov var4[di],ax ; save it
stimer0:mov byte ptr outn[di],1 ; set output
hold var2 ; hold?
jz stimer3 ; no, clear flag & exit
mov byte ptr var5[di],2 ; yes, set hold flag
jmp short stimerz ; then exit
;
stimer1:test byte ptr var5[di],2 ; hold high?
jz stimer2 ; no, branch
mov ax,cs:seconds ; yes, get timer value
sub ax,var4[di] ; get lapsed time
getv dl,var2 ; get hold time
mov dh,0 ; /
getv cl,var3 ; get period
shl dx,cl ; bump
cmp dx,ax ; out of gas?
jnb stimerz ; no, exit
mov byte ptr outn[di],0 ; ...clear output
stimer3:mov byte ptr var5[di],0 ; yes, clear flags
jmp short stimerz ; then exit
;
stimer2:tick var0,var5+1 ; strobe tick?
jnc stimerz ; no, just exit
mov ax,cs:seconds ; get current ticks
mov var4[di],ax ; save it
testv var1,-1 ; delay = 0
jz stimer0 ; yes, go set
mov byte ptr var5[di],1 ; else flag delay
mov byte ptr outn[di],0 ; ...clear output
stimerz:nextl ; exit
;==============================================================
; interference clock
; inputs: 0: hold/reset input
; 1-4: clock inputs
; 5x:
; 5z: clock ticks
; output: strobe upon any clock input
;--------------------------------------------------------------
public _iclock
_iclock:
hold var0 ; hold?
jz iclock0 ; no, branch
jmp iclockz ; else exit
;
iclock0:tick var1,var5+1 ; clock
jnc iclock1 ; branch if no tick
mov byte ptr outn[di],1 ; else set output
iclock1:
tickb1 var2,var5+1 ; clock
jnc iclock2 ; branch if no tick
mov byte ptr outn[di],1 ; else set output
iclock2:
tickb2 var3,var5+1 ; clock
jnc iclock3 ; branch if no tick
mov byte ptr outn[di],1 ; else set output
iclock3:
tickb3 var4,var5+1 ; clock
jnc iclockz ; branch if no tick
mov byte ptr outn[di],1 ; else set output
iclockz:nextt ; exit
;==============================================================
; interference clock
; inputs: 0: clock
; 1: hold/reset input
; 2-5: count inputs
; 6x:
; 6z: clock ticks
; 7-8: change detectors
; 9-10:countdown registers
; output: strobe upon any clock input
;--------------------------------------------------------------
public _kclock
_kclock:
hold var1 ; hold?
jz kclocka ; no, branch
kclockb:mov ax,101H ; yes, clear registers
mov var9[di],ax ; /
mov var10[di],ax ; /
jmp kclockz ; exit
;
kclocka:tick var0,var6+1 ; clock
jc kclockd ; do it if tick
jmp kclockz ; branch if no tick
;
kclockd:getv al,var2 ; input change?
getv ah,var3 ; /
cmp ax,var7[di] ; /
jz kclockc ; no, branch
mov var7[di],ax ; yes, reset
jmp short kclockb ; /
kclockc:getv al,var4 ; input change?
getv ah,var5 ; /
cmp ax,var8[di] ; /
jz kclock0 ; no, branch
mov var8[di],ax ; yes, reset
jmp short kclockb ; /
;
kclock0:test byte ptr var9[di],-1 ; register zero'd?
jz kclock1 ; yes, branch
dec byte ptr var9[di] ; no, count down
jnz kclock1 ; branch if not zero'd
getv al,var2 ; else get count
mov byte ptr var9[di],al ; reset register
mov byte ptr outn[di],1 ; set output strobe
;
kclock1:test byte ptr var9+1[di],-1 ; register zero'd?
jz kclock2 ; yes, branch
dec byte ptr var9+1[di] ; no, count down
jnz kclock2 ; branch if not zero'd
getv al,var3 ; else get count
mov byte ptr var9+1[di],al ; reset register
mov byte ptr outn[di],1 ; set output strobe
;
kclock2:test byte ptr var10[di],-1 ; register zero'd?
jz kclock3 ; yes, branch
dec byte ptr var10[di] ; no, count down
jnz kclock3 ; branch if not zero'd
getv al,var4 ; else get count
mov byte ptr var10[di],al ; reset register
mov byte ptr outn[di],1 ; set output strobe
;
kclock3:test byte ptr var10+1[di],-1 ; register zero'd?
jz kclockz ; yes, branch
dec byte ptr var10+1[di] ; no, count down
jnz kclockz ; branch if not zero'd
getv al,var5 ; else get count
mov byte ptr var10+1[di],al ; reset register
mov byte ptr outn[di],1 ; set output strobe
;
kclockz:nextt ; exit
;==============================================================
; Index counter, incrementing
; inputs: 0: clock up, 1: hold/reset 2: inc/dec 3x: tick flag
; output: index
;--------------------------------------------------------------
public _icount
_icount:
hold var1 ; hold?
jz icount0 ; branch if no hold
mov word ptr outn[di],100h; else zip output/index
jmp short icountx ; exit with video update
icount0:tick var0,var3 ; clock tick
jc icount1 ; branch if there is a tick
nextx ; else exit easy
icount1:testv var2,-1 ; test inc/dec flag
jnz icount2 ; branch if decrement
inc word ptr outn[di]; inc index
jmp next ; exit with video update
icount2:dec word ptr outn[di]; dec index
icountx:nextv ; exit
;==============================================================
; Index counter, with mask
; inputs: 0: clock up, 1: hold/reset 2: mask
; 3x: tick flag, 3z: tick count
; output: index
;--------------------------------------------------------------
public _ocount
_ocount:
hold var1 ; hold?
jz ocount0 ; branch if no hold
mov byte ptr var3+1[di],0; else zip index
jmp short ocountx ; exit with video update
ocount0:tick var0,var3 ; clock tick
jnc ocountx ; branch if no tick
inc byte ptr var3+1[di]; inc index
ocountx:getv al,var2 ; get the mask
and al,var3+1[di] ; and with count
putn al ; send it out
nextv ; exit
;==============================================================
; Index counter, adding
; inputs: 0: clock up, 1: hold/reset 2: increment 3x: tick flag
; output: index
;--------------------------------------------------------------
public _jcount
_jcount:
hold var1 ; hold?
jz jcount0 ; branch if no hold
mov word ptr outn[di],100H; else zip output/index
jcountx:jmp next ; exit
jcount0:tick var0,var3 ; clock tick
jc jcount1 ; branch if there is a tick
nextx ; else exit easy
jcount1:getv al,var2 ; get the increment
add outn[di],al ; add to the index
nextv ; exit with video update
;==============================================================
; Index counter, adding with upper limit
; inputs: 0: clock up, 1: hold/reset 2: increment
; 3: inc/dec 4: top limit 5x: tick
; output: index
;--------------------------------------------------------------
public _kcount
_kcount:
hold var1 ; hold?
jz kcount0 ; branch if no hold
testv var3,-1 ; counting up or down
jnz kcounta ; branch if counting down
mov al,0 ; up, set to bottom limit
jmp short kcountb ; /
kcounta:getv al,var4 ; down, set to top limit
kcountb:mov ah,al ; /
mov outn[di],ax ; /
jmp next ; exit
kcount0:tick var0,var5 ; clock tick
jc kcount1 ; branch if there is a tick
nextx ; else exit easy
kcount1:mov dl,0 ; dl = 0 = bottom
getv dh,var4 ; dh = the top limit
jmp lcountk ; continue with lcount routine
;==============================================================
; Index counter, adding with upper and lower limit
; inputs: 0: clock up, 1: hold/reset 2: increment
; 3: inc/dec 4: top limit 5: bottom limit
; 6x: tick
; output: index
;--------------------------------------------------------------
public _lcount
_lcount:
hold var1 ; hold?
jz lcount0 ; branch if no hold
testv var3,-1 ; counting up or down
jnz lcounta ; branch if counting down
getv al,var5 ; up, set to bottom limit
jmp short lcountb ; /
lcounta:getv al,var4 ; down, set to top limit
lcountb:mov ah,al ; /
mov outn[di],ax ; /
jmp next ; exit
lcount0:tick var0,var6 ; clock tick
jc lcount1 ; branch if there is a tick
nextx ; else exit easy
lcount1:getv dl,var5 ; dl = the lower limit
getv dh,var4 ; dh = the top limit
cmp dh,dl ; top < bottom ?
jnb lcountk ; no, branch
xchg dh,dl ; yes, swap
lcountk:inc dh ; bump so top is included
getv al,var2 ; al = the increment
getv ah,var3 ; ah = inc/dec
test ah,-1 ; inc or dec?
jnz lcount2 ; branch if dec
; ; counting up
add al,outn+1[di] ; add inc to index
cmp al,dh ; over the top?
jna lcount3 ; no, branch
sub al,dh ; yes, subtract top
add al,dl ; add bottom
lcount3:mov ah,al ; set new index
dec al ; show index -1
mov outn[di],ax ; /
jmp next ; display & exit
; ; counting down
lcount2:mov cl,outn+1[di] ; get index
sub cl,al ; subtract inc
jc lcount5 ; branch if rollover
cmp cl,dl ; below the limit
jnb lcount4 ; no, branch
lcount5:add cl,dh ; yes, add top
sub cl,dl ; subtract bottom
lcount4:mov ch,cl ; set new index
mov outn[di],cx ; /
jmp next ; display & exit
;==============================================================
; Index counter, adding with upper and lower limit
; inputs: 0: clock up, 1: hold/reset 2: increment
; 3: inc/dec 4: top limit 5: bottom limit
; 6x: tick
; output: index
;--------------------------------------------------------------
public _mcount
_mcount:
hold var1 ; hold?
jz mcount0 ; branch if no hold
testv var3,-1 ; counting up or down
jnz mcounta ; branch if counting down
getv al,var5 ; up, set to bottom limit
jmp short mcountb ; /
mcounta:getv al,var4 ; down, set to top limit
mcountb:mov ah,al ; /
mov outn[di],ax ; /
jmp next ; exit
mcount0:tick var0,var6 ; clock tick
jc mcount1 ; branch if there is a tick
nextx ; else exit easy
mcount1:getv dl,var5 ; dl = the lower limit
getv dh,var4 ; dh = the top limit
cmp dh,dl ; top < bottom ?
jnb mcountk ; no, branch
xchg dh,dl ; yes, swap
mcountk:inc dh ; bump so top is included
getv al,var2 ; al = the increment
getv ah,var3 ; ah = inc/dec
test ah,-1 ; inc or dec?
jnz mcount2 ; branch if dec
; ; counting up
add al,outn+1[di] ; add inc to index
cmp al,dh ; over the top?
jna mcount3 ; no, branch
mov al,dh ; get hi count
sub al,dl ; get hi-lo
shr al,1 ; /2
mov ah,al ; hold
shr al,1 ; 1/4
add al,ah ; 3/4
add al,dl ; offset from bottom
mcount3:mov ah,al ; set new index
mov outn[di],ax ; /
jmp next ; display & exit
; ; counting down
mcount2:mov cl,outn+1[di] ; get index
sub cl,al ; subtract inc
jc mcount5 ; branch if rollover
cmp cl,dl ; below the limit
jnb mcount4 ; no, branch
mcount5:mov cl,dh ; get hi count
sub cl,dl ; get hi-lo
shr cl,1 ; 1/2
shr cl,1 ; 1/4
add cl,dl ; offset from bottom
mcount4:mov ch,cl ; set new index
mov outn[di],cx ; /
jmp next ; display & exit
;==============================================================
; Index counter, incrementing, 16 bit
; inputs: 0: clock up
; 1: hold/reset
; 2: reset count lo
; 3: reset count hi
; 4: reset
; 5: shift output
; 6: up/down
; 7x:tick flag
; 8: index
; output: index
;--------------------------------------------------------------
public _ncount
_ncount:
testv var4,-1 ; reset?
jz ncount0 ; no, branch
getv al,var2 ; yes, get reset count lo
getv ah,var3 ; ... and reset count hi
mov var8[di],ax ; reset
;
ncount0:hold var1 ; hold?
jnz ncountx ; branch if no hold
;
tick var0,var7 ; clock tick
jnc ncountx ; branch if no tick
mov ax,1 ; setup for inc
testv var6,-1 ; up or down
jz ncount1 ; branch if up
mov ax,-1 ; else setup for down
ncount1:
add var8[di],ax ; bump index
;
ncountx:mov ax,word ptr var8[di] ; get the index
getv cl,var5 ; get shift byte
shr ax,cl ; bump right
putn al ; send it out
nextv ; exit
;==============================================================
; Sequencer/Switcher
; inputs: 0: stage addr, 1 - 16: stages, xl: old stage
; output: value of stage pointed to by var0
;
public _wseq
_wseq:
getv al,var0 ; get variable0
and al,15 ; 16 stages
mov cl,al ; save it
mov ch,var1+32[di] ; get saved last stage
and ch,15 ; just to be safe
mov var1+32[di],al ; store the new stage
mov ah,0 ; make new stage into word
add ax,ax ; /
mov bx,ax ; bx = offset to the stage
mov bx,var1[bx+di] ; get the value
mov al,[bx] ; /
putn al ; send to output
;--------------------------------------------------------------
; got the value, now clear old stage led, and set the new
;--------------------------------------------------------------
cmp cl,ch ; have stages changed?
jz wseqx ; no, then just exit
gettag ; es:bx = screen addr of tag
dec bx ; point to leds
add ch,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul ch ; ax = offset to old stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],yellow; turn the led off
add cl,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul cl ; ax = offset to new stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],hi+red; turn the led on
wseqx:
mov di,2[si] ;; set di pointing to variable list
nextv ; show the output
;==============================================================
; Sequencer/Switcher
; inputs: 0: stage addr, 1 - 8: stages, xl: old stage
; output: value of stage pointed to by var0
;
public _xseq
_xseq:
getv al,var0 ; get variable0
and al,7 ; 8 stages
mov cl,al ; save it
mov ch,var1+16[di] ; get saved last stage
and ch,7 ; just to be safe
mov var1+16[di],al ; store the new stage
mov ah,0 ; make new stage into word
add ax,ax ; /
mov bx,ax ; bx = offset to the stage
mov bx,var1[bx+di] ; get the value
mov al,[bx] ; /
putn al ; send to output
;--------------------------------------------------------------
; got the value, now clear old stage led, and set the new
;--------------------------------------------------------------
cmp cl,ch ; have stages changed?
jz xseqx ; no, then just exit
gettag ; es:bx = screen addr of tag
dec bx ; point to leds
add ch,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul ch ; ax = offset to old stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],yellow; turn the led off
add cl,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul cl ; ax = offset to new stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],hi+red; turn the led on
xseqx:
mov di,2[si] ; set di pointing to variable list
nextv ; show the output
;==============================================================
; Sequencer/Switcher
; inputs: 0: stage addr, 1 - 4: stages, xl: old stage
; output: value of stage pointed to by var0
;
public _yseq
_yseq:
getv al,var0 ; get variable0
and al,3 ; 4 stages
mov cl,al ; save it
mov ch,var1+8[di] ; get saved last stage
and ch,3 ; just to be safe
mov var1+8[di],al ; store the new stage
mov ah,0 ; make new stage into word
add ax,ax ; /
mov bx,ax ; bx = offset to the stage
mov bx,var1[bx+di] ; get the value
mov al,[bx] ; /
putn al ; send to output
;--------------------------------------------------------------
; got the value, now clear old stage led, and set the new
;--------------------------------------------------------------
cmp cl,ch ; have stages changed?
jz yseqx ; no, then just exit
gettag ; es:bx = screen addr of tag
dec bx ; point to leds
add ch,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul ch ; ax = offset to old stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],yellow; turn the led off
add cl,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul cl ; ax = offset to new stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],hi+red; turn the led on
yseqx:
mov di,2[si] ; set di pointing to variable list
nextv ; show the output
;==============================================================
; Sequencer/Switcher
; inputs: 0: stage addr, 1 - 2: stages, xl: old stage
; output: value of stage pointed to by var0
;
public _zseq
_zseq:
getv al,var0 ; get variable0
and al,1 ; 1 stages
mov cl,al ; save it
mov ch,var1+4[di] ; get saved last stage
and ch,1 ; just to be safe
mov var1+4[di],al ; store the new stage
mov ah,0 ; make new stage into word
add ax,ax ; /
mov bx,ax ; bx = offset to the stage
mov bx,var1[bx+di] ; get the value
mov al,[bx] ; /
putn al ; send to output
;--------------------------------------------------------------
; got the value, now clear old stage led, and set the new
;--------------------------------------------------------------
cmp cl,ch ; have stages changed?
jz zseqx ; no, then just exit
gettag ; es:bx = screen addr of tag
dec bx ; point to leds
add ch,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul ch ; ax = offset to old stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],yellow; turn the led off
add cl,4 ; offset to 2nd var loc in screen
mov al,160 ; point to stage led
mul cl ; ax = offset to new stage led
mov di,ax ; put in di for indexing
mov byte ptr es:[bx+di],hi+red; turn the led on
zseqx:
mov di,2[si] ; set di pointing to variable list
nextv ; show the output
;==============================================================
; Sequencer/Switcher
; output: "a" input if var0 AND var1 = 0, else "b" input
; inputs:
; 0, 1: test inputs, ANDed to give flag
; 2: input stage "a"
; 3: input stage "b"
;
public _useq
_useq: getv dl,var0 ; get flag vars
getv dh,var1 ; /
mov ch,yellow ; set up led colors
mov cl,red+hi ; /
getv al,var2 ; get "a" input
;
and dh,dl ; test
jz useq0 ; branch if "b" input
xchg ch,cl ; else setup for 2nd
getv al,var3 ; get "b" input
;
useq0: gettag ; get screen address of leds
add bx,799 ; set up input leds
mov es:[bx],cl ; do the leds
mov es:160[bx],ch ; /
;
putn al ; send to output
nextv ; exit
;==============================================================
; Sequencer/Switcher
; output: "a" input if var0 AND var1 = 0, else "b" input
; inputs:
; 0, 1: test inputs, ANDed to give flag
; 2: input stage "a"
; 3: input stage "b"
; 4: offset
;
public _vseq
_vseq: getv dl,var0 ; get flag vars
getv dh,var1 ; /
mov ch,yellow ; set up led colors
mov cl,red+hi ; /
getv al,var2 ; get "a" input
;
and dh,dl ; test
jz vseq0 ; branch if "b" input
xchg ch,cl ; else setup for 2nd
getv al,var3 ; get "b" input
;
vseq0: gettag ; get screen address of leds
add bx,799 ; set up input leds
mov es:[bx],cl ; do the leds
mov es:160[bx],ch ; /
;
getv ah,var4 ; get the offset
add al,ah ; put them together
putn al ; send to output
nextv ; exit
;==============================================================
; Pass input thru to output on nz test input, zero on low
; inputs: 0: switch
; 1: value1, 2: value2
; output: value/0
;--------------------------------------------------------------
public _passt
_passt: getv al,var1 ; al = input a
mov ch,yellow ; set up led colors
mov cl,red+hi ; /
testv var0,-1 ; test a/b switch
jz passt1 ; branch if 1st input
;
getv al,var2 ; al = input b
xchg ch,cl ; else setup for 2nd
;
passt1: putn al ; put it away
;
gettag ; get screen address of leds
dec bx ; /
mov bp,bx ; save it
add bx,640 ; bx = screen addr of 1st led
mov es:[bx],cl ; do the leds
mov es:160[bx],ch ; /
;
nextv ; show it
;==============================================================
; Pass input thru to output on nz test input, zero on low
; inputs: 0: switch
; 1: value1, 2: value2, 3: offset
; output: value/0
;--------------------------------------------------------------
public _passq
_passq: getv al,var1 ; al = input a
mov ch,yellow ; set up led colors
mov cl,red+hi ; /
testv var0,-1 ; test a/b switch
jz passq1 ; branch if 1st input
;
getv al,var2 ; al = input b
xchg ch,cl ; else setup for 2nd
;
passq1: getv ah,var3 ; get offset
add al,ah ; /
putn al ; put it away
;
gettag ; get screen address of leds
dec bx ; /
mov bp,bx ; save it
add bx,640 ; bx = screen addr of 1st led
mov es:[bx],cl ; do the leds
mov es:160[bx],ch ; /
;
nextv ; show it
;==============================================================
; Standard 256 byte sequencer with input mask
; inputs: 0: address 1: write enable, 2: input, 3: input mask
; 4x: module number, 4z, init flag
; output: byte addressed by address
;--------------------------------------------------------------
public _pseq
_pseq: cmp byte ptr var4+1[di],0abh; initialized?
jnz pseq2 ; no, branch
test usrflg,1 ; user input
jnz pseq1 ; yes, no go
;
mov ax,seg bufsp ; setup seg register
mov es,ax ; es = seg addr
getv dl,var0 ; get address
mov dh,0 ; /
mov bh,var4[di] ; get hi address
mov bl,0 ; /
add bx,dx ; set up as index
mov dx,bx ; save
mov al,es:[bx] ; get the byte
putn al ; send it out
;
testv var1,-1 ; write enabled?
jz pseq1 ; no, branch
getv al,var2 ; yes, get input
getv ah,var3 ; get mask
and al,ah ; mask the input
not ah ; complement
mov bx,dx ; get address again
and es:[bx],ah ; clear old bits
or es:[bx],al ; put in new bits
; or _mpab,8 ; set buffer used flag
pseq1: nextv ; exit with video update
;
pseq2: mov al,modnum ; get module number
mov var4[di],al ; save it
mov byte ptr var4+1[di],0abh; set init flag
initv var3,0ffh ; mask <- FF
gettag ; es:bx = screen addr of tag
tohex ; convert to hex
mov es:-2[bx],al ; show the default number
nextx ; exit
;--------------------------------------------------------------
; magenta input
;
public upseq
upseq: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset upseqx
mov di,varsav ; point to variable list
mov al,outn[di] ; get the output value
mov var4[di],al ; save
jmp workx ; on to the next stage
;
upseqx: mov di,varsav ; point to variable list
mov al,outn[di] ; get the new channel
xchg var4[di],al ; set it, get orig patch
mov outn[di],al ; restore
jmp _cancel ; exit
;==============================================================
; Standard 256 byte sequencer with offset
; inputs: 0: address, 1: offset, 2x: mod #, 2z: init flag
; output: byte addressed by address
;--------------------------------------------------------------
public _qseq,_rseq,_sseq,_tseq
_tseq: nop
_sseq: nop
_rseq: nop
_qseq: cmp byte ptr var2+1[di],0abh; initialized?
jnz qseq1 ; no, branch
test usrflg,1 ; user input
jnz qseq0 ; yes, no go
;
mov ax,seg bufsp ; setup seg register
mov es,ax ; es = seg addr
getv dl,var1 ; get offset
mov dh,0 ; (not needed)
getv bl,var0 ; get address
mov bh,var2[di] ; get hi address
add bl,dl ; set up as index
mov al,es:[bx] ; get the byte
putn al ; send it out
qseq0: nextv ; exit with video update
;
qseq1: mov al,modnum ; get module number
mov var2[di],al ; save it
mov byte ptr var2+1[di],0abh; set init flag
gettag ; es:bx = screen addr of tag
tohex ; convert to hex
mov es:-2[bx],al ; show the default number
nextx ; exit
;--------------------------------------------------------------
; magenta input
;
public uqseq
uqseq: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset uqseqx
mov di,varsav ; point to variable list
mov al,outn[di] ; get the output value
mov var2[di],al ; save
jmp workx ; on to the next stage
;
uqseqx: mov di,varsav ; point to variable list
mov al,outn[di] ; get the new channel
xchg var2[di],al ; set it, get orig patch
mov outn[di],al ; restore
jmp _cancel ; exit
;==============================================================
; 65K byte Sequencer with input mask
; inputs: 0: address lo, 1: address hi,
; 2: write enable, 3: input, 4: input mask, 5x: init flag
; output: byte addressed by address + offset
;--------------------------------------------------------------
public _puseq
_puseq:
cmp byte ptr var5[di],0abh; initialized?
jnz puseq2 ; no, branch
mov ax,seg buffs ; setup seg register
mov es,ax ; es = seg addr
getv dl,var0 ; get address lo
getv dh,var1 ; get address hi
mov bx,dx ; set up as index
mov al,es:[bx] ; get the byte
putn al ; send it out
;
testv var2,-1 ; write enabled?
jz puseq1 ; no, branch
getv al,var3 ; yes, get input
getv ah,var4 ; get mask
and al,ah ; mask the input
not ah ; complement
mov bx,dx ; get address again
and es:[bx],ah ; clear old bits
or es:[bx],al ; put in new bits
; or _mpab,4 ; set buffer used flag
puseq1: nextv ; exit with video update
;
puseq2: mov al,modnum ; get module number
mov byte ptr var5[di],0abh; set init flag
initv var4,0ffh ; mask <- FF
nextx ; exit
;==============================================================
; 65K byte sequencer with offset
; inputs: 0: address lo, 1: address hi, 2: offset
; output: byte addressed by address
;--------------------------------------------------------------
public _quseq,_ruseq,_suseq,_tuseq
_tuseq: nop
_suseq: nop
_ruseq: nop
_quseq:
mov ax,seg buffs ; setup seg register
mov es,ax ; es = seg addr
getv dl,var0 ; get address lo
getv dh,var1 ; get address hi
getv bl,var2 ; get offset
mov bh,0 ; /
add bx,dx ; set up as index
mov al,es:[bx] ; get the byte
putn al ; send it out
nextv ; exit with video update
;==============================================================
; Delay Sequencer
; inputs: 0: clock, 1: page address, 2: read offset, 3: write enable,
; 4: input, 5: offset, 6x: clock tick
; inputs: 0: clock
; 1: input
; 2: read offset
; 3: write enable
; 4: offset
; 5x: page address
; 5z: index
; 6x: clock tick
; 6z: init flag
; output: byte addressed by index (hi byte of output addr) + var2
; AND 15 + (var1 * 16), AFTER write operation.
; Thus, a read offset of 0 causes the output to track the input,
; an offset of 1 tracks 1 clock behind, etc.
;--------------------------------------------------------------
public _euseq
_euseq:
cmp byte ptr var6+1[di],0abh; initialized?
jnz euseqi ; no, go do it
;
tick var0,var6 ; clock tick
jnc euseqx ; exit if no tick
;
mov ax,seg buftu ; setup seg register
mov cl,var5[di] ; ch = buffer page addr low
mov ch,0 ; cx = buffer page addr
add ax,cx ; ax = seg addr of 16 byte buffer
mov es,ax ; es = seg addr
mov ah,var5+1[di] ; ah = index offset
;
testv var3,-1 ; write enabled?
jz euseq2 ; no, branch
getv al,var1 ; yes, get input
mov bl,ah ; set up offset
and bl,15 ; 15 bytes in the buffer
mov bh,0 ; /
mov es:[bx],al ; write the byte
;
euseq2: getv al,var2 ; al = read offset
neg al ; read behind
add al,ah ; al = index-offset
and al,15 ; 15 bytes in the buffer
mov bl,al ; set up an index pointer
mov bh,0 ; /
mov al,es:[bx] ; get the read byte
getv dl,var4 ; get offset
add al,dl ; add to output
putn al ; send it out
;
inc ah ; bump index
mov var5+1[di],ah ; set the new index
nextv ; exit with video update
euseqx: nextx
;
euseqi: mov byte ptr var6+1[di],0abh; set init flag
initv var3,1 ; write enable
mov al,modnum ; get module number
mov ah,0 ; zip index
mov var5[di],ax ; save it
gettag ; es:bx = screen addr of tag
tohex ; convert to hex
mov es:-2[bx],al ; show the default number
nextx ; exit
;--------------------------------------------------------------
; magenta input
;
public ueuseq
ueuseq: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset ueuseqx
mov di,varsav ; point to variable list
mov al,outn[di] ; get the output value
mov var5[di],al ; save
jmp workx ; on to the next stage
;
ueuseqx:mov di,varsav ; point to variable list
mov al,outn[di] ; get the new channel
xchg var5[di],al ; set it, get orig patch
mov outn[di],al ; restore
jmp _cancel ; exit
;==============================================================
; set/clear mute flags
; inputs: 0: flags 0-7, 1: flags 8-15,
; 2: shift, 3: mask
; 4x: last var0, 4z: last var1
;
; output: 16bit mute word, shifted & masked
;--------------------------------------------------------------
public _domute
_domute:test valflg,-1 ; inputting now
jnz domutex ; yes, just get them
;
getv al,var0 ; get mute flags
getv ah,var1 ; /
not ax ; flip polarity
;
mov dx,ax ; save it
xor ax,var4[di] ; bits set are changes
mov var4[di],dx ; save the new value
mov cx,ax ; save flag bits
not ax ; flip flag bits
and mute,ax ; strip changed bits
and cx,dx ; get new changed bits
or mute,cx ; put them away
;
domutex:mov dx,mute ; get the mute word
getv cl,var2 ; get the shift
ror dx,cl ; shift right
not dl ; flip bits
getv al,var3 ; get mask
and al,dl ; mask the mute flags
putn al ; send it out
nextv ; exit
;==============================================================
; External call via software interrupt
; output: returned value of AL
; inputs:
; 0: clock
; 1: interrupt number
; 2: value loaded into AH
; 3: value loaded into AL
; 4: value loaded into BH
; 5: value loaded into BL
; 6: value loaded into CH
; 7: value loaded into CL
; 8: value loaded into DH
; 9: value loaded into DL
; 10x: clock tick
;--------------------------------------------------------------
public _xcall
_xcall: tick var0,var10 ; tick clock
jnc xcallx ; exit if no tick
;
getv al,var1 ; get the interrupt number
test al,-1 ; anything there
jz xcallx ; no, exit
;
mov byte ptr cs:xcalli+1,al; set up the int number
getv ah,var2 ; load registers
getv al,var3 ; /
getv ch,var4 ; /
getv cl,var5 ; /
mov bp,cx ; /
getv ch,var6 ; /
getv cl,var7 ; /
getv dh,var8 ; /
getv dl,var9 ; /
mov bx,bp ; /
push si ; save needed registers
push di ; /
push ds ; /
xcalli: int 64 ; go do it
pop ds ; restore registers
pop di ; /
pop si ; /
mov xcax,ax ; save registers
mov xcbx,bx ; /
mov xccx,cx ; /
mov xcdx,dx ; /
pushf ; get flags
pop ax ; /
putn al ; send low flags to output
xcallx: nextv ; exit
;==============================================================
; read a register after xcall
; output: xcall register storage
; inputs: 0: strobe, 1: register number, 2x: clock tick
; 0 = al, 1 = ah, 2 = bl, 3 = bh,
; 4 = cl, 5 = bh, 6 = dl, 7 = dh
;--------------------------------------------------------------
public _rcall
_rcall: tick var0,var2 ; clock tick
jnc rcallx ; exit if no clock
getv al,var1 ; get the register number
and ax,7 ; 8 registers allowed
mov bx,offset dgroup:xcax; get table location
add bx,ax ; add offset
mov al,[bx] ; get the register
putn al ; send it out
rcallx: nextv ; exit
;==============================================================
; read a byte from the keyboard
; output: ascii keyboard data
; inputs: 0: hold
;--------------------------------------------------------------
public _xkbd
_xkbd:
hold var0 ; hold?
jnz xkbdx ; yes, exit
and byte ptr outn[di],7fh; strip old key flag
mov ah,6 ; dos direct console i/o
mov dl,0ffh ; input request
int 21h ; call dos
jz xkbdx ; exit if no input
or al,al ; function key
jz xkbd0 ; yes, don't set flag
or al,80H ; set new key flag
xkbd0: putn al ; send it out
xkbdx: nextv ; exit
;==============================================================
; read a byte from MIDI to s-sequencer
; output: index into s-sequencer
; inputs: 0: reset strobe, 1: enable, 2x: tick
;--------------------------------------------------------------
public _xmidii
_xmidii:
tick var0,var2 ; strobe tick?
jnc xmidii0 ; no, branch
mov cs:midatix,0 ; yes, clear index
;
xmidii0:getv al,var1 ; get write enable flag
mov cs:misend,al ; set/clear the flag
;
mov al,cs:midatix ; get index
putn al ; send it out
nextv ; exit
;==============================================================
; show output buffer status
; inputs: none
; output: flag bits 0,1 set if output buffer not empty
;--------------------------------------------------------------
public _tstmob
_tstmob:call tstmob ; check it
putn al ; send it out
nextl ; show it
;==============================================================
; show mpu input flags, set mpu input mask
; 0 = no input, 1=mpu#1, 2=mpu#2
; inputs: 0: reset input flag
; 1: mpu input mask
; 2x init flag
; output: mpu input flags
;--------------------------------------------------------------
public _mpuins
_mpuins:cmp byte ptr var2[di],0abh ; initialized?
jnz mpuins0 ; no, branch
;
getv al,var1 ; get mask byte
mov cs:_mpuinm,al ; set mask
;
mov al,cs:_mpuinf ; get mpu input flag
putn al ; send it out
;
testv var0,-1 ; want to clear mpu flag?
jnz mpuins1 ; no, branch
mov cs:_mpuinf,0 ; clear mpu flag
;
mpuins1:nextl ; show it
;
mpuins0:mov byte ptr var2[di],0abh ; no, set init values
initv var1,3 ; default is all ok
nextx ; exit
;;==============================================================
; output a byte to output port
; output: none
; inputs:
; 0: clock
; 1: value to be output
; 2: output port address hi
; 3: output port address lo
; 4x: clock tick
;--------------------------------------------------------------
public _outpb
_outpb: tick var0,var4 ; clock tick
jnc outpbx ; exit if no clock
getv dh,var2 ; get the address
getv dl,var3 ; /
getv al,var1 ; get the value
out dx,al ; send it out
outpbx: nextx ; exit
;==============================================================
; input a byte from input port
; output: value from port
; inputs:
; 0: clock
; 1: input port address hi
; 2: input port address lo
; 3x: clock tick
;--------------------------------------------------------------
public _inptb
_inptb: tick var0,var3 ; clock tick
jnc inptbx ; exit if no clock
getv dh,var1 ; get the address
getv dl,var2 ; /
in al,dx ; get the value from port
putn al ; send it
inptbx: nextv ; exit & show
;==============================================================
; input a byte from memory
; output: value from memory
; inputs:
; 0: clock
; 1: seg addr hi
; 2: input port address hi
; 3: input port address lo
; 4x: clock tick
;--------------------------------------------------------------
public _peek
_peek: tick var0,var4 ; clock tick
jnc peekx ; exit if no clock
getv dh,var1 ; get seg hi
getv ah,var2 ; get address hi
getv bl,var3 ; get address lo
mov bh,ah ; bx = address
mov dl,0 ; dx = seg
mov es,dx ; es = seg
mov al,es:[bx] ; get the byte
putn al ; send it
peekx: nextv ; exit & show
;==============================================================
; output a byte to memory
; output: none
; inputs:
; 0: clock
; 1: value to be output
; 2: seg addr hi
; 3: input port address hi
; 4: input port address lo
; 5x: clock tick
;--------------------------------------------------------------
public _poke
_poke: tick var0,var5 ; clock tick
jnc pokex ; exit if no clock
getv al,var1 ; get the value
getv dh,var2 ; get seg hi
getv ah,var3 ; get address hi
getv bl,var4 ; get address lo
mov bh,ah ; bx = address
mov dl,0 ; dx = seg
mov es,dx ; es = seg
mov es:[bx],al ; put the byte
putn al ; send it
pokex: nextx ; exit
;==============================================================
; System Exclusive Receive
; inputs:
; 0: Address Low of sequencer "S" where data will go
; 1: Address High of sequencer "S"
; 2: Strobe to start receive
; 3: Shift output value
; 4xz: Index into seq "s"
; 5x: strobe tick
; output: Next available seq addr, shifted right by input 3
;--------------------------------------------------------------
public _sxget
_sxget: tick var2,var5 ; wanna do it?
jc sxget0 ; yes, branch
jmp sxgetx ; no, exit to readout
;
sxget0: mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
mov al,'X' ; set output byte
mov es:320[bx],al ; put to the screen
mov es:322[bx],al ; /
mov ax,80H ; to set hi bit
mov outn[di],ax ; trash output
or es:321[bx],al ; put to the screen
or es:323[bx],al ; /
;
sxget6: call allclr ; clear midi channel
;
mov word ptr var4[di],-2 ; setup error flag
mov cs:miflag,0 ; clear input data flag
;
mov ax,seg buffs ; setup seg register
mov es,ax ; es = seg addr
getv dl,var0 ; get address lo
getv dh,var1 ; get address hi
mov bx,dx ; set up as index
;
mov bp,cs:ticks ; get timer
add bp,11640 ; timeout in 20 sec.
;
sxget1: test cs:miflag,-1 ; anything there?
jnz sxget2 ; yes, branch
cmp bp,cs:ticks ; timeout?
jnz sxget1 ; no, keep looking
jmp sxgetx ; yes, exit
;
sxget2: mov cs:miflag,0 ; clear input flag
cmp cs:midata,0f0h ; system exclusive?
jnz sxget1 ; no, keep looking
mov byte ptr es:[bx],0f0h ; yes, send the data
inc bx ; bump index
jz sxgetx ; exit if index overflow
;
sxget3: test cs:miflag,-1 ; anything there?
jnz sxget4 ; yes, branch
cmp bp,cs:ticks ; timeout?
jnz sxget3 ; no, keep looking
;
sxget4: mov cs:miflag,0 ; clear input flag
mov al,cs:midata ; get the data
mov es:[bx],al ; put it in the seq memory
cmp al,0f7h ; EOX?
jz sxget5 ; yes, branch
inc bx ; bump index
jz sxgetx ; exit if index overflow
jmp short sxget3 ; else back to the loop
;
sxget5: mov var4[di],bx ; set the new index
mov _header+7,1 ; set buffer used flag
;
sxgetx: mov ax,var4[di] ; get the index
inc ax ; bump one
getv cl,var3 ; get shift byte
shr ax,cl ; bump right
putn al ; send it out
mov al,7fH ; to set lo bit
mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
and es:321[bx],al ; put to the screen
and es:323[bx],al ; /
nextv ; exit
;==============================================================
; System Exclusive Send
; inputs:
; 0: Address Low of sequencer "S" where data is found
; 1: Address High of sequencer "S"
; 2: Strobe to start send
; 3: Shift output value
; 4xz: Index into seq "s"
; 5x: strobe tick
; output: Next available seq addr, shifted right by input 3
;--------------------------------------------------------------
public _sxput
_sxput: tick var2,var5 ; wanna do it?
jc sxput0 ; yes, branch
jmp sxputx ; no, exit to readout
;
sxput0: mov word ptr var4[di],-2 ; setup error flag
mov midip,0 ; set midi port 0
;
mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
mov al,'X' ; set output byte
mov es:320[bx],al ; put to the screen
mov es:322[bx],al ; /
mov ax,80H ; to set hi bit
mov outn[di],ax ; trash output
or es:321[bx],al ; put to the screen
or es:323[bx],al ; /
;
mov ax,seg buffs ; setup seg register
mov es,ax ; es = seg addr
getv dl,var0 ; get address lo
getv dh,var1 ; get address hi
mov bp,dx ; set up as index
;
sxput1: call allclr ; clear midi channels
;
sxput2: mov al,es:[bp] ; get the data byte
mov ah,al ; save in ah
call allmidi ; send it to buffer
sendmb ; send it to MIDI
;
cmp ah,0f7h ; EOX?
jz sxput3 ; yes, branch
inc bp ; bump index
jz sxputx ; exit if index overflow
jmp short sxput2 ; else back to the loop
;
sxput3: mov var4[di],bp ; set the new index
;
sxputx: mov ax,var4[di] ; get the index
inc ax ; bump one
getv cl,var3 ; get shift byte
shr ax,cl ; bump right
putn al ; send it out
mov al,7fH ; to set lo bit
mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
and es:321[bx],al ; put to the screen
and es:323[bx],al ; /
nextv ; exit
;==============================================================
; MIDI Program change
; inputs:
; 0: channel
; 1: delay
; 2: strobe
; 3: input
; 4x: strobe tick
; output: none
;--------------------------------------------------------------
public _patcho
_patcho:
test lodflg,-1 ; load happen?
jnz patcho1 ; yes, force change
test clrchf,3 ; clear chan flag?
jz patcho2 ; yes, force change
or clrchf,2 ; setup to clear
jmp patcho1 ; go do it
;
patcho2:tick var2,var4 ; clock tick
jnc patchox ; exit if no strobe
;
patcho1:call allclr ; clear all midi channels
getv al,var0 ; get channel
mchan al ; /
or al,0c0H ; MIDI Program Change
call tomidi ; send it to midi
;
getv al,var3 ; get value input
mov outn[di],al ; send to output
and al,127 ; strip msb
call tomidi ; send to midi
;
getv al,var1 ; get delay value
or al,al ; split if 0
jz patchox ; /
mov ah,0 ; make it a word
add ax,cs:ticks ; add current ticks
patcho0:cmp al,byte ptr cs:ticks ; reached it yet?
jnz patcho0 ; no, loop
patchox:nextv
;==============================================================
; Programmer output values
; inputs: 0x: channel
; output: sequencer send to the controller
;--------------------------------------------------------------
public _pcouta
_pcouta:cmp byte ptr var0+1[di],0abh; initialized?
jz pcouta0 ; yes, branch
;
pcouti: mov al,modnum ; get module number
mov var0[di],al ; save it
gettag ; es:bx = screen addr of tag
tohex ; convert to hex
mov es:-2[bx],al ; show the default number
mov byte ptr var0+1[di],0abh; set init flag
nextx
;
pcouta0:test usrflg,1 ; user input
jnz pcoutax ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcva ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutax:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutb
_pcoutb:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutb0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutb0:test usrflg,1 ; user input
jnz pcoutbx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvb ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutbx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutc
_pcoutc:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutc0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutc0:test usrflg,1 ; user input
jnz pcoutcx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvc ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutcx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutd
_pcoutd:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutd0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutd0:test usrflg,1 ; user input
jnz pcoutdx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvd ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutdx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoute
_pcoute:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoute0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoute0:test usrflg,1 ; user input
jnz pcoutex ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcve ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutex:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutf
_pcoutf:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutf0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutf0:test usrflg,1 ; user input
jnz pcoutfx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvf ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutfx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutg
_pcoutg:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutg0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutg0:test usrflg,1 ; user input
jnz pcoutgx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvg ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutgx:nextv ; exit with display
;--------------------------------------------------------------
public _pcouth
_pcouth:cmp byte ptr var0+1[di],0abh; initialized?
jz pcouth0 ; yes, branch
jmp pcouti ; no, initialize
;
pcouth0:test usrflg,1 ; user input
jnz pcouthx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvh ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcouthx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutx
_pcoutx:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutx0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutx0:test usrflg,1 ; user input
jnz pcoutxx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvx ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutxx:nextv ; exit with display
;--------------------------------------------------------------
public _pcouty
_pcouty:cmp byte ptr var0+1[di],0abh; initialized?
jz pcouty0 ; yes, branch
jmp pcouti ; no, initialize
;
pcouty0:test usrflg,1 ; user input
jnz pcoutyx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvy ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutyx:nextv ; exit with display
;--------------------------------------------------------------
public _pcoutz
_pcoutz:cmp byte ptr var0+1[di],0abh; initialized?
jz pcoutz0 ; yes, branch
jmp pcouti ; no, initialize
;
pcoutz0:test usrflg,1 ; user input
jnz pcoutzx ; yes, no go
mov bl,var0[di] ; get channel
mov bh,0 ; bx = channel
add bx,offset dgroup:pcvz ; add table to offset
mov al,[bx] ; get the value
putn al ; send it out
pcoutzx:nextv ; exit with display
;--------------------------------------------------------------
; magenta input
;
public upcout
upcout: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset upcoutx
mov di,varsav ; point to variable list
mov al,outn[di] ; get the output value
mov var0[di],al ; save
jmp workx ; on to the next stage
upcoutx:mov di,varsav ; point to variable list
mov al,outn[di] ; get the new channel
xchg var0[di],al ; set it, get orig patch
mov outn[di],al ; restore
jmp _cancel ; exit
;==============================================================
; add switch
; inputs: 0: switch bits
; 1-8: switch inputs
; output: sequencer send to the controller
;--------------------------------------------------------------
public _addswa
_addswa:getv dl,var0 ; get the bits byte
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,640 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var1 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,8 ; 8 to do
addswa1:
test dl,ah ; is the bit hi?
jz addswa3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short addswa4 ; branch
addswa3:
mov byte ptr es:[bp],yellow ; turn the led off
addswa4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop addswa1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
addswax:nextv ; exit with display
;==============================================================
; Programmer add switch output values
; inputs: 0-3: switch inputs
; 4: control byte
; output: sequencer send to the controller
;--------------------------------------------------------------
public _psouta
_psouta:getv dl,var4 ; get the value
mov cl,4 ; get shift
shr dl,cl ; shift down
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psouta1:
test dl,ah ; is the bit hi?
jz psouta3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psouta4 ; branch
psouta3:
mov byte ptr es:[bp],yellow ; turn the led off
psouta4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psouta1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutax:nextv ; exit with display
;--------------------------------------------------------------
public _psoutc
_psoutc:getv dl,var4 ; get the value
mov cl,4 ; get shift
shr dl,cl ; shift down
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psoutc1:
test dl,ah ; is the bit hi?
jz psoutc3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psoutc4 ; branch
psoutc3:
mov byte ptr es:[bp],yellow ; turn the led off
psoutc4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psoutc1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutcx:nextv ; exit with display
;--------------------------------------------------------------
public _psoutb
_psoutb:getv dl,var4 ; get the value
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psoutb1:
test dl,ah ; is the bit hi?
jz psoutb3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psoutb4 ; branch
psoutb3:
mov byte ptr es:[bp],yellow ; turn the led off
psoutb4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psoutb1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutbx:nextv ; exit with display
;--------------------------------------------------------------
public _psoutd
_psoutd:getv dl,var4 ; get the value
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psoutd1:
test dl,ah ; is the bit hi?
jz psoutd3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psoutd4 ; branch
psoutd3:
mov byte ptr es:[bp],yellow ; turn the led off
psoutd4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psoutd1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutdx:nextv ; exit with display
;==============================================================
; Programmer add switch output values
; inputs: 0-3: switch inputs
; 4: control byte 5: shift
; output: sequencer send to the controller
;--------------------------------------------------------------
public _psoute
_psoute:getv dl,var4 ; get the value
getv cl,var5 ; get shift
shr dl,cl ; shift down
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psoute1:
test dl,ah ; is the bit hi?
jz psoute3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psoute4 ; branch
psoute3:
mov byte ptr es:[bp],yellow ; turn the led off
psoute4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psoute1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutex:nextv ; exit with display
;--------------------------------------------------------------
public _psoutf
_psoutf:getv dl,var4 ; get the value
getv cl,var5 ; get shift
shr dl,cl ; shift down
and dl,15 ; mask
;
gettag ; es:bx = screen addr of tag
dec bx ; drop back 1 for led
add bx,480 ; bx = screen addr of 1st stage led
mov bp,bx ; bp = leds
add di,var0 ; point to first stage
;
mov ah,1 ; set bit flag
mov al,0 ; clear the add register
mov cx,4 ; 4 to do
psoutf1:
test dl,ah ; is the bit hi?
jz psoutf3 ; no, turn it off
mov byte ptr es:[bp],red+hi ; else turn the led on
mov bx,[di] ; get the value addr
add al,[bx] ; add in the value
jmp short psoutf4 ; branch
psoutf3:
mov byte ptr es:[bp],yellow ; turn the led off
psoutf4:
add di,2 ; point to next val
shl ah,1 ; bump bit pointer
add bp,160 ; point to next led
loop psoutf1 ; do it again
;
mov di,2[si] ; set di pointing to variable list
putn al ; send it out
psoutfx:nextv ; exit with display
;==============================================================
; MIDI sys excl send (8 bytes max)
; inputs: 0: trigger, 1-8 input values to send, 9x: clock tick
; output: none
;--------------------------------------------------------------
public _sysxo
_sysxo:
tick var0,var9 ;
jnc sysxox ; exit if no tick
mov al,0F0H ; send sys ex opcode
call allmidi ; send to midi
mov cx,8 ; 8 data bytes
sysxo1: getv al,var1 ; get byte
test al,80H ; don't send if ms bit is hi
jnz sysxo2 ; /
call allmidi ; else dump to midi
sysxo2: add di,2 ; bump pointer
loop sysxo1 ; do them all
mov al,0F7H ; send eox
call allmidi ; /
sysxox: nextx ; exit
;==============================================================
; MIDI Control change
; inputs: 0: clock, 1: channel, 2: Control number, 3: Control value
; 4x: clock tick
; output: none
;--------------------------------------------------------------
public _ctrlo
_ctrlo:
tick var0,var4 ; clock tick
jnc ctrlox ; exit if no tick
getv al,var1 ; get channel
mchan al ; strip & set
or al,0B0H ; MIDI Control Change
call tomidi ; send it to midi
getv al,var2 ; get control number
and al,127 ; /
call tomidi ; send data to midi
getv al,var3 ; get control value
and al,127 ; /
call tomidi ; send data to midi
ctrlox: nextx
;==============================================================
; MIDI Control mapping
; first group of control modules
;--------------------------------------------------------------
public _mapo
_mapo: test usrflg,1 ; inputting now
jnz mapox ; yes, exit
;
mov bp,si ; save si
mov si,6[di] ; set up for show
mov es,4[di] ; /
mov bx,offset dgroup:ctrlmap; point to control map
add si,320 ; point to 1st value screen location
add di,var0 ; point to 1st value in module
mov cx,8 ; # of values
;
mapo1: mov al,[bx] ; look at value
cmp al,[di] ; same as in module?
jz mapo1a ; yes, branch
mov [di],al ; no, make same
tohex al ; display
mov es:[si],ah ; /
mov es:2[si],al ; /
mapo1a: inc bx ; next map number
add di,2 ; next value location
add si,160 ; next screen location
loop mapo1 ; do another
;
mov si,bp ; restore si
mapox: nextx ; exit
;--------------------------------------------------------------
public umapo
umapo: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset umapox
jmp workx ; on to the next stage
umapox:
mov bx,holdv ; get offset to the value
mov di,varsav ; get value table for module
mov dl,10[bx+di] ; get current value
shr bx,1 ; /2 for byte table
dec bx ; 1->n --> 0->n-1
mov di,offset dgroup:ctrlmap; point to control map
mov [di+bx],dl ; set new ctrl code
jmp _cancel
;==============================================================
; MIDI Control mapping
; second group of control modules
;--------------------------------------------------------------
public _mapp
_mapp: test usrflg,1 ; inputting now
jnz mappx ; yes, exit
;
mov bp,si ; save si
mov si,6[di] ; set up for show
mov es,4[di] ; /
mov bx,offset dgroup:ctrlmpp; point to control map
add si,320 ; point to 1st value screen location
add di,var0 ; point to 1st value in module
mov cx,8 ; # of values
;
mapp1: mov al,[bx] ; look at value
cmp al,[di] ; same as in module?
jz mapp1a ; yes, branch
mov [di],al ; no, make same
tohex al ; display
mov es:[si],ah ; /
mov es:2[si],al ; /
mapp1a: inc bx ; next map number
add di,2 ; next value location
add si,160 ; next screen location
loop mapp1 ; do another
;
mov si,bp ; restore si
mappx: nextx ; exit
;--------------------------------------------------------------
public umapp
umapp: pop ax ; stack bullshit
mov cmdflg,10 ; set up special routine
mov special,offset umappx
jmp workx ; on to the next stage
umappx:
mov bx,holdv ; get offset to the value
mov di,varsav ; get value table for module
mov dl,10[bx+di] ; get current value
shr bx,1 ; /2 for byte table
dec bx ; 1->n --> 0->n-1
mov di,offset dgroup:ctrlmpp; point to control map
mov [di+bx],dl ; set new ctrl code
jmp _cancel
;==============================================================
; MIDI note out.
; All parameters except Velocity are sent when changed.
; Velocity changes are ignored except zero transitions.
; When Velocity = 0, a Key-off message is sent with the currently
; saved note; the first NZ Velocity seen will send a Key-on message
; with the note value at the input, which gets saved, and the given
; velocity level. While Velocity stays NZ, any change in note values
; will cause an immediate Key-off message with the old note, then a
; Key on message with the new note, and the latest Velocity value for
; that note.
;--------------------------------------------------------------
; inputs:
; 0: Channel
; 1: Hold
; 2: Hold AND
; 3: Transpose
; 4: Transpose
; 5: Velocity Offset
; 6: Release Value
; 7, 9,11,13: Note value
; 8, 10,12,14: Velocity
; ---------------------
; 15x,16x,17x,18x: saved note
; 15+,16+,17+,18+: velocity tick flags
; ---------------------
; outn+1: b7 = initialized flag
; ---------------------
; temp0: transpose offset
; temp1: velocity offset
; temp2: release value
; temp3: enable flag
; ---------------------
; dh: channel
;--------------------------------------------------------------
public _noteo,_noteo1,_noteo2,_noteo3
_noteo3:nop
_noteo2:nop
_noteo1:nop
_noteo:
test byte ptr outn+1[di],80h ; initialized?
jnz noteo1 ; yes, branch
;--------------------------------------------------------------
; initialize
;--------------------------------------------------------------
mov cx,8 ; 4 note+velocity inputs
mov bx,0 ; use for index
noteo0: mov byte ptr var15[bp+di],0 ; clear
inc bx ; bump index
loop noteo0 ; loop
initv var2,0ffh ; Hold mask <- FF
mov byte ptr outn+1[di],80h ; set init flag
nextx ; ... on to next module
;--------------------------------------------------------------
; Get Channel Number
;--------------------------------------------------------------
noteo1: getv dh,var0 ; get it
mchan dh ; mask & set
xchg outn[di],dh ; save for next time
cmp outn[di],dh ; same as last?
jnz noteo2a ; no, mute with old
;--------------------------------------------------------------
; Check for Enable/Mute
;--------------------------------------------------------------
mov temp3,0 ; zip enable flag
getv al,var1 ; get enable
getv ah,var2 ; get enable mask
and al,ah ; /
jz noteo2a ; mute if not enabled
mov al,mprstf ; stop set
or al,lodflg ; or load flag
jz noteo2x ; branch if no mute
noteo2a:mov temp3,1 ; else set it
noteo2x:mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
dec bx ; point to led
test temp3,1 ; test for z
mov al,red ; set up for z
jnz noteo2b ; branch if z
mov al,red+hi ; else set up for nz
noteo2b:mov es:[bx],al ; set the led
;--------------------------------------------------------------
; Get note Transpose value
;--------------------------------------------------------------
getv al,var3 ; get it
getv ah,var4 ; get it
add al,ah ; add together
mov temp0,al ; put it away
;--------------------------------------------------------------
; Get Velocity offset
;--------------------------------------------------------------
getv al,var5 ; get it
mov temp1,al ; put it away
;--------------------------------------------------------------
; Get Release value
;--------------------------------------------------------------
getv al,var6 ; get it
and al,127 ; strip msb
mov temp2,al ; put it away
;--------------------------------------------------------------
; Key/velocity "A"
;--------------------------------------------------------------
push si ; save si
mov si,di ; use as saved value ptr
add si,var15 ; si = onv, si+1 = vflag
mov bp,4 ; do 4 of them
;
noteo4: test temp3,1 ; mute?
jnz noteo4a ; yes, branch
;
getv ah,var8 ; get velocity
or ah,ah ; is it on?
jnz noteo4b ; yes, branch
;
noteo4a:test byte ptr 1[si],1 ; was note on
jz noteo4x ; no, exit
;
mov al,[si] ; yes, turn old note off
call noteoff ; /
mov byte ptr 1[si],0 ; zip vflag
jmp noteo4x ; exit
;
noteo4b:test byte ptr 1[si],1 ; was note on
jnz noteo4c ; yes, branch
;
getv al,var7 ; get the note
add al,temp0 ; add offset
mov [si],al ; save it
call noteon ; turn it on
mov byte ptr 1[si],1 ; flag it
jmp noteo4x ; exit
;
noteo4c:getv al,var7 ; get the note
add al,temp0 ; add offset
cmp al,[si] ; has it changed?
jz noteo4x ; no, exit
;
xchg al,[si] ; yes, swap new w old
call noteoff ; turn old off
mov al,[si] ; turn new on
call noteon
;
noteo4x:
add si,2 ; bump pointers
add di,4 ; /
dec bp ; dec loop index
jnz noteo4 ; loop
pop si ; restore si
nextx
;--------------------------------------------------------------
; Note On
; call nv in al, v in ah
;--------------------------------------------------------------
Noteon:
xchg al,dh ; get channel
or al,090H ; MIDI Key-on
call tomidi ; send Key-on+channel
xchg al,dh ; get nv, restore channel
and al,127 ; strip msb
call tomidi ; send Note value
mov al,ah ; get velocity
add al,temp1 ; add offset
jns noteon1 ; branch if < 128
mov al,127 ; else make 127
noteon1:call tomidi ; send Velocity
ret ; exit
;--------------------------------------------------------------
; Note Off
; call nv in al
;--------------------------------------------------------------
Noteoff:
xchg al,dh ; get channel
or al,080H ; MIDI Key-off
call tomidi ; send Key-off+channel
xchg al,dh ; get nv, restore channel
and al,127 ; strip msb
call tomidi ; send Note value
mov al,temp2 ; get release value
call tomidi ; send release value
ret ; exit
;==============================================================
; MIDI channel output controller
;--------------------------------------------------------------
; inputs:
; 0: channel
; 1: Hold
; 2: Program change
; 3: After Touch
; 4: Pitch Bend
; ---------------------
; 5: Volume (mapo 0)
; 6: Mod whl (mapo 1)
; 7: controller A (mapo 2)
; 8: controller B (mapo 3)
; 9: controller C (mapo 4)
; 10:controller D (mapo 5)
; 11:controller 1 (mapo 6)
; 12:controller 2 (mapo 7)
; ---------------------
; 13x: old program change
; 13+: old after touch
; 14x: old pitch bend
; 15x - 18+: old controller values
; ---------------------
; outn+1: b7 = initialized flag
; ---------------------
; dh: channel
;--------------------------------------------------------------
public _chano,_chanl
_chanl: mov bp,offset dgroup:ctrlmpp; index for ctrlmap
jmp chanl0 ; start w 2nd map
;--------------------------------------------------------------
_chano: mov bp,offset dgroup:ctrlmap; index for ctrlmap
chanl0: test byte ptr outn+1[di],80h ; initialized?
jnz chano1 ; yes, branch
;--------------------------------------------------------------
; initialize
;--------------------------------------------------------------
initv var1,1 ; Hold <- 1
initv var4,080h ; Bend <- 80H
initv var5,07fh ; Volume <- 7fH
mov byte ptr outn+1[di],80h ; set init flag
;
chano0: mov cx,12 ; 12 save areas
mov bx,0 ; use for index
chano0a:mov byte ptr var13[bx+di],-1; set to force change
inc bx ; bump index
loop chano0a ; loop
or clrchf,2 ; setup to clear
chano0x:
nextx ; ... on to next module
;--------------------------------------------------------------
; Get Channel Number
;--------------------------------------------------------------
chano1:
getv dh,var0 ; get it
mchan dh ; mask & set
test valflg,-1 ; inputting values?
jnz chano1a ; yes, branch out
xchg outn[di],dh ; save for next time
cmp outn[di],dh ; same as last?
jnz chano0 ; no, force change
chano1a:
;--------------------------------------------------------------
; Check for Hold
;--------------------------------------------------------------
getv al,var1 ; get hold
or al,mprstf ; or program reset
or al,lodflg ; or load flag
or al,clrchf ; clear chan flag?
jnz chano1b ; yes, force change
mov al,0 ; clear led flag
;--------------------------------------------------------------
chano1b:mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
dec bx ; point to led
test al,-1 ; test for z
jz chano1c ; branch if z
mov byte ptr es:[bx],red ; clr the led
jmp chano0 ; reset stuff
chano1c:mov byte ptr es:[bx],red+hi ; set the led
;--------------------------------------------------------------
; Patch Change
;--------------------------------------------------------------
getv al,var2 ; get input value
cmp al,var13[di] ; any change
jz chano2x ; no, branch
and al,7fh ; mask
mov var13[di],al ; yes, store the new value
mov ah,0C0H ; MIDI Patch Change
or ah,dh ; add in channel info
xchg al,ah ; fix
call tomidi ; send it to midi
xchg al,ah ; fix
call tomidi ; send value to midi
chano2x:
;--------------------------------------------------------------
; Aftertouch
;--------------------------------------------------------------
getv al,var3 ; get input value
cmp al,var13+1[di] ; any change
jz chano3x ; no, branch
and al,127 ; strip msb
mov var13+1[di],al ; yes, store the new value
mov ah,0D0H ; MIDI After Touch
or ah,dh ; add in channel info
xchg al,ah ; fix
call tomidi ; send it to midi
xchg al,ah ; fix
call tomidi ; send value to midi
chano3x:
;--------------------------------------------------------------
; Pitch Bend
;--------------------------------------------------------------
getv al,var4 ; get input value
cmp al,var14[di] ; any change
jz chano5x ; no, branch
mov var14[di],al ; yes, store the new value
; add al,80h ; center for pitch bend
shr al,1 ; strip lsb
rcr ch,1 ; put in ch
rcr ch,1 ; mov into position
and ch,64 ; clean it up
mov ah,0E0H ; MIDI Pitch Bend
or ah,dh ; add in channel info
xchg ah,al ; fix
call tomidi ; send it to midi
mov al,ch ; fix
call tomidi ; send ls value to midi
mov al,ah ; fix
call tomidi ; send ms value to midi
chano5x:
;--------------------------------------------------------------
; Controllers mapped by mapo module into array: ctrlmap 0-5
;--------------------------------------------------------------
push si ; save si
mov si,di ; use as pointer
add si,var15 ; /
mov cx,6 ; 6 to do
chano6:
getv al,var5 ; get input value
cmp al,[si] ; any change
jz chano6a ; no, branch
and al,127 ; strip msb
mov [si],al ; yes, store the new value
mov ah,0B0H ; MIDI Control Change
or ah,dh ; add in channel info
xchg ah,al ; fix
call tomidi ; send it to midi
mov al,ds:[bp] ; mapped ctrl number
call tomidi ; send it to midi
xchg ah,al ; fix
call tomidi ; send value to midi
chano6a:inc bp ; bump pointers
inc si ; /
add di,2 ; /
loop chano6 ; loop
;--------------------------------------------------------------
; Controllers mapped by mapo module into array: ctrlmap 6,7
;--------------------------------------------------------------
mov cx,2 ; 2 to do
chano7:
getv al,var5 ; get input value
and al,127 ; strip msb, test for Z
jz chano7b ; branch if Z
mov al,127 ; else make 127
chano7b:cmp al,[si] ; any change
jz chano7a ; no, branch
mov [si],al ; yes, store the new value
mov ah,0B0H ; MIDI Control Change
or ah,dh ; add in channel info
xchg ah,al ; fix
call tomidi ; send it to midi
mov al,ds:[bp] ; mapped ctrl number
call tomidi ; send it to midi
xchg ah,al ; fix
call tomidi ; send value to midi
chano7a:inc bp ; bump pointers
inc si ; /
add di,2 ; /
loop chano7 ; loop
;
pop si ; restore si
nextx ; exit
;==============================================================
; MIDI event programmer/sequencer
; normal output, all inputs are magenta user inputs.
; -- all number inputs use addr+1 to hold output flag copy
; inputs:
; 0x: user input to change address
; 1x: end address
; 2x: Undo switch
; 2+: user input flag
; 3x: Store switch
; 3+: initialized flag
; 4x: Recall switch
; 4+: module number
; 5x: Save switch
; 6x: Measures to next (first of sequencer data)
; 7x: stage 1
; 8x: stage 2
; 9x: stage 3
; 10x: stage A
; 11x: stage B
; 12x: stage C
; 13x: stage D
; 14x: stage w slew E
; 15x: slew value for E
; 16x: stage w slew F
; 17x: slew value for F
; 18x: stage w slew G
; 19x: slew value for G
; 20x: stage w slew H
; 21x: slew value for H
; slewc: slew value buffer C
; slewd: slew value buffer D
; slewe: slew value buffer E
; slewf: slew value buffer F
; pubuf: Undo Buffer
; psbuf: Save Buffer
;--------------------------------------------------------------
public _progo
_progo: cmp byte ptr var3+1[di],0abh; initialized?
jz progoii ; yes, branch
;
mov cx,98 ; big mother
mov bx,var0 ; clear variable space
progoi: mov byte ptr [bx+di],0 ; zip it
inc bx ; bump address
loop progoi ; loop
;
mov al,modnum ; get module number
mov byte ptr var4+1[di],al ; save it
mov byte ptr var3+1[di],0abh; set init flag
;
progoii:test usrflg,1 ; user input now?
jz progo0 ; no, branch
mov byte ptr var2+1[di],1 ; yes, set show differences
nextx ; ...easy exit
;--------------------------------------------------------------
; process master reset
;
progo0: mov al,mpadrf ; address change?
or al,al ; /
jz progo0a ; no, branch
mov al,mpadr ; yes, get master address
mov var0[di],al ; set local address = master
progo0a:
;--------------------------------------------------------------
mov bp,si ; save si
mov es,4[di] ; get screen seg addr
mov si,6[di] ; get screen ofst addr
;--------------------------------------------------------------
test mpmodf,1 ; programming or playing?
jz progo1 ; branch if playing
jmp progo2 ; else jump to programming
;--------------------------------------------------------------
; mode = playing
;--------------------------------------------------------------
;
progo1: test mmstart,1 ; master measure start?
jz progo1b ; no, branch
cmp byte ptr var6[di],0 ; local measure count = 0?
jz progo1a ; yes, branch
dec byte ptr var6[di] ; no, count down 1
jmp short progo1b ; ...on to the next
;--------------------------------------------------------------
; address change
;
progo1a:mov al,var1[di] ; is end <= address
cmp al,byte ptr var0[di] ; /
jbe progo1b ; yes, don't bump address
test mprstf,-1 ; master reset?
jnz progo1b ; yes, don't bump address
inc byte ptr var0[di] ; else bump sequencer address
progo1b:mov al,var0[di] ; has address changed
cmp al,var0+1[di] ; /
jz progo1c ; no, branch
putn al ; yes, send it out
call sq_ob ; yes copy seq to output buffer
mov byte ptr var2+1[di],1 ; set show differences
showpq 0 ; display address
progo1c:showpq 6 ; display measure counter
jmp progo3 ; branch to common stuff
;--------------------------------------------------------------
; mode = programming
;--------------------------------------------------------------
; address change
;
progo2: mov al,var0[di] ; has address changed
cmp al,var0+1[di] ; /
jz progo2a ; no, branch
putn al ; yes, send it out
call ob_ub ; output buf to undo buf
call sq_ob ; sequencer to output buf
showpq 0 ; display the new value
mov byte ptr var2+1[di],1 ; set show differences
progo2a:
;--------------------------------------------------------------
; measures counter
;
mov al,var6[di] ; measures value changed?
cmp al,var6+1[di] ; /
jz progo2e ; no, branch
mov var6+1[di],al ; yes, clear flag
showpv 6 ; display measure counter
mov byte ptr var2+1[di],1 ; set show differences
progo2e:
;--------------------------------------------------------------
; undo button
;
test byte ptr var2[di],1 ; undo button pushed?
jz progo2b ; no, branch
mov byte ptr var2[di],0 ; clear the button
call ub_ob ; swap undo with output
jmp short progo2z ; show & tell
progo2b:
;--------------------------------------------------------------
; store button
;
test byte ptr var3[di],1 ; store button pushed?
jz progo2c ; no, branch
mov byte ptr var3[di],0 ; clear the button
call sq_ub ; sequencer to undo buf
call ob_sq ; output buffer to seq
; or _mpab,2 ; set buffer used flag
jmp short progo2z ; show & tell
progo2c:
;--------------------------------------------------------------
; recall button
;
test byte ptr var4[di],1 ; recall button pushed?
jz progo2d ; no, branch
mov byte ptr var4[di],0 ; clear the button
call ob_ub ; output buf to undo buf
call sb_ob ; save buf to out buf
jmp short progo2z ; show & tell
progo2d:
;--------------------------------------------------------------
; save button
;
test byte ptr var5[di],1 ; save button pushed?
jz progo2x ; no, branch
mov byte ptr var5[di],0 ; clear the button
call ob_sb ; output buf to save buf
;--------------------------------------------------------------
progo2z:mov byte ptr var2+1[di],1 ; set show differences
progo2x:
;--------------------------------------------------------------
; common code for programming or playing
;--------------------------------------------------------------
; process outbyte
;
progo3:
mov al,var7[di] ; out byte change?
cmp al,var7+1[di] ; /
jz progo3a ; no, jmp to next
mov var7+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvx ; point to outval table
mov [bx],al ; put value to the table
progo3a:showpv 7 ; update display
;--------------------------------------------------------------
mov al,var8[di] ; out byte change?
cmp al,var8+1[di] ; /
jz progo3b ; no, jmp to next
mov var8+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvy ; point to outval table
mov [bx],al ; put value to the table
progo3b:showpv 8 ; update display
;--------------------------------------------------------------
mov al,var9[di] ; out byte change?
cmp al,var9+1[di] ; /
jz progo3c ; no, jmp to next
mov var9+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvz ; point to outval table
mov [bx],al ; put value to the table
progo3c:showpv 9 ; update display
;--------------------------------------------------------------
; send non-slew output values
;
;progo4:
;--------------------------------------------------------------
mov al,var10[di] ; out byte change?
cmp al,var10+1[di] ; /
jz progo4a ; no, jmp to next
mov var10+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcva ; point to outval table
mov [bx],al ; put value to the table
progo4a:showpv 10 ; update display
;--------------------------------------------------------------
mov al,var11[di] ; out byte change?
cmp al,var11+1[di] ; /
jz progo4b ; no, jmp to next
mov var11+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvb ; point to outval table
mov [bx],al ; put value to the table
progo4b:showpv 11 ; update display
;--------------------------------------------------------------
mov al,var12[di] ; out byte change?
cmp al,var12+1[di] ; /
jz progo4c ; no, jmp to next
mov var12+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvc ; point to outval table
mov [bx],al ; put value to the table
progo4c:showpv 12 ; update display
;--------------------------------------------------------------
mov al,var13[di] ; out byte change?
cmp al,var13+1[di] ; /
jz progo4d ; no, jmp to next
mov var13+1[di],al ; yes, set flag
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvd ; point to outval table
mov [bx],al ; put value to the table
progo4d:showpv 13 ; update display
;--------------------------------------------------------------
; send values with slew
;
mov bx,slewe ; point to slew buffer
mov dx,var14[di] ; get input & target
mov cl,var15[di] ; get rate
call pslew ; get new slew value
cmp var14[di],dx ; did it change?
mov var14[di],dx ; (put it away)
jz progo4e ; no change,split
;
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcve ; point to outval table
mov [bx],dh ; put value to the table
;
progo4e:showpp 14 ; update display
showpq 15 ; display & flag rate
;--------------------------------------------------------------
mov bx,slewf ; point to slew buffer
mov dx,var16[di] ; get input & target
mov cl,var17[di] ; get rate
call pslew ; get new slew value
cmp var16[di],dx ; did it change?
mov var16[di],dx ; (put it away)
jz progo4f ; no change,split
;
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvf ; point to outval table
mov [bx],dh ; put value to the table
;
progo4f:showpp 16 ; update display
showpq 17 ; display & flag rate
;--------------------------------------------------------------
mov bx,slewg ; point to slew buffer
mov dx,var18[di] ; get input & target
mov cl,var19[di] ; get rate
call pslew ; get new slew value
cmp var18[di],dx ; did it change?
mov var18[di],dx ; (put it away)
jz progo4g ; no change,split
;
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvg ; point to outval table
mov [bx],dh ; put value to the table
;
progo4g:showpp 18 ; update display
showpq 19 ; display & flag rate
;--------------------------------------------------------------
mov bx,slewh ; point to slew buffer
mov dx,var20[di] ; get input & target
mov cl,var21[di] ; get rate
call pslew ; get new slew value
cmp var20[di],dx ; did it change?
mov var20[di],dx ; (put it away)
jz progo4h ; no change,split
;
mov bl,var4+1[di] ; bx = Channel
mov bh,0 ; /
add bx,offset dgroup:pcvh ; point to outval table
mov [bx],dh ; put value to the table
;
progo4h:showpp 20 ; update display
showpq 21 ; display & flag rate
;--------------------------------------------------------------
; module execution ends here
; clean up & display output value
;--------------------------------------------------------------
test byte ptr var2+1[di],1 ; show differences?
jz progo6a ; no, branch
call sq?ob ; show if ob <> seq
progo6a:mov si,bp ; restore si
mov byte ptr var2+1[di],0 ; clear user input flag
nextv ; display output, exit
;--------------------------------------------------------------
; subroutine to update slew value
; call with bx = slew buffer offset (slewc, slewd, etc.)
; dx = input/output (dh), target (dl)
; cl = rate
; returns with dx = input/output, target
;
; formula:
; initialize:
; input * 256 --> sum; input --> output
; thereafter until sum/256 = target:
; sum - input + target --> sum
; sum/256 --> output
;
; buffer offsets for values:
; 0: sum
; 2: saved input
; 3: saved target
; 4: saved rate
; 5: busy
;--------------------------------------------------------------
pslew: test byte ptr 5[bx+di],1 ; busy?
jnz pslewa ; yes, branch
cmp dl,dh ; no, see if target=output
jnz pslewb ; not equal, go slew
cmp dh,2[bx+di] ; else see if input has changed
jz pslewx ; exit if no change
;
pslewb: mov 3[bx+di],dl ; save target
mov 2[bx+di],dh ; save input
mov 4[bx+di],cl ; save rate
;
mov dh,dl ; target --> output
or cl,cl ; rate = 0?
jz pslewx ; yes, just exit
; test mpmodf,1 ; programming or playing?
; jnz pslewx ; just exit if programming
mov byte ptr 5[bx+di],1 ; else flag busy
;
mov al,2[bx+di] ; ax = input * 128
mov ah,0 ; /
mov cl,7 ; /
shl ax,cl ; /
; mov ah,2[bx+di] ; ax = input * 256
; mov al,0 ; /
mov [bx+di],ax ; set new sum
mov dh,2[bx+di] ; input --> output
jmp short pslewx ; exit
;
pslewa: dec byte ptr 4[bx+di] ; countdown
jnz pslewx ; /
or cl,cl ; rate set to 0?
jnz pslewc ; no, go on
mov dh,dl ; yes, set output=target
jmp short pslewz ; exit finished
;
pslewc: mov 4[bx+di],cl ; save rate count
mov ax,[bx+di] ; ax = sum
mov cl,2[bx+di] ; cx = input
mov ch,0 ; /
sub ax,cx ; ax = sum - input
mov cl,3[bx+di] ; cx = target
add ax,cx ; ax = sum - input + target
mov [bx+di],ax ; save new sum
mov cl,7 ; ax = new sum / 128
;
shr ax,cl ; /
mov dh,al ; dh = new sum / 128
; mov dh,ah ; dh = new sum / 256
pslewz: cmp dh,dl ; output = target
jnz pslewx ; no, exit
mov byte ptr 5[bx+di],0 ; yes, flag not busy
;
pslewx: ret ; exit
;--------------------------------------------------------------
; subroutines to copy sequencer buffers
;
; ob_sb = obuf --> sbuf = output buffer to save buffer
; ob_ub = obuf --> ubuf = output buffer to undo buffer
; ob_sq = obuf --> seq = output buffer to sequencer
; sb_ob = sbuf --> obuf = save buffer to output buffer
; sq_ob = seq --> obuf = sequencer to output buffer
; sq_ub = seq --> ubuf = sequencer to undo buffer
; ub_ob = ubuf <-> obuf = undo buffer swapped with output buffer
; sq?ob = show red if sq <> ob, else show yellow
;--------------------------------------------------------------
; ob_sb = obuf --> sbuf = output buffer to save buffer
;
ob_sb: mov bx,di ; use bx for sbuf addr
add bx,psbuf ; bx = sbuf addr
jmp short ob_ub0 ; go do it
;--------------------------------------------------------------
; ob_ub = obuf --> ubuf = output buffer to undo buffer
;
ob_ub: mov bx,di ; use bx for sbuf addr
add bx,pubuf ; bx = ubuf addr
;
ob_ub0: mov si,di ; get offset to obuf
add si,var6 ; /
;
mov cx,16 ; 16 in a loop
ob_ubl: mov al,[si] ; get obuf byte
mov [bx],al ; put it away
inc bx ; bump pointers
add si,2 ; /
loop ob_ubl ; loop til done
;
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; ob_sq = obuf --> seq = output buffer to sequencer
;
ob_sq: mov ah,var4+1[di] ; offset for channel
mov al,0 ; /
add ax, seg bufpa ; base seg of seq buffer
mov es,ax ; es = seg addr of seq buf
mov al,var0[di] ; get seq step
mov bl,16 ; bump up
mul bl ; ax = seq addr
mov bx,ax ; es:bx = seq addr
;
mov si,di ; get offset to obuf
add si,var6 ; /
;
mov cx,16 ; 16 in a loop
ob_sql: mov al,[si] ; get buffer byte
mov es:[bx],al ; put to sequencer
inc bx ; bump pointers
add si,2 ; /
loop ob_sql ; loop til done
;
mov es,4[di] ; restore screen seg addr
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; sb_ob = sbuf --> obuf = save buffer to output buffer
;
sb_ob: mov bx,di ; use bx for sbuf addr
add bx,psbuf ; bx = sbuf addr
mov si,di ; get offset to obuf
add si,var6 ; /
;
mov cx,16 ; 16 in a loop
sb_obl: mov al,[bx] ; get sbuf byte
mov [si],al ; put to obuf
inc bx ; bump pointers
add si,2 ; /
loop sb_obl ; loop til done
;
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; sq_ob = seq --> obuf = sequencer to output buffer
;
sq_ob: mov ah,var4+1[di] ; offset for channel
mov al,0 ; /
add ax,seg bufpa ; base seg of seq buffer
mov es,ax ; es = seg addr of seq buf
mov al,var0[di] ; get seq step
mov bl,16 ; bump up
mul bl ; ax = seq addr
mov bx,ax ; es:bx = seq addr
;
mov si,di ; get offset to obuf
add si,var6 ; /
;
mov cx,16 ; 16 in a loop
sq_obl: mov al,es:[bx] ; get the byte
mov [si],al ; put it away
inc bx ; bump pointers
add si,2 ; /
loop sq_obl ; loop til done
;
mov es,4[di] ; restore screen seg addr
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; sq_ub = seq --> ubuf = sequencer to undo buffer
;
sq_ub: mov ah,var4+1[di] ; offset for channel
mov al,0 ; /
add ax, seg bufpa ; base seg of seq buffer
mov es,ax ; es = seg addr of seq buf
mov al,var0[di] ; get seq step
mov bl,16 ; bump up
mul bl ; ax = seq addr
mov bx,ax ; es:bx = seq addr
;
mov si,di ; use si for sbuf addr
add si,pubuf ; si = ubuf addr
;
mov cx,16 ; 16 bytes to move
sq_ubl: mov al,es:[bx] ; get seq byte
mov [si],al ; put it in ubuf
loop sq_ubl ; loop til done
;
mov es,4[di] ; restore screen seg addr
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; ub_ob = ubuf <-> obuf = undo buffer swapped with output buffer
;
ub_ob: mov bx,di ; use bx for sbuf addr
add bx,pubuf ; bx = ubuf addr
;
mov si,di ; get offset to obuf
add si,var6 ; /
;
mov cx,16 ; 16 in a loop
ub_obl: mov al,[si] ; get obuf byte
xchg [bx],al ; put it away
mov [si],al ; swap
inc bx ; bump pointers
add si,2 ; /
loop ub_obl ; loop til done
;
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; sq?ob show red for each of the 16 values when sq <> ob,
; else show yellow
;
sq?ob: mov ah,var4+1[di] ; offset for channel
mov al,0 ; /
add ax, seg bufpa ; base seg of seq buffer
mov es,ax ; es = seg addr of seq buf
mov cx,ax ; cx = copy of above
mov al,var0[di] ; get seq step
mov bl,16 ; bump up
mul bl ; ax = seq addr
mov bx,ax ; es:bx = seq addr
;
mov si,di ; get offset to obuf
add si,var6 ; ds:si = offset to obuf
;
push bp ; save current bp
mov bp,ds:4[di] ; bp = screen seg
mov dx,6[di] ; dx = screen address
add dx,160*6+480 ; dx = offset to var6
dec dx ; back up to point to label
xchg dx,di ; di = offset to var6
; ; dx = old di (save)
mov ah,16 ; 16 in a loop
sq?obl: mov al,es:[bx] ; get the byte at var
cmp [si],al ; same
mov al,yellow ; pretend it is
jz sq?ob2 ; yes, branch
mov al,red
sq?ob2: mov es,bp ; get screen seg
mov es:[di],al ; set color
mov es,cx ; seq seg
inc bx ; bump pointers
add si,2 ; /
add di,160 ; /
dec ah ; loop til done
jnz sq?obl ; /
;
pop bp ; restore bp
mov di,dx ; restor variable indes
mov es,4[di] ; restore screen seg addr
mov si,6[di] ; get screen ofst addr
ret
;--------------------------------------------------------------
; process magenta inputs
;
public uprogo
uprogo: pop ax ; stack bullshit
mov di,varsav ; get value table for module
cmp magflg,0 ; no-value?
jnz uprogb ; no, branch
mov bx,holdv ; get offset to the value
xor byte ptr 10[bx+di],1 ; flip value of input
uprogr: jmp _cancel ; exit
;
uprogb: mov cmdflg,10 ; set up special routine
mov special,offset uprogr ; data exit
jmp workx ; on to the next stage
;==============================================================
; beep a note on the pc speaker
; inputs: 0: gate, 1: pitch, 2x: note flags
; output: gate
;--------------------------------------------------------------
public _bopo
_bopo:
test mprstf,-1 ; stopped?
jz bopogo ; no, go on
call toneoff ; yes, turn off the speaker
jmp bopox ; exit
bopogo: getv al,var0 ; get the gate
mov dl,var2[di] ; dl = on/off flags
or al,al ; gate on?
jz bopo1 ; no, branch
and dl,offlg xor -1 ; yes, clear off flag
test dl,onflg ; is on flag set?
jz bopo2 ; no, branch
bopo3:
mov di,2[si] ;; set di pointing to variable list
nextx ; yes, easy exit
bopo2: or dl,onflg ; no, set on flag
mov var2[di],dl ; put it away
;--------------------------------------------------------------
; note on
getv al,var1 ; get the pitch
call pitch ; play it
mov cx,dx ; /
call toneset ; /
call toneon ; /
mov ah,-1 ; load True
putn ah ; flag to the output
jmp short bopox
;--------------------------------------------------------------
bopo1: and dl,onflg xor -1 ; clock is off, clear on flag
test dl,offlg ; off flag set?
jnz bopo3 ; yes, easy exit
or dl,offlg ; no, set the off flag
mov var2[di],dl ; put it away
call toneoff ; turn off the note
mov ah,0 ; load False
putn ah ; flag to the output
bopox:
mov di,2[si] ;; set di pointing to variable list
nextx ; exit
;--------------------------------------------------------------
; play tones on the pc speaker
;
;--------------------------------------------------------------
; initialize timer chip
; Just called once
;
toneinit:
; mov al,2*40h+3*10h+3*2
; out 43h,al
ret
;--------------------------------------------------------------
; convert from frequency to period
; input: frequency in CX
; output: period in CX
;
freq: push dx
push ax
;
mov dx,12H
mov ax,34deh
div cx
mov cx,ax
;
pop ax
pop dx
ret
;--------------------------------------------------------------
; convert from a pitch to a number
; input: pitch number in al
; output: value for TONESET in DX
;--------------------------------------------------------------
pitch: push cx
push bx
push ax
;
mov ah,0
mov cl,12
div cl
;
mov dl,al
mov al,ah
cbw
sal ax,1
mov bx,ax
mov cx,notes[bx]
call freq
;
xchg cx,dx
neg cl
add cl,8
sal dx,cl
;
pop ax
pop bx
pop cx
ret
;--------------------------------------------------------------
; select a tone
; input: tone in CX
; output: none
;
toneset:push ax
;
mov al,cl
out 42h,al
jmp short $+2
mov al,ch
out 42h,al
;
pop ax
ret
;--------------------------------------------------------------
; turn tone on
;
toneon: push ax
in al,61H
or al,3
out 61h,al
pop ax
ret
;--------------------------------------------------------------
; turn tone off
;
toneoff:push ax
in al,61h
and al,0fch
out 61h,al
pop ax
ret
;==============================================================
; pushbutton routine
; output is turned on/off every other push
; input is set only by user routine
;--------------------------------------------------------------
public _pusha
_pusha:
nextl ; exit
;--------------------------------------------------------------
public upusha
upusha: mov di,varsav ; point to variable list
xor byte ptr 8[di],1; flip the output
pop ax ; keep stack right
jmp _cancel ; return clean
;==============================================================
; pushbutton routine
; output is a single strobe, lasting from start of loop to priority.
; input is set only by user routine
;--------------------------------------------------------------
public _pushb
_pushb:
nextt
;--------------------------------------------------------------
public upushb
upushb: mov di,varsav ; point to variable list
mov byte ptr 8[di],1; set hi
pop ax ; keep stack right
jmp _cancel ; return clean
;==============================================================
; pushbutton routine
; output is incremented/decremented every push, depending on
; cursor location on magenta pad.
; input is set only by user routine
;--------------------------------------------------------------
public _pushc
_pushc: nextv ; update screen
;--------------------------------------------------------------
public upushc
upushc: pop ax ; stack bullshit
cmp magflg,1 ; inc/dec?
jnz upushc1 ; no, branch
;
mov di,varsav ; get value table for module
mov ax,curadr ; up or down button?
cmp ax,cmdloc ; if same, it's up
jz upushc2 ; branch if same
dec byte ptr outn[di] ; dec output value
jmp _cancel ; exit
upushc2:inc byte ptr outn[di] ; inc output value
jmp _cancel ; exit
upushc1:mov cmdflg,10 ; set up special routine
mov special,offset upushc3 ; data exit
jmp workx ; exit
upushc3:mov di,varsav ; get value table
mov al,byte ptr var0[di] ; get new value
mov byte ptr outn[di],al ; send it out
jmp _cancel ; exit
;==============================================================
; Exit routine for modules that use msb of output byte.
; It displays output value, then executes the next module on the list.
; assumes di has been set to variable table
;
next: mov es,4[di] ; get seg addr
mov bx,6[di] ; get module screen address
mov al,8[di] ; get output value
tohex ; convert to hex word
mov es:320[bx],ah ; put to the screen
mov es:322[bx],al ; /
nextx ; easy exit
;--------------------------------------------------------------
; Just execute the next module on the list.
;
public _dummy
_dummy: nextx ; easy exit
;--------------------------------------------------------------
; this code converts in-line macros to jumps at the end of modules
;
public _nextv,_nextx,_nextl,_nextt
_nextv: @nextv
_nextx: @nextx
_nextl: @nextl
_nextt: @nextt
;==============================================================
; user input routines for magenta inputs
;
;--------------------------------------------------------------
public ugatel
ugatel: pop ax
jmp _cancel
;==============================================================
_TEXT ENDS
END