home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / fish / audio / utils / med_424 / programmers / modplayer / modplayer.a < prev    next >
Text File  |  1990-12-30  |  36KB  |  1,394 lines

  1. ;    MED V2.10 player routine by Teijo Kinnunen 1990
  2. ;    modplayer.a - the module player
  3. ;    use the A68k-assembler (or compatible) from Fish #186
  4. ac_ptr    EQU    $00
  5. ac_len    EQU    $04
  6. ac_per    EQU    $06
  7. ac_vol    EQU    $08
  8. T03SZ    EQU    24
  9. T415SZ    EQU    8
  10.  
  11. DIM    EQU    1    ;set to 0 if you don't need _DimOffPlayer
  12. MIDI    EQU    1    ;If your song(s) contain only Amiga-samples and
  13.             ;4 tracks, set MIDI to 0. This makes the player
  14.             ;much shorter.
  15.  
  16.     IFNE    MIDI
  17.         xdef    _ResetMIDI
  18.     ENDC
  19.  
  20.         section    "text",code
  21.         EVEN
  22.  
  23. _ChannelOff:    ;d0 = channel #
  24.     IFNE    MIDI
  25.         lea    trackdataptrs(pc),a1
  26.         lsl.b    #2,d0
  27.         adda.w    d0,a1
  28.         lsr.b    #2,d0
  29.         movea.l    (a1),a1
  30.         move.b    6(a1),d1    ;first: is it MIDI??
  31.         beq.s    notcomidi    ;not a midi note
  32.         clr.b    6(a1)
  33.         lea    noteondata(pc),a0
  34.         clr.l    (a0)        ; new midi msg
  35.         move.b    d1,1(a0)
  36.         move.b    3(a1),(a0)    ;prev midi channel
  37.         or.b    #$80,(a0)        ;note off
  38.         moveq.l    #3,d0
  39.         bra.w    _AddMIDIData
  40. notcomidi:
  41.     ENDC
  42.         cmp.b    #4,d0
  43.         bge.s    notamigatrk
  44.         moveq.l    #1,d1
  45.         lsl.w    d0,d1
  46.         move.w    d1,$dff096
  47. notamigatrk:    rts
  48. ; track # = d7, note vol = d0, song = a4
  49. GetRelVol:    clr.w    d1
  50.         clr.w    d2
  51.         move.b    786(a4),d1        ;master volume
  52.         lea    770(a4),a0
  53.         move.b    0(a0,d7.w),d2        :track volume
  54.         mulu    d2,d0
  55.         mulu    d1,d0    ;d0 = master v. * track v. * volume
  56.         lsr.l    #4,d0
  57.         lsr.w    #8,d0
  58.         rts
  59. _SoitaNuotti:    ;d0 = trk #, d1 = note #, d2 = vol, d3 = instr # a3 = addr of instr
  60.         movem.l    d3-d7,-(sp)    ;All right, let's start!!
  61.         move.w    d2,-(sp)
  62.         clr.l    d4
  63.         bset    d0,d4    ;d4 is mask for this channel
  64.         movea.l    24(a6),a0    ;Is this instrument in mem?
  65.         move.w    d3,d7
  66.         lsl.w    #2,d7            ;d7 = instr.num << 2
  67.         tst.l    0(a0,d7.w)
  68.     IFNE    MIDI
  69.         bne.s    inmem
  70.         tst.b    4(a3)            ;is MIDI channel set
  71.     ENDC
  72.         beq.w    retsn2            ; NO!!!
  73. inmem:        add.b    766(a4),d1    ;add play transpose
  74.         add.b    7(a3),d1    ;and instr. transpose
  75.         cmp.b    #4,d0
  76.         bge.s    nodmaoff    ;track # >= 4: not an Amiga channel
  77.         move.w    d4,$dff096        ;stop this channel (dmacon)
  78. nodmaoff:
  79.     IFNE    MIDI
  80.         move.b    6(a5),d6        ;get prev. midi note
  81.         beq.s    noprevmidi
  82.         clr.b    6(a5)
  83.         lea    noteondata(pc),a0
  84.         move.b    d6,1(a0)
  85.         move.b    3(a5),(a0)    ;prev midi channel
  86.         or.b    #$90,(a0)        ;note off
  87.         clr.b    2(a0)        ;clear volume
  88.         movem.l    d0-d1,-(sp)
  89.         moveq.l    #3,d0
  90.         bsr.w    _AddMIDIData
  91.         movem.l    (sp)+,d0-d1
  92. noprevmidi:    tst.b    4(a3)
  93.         bne.w    handleMIDInote
  94.     ENDC
  95. tlwtst0:        tst.b    d1
  96.         bgt.s    notenot2low
  97.         add.b    #12,d1    ;note was too low, octave up
  98.         bra.s    tlwtst0
  99. notenot2low:    cmp.b    #63,d1
  100.         ble.s    endpttest
  101.         sub.b    #12,d1    ;note was too high, octave down
  102. endpttest:    cmp.b    #4,d0        ;test track # again
  103.         bge.w    retsn2        ;no Amiga instruments in tracks > 3
  104.         or.w    d4,dmaonmsk
  105.         subq.b    #1,d1
  106.         movea.l    10(a5),a1    ;base of this channel's regs
  107.         movea.l    24(a6),a0        ;get the address of...
  108.         movea.l    0(a0,d7.w),a0        ;...this instrument
  109.         lsl.w    #1,d3
  110.         bsr.w    getinsdata
  111.         move.l    d0,ac_ptr(a1)        ;put it in ac_ptr
  112.         cmp.w    #1,d3
  113.         bhi.s    repeat
  114.         
  115.         move.l    chipzero(pc),14(a5)    ;pointer of zero word
  116.         move.w    #1,18(a5)        ;length: 1 word
  117.         lsr.l    #1,d1            ;shift length right
  118.         move.w    d1,ac_len(a1)        ;and put to custom chip
  119.         bra.s    retsn1
  120.  
  121. repeat:        tst.w    d2
  122.         beq.s    begin0        ;rep. start < 2
  123.         move.w    d2,ac_len(a1)    ;move repeat to hardware
  124.         bra.s    beginn0
  125. begin0:        move.w    d3,ac_len(a1)
  126. beginn0:        lsl.l    #1,d2        ;shift
  127.         add.l    d2,d0        ;d0 = starting address of repeat
  128.         move.l    d0,14(a5)    ;remember rep. start
  129.         move.w    d3,18(a5)    ;remember rep. length
  130.                 
  131. retsn1:        move.w    d5,ac_per(a1)    ;getinsdata puts period to d5
  132.         move.w    d5,8(a5)
  133.         move.w    (sp),ac_vol(a1)        ;volume
  134. retsn2:        addq.l    #2,sp    ;forget volume
  135.         movem.l    (sp)+,d3-d7
  136.         rts
  137.  
  138.     IFNE    MIDI
  139. handleMIDInote:
  140.         lea    noteondata(pc),a0
  141.         add.b    #23,d1        ;2 octaves higher and -1
  142.         bpl.s    mnot2low    ;note number not too low
  143.         add.b    #12,d1        ;it was too low, 1 octave up
  144.         bra.s    endmtst
  145. mnot2low:    tst.b    d1        ;is it too high then??
  146.         bpl.s    endmtst        ;no, not greater than 127
  147.         sub.b    #12,d1        ;1 octave down, if yes
  148. endmtst:        move.b    d1,1(a0)    ;MIDI msg note #
  149.         move.b    d1,6(a5)    ;save this note number
  150.         move.b    d2,d4        ;temporary save the volume
  151.         subq.b    #1,d2        ;if 64 => 63
  152.         bpl.s    nooops
  153.         clr.b    d2        ;oops, too low!!
  154. nooops:        lsl.b    #1,d2        ;volume 0 - 63 => 0 - 127
  155.         bclr    #7,d2        ;be sure that bit 7 is clear
  156.         move.b    d2,2(a0)    ;MIDI msg volume
  157.         clr.w    d1
  158.         move.b    4(a3),d1    ;get midi chan of this instrument
  159.         subq.b    #1,d1        ;from 1-16 to 0-15
  160.         move.b    d1,3(a5)    ;save to prev midi channel
  161.         move.b    #$90,(a0)    ;MIDI: Note on
  162.         or.b    d1,(a0)        ;MIDI msg Note on & channel
  163.         move.b    5(a3),d2    ;get preset #
  164.         beq.s    nochgpres    ;zero = no preset
  165.         lea    prevmidicpres(pc),a1
  166.         cmp.b    0(a1,d1.w),d2    ;is this previous preset ??
  167.         beq.s    nochgpres    ;yes...no need to change
  168.         move.b    d2,0(a1,d1.w)    ;save preset to prevmidicpres
  169.         subq.b    #1,d2        ;sub 1 to get 0 - 127
  170.         lea    preschgdata(pc),a0
  171.         move.b    #$c0,(a0)    ;command: $C
  172.         or.b    d1,(a0)        ;"or" midi channel
  173.         move.b    d2,1(a0)    ;push the number to second byte
  174.         moveq.l    #5,d0        ;Noteondata follows preschgdata
  175.         bra.s    preschanged    ;struct, so this is a bit faster
  176. nochgpres:    moveq.l    #3,d0
  177. preschanged:    bsr.w    _AddMIDIData
  178.         move.w    d3,d7
  179.         bra.w    retsn2
  180.     ENDC
  181.  
  182. waitamoment:    move.l    d0,-(sp)
  183.         moveq.l    #$79,d0
  184. wl0:        move.b    $dff007,d1
  185. wl1:        cmp.b    $dff007,d1
  186.         beq.s    wl1
  187.         dbf    d0,wl0
  188.         move.l    (sp)+,d0
  189.         rts
  190. pushnewvals:    movea.l    (a1)+,a5
  191.         lsr.b    #1,d0
  192.         bcc.s    rpnewv
  193.         movea.l    10(a5),a0
  194.         move.l    14(a5),ac_ptr(a0)
  195.         move.w    18(a5),ac_len(a0)
  196. rpnewv:        rts
  197. _StartDMA:        ;This small routine turns on audio DMA
  198.         move.w    dmaonmsk(pc),d0    ;dmaonmsk contains the mask of
  199.         beq.s    rpnewv    ;the channels that must be turned on
  200.         bset    #15,d0    ;DMAF_SETCLR: set these bits in dmacon
  201.         bsr.s    waitamoment
  202.         move.w    d0,$dff096    ;do that!!!
  203.         bsr.s    waitamoment
  204.         lea    trackdataptrs(pc),a1
  205.         bsr.s    pushnewvals
  206.         bsr.s    pushnewvals
  207.         bsr.s    pushnewvals
  208.         bra.s    pushnewvals
  209.  
  210. dmaonmsk:    dc.w    0
  211.     IFNE    MIDI
  212. prevmidicpres:    dc.l    0,0,0,0 ; 16 bytes
  213. prevmidipbend:    dc.w    $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
  214.         dc.w    $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
  215.     ENDC
  216. ;    Track-data structure for each track
  217. ;    0(ax) previous note    1(ax) previous instrument
  218. ;    2(ax) previous volume    3(ax) previous midi channel
  219. ;    4(ax) command        5(ax) command qualifier (data byte)
  220. ;    6(ax) prev MIDI note    7(ax) prev. portamento speed (on MIDI
  221. ;---and for Amiga tracks also..       tracks it's only pad byte)
  222. ;    8(ax) previous period(w) 10(ax) base address of audio registers(l)
  223. ;    14(ax) new sample ptr(l) 18(ax) new sample length(w)
  224. ;    20(ax) portamento target period(w)
  225. ;    22(ax) curr vibrato offs 23(ax) curr vibrato speed/size
  226. t03d:        dc.w    0,0,0,0,0
  227.         dc.l    $dff0a0,0
  228.         dc.w    0,0,0,0,0,0,0,0
  229.         dc.l    $dff0b0,0
  230.         dc.w    0,0,0,0,0,0,0,0
  231.         dc.l    $dff0c0,0
  232.         dc.w    0,0,0,0,0,0,0,0
  233.         dc.l    $dff0d0,0
  234.         dc.w    0,0,0        ;24 bytes * 4 tracks = 92 bytes
  235.     IFNE    MIDI
  236. t415d:        ds.b    8*12    ;8 bytes * 12 tracks = 96 bytes
  237.     ENDC
  238. trackdataptrs:    dc.l    t03d,t03d+T03SZ,t03d+2*T03SZ,t03d+3*T03SZ
  239.     IFNE    MIDI
  240.         dc.l    t415d,t415d+T415SZ,t415d+2*T415SZ,t415d+3*T415SZ
  241.         dc.l    t415d+4*T415SZ,t415d+5*T415SZ,t415d+6*T415SZ
  242.         dc.l    t415d+7*T415SZ,t415d+8*T415SZ,t415d+9*T415SZ
  243.         dc.l    t415d+10*T415SZ,t415d+11*T415SZ
  244.     ENDC
  245. nextblock:    dc.b    0
  246.         even
  247. numtracks:    dc.w    0
  248. _IntHandler:
  249.         movem.l    d2-d7/a2-a6,-(sp)
  250.         move.l    currentmodule(pc),d0
  251.         beq.s    stopplay
  252.         move.l    d0,a6     ;a6 contains ptr to this mod
  253.         tst.w    40(a6)    ;are we playing
  254.         bne.s    playing        ;yes, we are
  255. stopplay1:    move.b    #$05,50(a6)    ;counter ready for next note
  256. stopplay:    bclr    #0,$bfee01    ;stop the timer
  257.         move.w    #$000f,$dff096    ;stop audio DMA
  258.         movem.l    (sp)+,d2-d7/a2-a6    ;exit interrupt
  259.         rts
  260. playing:        clr.w    dmaonmsk
  261.         movea.l    8(a6),a4    ;ptr to MMD0song
  262.         add.b    #1,50(a6)
  263.         cmp.b    #6,50(a6)    ;if counter = 6: new note and fx
  264.         bne.w    nonewnote    ;if counter is not 6: just do fx
  265.     IFNE    DIM
  266.         move.w    dimval(pc),d0
  267.         beq.s    nodim
  268.         sub.w    dimstep(pc),d0
  269.         bgt.s    nostpdim
  270.         move.b    dimstart(pc),786(a4)
  271.         clr.w    40(a6)
  272.         clr.w    dimval
  273.         bra.s    stopplay1
  274. nostpdim:    move.w    d0,dimval
  275.         lsr.w    #7,d0
  276.         move.b    d0,786(a4)
  277.     ENDC
  278. ; --- new note!! first get address of current block
  279. nodim:        movea.l    16(a6),a0    ;a0 = address of 1st block's address
  280.         move.w    42(a6),d2
  281.         lsl.w    #2,d2        ;shift to longword index
  282.         movea.l    0(a0,d2.w),a2    ;get the pointer of the block
  283.         clr.w    d0
  284.         move.b    1(a2),d0    ;get number of lines in this block
  285. ; and advance song pointers
  286.         lea    48(a6),a3
  287.         addq.w    #1,(a3)        ;very important!!! advance line!!
  288.         cmp.w    (a3),d0         ;important too!!! advance block??
  289.         blt.s    chgblock    ;yes!!!
  290.         tst.b    nextblock    ;command F00 ??
  291.         beq.s    nochgblock    ;no, don't change block
  292. chgblock:    clr.w    (a3)        ;clear line number
  293.         cmp.w    #2,40(a6)    ;play block or play song
  294.         bne.s    nonewseq    ;play block only...
  295.         cmp.b    #$01,nextblock
  296.         beq.s    posjump
  297.         addq.w    #1,46(a6)    ;advance sequence number
  298. posjump:        move.w    506(a4),d0    ;get the highest seq number
  299.         move.w    46(a6),d1    ;and current seq number
  300.         cmp.w    d0,d1    ;is this the highest seq number
  301.         blt.s    nostartagain    ;no
  302.         clr.w    46(a6)    ;yes: play song again
  303.         clr.w    d1            ;...forever!!!
  304. nostartagain:    clr.w    d0
  305.         lea    508(a4),a1    ;offset of sequence table
  306.         move.b    0(a1,d1.w),d0    ;get number of the block
  307.         move.w    d0,42(a6)    ;and put it to block number var
  308.         clr.w    d1
  309.         move.b    505(a4),d1    ;get number of blocks
  310.         subq.w    #1,d1        ;# of blocks-1 = # of highest block
  311.         cmp.w    d1,d0        ;is this block number too big
  312.         blt.s    nolstblk    ;no
  313.         move.w    d1,42(a6)    ;yes..then play just the last block
  314.         move.w    d1,d0
  315. nolstblk:    lsl.w    #2,d0
  316.         movea.l    0(a0,d0.w),a2    ;get address of new block
  317. nonewseq:    clr.b    nextblock    ;clear this if F00 set it
  318. nochgblock:    move.w    (a3),44(a6)
  319. ; --- now start to play it
  320.         clr.b    50(a6)
  321.         clr.l    d7        ;number of track
  322.         move.b    (a2),numtracks+1    ;save # of tracks
  323.         addq.l    #2,a2    ;skip block header...
  324.         move.w    numtracks(pc),d3
  325.         mulu    #3,d3
  326.         move.w    44(a6),d2
  327.         mulu    d2,d3
  328.         adda.l    d3,a2        ;a2 = address of this line
  329.         pea    trackdataptrs(pc)
  330. trloop0:        clr.w    d5
  331.         move.l    (sp),a1
  332.         movea.l    (a1)+,a5    ;get address of this track's struct
  333.         move.l    a1,(sp)
  334. ; ---------------- get the note numbers
  335.         move.b    (a2)+,d5    ;get the number of this note
  336.         move.b    (a2)+,d6    ;and the 4 numbers containing fx
  337.         lsl.w    #8,d6
  338.         move.b    (a2)+,d6
  339.         move.b    d6,5(a5)    ;save the fx numbers
  340. ; ---------------- clear some instrument # flags
  341.         clr.b    d4        ;d4 is a flag: if set, instr. is
  342.         clr.b    d3        ;in range G-V. If clr, it's 1-F.
  343. ; ---------------- and set them, if needed
  344.         bclr    #7,d5        ;d3 is also a flag. If it's set,
  345.         sne.b    d4        ;the instr. is in range 10 - 1V
  346.         bclr    #6,d5
  347.         sne.b    d3
  348. ; ---------------- check if there's an instrument number
  349.         move.w    #$f000,d0
  350.         and.w    d6,d0        ;d0 now contains only the # of instr
  351.         bne.s    instnum        ;instrument number is not 0
  352.         tst.b    d4        ;maybe it's G (instr. #0, d4 set)
  353.         bne.s    instnum        ;yes, it really was G!!
  354.         tst.b    d3
  355.         beq.s    noinstnum    ;it wasn't 10 - 1V either..
  356. ; ---------------- if there was, GET IT!!
  357. instnum:        lsr.w    #8,d0        ;shift it right to get number 0-F
  358.         lsr.b    #4,d0
  359.         tst.b    d4
  360.         beq.s    nogtov2
  361.         add.w    #16,d0        ;if G-V, add 16 to the number
  362. nogtov2:        tst.b    d3
  363.         beq.s    no10to1v
  364.         add.w    #32,d0
  365. ; ---------------- finally, save the number
  366. no10to1v:    subq.b    #1,d0
  367.         move.b    d0,1(a5) ;remember instr. number!
  368. ; ---------------- get the pointer of data's of this sample in Song-struct
  369.         asl.w    #3,d0        ;get address of this sample's data
  370.         lea    0(a4,d0.w),a3
  371.         moveq.l    #0,d0
  372. ; ---------------- get volume and make it relative (0 - 100 %)
  373.         move.b    6(a3),d0
  374.         bsr.w    GetRelVol
  375.         move.b    d0,2(a5)    ;vol of this instr to prevvol
  376. ; ---------------- check the commands
  377. noinstnum:    move.w    d6,d0        ;effect again...
  378.         lsr.w    #8,d0
  379.         and.b    #$0f,d0        ;now check only the effect part
  380.         move.b    d0,4(a5)    ;save the effect number
  381.         beq.w    noeffect    ;no effect
  382. ; ---------------- there was a command (effect), but what??
  383.         cmp.b    #$0f,d0        ;yes effect...is it Tempo???
  384.         bne.s    not0f        ;not Tempo
  385. ; ---------------- it was tempo (F)
  386.         tst.b    d6        ;Tempo !!!
  387.         beq.s    fx0fchgblck    ;if effect qualifier (last 2 #'s)..
  388.         cmp.b    #$f0,d6        ;..is zero, go to next block
  389.         bhi.s    fx0fspecial    ;if it's F1-FF something special
  390. ; ---------------- just an ordinary "change tempo"-request
  391.         clr.l    d0        ;will happen!!!
  392.         move.b    d6,d0
  393.         bsr    _SetTempo    ;change The Tempo
  394.         bra.w    noeffect
  395. ; ---------------- no, it was FFx, something special will happen!!
  396. fx0fspecial:    cmp.b    #$f2,d6    ; | rest - play | SpecialFX#2: no note..yet
  397.         bne.s    isfxfe    ;not SpecFX2
  398. ; ---------------- it was FF2, nothing to do now
  399.         move.b    d5,(a5)    ;Yes!!! Save the note number
  400.         clr.w    d5    ; clear the number for awhile
  401.         bra.w    noeffect
  402. isfxfe:        cmp.b    #$fe,d6
  403.         bne.s    notcmdfe
  404. ; ---------------- it was FFE, stop playing
  405.         clr.w    40(a6)
  406.         bra.w    noeffect
  407. notcmdfe:    cmp.b    #$fd,d6 ;change period
  408.         bne.w    noeffect
  409. ; ---------------- FFD, change the period, don't replay the note
  410.         cmp.b    #$04,d7 ;no tracks 4 - 15, thank you!!
  411.         bge.w    noeffect
  412.         lea    periods(pc),a0
  413.         tst.b    d5
  414.         beq.w    noeffect ;hey, no note here!!
  415.         subq.b    #1,d5    ;sub 1 to make "real" note number
  416.         lsl.b    #1,d5
  417.         move.w    0(a0,d5.w),d0 ;get the period
  418.         movea.l    10(a5),a0
  419.         move.w    d0,ac_per(a0) ;push the period
  420.         clr.b    d5 ;and clear it so that it won't be replayed
  421.         bra.w    noeffect      ;done!!
  422. ; ---------------- F00, called Pattern Break in ST
  423. fx0fchgblck:    st.b    nextblock    ;next block????...YES!!!! (F00)
  424.         bra.w    noeffect
  425. ; ---------------- was not Fxx, then it's something else!!
  426. not0f:        cmp.b    #$0c,d0        ;new volume???
  427.         bne.s    not0c        ;NO!!!!!!!!!!!!!!!!!!!!!!
  428. ; ---------------- change volume
  429.         move.b    d6,d0
  430.         lsr.b    #4,d0        ;get number from left
  431.         mulu    #10,d0        ;number of tens
  432.         move.b    d6,d1        ;get again
  433.         and.b    #$0f,d1        ;this time don't get tens
  434.         add.b    d1,d0        ;add them
  435.         cmp.b    #64,d0
  436.         bls.s    novolov64
  437.         moveq.l    #64,d0
  438. novolov64:    bsr.w    GetRelVol
  439.         move.b    d0,2(a5)    ;and save it....
  440.         bra.s    noeffect
  441. not0c:        cmp.b    #$0b,d0
  442.         bne.s    not0b
  443. ; ---------------- cmd Bxx, "position jump", like Goto, yäk!!
  444.         move.w    d6,d0
  445.         and.w    #$00ff,d0
  446.         cmp.w    506(a4),d0    ;test the song length
  447.         bhi.s    noeffect
  448.         move.w    d0,46(a6)
  449.         move.b    #$01,nextblock
  450.         bra.s    noeffect
  451. ; ---------------- try portamento (3)
  452. not0b:        cmp.b    #$03,d0
  453.         bne.s    noeffect
  454.         subq.b    #1,d5
  455.         bmi.s    endtrkloop    ;it was 0, do nothing
  456.         cmp.b    #4,d7
  457.         bge.s    endtrkloop    ;hey, what are you trying to do??
  458.         lea    periods(pc),a0
  459.         add.b    766(a4),d5    ;play transpose
  460.         clr.w    d0
  461.         move.b    1(a5),d0
  462.         asl.w    #3,d0
  463.         add.b    7(a4,d0.w),d5    ;and instrument transpose
  464.         bmi.s    endtrkloop    ;again.. too low
  465.         lsl.w    #1,d5
  466.         move.w    0(a0,d5.w),20(a5) ;period of this note is the target
  467.         move.b    d6,7(a5)    ;remember size
  468.         clr.b    d5    ;don't play this one
  469. ; ---------------- everything is checked now: play or not to play??
  470. noeffect:    tst.b    d5    ;Now we'll check if we have to play a note
  471.         beq.s    endtrkloop    ;no.
  472. ; ---------------- we decided to play
  473.         move.b    d5,(a5)
  474.         move.w    d7,d0
  475.         move.w    d5,d1
  476.         clr.w    d3
  477.         move.b    1(a5),d3
  478.         move.w    d3,d2
  479.         asl.w    #3,d3        ;get address of this sample's data
  480.         lea    0(a4,d3.w),a3
  481.         move.w    d2,d3
  482.         clr.w    d2
  483.         move.b    2(a5),d2    ;get volume
  484.         bsr    _SoitaNuotti    ;play it!!!!!!!!!!!
  485. ; ---------------- end of loop: handle next track, or quit
  486. endtrkloop:    addq.b    #1,d7
  487.         cmp.w    numtracks(pc),d7
  488.         blt.w    trloop0
  489.         addq.l    #4,sp        ;trackdataptrs
  490. nonewnote:
  491. ;    *********************** This code produces the effects **
  492.         clr.l    d7    ;clear track count
  493.         lea    trackdataptrs(pc),a2
  494. trloop1:        movea.l    (a2)+,a5
  495.         clr.w    d5
  496.         clr.w    d4
  497.         move.b    4(a5),d6    ;get the fx number
  498.         move.b    5(a5),d4    ;and the last 2 #'s
  499.     IFNE    MIDI
  500.         tst.b    6(a5)        ;first: is it MIDI??
  501.         bne.w    midifx
  502.     ENDC
  503.         cmp.b    #4,d7
  504.         bge.w    endl    ;no non-MIDI effects in tracks 4 - 15
  505.         cmp.b    #1,d6        ;effect #1
  506.         bne.s    nofx01
  507. ;    **************************************** Effect 01 ******
  508.         btst    #5,767(a4)
  509.         beq.s    nost1
  510.         move.b    769(a4),d0
  511.         cmp.b    50(a6),d0
  512.         ble.w    endl
  513. nost1:        sub.w    d4,8(a5)    ;slide it up!!!
  514.         move.w    8(a5),d5
  515.         cmp.w    #113,d5        ;too high???
  516.         bge    newvals
  517.         move.w    #113,d5        ;yes, too high!!!
  518.         move.w    d5,8(a5)
  519.         bra    newvals
  520. ;    *********************************************************
  521. nofx01:        cmp.b    #2,d6
  522.         bne.s    nofx02
  523. ;    **************************************** Effect 02 ******
  524.         btst    #5,767(a4)
  525.         beq.s    nost2
  526.         move.b    769(a4),d0
  527.         cmp.b    50(a6),d0
  528.         ble.w    endl
  529. nost2:        add.w    d4,8(a5)    ;slide it down!!!!!!!!!
  530.         move.w    8(a5),d5
  531.         cmp.w    #856,d5        ;too low??
  532.         ble    newvals
  533.         move.w    #856,d5        ;too low.
  534.         move.w    d5,8(a5)
  535.         bra    newvals
  536. ;    *********************************************************
  537. nofx02:        tst.b    d6
  538.         bne.s    nofx00
  539. ;    **************************************** Effect 00 ******
  540.         tst.b    d4    ;both fxqualifiers are 0s: no arpeggio!!
  541.         beq.w    endl
  542.         move.b    (a5),d1
  543.         bsr.w    DoArpeggio
  544.         subq.b    #1,d4        ;-1 to make it 0 - 127
  545.         add.b    766(a4),d4    ;add play transpose
  546.         clr.w    d0
  547.         move.b    1(a5),d0    ;prev. instr #
  548.         asl.w    #3,d0        ;get address of this sample's data
  549.         add.b    7(a4,d0.w),d4    ;add instrument transpose
  550.         lsl.b    #1,d4        ;shift to make index for UWORD
  551.         lea    periods(pc),a1
  552.         move.w    0(a1,d4.w),d5
  553.         bra.w    newvals
  554. ;    *********************************************************
  555. nofx00:        cmp.b    #$0d,d6
  556.         beq.s    fx0d
  557.         cmp.b    #$0a,d6
  558.         bne.s    nofx0d
  559. ;    **************************************** Effect 0D ******
  560. fx0d:        btst    #5,767(a4)
  561.         beq.s    nostD
  562.         move.b    769(a4),d0
  563.         cmp.b    50(a6),d0
  564.         ble.w    endl
  565. nostD:        move.b    d4,d1
  566.         move.b    2(a5),d0    ;move previous vol to d0
  567.         and.b    #$f0,d1
  568.         bne.s    crescendo
  569.         sub.b    d4,d0    ;sub from prev. vol
  570.         bpl.s    novolund0
  571.         clr.b    d0    ;volumes under zero not accepted!!!
  572. novolund0:    move.b    d0,2(a5)    ;put new vol back
  573.         bra.w    newvals
  574. crescendo:    lsr.b    #4,d1
  575.         add.b    d1,d0
  576.         cmp.b    #64,d0
  577.         ble.s    novolover64
  578.         moveq.l    #64,d0
  579. novolover64:    move.b    d0,2(a5)
  580.         bra.w    newvals
  581. ;    *********************************************************
  582. nofx0d:        cmp.b    #5,d6
  583.         bne.s    nofx05
  584. ;    **************************************** Effect 05 ******
  585.         move.w    8(a5),d5 ;this is very simple: get the old period
  586.         cmp.b    #3,50(a6)    ;and..
  587.         bge.w    newvals        ;if counter < 3
  588.         sub.w    d4,d5    ;subtract effect qualifier
  589.         bra.w    newvals
  590. ;    *********************************************************
  591. nofx05:        cmp.b    #$03,d6
  592.         bne.s    nofx03
  593. ;    **************************************** Effect 03 ******
  594.         btst    #5,767(a4)
  595.         beq.s    nost3
  596.         move.b    769(a4),d0
  597.         cmp.b    50(a6),d0
  598.         ble.w    endl
  599. nost3:        move.w    20(a5),d0    ;d0 = target period
  600.         beq.w    newvals    ;no target period specified
  601.         move.w    8(a5),d1    ;d1 = curr. period
  602.         move.b    7(a5),d4    ;get prev. speed
  603.         cmp.w    d0,d1
  604.         bhi.s    subper    ;curr. period > target period
  605.         add.w    d4,d1    ;add the period
  606.         cmp.w    d0,d1
  607.         bge.s    targreached
  608.         bra.s    targnreach
  609. subper:        sub.w    d4,d1    ;subtract
  610.         cmp.w    d0,d1
  611.         bgt.s    targnreach
  612. targreached:    move.w    20(a5),d1 ;eventually push target period
  613.         clr.w    20(a5) ;now we can forget everything
  614. targnreach:    move.w    d1,8(a5)
  615.         move.w    d1,d5
  616.         bra.w    newvals
  617. ;    *********************************************************
  618. nofx03:        cmp.b    #$0c,d6
  619.         bne.s    nofx0c
  620.         tst.b    50(a6)
  621.         bne.w    endl
  622.         bra.w    newvals
  623. ;    *********************************************************
  624. nofx0c:        cmp.b    #$04,d6
  625.         bne.s    nofx04
  626. ;    **************************************** Effect 04 ******
  627.         tst.b    d4
  628.         beq.s    nonvib
  629.         move.b    d4,23(a5)
  630. nonvib:        move.b    22(a5),d0
  631.         lsr.b    #2,d0
  632.         and.w    #$1f,d0
  633.         clr.w    d1
  634.         move.b    sinetable(pc,d0.w),d1
  635.         move.b    23(a5),d0
  636.         and.w    #$000f,d0
  637.         mulu    d0,d1
  638.         lsr.w    #6,d1
  639.         move.w    8(a5),d5
  640.         tst.b    22(a5)
  641.         bmi.s    subvib
  642.         add.w    d1,d5
  643.         bra.s    nsubvib
  644. subvib:        sub.w    d1,d5
  645. nsubvib:        move.b    23(a5),d0
  646.         lsr.b    #2,d0
  647.         and.b    #$3c,d0
  648.         add.b    d0,22(a5)
  649.         bra.w    newvals
  650. sinetable:    dc.b $00,$18,$31,$4a,$61,$78,$8d,$a1,$b4,$c5,$d4,$e0,$eb,$f4,$fa,$fd
  651.         dc.b $ff,$fd,$fa,$f4,$eb,$e0,$d4,$c5,$b4,$a1,$8d,$78,$61,$4a,$31,$18
  652. ;    *********************************************************
  653. nofx04:        cmp.b    #$0f,d6
  654.         bne.w    nofx0f
  655. ;    **************************************** Effect 0F ******
  656. fx0f:        cmp.b    #$ff,d4
  657.         bne.s    no0fff
  658.         move.w    d7,d0
  659.         bsr.w    _ChannelOff
  660.         bra.w    endl
  661. no0fff:        cmp.b    #$f1,d4
  662.         bne.s    no0ff1
  663.         cmp.b    #3,50(a6)
  664.         bne.w    endl
  665.         bra.s    playfxnote
  666. no0ff1:        cmp.b    #$f2,d4
  667.         bne.s    no0ff2
  668.         cmp.b    #3,50(a6)
  669.         bne.w    endl
  670.         bra.s    playfxnote
  671. no0ff2:        cmp.b    #$f3,d4
  672.         bne.s    no0ff3
  673.         move.b    50(a6),d0
  674.         and.b    #2+4,d0        ;is 2 or 4
  675.         beq.s    endl
  676. playfxnote:    clr.w    d0
  677.         move.b    1(a5),d0
  678.         asl.w    #3,d0        ;get address of this sample's data
  679.         lea    0(a4,d0.w),a3    ;a3 contains now address of it
  680.         move.w    d7,d0        ;track # to d0...
  681.         clr.w    d1
  682.         move.b    (a5),d1        ;get note # of previous note
  683.         clr.w    d2
  684.         move.b    2(a5),d2    ;get previous volume
  685.         clr.w    d3
  686.         move.b    1(a5),d3    ;and prev. sample #
  687.         bsr    _SoitaNuotti
  688.         bra.s    endl
  689. no0ff3:        cmp.b    #$f8,d4
  690.         beq.s    filteroff
  691.         cmp.b    #$f9,d4
  692.         bne.s    endl
  693.         bclr    #1,$bfe001
  694.         bra.s    endl
  695. filteroff:    bset    #1,$bfe001
  696.         bra.s    endl
  697. ;    *********************************************************
  698. nofx0f:        cmp.b    #$0c,d6
  699.         bne.s    endl
  700. newvals:        tst.w    d5    ;now: do the effects!!!
  701.         bne.s    nooldper
  702.         move.w    8(a5),d5 ;no new period specified: get the old
  703. nooldper:    movea.l    10(a5),a1    ;get channel address
  704.         move.w    d5,ac_per(a1)    ;push period
  705.         clr.w    d5
  706.     IFNE    DIM
  707.         tst.w    dimval
  708.         bne.s    endl
  709.     ENDC
  710.         move.b    2(a5),d5    ;get volume
  711.         move.w    d5,ac_vol(a1)    ;and push it
  712. endl:        addq.b    #1,d7    ;increment channel number
  713.         cmp.w    numtracks(pc),d7    ;all channels done???
  714.         blt.w    trloop1    ;not yet!!!
  715.  
  716.         bsr    _StartDMA    ;turn on DMA
  717. exitint:        movem.l    (sp)+,d2-d7/a2-a6
  718.         rts
  719. _SetTempo:    tst.b    allok
  720.         beq.s    exstempo
  721.         movea.l    currentmodule(pc),a0
  722.         movea.l    8(a0),a0
  723.         move.b    d0,765(a0)
  724.         cmp.b    #10,d0    ;If tempo <= 10, use SoundTracker tempo
  725.         bhi.s    calctempo
  726.         subq.b    #1,d0
  727.         move.b    d0,769(a0)
  728.         lsl.w    #1,d0
  729.         move.w    sttempo+2(pc,d0.w),d1
  730.         bra.s    pushtempo
  731. calctempo:    move.l    #470000,d1
  732.         divu    d0,d1
  733. pushtempo:    move.b    d1,$bfe401    ;and set the CIA timer
  734.         lsr.w    #8,d1
  735.         move.b    d1,$bfe501
  736. exstempo:    rts    ; vv-- These values are the SoundTracker tempos (approx.)
  737. sttempo:    dc.w    $0f00,2417,4833,7250,9666,12083,14500,16916,19332,21436,24163
  738.  
  739.     IFNE    MIDI
  740. midifx:        cmp.b    #1,d6
  741.         bne.s    nomidi01fx
  742.         lea    prevmidipbend(pc),a0
  743.         clr.w    d1
  744.         move.b    3(a5),d1    ;get previous midi channel
  745.         lsl.w    #1,d1        ;UWORD index
  746.         tst.b    d4        ;x100??
  747.         beq.s    resetpbend
  748.         move.w    0(a0,d1.w),d0    ;get previous pitch bend
  749.         lsl.w    #3,d4        ;multiply bend value by 8
  750.         add.w    d4,d0
  751.         cmp.w    #$3fff,d0
  752.         bls.s    bendpitch
  753.         move.w    #$3fff,d0
  754. bendpitch:    move.w    d0,0(a0,d1.w)    ;save current pitch bend
  755.         lsr.b    #1,d1        ;back to UBYTE
  756.         or.b    #$e0,d1
  757.         lea    noteondata(pc),a0
  758.         move.b    d1,(a0)        ;midi command & channel
  759.         move.b    d0,1(a0)    ;lower value
  760.         and.b    #$7f,1(a0)    ;clear bit 7
  761.         lsr.w    #7,d0
  762.         and.b    #$7f,d0        ;clr bit 7
  763.         move.b    d0,2(a0)    ;higher 7 bits
  764.         moveq.l    #3,d0
  765.         bsr.w    _AddMIDIData
  766.         bra.w    endl
  767. nomidi01fx:    cmp.b    #2,d6
  768.         bne.s    nomidi02fx
  769.         lea    prevmidipbend(pc),a0
  770.         clr.w    d1
  771.         move.b    3(a5),d1
  772.         lsl.w    #1,d1
  773.         tst.b    d4
  774.         beq.s    resetpbend    ;x200??
  775.         move.w    0(a0,d1.w),d0
  776.         lsl.w    #3,d4
  777.         sub.w    d4,d0
  778.         bpl.s    bendpitch    ;not under 0
  779.         clr.w    d0
  780.         bra.s    bendpitch
  781. resetpbend:    tst.b    50(a6)
  782.         bne.w    endl
  783.         move.w    #$2000,d0
  784.         bra.s    bendpitch
  785. nomidi02fx:    cmp.b    #$04,d6
  786.         bne.s    nomidi04fx
  787.         moveq    #$01,d0
  788.         bra.s    pushctrldata
  789. nomidi04fx:    cmp.b    #$0e,d6        ;with MIDI, this is "pan", when
  790.         bne.s    nomidi0efx    ;values are 0 - $7f
  791.         moveq    #$0a,d0
  792. pushctrldata:    tst.b    50(a6)        ;do it only once in a note
  793.         bne.w    endl        ;(when counter = 0)
  794.         lea    noteondata(pc),a0 ;push "control change" data,
  795.         move.b    3(a5),(a0)      ;d0 = 1. databyte, d4 = 2. db
  796.         or.b    #$b0,(a0)
  797.         move.b    d0,1(a0)
  798.         move.b    d4,2(a0)
  799.         bmi.w    endl    ;0 - $7f!!
  800.         moveq.l    #3,d0
  801.         bsr.w    _AddMIDIData
  802.         bra.w    endl
  803. nomidi0efx:    cmp.b    #$0f,d6
  804.         bne.w    endl
  805.         cmp.b    #$fa,d4        ;hold pedal ON
  806.         bne.s    nomffa
  807.         moveq    #$40,d0
  808.         moveq    #$7f,d4
  809.         bra.s    pushctrldata
  810. nomffa:        cmp.b    #$fb,d4        ;hold pedal OFF
  811.         bne.s    nomffb
  812.         moveq    #$40,d0
  813.         moveq    #$00,d4
  814.         bra.s    pushctrldata
  815. nomffb:        bra.w    fx0f
  816.     ENDC
  817.  
  818. DoArpeggio:    ; begin note in d1, note num returned in d4
  819.         move.b    50(a6),d0
  820.         tst.b    d0
  821.         beq.s    arpg03
  822.         cmp.b    #3,d0
  823.         bne.s    arpgn03
  824. arpg03:        and.b    #$0f,d4        ;counter = 0 or 3: get last number
  825.         add.b    d1,d4        ;add it to note number
  826.         rts
  827. arpgn03:        cmp.b    #1,d0
  828.         beq.s    arpg14
  829.         cmp.b    #4,d0
  830.         bne.s    arpgn14
  831. arpg14:        lsr.b    #4,d4    ;counter = 1 or 4: get the first number
  832.         add.b    d1,d4    ;add to prev. note
  833.         rts
  834. arpgn14:        move.b    d1,d4    ;2 or 5: the previous note
  835. cmdrts:        rts
  836.  
  837.     IFNE    MIDI
  838. _ResetMIDI:    tst.b    allok
  839.         beq.s    cmdrts    ;the nearest "rts"
  840.         movem.l    d2/a2,-(sp)
  841.         lea    prevmidicpres(pc),a0
  842.         clr.l    (a0)+    ;force presets to be set again
  843.         clr.l    (a0)+    ;(clear prev. preset numbers)
  844.         clr.l    (a0)+
  845.         clr.l    (a0)+
  846.         clr.b    lastcmdbyte
  847.         lea    midiresd(pc),a2
  848.         move.b    #$e0,(a2)    ;reset pitchbenders & mod. wheel
  849.         move.b    #$b0,3(a2)
  850.         moveq.l    #15,d2
  851. respbendl:    movea.l    a2,a0
  852.         moveq.l    #6,d0
  853.         bsr.w    _AddMIDIData
  854.         addq.b    #1,(a2)
  855.         addq.b    #1,3(a2)
  856.         dbf    d2,respbendl
  857.         lea    prevmidipbend(pc),a2
  858.         moveq.l    #15,d2
  859. resprevpbends:    move.w    #$2000,(a2)+
  860.         dbf    d2,resprevpbends
  861.         movem.l    (sp)+,d2/a2
  862.         rts
  863. midiresd:    dc.b    $e0,$00,$40,$b0,$01,$00
  864.     ENDC
  865.  
  866. getinsdata:    clr.l    d2
  867.         move.w    4(a0),d0    ;Soitin-struct in a0, instr#<<1: d3
  868.         bne.s    iff5or3oct    ;note # in d1 (0 - ...)
  869.         move.l    a0,d0
  870.         lea    periods(pc),a0
  871.         lsl.b    #1,d1
  872.         move.w    0(a0,d1.w),d5 ;put period to d5
  873.         move.l    d0,a0
  874.         addq.l    #6,d0        ;Skip structure
  875.         move.l    (a0),d1        ;length
  876.         move.w    (a3),d2
  877.         move.w    2(a3),d3
  878.         rts
  879. iff5or3oct:    movem.l    a1/d6-d7,-(sp)
  880.         clr.l    d7
  881.         move.w    d1,d7
  882.         divu    #12,d7    ;octave #
  883.         move.l    d7,d5
  884.         swap    d5    ;note number in this oct (0-11) is in d5
  885.         move.l    (a0),d1
  886.         cmp.b    #2,d0
  887.         bne.s    no3oct
  888.         addq.l    #6,d7
  889.         divu    #7,d1    ;get length of the 1st octave
  890.         bra.s    no5oct
  891. no3oct:        divu    #31,d1    ;get length of the 1st octave (5 octaves)
  892. no5oct:        move.l    d1,d0        ;d0 and d1 = length of the 1st oct
  893.         move.w    (a3),d2
  894.         move.w    2(a3),d3
  895.         clr.w    d6
  896.         move.b    shiftcnt(pc,d7.w),d6
  897.         lsl.w    d6,d2
  898.         lsl.w    d6,d3
  899.         lsl.w    d6,d1
  900.         move.b    mullencnt(pc,d7.w),d6
  901.         mulu    d6,d0        ;offset of this oct from 1st oct
  902.         add.l    a0,d0        ;add base address to offset
  903.         addq.l    #6,d0        ;skip structure
  904.         lea    periods(pc),a1
  905.         add.b    octstart(pc,d7.w),d5
  906.         lsl.b    #1,d5
  907.         move.w    0(a1,d5.w),d5
  908.         movem.l    (sp)+,a1/d6-d7
  909.         rts    ;returns period in d5
  910. shiftcnt:    dc.b    4,3,2,1,1,0,2,2,1,1,0,0
  911. mullencnt:    dc.b    15,7,3,1,1,0,3,3,1,1,0,0
  912. octstart:    dc.b    12,12,12,12,24,24,0,12,12,24,24,36
  913.  
  914. _AudioInit:    movem.l    a6/d2,-(sp)
  915.         clr.l    d2
  916.         movea.l    4,a6
  917. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ alloc signal bit
  918.         addq.l    #1,d2
  919.         st.b    d0    ; -1
  920.         jsr    -$14a(a6)    ;AllocSignal()
  921.         tst.b    d0
  922.         bmi.w    initerr
  923.         move.b    d0,sigbitnum
  924. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ prepare IORequest
  925.         lea    allocport(pc),a1
  926.         move.b    d0,15(a1)    ;set mp_SigBit
  927.         move.l    a1,-(sp)
  928.         suba.l    a1,a1
  929.         jsr    -$126(a6)    ;FindTask(0)
  930.         move.l    (sp)+,a1
  931.         move.l    d0,16(a1)    ;set mp_SigTask
  932.         lea    reqlist(pc),a0
  933.         move.l    a0,(a0)        ;NEWLIST begins...
  934.         addq.l    #4,(a0)
  935.         clr.l    4(a0)
  936.         move.l    a0,8(a0)    ;NEWLIST ends...
  937. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ open audio.device
  938.         addq.l    #1,d2
  939.         lea    allocreq(pc),a1
  940.         lea    audiodevname(pc),a0
  941.         clr.l    d0
  942.         clr.l    d1
  943.         movea.l    4,a6
  944.         jsr    -$1bc(a6)    ;OpenDevice()
  945.         tst.l    d0
  946.         bne.s    initerr
  947.         st.b    audiodevopen
  948. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ open ciaa.resource
  949.         addq.l    #1,d2
  950.         clr.l    d0
  951.         lea    ciaaname(pc),a1
  952.         jsr    -$1f2(a6)    ;OpenResource()
  953.         tst.l    d0
  954.         beq.s    initerr
  955.         move.l    d0,_ciaaresource
  956. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ attach interrupt
  957.         addq.l    #1,d2
  958.         move.l    d0,a6
  959.         lea    timerinterrupt(pc),a1
  960.         clr.l    d0    ;Bit number 0: Timer A
  961.         jsr    -$6(a6)    ;AddICRVector
  962.         tst.l    d0
  963.         bne.s    initerr
  964.         and.b    #%10000000,$bfee01
  965.         st.b    timeropen
  966.         clr.l    d0
  967. initret:        movem.l    (sp)+,a6/d2
  968.         rts
  969. initerr:        move.l    d2,d0
  970.         bra.s    initret
  971.  
  972. _AudioRem:    move.l    a6,-(sp)
  973.         tst.b    timeropen
  974.         beq.s    rem1
  975. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ remove interrupt
  976.         move.l    _ciaaresource(pc),a6
  977.         lea    timerinterrupt(pc),a1
  978.         clr.l    d0    ;Bit number 0: Timer A
  979.         jsr    -$c(a6)        ;RemICRVector
  980. ;There is no CloseResource(). I'm not sure if I should use CloseLibrary()??
  981.         clr.b    timeropen
  982. rem1:        movea.l    4,a6
  983.         tst.b    audiodevopen
  984.         beq.s    rem2
  985.         move.w    #$000f,$dff096    ;stop audio DMA
  986. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ close audio.device
  987.         lea    allocreq(pc),a1
  988.         jsr    -$1c2(a6)    ;CloseDevice()
  989.         clr.b    audiodevopen
  990. rem2:        clr.l    d0
  991.         move.b    sigbitnum(pc),d0
  992.         bmi.s    rem3
  993. ;    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ free signal bit
  994.         jsr    -$150(a6)    ;FreeSignal()
  995.         move.b    #-1,sigbitnum
  996. rem3:        move.l    (sp)+,a6
  997.         rts
  998.  
  999.     IFNE    MIDI
  1000.  
  1001. _GetSerial:    move.l    a6,-(sp)    ;Get serial port for MIDI
  1002.         bsr.s    GetSer2
  1003.         tst.l    d0        ;got the port??
  1004.         beq.s    rgser        ;yes
  1005.         movea.l    4,a6        ;no..try to flush serial.device:
  1006.         jsr    -$84(a6)        ;Forbid
  1007.         lea    $15e(a6),a0        ;ExecBase->DeviceList
  1008.         lea    serdev(pc),a1        ;"serial.device"
  1009.         jsr    -$114(a6)        ;FindName
  1010.         tst.l    d0
  1011.         beq.s    serdnotf        ;no serial.device!!
  1012.         move.l    d0,a1
  1013.         jsr    -$1b6(a6)        ;RemDevice
  1014. serdnotf:    jsr    -$8a(a6)        ;and Permit
  1015.         bsr.s    GetSer2        ;now try it again...
  1016. rgser:        move.l    (sp)+,a6
  1017.         rts
  1018.  
  1019. GetSer2:        move.l    4,a6
  1020.         clr.l    d0
  1021.         lea    miscresname(pc),a1
  1022.         jsr    -$1f2(a6)    ;OpenResource()
  1023.         move.l    d0,miscresbase
  1024.         tst.l    d0
  1025.         beq.s    gserror
  1026.         move.l    d0,a6
  1027.         lea    medname(pc),a1
  1028.         clr.l    d0        ;serial port
  1029.         jsr    -$6(a6)        ;AllocMiscResource()
  1030.         tst.l    d0
  1031.         bne.s    gserror
  1032.         st.b    serportalloc
  1033.         clr.w    intrson
  1034.         move.w    $dff01c,d0
  1035.         btst    #0,d0
  1036.         sne.b    intrson
  1037.         moveq.l    #0,d0        ;TBE
  1038.         lea    serinterrupt(pc),a1
  1039.         move.l    4,a6
  1040.         jsr    -$a2(a6)    ;SetIntVector()
  1041.         move.l    d0,prevtbe
  1042.         move.w    #$8001,$dff09a    ;TBE on!!
  1043.         move.w    #114,$dff032    ;set baud rate (SERPER)
  1044.         moveq    #0,d0
  1045. retgs:        rts
  1046. gserror:        st    d0
  1047.         rts
  1048.  
  1049. intrson:        dc.b    0,0
  1050.  
  1051. _FreeSerial:    move.l    a6,-(sp)
  1052.         tst.l    miscresbase
  1053.         beq.s    retfs
  1054.         tst.b    serportalloc
  1055.         beq.s    retfs
  1056.         move.w    #$0001,$dff09a    ;disable TBE
  1057.         movea.l    prevtbe(pc),a1
  1058.         moveq.l    #0,d0
  1059.         movea.l    4,a6
  1060.         jsr    -$a2(a6)    ;SetIntVector()
  1061.         clr.b    serportalloc
  1062.         tst.b    intrson
  1063.         beq.s    notbebackon
  1064.         move.w    #$8001,$dff09a
  1065. notbebackon:    movea.l    miscresbase(pc),a6
  1066.         clr.l    d0        ;serial port
  1067.         jsr    -$c(a6)        ;FreeMiscResource()
  1068.         clr.b    lastcmdbyte
  1069. retfs:        move.l    (sp)+,a6
  1070.         rts
  1071.  
  1072. prevtbe:        dc.l    0
  1073.         
  1074. SerIntHandler:    move.w    #$4000,$9a(a0)    ;disable...
  1075.         addq.b    #1,$126(a6)
  1076.         move.w    #1,$9c(a0)    ;clear intreq bit
  1077.         move.b    bytesinbuff(pc),d0
  1078.         beq.s    exsih        ;buffer empty
  1079.         movea.l    4(a1),a5    ;get buffer read pointer
  1080.         move.w    #$100,d1    ;Stop bit
  1081.         move.b    (a5),d1        ;get byte
  1082.         move.w    d1,$30(a0)    ;and push it out!! (SERDAT)
  1083.         addq.l    #1,a5        ;add 1
  1084.         cmpa.l    a1,a5        ;shall we reset ptr??
  1085.         bne.s    norrbuffptr    ;not yet..
  1086.         lea    sendbuffer(pc),a5
  1087. norrbuffptr:    subq.b    #1,d0        ;one less bytes in buffer
  1088.         move.b    d0,bytesinbuff    ;remember it
  1089.         move.l    a5,4(a1)    ;push new read pointer back
  1090. exsih:        subq.b    #1,$126(a6)
  1091.         bge.s    exsih0
  1092.         move.w    #$c000,$9a(a0)
  1093. exsih0:        rts
  1094.  
  1095. _AddMIDIData:    tst.b    serportalloc
  1096.         beq.s    retamd
  1097.         movem.l    a2/a6,-(sp)
  1098.         movea.l    4,a6
  1099.         move.w    #$4000,$dff09a    ;Disable interrupts
  1100.         addq.b    #1,$126(a6)    ;ExecBase->IDNestCnt
  1101.         move.b    bytesinbuff(pc),d1
  1102.         bne.s    noTBEreq
  1103.         move.w    #$8001,$dff09c    ;request TBE
  1104. noTBEreq:    lea    buffptr(pc),a2    ;end of buffer (ptr)
  1105.         movea.l    (a2),a1        ;buffer pointer
  1106. adddataloop:    move.b    (a0)+,d1    ;get byte
  1107.         bpl.s    norscheck    ;this isn't a status byte
  1108.         cmp.b    #$ef,d1        ;forget system messages
  1109.         bhi.s    norscheck
  1110.         cmp.b    lastcmdbyte(pc),d1 ;same as previos status byte??
  1111.         beq.s    samesb        ;yes, skip
  1112.         move.b    d1,lastcmdbyte    ;no, don't skip but remember!!
  1113. norscheck:    move.b    d1,(a1)+    ;push it to midi send buffer
  1114.         addq.b    #1,bytesinbuff
  1115. samesb:        cmpa.l    a2,a1    ;end of buffer??
  1116.         bne.s    noresbuffptr    ;no, no!!
  1117.         lea    sendbuffer(pc),a1 ;better reset it to avoid trashing
  1118. noresbuffptr:    subq.b    #1,d0
  1119.         bne.s    adddataloop
  1120.         move.l    a1,(a2)        ;push new buffer ptr back
  1121. overflow:    subq.b    #1,$126(a6)
  1122.         bge.s    retamd1
  1123.         move.w    #$c000,$dff09a    ;enable interrupts again
  1124. retamd1:        movem.l    (sp)+,a2/a6
  1125. retamd:        rts
  1126.     ENDC
  1127.  
  1128.         xdef    _InitPlayer
  1129.         xdef    _PlayModule
  1130.         xdef    _ContModule
  1131.         xdef    _StopPlayer
  1132.         xdef    _RemPlayer
  1133.     IFNE    DIM
  1134.         xdef    _DimOffPlayer
  1135.     ENDC
  1136.         xdef    _SetTempo
  1137.  
  1138. _InitPlayer:    move.l    a6,-(sp)
  1139.         lea    filterpos(pc),a0
  1140.         clr.b    (a0)
  1141.         btst    #1,$bfe001
  1142.         sne.b    (a0)
  1143.     IFNE    MIDI
  1144.         bsr.w    _GetSerial
  1145.         tst.l    d0
  1146.         bne.s    iperror
  1147.     ENDC
  1148.         bsr.w    _AudioInit
  1149.         tst.l    d0
  1150.         bne.s    iperror
  1151.         move.l    4,a6
  1152.         moveq    #8,d0
  1153.         move.l    #$10002,d1
  1154.         jsr    -$c6(a6)
  1155.         tst.l    d0
  1156.         beq.s    iperror
  1157.         move.l    d0,chipzero
  1158.     IFNE    MIDI
  1159.         moveq.l    #5,d0    ;INTB_VERTB
  1160.         lea    vbinterrupt(pc),a1
  1161.         jsr    -$a8(a6)    ;AddIntServer()
  1162.         move.b    #1,intserv
  1163.     ENDC
  1164.         st.b    allok
  1165.         moveq.l    #6,d0
  1166.         bsr.w    _SetTempo    ;default tempo
  1167.         clr.l    d0    ;Init OK
  1168. xip:        move.l    (sp)+,a6
  1169.         rts
  1170.  
  1171. iperror:        bsr.s    _RemPlayer    ;free all stuff
  1172.         moveq    #-1,d0
  1173.         bra.s    xip
  1174.  
  1175. _RemPlayer:    move.l    a6,-(sp)
  1176.         move.l    4,a6
  1177.         lea    currentmodule(pc),a0
  1178.         tst.l    (a0)
  1179.         beq.s    nostpplr
  1180.         movea.l    (a0),a0
  1181.         tst.w    40(a0)
  1182.         beq.s    nostpplr
  1183.         bsr.w    _StopPlayer
  1184. nostpplr:    lea    allok(pc),a0
  1185.         clr.b    (a0)+
  1186.         bclr    #1,$bfe001    ;filter back on
  1187.         move.b    (a0),d0        ;prev. filter??
  1188.         and.b    #2,d0        ;only leave the filter bit
  1189.         or.b    d0,$bfe001
  1190.         lea    chipzero(pc),a0
  1191.         movea.l    (a0),a1
  1192.         clr.l    (a0)
  1193.         move.l    a1,d0
  1194.         beq.s    nofreecz
  1195.         moveq    #8,d0
  1196.         jsr    -$d2(a6)    ;FreeMem()
  1197. nofreecz:    bsr.w    _AudioRem
  1198.     IFNE    MIDI
  1199.         tst.b    intserv
  1200.         beq.s    noremvbis
  1201.         moveq.l    #5,d0    ;INTB_VERTB
  1202.         lea    vbinterrupt(pc),a1
  1203.         jsr    -$ae(a6)    ;RemIntServer()
  1204.         clr.b    intserv
  1205. noremvbis:    bsr.w    _FreeSerial
  1206.     ENDC
  1207.         move.l    (sp)+,a6
  1208. xremp:        rts
  1209.  
  1210. _PlayModule:    tst.b    allok
  1211.         beq.s    xremp
  1212.         move.l    a0,d0
  1213.         bne.s    newcmod
  1214.         lea    currentmodule(pc),a0
  1215.         tst.l    (a0)    ;try old module
  1216.         beq.w    xpmod3
  1217.         movea.l    (a0),a0
  1218. newcmod:        lea    40(a0),a1
  1219.         clr.l    (a1)+    ;reset everything
  1220.         clr.l    (a1)+
  1221.         clr.w    (a1)
  1222.         not.w    (a1)+
  1223.         move.b    #$05,(a1)
  1224.         movea.l    8(a0),a1
  1225.     IFNE    DIM
  1226.         clr.w    dimval
  1227.     ENDC
  1228.         btst    #0,767(a1)    ;filter??
  1229.         bne.s    filteron
  1230.         bset    #1,$bfe001
  1231.         bra.s    _ContModule
  1232. filteron:    bclr    #1,$bfe001
  1233. _ContModule:    tst.b    allok
  1234.         beq.s    xpmod3
  1235.         move.l    a6,-(sp)
  1236.         movea.l    4,a6
  1237.         move.w    #$4000,$dff09a    ;please don't disturb!!!
  1238.         addq.b    #1,$126(a6)
  1239.         move.l    a0,d0
  1240.         bne.s    newcmod2
  1241.         lea    currentmodule(pc),a0
  1242.         tst.l    (a0)
  1243.         beq.s    exitpmod
  1244.         movea.l    (a0),a0
  1245. newcmod2:    tst.b    timeropen
  1246.         beq.s    exitpmod
  1247.         move.w    46(a0),d1
  1248.         movea.l    8(a0),a1
  1249.         move.w    764(a1),d0
  1250.     IFNE    DIM
  1251.         move.b    786(a1),dimstart
  1252.     ENDC
  1253.         adda.w    d1,a1
  1254.         move.b    508(a1),43(a0)    ;init pblock
  1255.         move.l    a0,currentmodule
  1256.         move.w    #2,40(a0)    ;pstate = play song
  1257.         bsr.w    _SetTempo
  1258.         or.b    #1,$bfee01
  1259.         move.w    #$000f,$dff096
  1260. exitpmod:    subq.b    #1,$126(a6)
  1261.         bge.s    xpmod2
  1262.         move.w    #$c000,$dff09a    ;enable interrupts again
  1263. xpmod2:        move.l    (sp)+,a6
  1264. xpmod3:        rts
  1265.  
  1266. _StopPlayer:    tst.b    allok
  1267.         beq.s    stpplrend
  1268.         tst.l    currentmodule
  1269.         beq.s    nocurrm
  1270.         movea.l    currentmodule(pc),a0
  1271.         clr.w    40(a0)        ;the interrupt will stop the timer
  1272. nocurrm:
  1273.     IFNE    DIM
  1274.         clr.w    dimval
  1275.     ENDC
  1276.     IFNE    MIDI
  1277.         move.b    #$af,stpdata
  1278. stpplrloop:    lea    stpdata(pc),a0
  1279.         addq.b    #1,(a0)
  1280.         cmp.b    #$bf,(a0)
  1281.         bhi.s    stpplrend
  1282.         moveq.l    #3,d0
  1283.         bsr.w    _AddMIDIData
  1284.         bra.s    stpplrloop
  1285.     ENDC
  1286. stpplrend:    rts
  1287.  
  1288.     IFNE    DIM
  1289. _DimOffPlayer:    tst.b    allok
  1290.         beq.s    dimnocm
  1291.         tst.w    d0
  1292.         beq.s    dimstp
  1293.         moveq    #0,d1
  1294.         move.b    dimstart(pc),d1
  1295.         lsl.l    #7,d1        ;* 128
  1296.         move.w    d1,dimval
  1297.         divu    d0,d1
  1298.         move.w    d1,dimstep
  1299. dimnocm:        rts
  1300. dimstp:        bsr.s    _StopPlayer
  1301.         rts
  1302.     ENDC
  1303.  
  1304.     IFNE    MIDI
  1305. VBlankHandler:    subq.b    #1,(a1)
  1306.         bne.s    exitvblank
  1307.         move.b    #15,(a1)
  1308.         moveq.l    #1,d0
  1309.         lea    1(a1),a0
  1310.         bsr.w    _AddMIDIData
  1311. exitvblank    moveq.l    #0,d0
  1312.         rts
  1313.  
  1314. actsens:    dc.b    0,$FE
  1315. intserv:    dc.b    0
  1316. stpdata:    dc.b    0,$7b,0
  1317.  
  1318. sendbuffer:    ds.b    128
  1319. buffptr:        dc.l    sendbuffer
  1320. readbuffptr:    dc.l    sendbuffer
  1321. miscresbase:    dc.l    0
  1322. lastcmdbyte:    dc.b    0
  1323.     ENDC
  1324.         even
  1325.     IFNE    MIDI
  1326. preschgdata:    dc.b    0,0
  1327. noteondata:    dc.l    0
  1328.     ENDC
  1329. audiodevopen:    dc.b    0
  1330. timeropen:    dc.b    0
  1331.     IFNE    DIM
  1332. dimval:        dc.w    0
  1333. dimstep:        dc.w    0
  1334. dimstart:    dc.b    0
  1335.     ENDC
  1336.     IFNE    MIDI
  1337. serportalloc:    dc.b    0
  1338. bytesinbuff:    dc.b    0
  1339.     ENDC
  1340. sigbitnum:    dc.b    -1
  1341. allok:        dc.b    0
  1342. filterpos:    dc.b    0
  1343.         even
  1344. timerinterrupt:    dc.w    0,0,0,0,0
  1345.         dc.l    timerintname,0,_IntHandler
  1346.     IFNE    MIDI
  1347. serinterrupt:    dc.w    0,0,0,0,0
  1348.         dc.l    serintname,buffptr,SerIntHandler
  1349. vbinterrupt:    dc.w    0,0,0,0,0
  1350.         dc.l    vbintname,actsens,VBlankHandler
  1351.     ENDC
  1352. allocport:    dc.l    0,0    ;succ, pred
  1353.         dc.b    4,0    ;NT_MSGPORT
  1354.         dc.l    0    ;name
  1355.         dc.b    0,0    ;flags = PA_SIGNAL
  1356.         dc.l    0    ;task
  1357. reqlist:    dc.l    0,0,0    ;list head, tail and tailpred
  1358.         dc.b    5,0
  1359. allocreq:    dc.l    0,0
  1360.         dc.b    5,127    ;NT_MESSAGE, use maximum priority (127)
  1361.         dc.l    0,allocport    ;name, replyport
  1362.         dc.w    68        ;length
  1363.         dc.l    0    ;io_Device
  1364.         dc.l    0    ;io_Unit
  1365.         dc.w    0    ;io_Command
  1366.         dc.b    0,0    ;io_Flags, io_Error
  1367.         dc.w    0    ;ioa_AllocKey
  1368.         dc.l    sttempo    ;ioa_Data
  1369.         dc.l    1    ;ioa_Length
  1370.         dc.w    0,0,0    ;ioa_Period, Volume, Cycles
  1371.         dc.w    0,0,0,0,0,0,0,0,0,0    ;ioa_WriteMsg
  1372. ciaaname:    dc.b    'ciaa.resource',0
  1373. timerintname:    dc.b    'Player: TimerInterrupt',0
  1374.     IFNE    MIDI
  1375. serintname:    dc.b    'Player: SerialInterrupt',0
  1376. vbintname:    dc.b    'Player: VBlankInterrupt',0
  1377.     ENDC
  1378. audiodevname:    dc.b    'audio.device',0
  1379.     IFNE    MIDI
  1380. miscresname:    dc.b    'misc.resource',0
  1381. serdev:        dc.b    'serial.device',0
  1382.     ENDC
  1383. medname:        dc.b    'MED player routine',0 ;yeah, our name
  1384. _ciaaresource:    dc.l    0
  1385. periods:        dc.w    856,808,762,720,678,640,604,570,538,508,480,453
  1386.         dc.w    428,404,381,360,339,320,302,285,269,254,240,226
  1387.         dc.w    214,202,190,180,170,160,151,143,135,127,120,113
  1388.         dc.w    214,202,190,180,170,160,151,143,135,127,120,113
  1389.         dc.w    214,202,190,180,170,160,151,143,135,127,120,113
  1390.         dc.w    214,202,190,180,170,160,151,143,135,127,120,113
  1391. currentmodule:    dc.l    0
  1392. chipzero:    dc.l    0
  1393.         end
  1394.