| ------------------------------------------------------------------------------ | seexec.s -- score event execution driver | Version 40 -- 1988-10-06 -- D.N. Lynx Crowe | struct s_entry | | se_exec(ep, sd) | struct s_entry |ep; | short sd; | Executes the event at 'ep', scrolling in direction 'sd'. | ------------------------------------------------------------------------------ .text .xdef _se_exec .xdef BadEvnt .xdef _xevent .xref _asgvce .xref _clkset .xref _getasg .xref _gettun .xref _procpfl .xref _selscor .xref _setdyn .xref _setloc .xref _setsv .xref _settmpo .xref _settune .xref _setv2gi .xref _anrs .xref _var2src .xref _curasg .xref _curintp .xref _cursect .xref _grpmode .xref _grpstat .xref _ins2grp .xref _nxtflag .xref _recsw .xref _s_trns .xref _trgtab .xref _varmode .xref _vce2grp .xref _vce2trg .xref _veltab .page | parameter offsets | ----------------- P_EP = 8 | WORD - 'ep' parameter offset P_SD = 12 | WORD - 'sd' parameter offset | event structure offsets -- MUST match score.h definitions | ----------------------- ------------------------------ | offset length | ------ ------ E_TIME = 0 | LONG E_SIZE = 4 | BYTE E_TYPE = 5 | BYTE E_DATA1 = 6 | BYTE E_NOTE = 6 | BYTE E_DATA2 = 7 | BYTE E_GROUP = 7 | BYTE E_BAK = 8 | LONG E_FWD = 12 | LONG E_DN = 16 | LONG E_VEL = 16 | WORD E_DATA4 = 18 | WORD E_UP = 20 | LONG E_LFT = 24 | LONG E_RGT = 28 | LONG | Miscellaneous constants | ----------------------- N_ETYPES = 25 | number of event types M_KSTATE = 0x01 | keys status bit N_KSTATE = 0xFE | keys status bit complement D_BAK = 1 | code for backward scrolling LCL_PRT = 2 | 0-origin local port number LCL_PCH = 0x1080 | port and channel for trigger .page | A few words about se_exec: | se_exec has to be very fast, so it's written in assembly language, | rather than C, which is usually pretty good, but not quite good enough | for this application. The faster this routine runs, the higher the | tempo we can keep up with. If this code is fast enough, we end up | hardware limited by the timer. _se_exec: link a6,#0 | link stack frames movea.l P_EP(a6),a0 | get event pointer 'ep' into a0 move.l a0,_xevent | save in xevent move.b E_TYPE(a0),d1 | get event type into d1.W andi.w #0x007F,d1 | ... and mask off new-data flag cmp.b #N_ETYPES,d1 | see if it's valid blt sexc1 | jump if it is BadEvnt: move.l a0,d0 | setup to return pointer we got bra done | exit exexit: movea.l _xevent,a0 | point at next event move.l E_FWD(a0),d0 | ... done: unlk a6 | done -- unlink stack frames rts | return to caller sexc1: lea sextab,a1 | get base of dispatch table lsl.w #2,d1 | multiplty event by 4 for index movea.l 0(a1,d1.W),a2 | get address of event routine jmp (a2) | jump to event execution routine | On entry, the individual execution routines only depend on a0 pointing at the | event they were dispatched for. | The usual C function register usage conventions apply: | d0..d2 and a0..a2 are used for scratch, and are not preserved. | d3..d6 and a3..a5 are register variables, and are preserved. | a6 = frame pointer, a7 = stack pointer, and are preserved. .page | exnbeg -- execute note begin | ------ ------------------ | If things need to be sped up, we could incorporate the functions of | asgvce() here, rather than calling it. asgvce() could also be re-written in | assembly language to make it a shade faster. exnbeg: cmpi.w #D_BAK,P_SD(a6) | check direction beq nendex | if backward, treat as note end nbegex: clr.w d1 | clear d1 move.b E_GROUP(a0),d1 | get group number add.w d1,d1 | ... | 2 lea _grpstat,a1 | point at grpstat tst.w 0(a1,d1.W) | see if group is enabled beq exexit | done if not move.b E_NOTE(a0),d1 | d1 = note number nn (0..127) move.w #LCL_PCH,d2 | put port and channel in d2 add.w d1,d2 | d2 = trg lea _trgtab,a1 | point at trgtab[trg] move.b 0(a1,d2.W),d0 | ... or.b #M_KSTATE,d0 | set trigger table entry on move.b d0,0(a1,d2.W) | ... lea _veltab,a1 | point at veltab add.w d2,d2 | ... move.w E_VEL(a0),0(a1,d2.W) | put velocity in veltab move.w E_VEL(a0),-(a7) | put velocity on the stack move.w d1,-(a7) | put note number on the stack move.w #1,-(a7) | put channel on the stack move.w #LCL_PRT,-(a7) | put port on the stack move.b E_GROUP(a0),d1 | d1 = group number (0..11) move.w d1,-(a7) | put group number on the stack jsr _asgvce | start the note add.l #10,a7 | clean up the stack bra exexit | done .page | exnend -- execute note end | ------ ---------------- | If things need to be sped up, we could incorporate the functions of | procpfl() here, rather than calling it. procpfl() could also be re-written in | assembly language to make it a shade faster. exnend: cmpi.w #D_BAK,P_SD(a6) | check direction beq nbegex | if backward, treat as beginning nendex: clr.w d1 | clear d1 move.b E_GROUP(a0),d1 | get group number add.w d1,d1 | ... | 2 lea _grpstat,a1 | point at grpstat tst.w 0(a1,d1.W) | check group status beq exexit | done if disabled move.b E_NOTE(a0),d1 | d1 = note number nn (0..127) move.w #LCL_PCH,d2 | put port and channel in d2 add.w d1,d2 | d2 = trg | 2 add.w d2,d2 | ... lea _trgtab,a1 | set trigger table entry off move.b 0(a1,d2.W),d0 | ... and.b #N_KSTATE,d0 | ... move.b d0,0(a1,d2.W) | ... bne exexit | done if note still active .page lsr.w #1,d2 | adjust d2 clr.w d1 | set loop index lea _vce2trg,a2 | point at vce2trg table exnend1: cmp.w (a2),d2 | see if this voice uses trg bne exnend2 | jump if not move.w #-1,(a2) | set entry to -1 move.l a2,-(a7) | save a2 on stack move.w d1,-(a7) | save d1 on stack move.w d2,-(a7) | save d2 on stack lea _vce2grp,a1 | put group on stack move.w d1,d0 | ... add.w d0,d0 | ... move.w 0(a1,d0.W),-(a7) | ... move.w d2,-(a7) | put trg on stack jsr _procpfl | process sustained voices addq.l #4,a7 | clean up stack move.w (a7)+,d2 | restore d2 move.w (a7)+,d1 | restore d1 movea.l (a7)+,a2 | restore a2 exnend2: addq.l #2,a2 | point at next vce2trg entry addq.w #1,d1 | loop until all are checked cmp.w #12,d1 | ... bne exnend1 | ... bra exexit | done .page | exsbgn -- execute section begin | ------ --------------------- exsbgn: clr.w d0 | get section number move.b E_DATA1(a0),d0 | ... move.w d0,_cursect | set section number bra exexit | done | exasgn -- execute assignment event | ------ ------------------------ exasgn: clr.w d0 | get assignment move.b E_DATA1(a0),d0 | ... move.w d0,-(a7) | getasg(curasg = asgn) move.w d0,_curasg | ... jsr _getasg | ... tst.w (a7)+ | ... bra exexit | done | extune -- execute tuning event | ------ -------------------- extune: clr.w d0 | get tuning move.b E_DATA1(a0),d0 | ... move.w d0,-(a7) | gettun(tuning) jsr _gettun | ... tst.w (a7)+ | ... bra exexit | done | extrns -- execute transposition event | ------ --------------------------- extrns: clr.w d0 | get group number move.b E_DATA1(a0),d0 | ... add.w d0,d0 | ... as an index in d0 lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if disabled lea _s_trns,a1 | set group transposition move.w E_LFT(a0),0(a1,d0.W) | ... jsr _settune | ... bra exexit | done .page | extmpo -- execute tempo event | ------ ------------------- extmpo: clr.w d0 | get tempo move.b E_DATA1(a0),d0 | ... move.w d0,-(a7) | settmpo(tempo) jsr _settmpo | ... tst.w (a7)+ | ... bra exexit | done | exstop -- execute stop event | ------ ------------------ exstop: clr.w -(a7) | stop the clock jsr _clkset | ... tst.w (a7)+ | ... bra exexit | that's all, folks | exintp -- execute interpolate event | ------ ------------------------- exintp: move.w E_DATA1(a0),_curintp | set interpolate value bra exexit | done .page | exinst -- execute instrument change event | ------ ------------------------------- exinst: clr.w d0 | get group number move.b E_DATA1(a0),d0 | ... in d0 add.w d0,d0 | ... as a word offset lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if not enabled lea _ins2grp,a1 | point at ins2grp[] clr.w d0 | get instrument number move.b E_DATA2(a0),d0 | ... in d0 clr.w d1 | get group number move.b E_DATA1(a0),d1 | ... in d1 move.w d1,-(a7) | put group number on stack add.w d1,d1 | make d1 a word pointer move.w 0(a1,d1.W),d2 | get ins2grp[group] and.w #0xFF00,d2 | mask off GTAG1..GTAG8 or.w d0,d2 | OR in new instrument number move.w d2,0(a1,d1.W) | set ins2grp[group] jsr _setv2gi | setv2gi(group) tst.w (a7)+ | clean up stack bra exexit | done .page | exdyn -- execute dynamics event | ----- ---------------------- exdyn: clr.w d0 | get group number move.b E_DATA1(a0),d0 | ... in d0 add.w d0,d0 | ... as a word offset lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if not enabled clr.w d0 | get dynamics move.b E_DATA2(a0),d0 | ... in d0 clr.w d1 | get group number move.b E_DATA1(a0),d1 | ... in d1 move.w d0,-(a7) | setdyn(group, dyn) move.w d1,-(a7) | ... jsr _setdyn | ... adda.l #4,a7 | clean up stack bra exexit | done | exlocn -- execute location event | ------ ---------------------- exlocn: clr.w d0 | get group number move.b E_DATA1(a0),d0 | ... in d0 add.w d0,d0 | ... as a word offset lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if not enabled clr.w d0 | get location move.b E_DATA2(a0),d0 | ... in d0 clr.w d1 | get group number move.b E_DATA1(a0),d1 | ... in d1 move.w d0,-(a7) | setloc(group, loc) move.w d1,-(a7) | ... jsr _setloc | ... adda.l #4,a7 | clean up stack bra exexit | done .page | exanrs -- execute analog resolution event | ------ ------------------------------- exanrs: move.b E_DATA1(a0),d0 | get group number andi.w #0x000F,d0 | ... in d0 add.w d0,d0 | ... as a word offset lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if not enabled clr.w d1 | get variable / group numbers move.b E_DATA1(a0),d1 | ... add.w d1,d1 | convert to word index clr.w d0 | get resolution move.b E_DATA2(a0),d0 | ... in d0 lea _anrs,a1 | point at resolution table base move.w d0,0(a1,d1.W) | save resolution in table bra exexit | done | exanvl -- execute analog value event | ------ -------------------------- exanvl: move.b E_DATA1(a0),d0 | get group number andi.w #0x000F,d0 | ... in d0 add.w d0,d0 | ... as a word offset lea _grpstat,a1 | check grpstat[grp] tst.w 0(a1,d0.W) | ... beq exexit | done if not enabled move.w E_DN(a0),-(a7) | put value on stack clr.w d2 | get variable / group numbers move.b E_DATA1(a0),d2 | ... into d2 move.w d2,d1 | extract group number andi.w #0x000F,d1 | ... into d1 lsr.w #3,d2 | extract variable number andi.w #0x001E,d2 | ... as a word index in d2 lea _var2src,a1 | point at variable map move.w 0(a1,d2.W),-(a7) | put source number on stack move.w d1,-(a7) | put group number on stack jsr _setsv | setsv(group, src, val) adda.l #6,a7 | clean up stack bra exexit | done | exnext -- next score | ------ ---------- exnext: move.w #1,_nxtflag | set next score flag bra exexit | done .page | expnch -- execute punch in/out | ------ -------------------- expnch: tst.w _recsw | recording ? beq exexit | ignore if not tst.w E_DATA1(a0) | punch in ? bne expnch5 | jump if so | punch out lea _grpmode,a1 | setup for group modes move.w #11,d0 | ... expnch0: cmpi.w #2,(a1) | in record mode ? bne expnch1 | jump if not clr.w (a1) | set to play mode expnch1: addq.l #2,a1 | point at next entry dbra d0,expnch0 | loop through all groups lea _varmode,a1 | setup for variable modes move.w #5,d1 | set variable count expnch4: clr.w d0 | clear offset expnch2: cmpi.w #2,0(a1,d0.W) | in record mode ? bne expnch3 | jump if not clr.w 0(a1,d0.W) | set to play mode expnch3: addq.w #2,d0 | update offset cmpi.w #24,d0 | check for final group bne expnch2 | loop through all groups add.l #32,a1 | point at next variable dbra d1,expnch4 | loop through all variables bra exexit .page | punch in expnch5: lea _grpmode,a1 | setup for group modes move.w #11,d0 | ... expnch6: cmpi.w #1,(a1) | in standby mode ? bne expnch7 | jump if not move.w #2,(a1) | set to record mode expnch7: addq.l #2,a1 | point at next entry dbra d0,expnch6 | loop through all groups lea _varmode,a1 | setup for variable modes move.w #5,d1 | set variable count expnch10: clr.w d0 | clear offset expnch8: cmpi.w #1,0(a1,d0.W) | in standby mode ? bne expnch9 | jump if not move.w #2,0(a1,d0.W) | set to record mode expnch9: addq.w #2,d0 | update offset cmpi.w #24,d0 | check for final group bne expnch8 | loop through all groups adda.l #32,a1 | point at next variable dbra d1,expnch10 | loop through all variables bra exexit .page | sextab -- score execution dispatch table -- MUST match score.h definitions | ------ ---------------------------------------------------------------- sextab: dc.l exexit | 0 null dc.l exexit | 1 score begin dc.l exsbgn | 2 section begin dc.l exexit | 3 section end dc.l exinst | 4 instrument change dc.l exnbeg | 5 note begin dc.l exnend | 6 note end dc.l exstop | 7 stop dc.l exintp | 8 interpolate dc.l extmpo | 9 tempo dc.l extune | 10 tuning dc.l exexit | 11 group status dc.l exlocn | 12 location dc.l exdyn | 13 dynamics dc.l exanvl | 14 analog value dc.l exanrs | 15 analog resolution dc.l exasgn | 16 I/O assign dc.l extrns | 17 transposition dc.l exexit | 18 repeat dc.l expnch | 19 punch in/out dc.l exexit | 20 -unused- (polyphonic pressure) dc.l exexit | 21 score end dc.l exexit | 22 -unused- (channel pressure) dc.l exexit | 23 bar marker dc.l exnext | 24 next score .bss | Variable storage areas | ---------------------- | globals: | -------- _xevent: ds.l 1 | next event pointer .end