| ------------------------------------------------------------------------------ | 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