home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 497b.lha / MED_v3.0 / Programmers / MODPlayer / modplayer.a < prev    next >
Encoding:
Text File  |  1991-04-03  |  49.2 KB  |  1,738 lines

  1. ;    MED V3.00 - © 1989 - 1991 by Teijo Kinnunen
  2. ;    modplayer.a    - the music player routine
  3.  
  4. ; This file can be assembled at least with the following assemblers:
  5. ;  A68k V2.61  (Fish #314)
  6. ;  HiSoft Devpac 2 (commercial)
  7. ; with minor modifications, it should work with other assemblers too
  8.  
  9. ac_ptr    EQU    $00
  10. ac_len    EQU    $04
  11. ac_per    EQU    $06
  12. ac_vol    EQU    $08
  13. T03SZ    EQU    74
  14. T415SZ    EQU    18
  15.  
  16. MIDI    EQU    0    ;1 = include MIDI code
  17. AUDDEV    EQU    1    ;1 = allocate channels using audio.device
  18. SYNTH    EQU    1    ;1 = include synth-sound handler
  19. CHECK    EQU    1    ;1 = do range checkings (track, sample in mem etc.)
  20. RELVOL    EQU    1    ;1 = include relative volume handling code
  21. IFF53    EQU    1    ;1 = play IFF 3- and 5-octave samples correctly
  22. ;****** Timing control ******
  23. VBLANK    EQU    0    ;1 = use VBlank interrupt (when absolutely necessary)
  24. CIAB    EQU    1    ;1 = use CIAB timers (default)
  25. ; Please use CIAB whenever possible to avoid problems with variable
  26. ; VBlank speeds and to allow the use of command F01 - FF0 (set tempo)
  27. ; If both are set to 0, the timing is left for you (never set both to 1!!),
  28. ; then you just call _IntHandler for each timing pulse.
  29.  
  30.         section    "text",code
  31.  
  32. _ChannelOff:    ;d0 = channel #
  33.         lea    trackdataptrs(pc),a1
  34.         lsl.b    #2,d0
  35.         adda.w    d0,a1
  36.         lsr.b    #2,d0
  37.         movea.l    (a1),a1
  38.     IFNE    MIDI
  39.         move.b    trk_prevmidin(a1),d1    ;first: is it MIDI??
  40.         beq.s    notcomidi    ;not a midi note
  41. choff_midi:    clr.b    trk_prevmidin(a1)
  42.         lea    noteondata(pc),a0
  43.         move.b    d1,1(a0)
  44.         move.b    trk_prevmidich(a1),(a0)    ;prev midi channel
  45.         clr.b    2(a0)
  46.         or.b    #$90,(a0)        ;note off
  47.         moveq    #3,d0
  48.         bra.w    _AddMIDIData
  49. notcomidi:
  50.     ENDC
  51.         cmp.b    #4,d0
  52.         bge.s    notamigatrk
  53.     IFNE    SYNTH
  54.         clr.l    trk_synthptr(a1)
  55.     ENDC
  56.         moveq    #1,d1
  57.         lsl.w    d0,d1
  58.         move.w    d1,$dff096
  59. notamigatrk:    rts
  60.  
  61. SoundOff:    move.l    d2,-(sp)
  62.         moveq    #15,d2
  63. SO_loop0    move.l    d2,d0
  64.         bsr.s    _ChannelOff
  65.         dbf    d2,SO_loop0
  66.         lea    _module(pc),a0
  67.         clr.l    (a0)        ;play nothing!!
  68.         move.l    (sp)+,d2
  69.         rts
  70.  
  71. _PlayNote:    ;d0(w) = trk #, d1 = note #, d2 = vol, d3(w) = instr # a3 = addr of instr
  72.         movem.l d3-d7,-(sp) ;All right, let's start!!
  73.         move.w    d2,-(sp)
  74.         moveq    #0,d4
  75.         bset    d0,d4    ;d4 is mask for this channel
  76.         movea.l    24(a6),a0    ;ptr to sample array
  77.         move.w    d3,d7
  78.         add.w    d3,d3            ;d3 = instr.num << 2
  79.         add.w    d3,d3
  80.         move.l    0(a0,d3.w),d5        ;get address of instrument
  81.     IFNE    MIDI
  82.         bne.s    inmem
  83.         tst.b    4(a3)            ;is MIDI channel set
  84.     ENDC
  85.     IFNE    CHECK
  86.         beq.w    retsn2            ; NO!!!
  87.     ENDC
  88. inmem:        add.b    766(a4),d1    ;add play transpose
  89.         add.b    7(a3),d1    ;and instr. transpose
  90.         cmp.b    #4,d0
  91.         bge.s    nodmaoff    ;track # >= 4: not an Amiga channel
  92.         move.l    d5,a1
  93.     IFNE    SYNTH
  94.         tst.l    trk_synthptr(a5)
  95.         beq.s    stpdma
  96.         cmp.w    #-1,4(a1)    ;type == SYNTHETIC??
  97.         beq.s    nostpdma
  98.     ENDC
  99. stpdma:        move.w    d4,$dff096        ;stop this channel (dmacon)
  100. nostpdma:
  101.     IFNE    SYNTH
  102.         clr.l    trk_synthptr(a5)
  103.     ENDC
  104. nodmaoff:
  105.     IFNE    MIDI
  106.         move.b    trk_prevmidin(a5),d6    ;get prev. midi note
  107.         beq.s    noprevmidi
  108.         clr.b    trk_prevmidin(a5)
  109.         lea    noteondata(pc),a0
  110.         move.b    d6,1(a0)
  111.         move.b    trk_prevmidich(a5),(a0)    ;prev midi channel
  112.         or.b    #$90,(a0)        ;note off
  113.         clr.b    2(a0)        ;clear volume
  114.         movem.w    d0-d1,-(sp)
  115.         moveq    #3,d0
  116.         bsr.w    _AddMIDIData
  117.         movem.w    (sp)+,d0-d1
  118. noprevmidi:    tst.b    4(a3)
  119.         bne.w    handleMIDInote
  120.     ENDC
  121.     IFNE    CHECK
  122.         cmp.w    #4,d0        ;track > 3???
  123.         bge.w    retsn2        ;no Amiga instruments here!!!
  124.     ENDC
  125. ; handle decay (for tracks 0 - 3 only!!)
  126.         clr.b    trk_fadespd(a5)        ;no fade yet..
  127.         move.b    trk_initdecay(a5),trk_decay(a5)    ;set decay
  128.         clr.b    trk_vibroffs(a5)    ;clr vibrato offset
  129.         or.w    d4,dmaonmsk
  130.         move.l    d5,a0
  131.         subq.b    #1,d1
  132.     IFNE    SYNTH
  133.         tst.w    4(a0)
  134.         bmi.w    handleSynthnote
  135.     ENDC
  136. tlwtst0:    tst.b    d1
  137.         bpl.s    notenot2low
  138.         add.b    #12,d1    ;note was too low, octave up
  139.         bra.s    tlwtst0
  140. notenot2low:    cmp.b    #62,d1
  141.         ble.s    endpttest
  142.         sub.b    #12,d1    ;note was too high, octave down
  143. endpttest:    move.w    d0,d4    ;d4 = track number
  144.         bsr.w    getinsdata
  145.         movea.l    trk_audioaddr(a5),a1 ;base of this channel's regs
  146.         move.w    (sp),ac_vol(a1)
  147.         add.w    d4,d4    ;d4 = trk << 1
  148.         move.w    d4,d6
  149.         add.w    d6,d6    ;d6 = trk << 2
  150.         move.l    d0,ac_ptr(a1)        ;put it in ac_ptr
  151.         cmp.w    #1,d3
  152.         bhi.s    repeat
  153.         
  154.         move.l    #_chipzero,trk_sampleptr(a5) ;pointer of zero word
  155.         move.w    #1,trk_samplelen(a5)    ;length: 1 word
  156.         lsr.l    #1,d1            ;shift length right
  157.         move.w    d1,ac_len(a1)        ;and put to custom chip
  158.         bra.s    retsn1
  159.  
  160. repeat:        tst.w    d2
  161.         beq.s    begin0        ;rep. start < 2
  162.         move.w    d2,ac_len(a1)    ;move repeat to hardware
  163.         bra.s    beginn0
  164. begin0:        move.w    d3,ac_len(a1)
  165. beginn0:    lsl.l    #1,d2        ;shift
  166.         add.l    d2,d0        ;d0 = starting address of repeat
  167.         move.l    d0,trk_sampleptr(a5)    ;remember rep. start
  168.         move.w    d3,trk_samplelen(a5)    ;remember rep. length
  169.                 
  170. retsn1:        move.w    d5,ac_per(a1)    ;getinsdata puts period to d5
  171.         move.w    d5,trk_prevper(a5)
  172.     IFNE    SYNTH
  173.         tst.l    trk_synthptr(a5)
  174.         bne.w    hSn2
  175.     ENDC
  176. retsn2:        addq.l    #2,sp    ;forget volume
  177.         movem.l    (sp)+,d3-d7
  178.         rts
  179.  
  180.     IFNE    MIDI
  181. handleMIDInote:
  182.         lea    noteondata(pc),a0
  183.         add.b    #23,d1        ;2 octaves higher and -1
  184.         bpl.s    mnot2low    ;note number not too low
  185.         add.b    #12,d1        ;it was too low, 1 octave up
  186.         bra.s    endmtst
  187. mnot2low:    tst.b    d1        ;is it too high then??
  188.         bpl.s    endmtst        ;no, not greater than 127
  189.         sub.b    #12,d1        ;1 octave down, if yes
  190. endmtst:    move.b    d1,1(a0)    ;MIDI msg note #
  191.         move.b    d1,trk_prevmidin(a5)    ;save this note number
  192.         move.b    d2,d4        ;temporary save the volume
  193.         subq.b    #1,d2        ;if 64 => 63
  194.         bpl.s    nooops
  195.         moveq    #0,d2        ;oops, too low!!
  196. nooops:        lsl.b    #1,d2        ;volume 0 - 63 => 0 - 127
  197.         bclr    #7,d2        ;be sure that bit 7 is clear
  198.         move.b    d2,2(a0)    ;MIDI msg volume
  199.         moveq    #0,d1
  200.         move.b    4(a3),d1    ;get midi chan of this instrument
  201.         subq.b    #1,d1        ;from 1-16 to 0-15
  202.         move.b    d1,trk_prevmidich(a5)    ;save to prev midi channel
  203.         move.b    #$90,(a0)    ;MIDI: Note on
  204.         or.b    d1,(a0)        ;MIDI msg Note on & channel
  205.         move.b    5(a3),d2    ;get preset #
  206.         beq.s    nochgpres    ;zero = no preset
  207.         lea    prevmidicpres(pc),a1
  208.         cmp.b    0(a1,d1.w),d2    ;is this previous preset ??
  209.         beq.s    nochgpres    ;yes...no need to change
  210.         move.b    d2,0(a1,d1.w)    ;save preset to prevmidicpres
  211.         subq.b    #1,d2        ;sub 1 to get 0 - 127
  212.         lea    preschgdata(pc),a0
  213.         move.b    #$c0,(a0)    ;command: $C
  214.         or.b    d1,(a0)        ;"or" midi channel
  215.         move.b    d2,1(a0)    ;push the number to second byte
  216.         moveq    #5,d0        ;Noteondata follows preschgdata
  217.         bra.s    preschanged    ;struct, so this is a bit faster
  218. nochgpres:    moveq    #3,d0
  219. preschanged:    bsr.w    _AddMIDIData
  220.         bra.s    retsn2
  221.     ENDC
  222.  
  223.     IFNE    SYNTH
  224. handleSynthnote:
  225.         move.b    d1,trk_prevnote2(a5)
  226.         move.l    a0,trk_synthptr(a5)
  227.         cmp.w    #-2,4(a0)    ;HYBRID??
  228.         bne.s    hSn_nossn
  229.         movea.l    278(a0),a0    ;yep, get the waveform pointer
  230.         bra.w    tlwtst0        ;go and play it
  231. hSn_nossn:    lea    _synthper(pc),a1
  232.         move.l    a1,trk_periodtbl(a5) ;save table ptr for synth periods
  233.         add.w    d1,d1
  234.         move.w    0(a1,d1.w),d1
  235.         movea.l    trk_audioaddr(a5),a1
  236.         move.b    trk_prevvol(a5),trk_synvol(a5)
  237.         move.w    d1,trk_prevper(a5)
  238.         move.w    d1,ac_per(a1)
  239.         clr.l    trk_sampleptr(a5)
  240. hSn2:        lea    trk_arpgoffs(a5),a1 ;clear synth-variables for new note
  241.         clr.l    (a1)+
  242.         clr.l    (a1)+
  243.         clr.l    (a1)+
  244.         clr.l    (a1)+
  245.         clr.b    (a1)+
  246.         addq.l    #1,a1    ;skip trk_prevnote2
  247.         movea.l    trk_synthptr(a5),a0
  248.         move.w    18(a0),(a1)+    ;trk_initvolxspd/trk_initwfxspd
  249.         clr.l    (a1)+
  250.         clr.w    (a1)
  251.         bsr.s    synth_start
  252.         bra.w    retsn2
  253.  
  254. synth_start:    move.l    a3,-(sp)
  255.         movea.l    trk_audioaddr(a5),a3    ;audio channel base address
  256.         subq.b    #1,trk_volxcnt(a5)    ;decrease execute counter..
  257.         bgt.w    synth_wftbl        ;not 0...go to waveform
  258.         move.b    trk_initvolxspd(a5),trk_volxcnt(a5) ;reset counter
  259.         move.b    trk_volchgspd(a5),d0    ;volume change??
  260.         beq.s    synth_nochgvol        ;no.
  261.         add.b    trk_synvol(a5),d0    ;add previous volume
  262.         bpl.s    synth_voln2l        ;not negative
  263.         moveq    #0,d0            ;was negative => 0
  264. synth_voln2l:    cmp.b    #$40,d0            ;too high??
  265.         ble.s    synth_voln2h        ;not 2 high.
  266.         moveq    #$40,d0            ;was 2 high => 64
  267. synth_voln2h:    move.b    d0,trk_synvol(a5)    ;remember new...
  268.         move.b    d0,ac_vol+1(a3)        ;and change it
  269. synth_nochgvol:    move.w    trk_volcmd(a5),d0    ;get table position ptr
  270.         tst.b    trk_volwait(a5)        ;WAI(t) active
  271.         beq.s    synth_getvolcmd        ;no
  272.         subq.b    #1,trk_volwait(a5)    ;yep, decr wait ctr
  273.         ble.s    synth_getvolcmd        ;0 => continue
  274.         bra.w    synth_wftbl        ;> 0 => still wait
  275. synth_inccnt:    addq.b    #1,d0
  276. synth_getvolcmd:
  277.         addq.b    #1,d0            ;advance pointer
  278.         move.b    21(a0,d0.w),d1        ;get command
  279.         bmi.s    synth_cmd        ;negative = command
  280.         move.b    d1,trk_synvol(a5)    ;set synthvol
  281.         move.b    d1,ac_vol+1(a3)        ;change it!!
  282.         bra.s    synth_endvol        ;end of volume executing
  283. synth_cmd:    and.w    #$000f,d1
  284.         add.b    d1,d1
  285.         move.w    synth_vtbl(pc,d1.w),d1
  286.         jmp    syv(pc,d1.w)
  287. synth_vtbl:    dc.w    syv_f0-syv,syv_f1-syv,syv_f2-syv,syv_f3-syv
  288.         dc.w    synth_endvol-syv,synth_endvol-syv,synth_endvol-syv
  289.         dc.w    synth_endvol-syv,synth_endvol-syv,synth_endvol-syv
  290.         dc.w    syv_fa-syv,syv_ff-syv,synth_endvol-syv
  291.         dc.w    synth_endvol-syv,syv_fe-syv,syv_ff-syv
  292. syv:
  293. syv_fe:        move.b    22(a0,d0.w),d0        ;JMP
  294.         bra.s    synth_getvolcmd
  295. syv_f0:        move.b    22(a0,d0.w),trk_initvolxspd(a5) ;change volume ex. speed
  296.         bra.s    synth_inccnt
  297. syv_f1:        move.b    22(a0,d0.w),trk_volwait(a5)    ;WAI(t)
  298.         addq.b    #1,d0
  299.         bra.s    synth_endvol
  300. syv_f3:        move.b    22(a0,d0.w),trk_volchgspd(a5) ;set volume slide up
  301.         bra.s    synth_inccnt
  302. syv_f2:        move.b    22(a0,d0.w),d1
  303.         neg.b    d1
  304.         move.b    d1,trk_volchgspd(a5) ;set volume slide down
  305.         bra.s    synth_inccnt
  306. syv_fa:        move.b    22(a0,d0.w),trk_wfcmd+1(a5) ;JWS (jump wform sequence)
  307.         clr.b    trk_wfwait(a5)
  308.         bra.s    synth_inccnt
  309. syv_ff:        subq.b    #1,d0
  310. synth_endvol:    move.w    d0,trk_volcmd(a5)
  311. synth_wftbl:    move.b    trk_synvol(a5),trk_prevvol(a5)
  312.         adda.w    #158,a0
  313.         subq.b    #1,trk_wfxcnt(a5)    ;decr. wf speed counter
  314.         bgt.w    synth_arpeggio        ;not yet...
  315.         move.b    trk_initwfxspd(a5),trk_wfxcnt(a5) ;restore speed counter
  316.         move.w    trk_wfcmd(a5),d0    ;get table pos offset
  317.         move.w    trk_wfchgspd(a5),d1    ;CHU/CHD ??
  318.         beq.s    synth_tstwfwai        ;0 = no change
  319. wytanwet:    add.w    trk_perchg(a5),d1    ;add value to current change
  320.         move.w    d1,trk_perchg(a5)    ;remember amount of change
  321.         add.w    trk_prevper(a5),d1    ;add initial period to it
  322.         cmp.w    #113,d1            ;overflow??
  323.         bge.s    synth_pern2h
  324.         moveq    #113,d1
  325. synth_pern2h:    move.w    d1,ac_per(a3)        ;push the changed period
  326. synth_tstwfwai:    tst.b    trk_wfwait(a5)        ;WAI ??
  327.         beq.s    synth_getwfcmd        ;not waiting...
  328.         subq.b    #1,trk_wfwait(a5)    ;decr wait counter
  329.         beq.s    synth_getwfcmd        ;waiting finished
  330.         bra.w    synth_arpeggio        ;still sleep...
  331. synth_incwfc:    addq.b    #1,d0
  332. synth_getwfcmd:    addq.b    #1,d0            ;advance position counter
  333.         move.b    -9(a0,d0.w),d1        ;get command
  334.         bmi.s    synth_wfcmd        ;negative = command
  335.         ext.w    d1            ;was positive->change wform
  336.         lsl.w    #2,d1            ;create index...
  337.         movea.l    120(a0,d1.w),a1        ;get wf address
  338.         addq.l    #2,a1            ;forget length-word
  339.         move.l    a1,ac_ptr(a3)        ;push new pointer
  340.         move.w    -(a1),ac_len(a3)    ;and the waveform length
  341.         bra.w    synth_wfend        ;no new commands now...
  342. synth_wfcmd:    and.w    #$000f,d1        ;get the right nibble
  343.         add.b    d1,d1            ;* 2
  344.         move.w    synth_wfctbl(pc,d1.w),d1
  345.         jmp    syw(pc,d1.w)        ;jump to command
  346. synth_wfctbl:    dc.w    syw_f0-syw,syw_f1-syw,syw_f2-syw,syw_f3-syw,syw_f4-syw
  347.         dc.w    syw_f5-syw,syw_f6-syw,synth_wfend-syw,synth_wfend-syw
  348.         dc.w    synth_wfend-syw,syw_fa-syw,syw_ff-syw
  349.         dc.w    syw_fc-syw,synth_getwfcmd-syw,syw_fe-syw,syw_ff-syw
  350. syw:
  351. syw_fe:        move.b    -8(a0,d0.w),d0        ;jump (JMP)
  352.         bra.s    synth_getwfcmd
  353. syw_fc:        move.w    d0,trk_arpsoffs(a5)    ;new arpeggio begin
  354.         move.w    d0,trk_arpgoffs(a5)
  355. synth_findare:    addq.b    #1,d0
  356.         tst.b    -9(a0,d0.w)
  357.         bpl.s    synth_findare
  358.         bra.s    synth_getwfcmd
  359. syw_f0:        move.b    -8(a0,d0.w),trk_initwfxspd(a5)    ;new waveform speed
  360.         bra    synth_incwfc
  361. syw_f1:        move.b    -8(a0,d0.w),trk_wfwait(a5)    ;wait waveform
  362.         addq.b    #1,d0
  363.         bra.s    synth_wfend
  364. syw_f4:        move.b    -8(a0,d0.w),trk_synvibdep+1(a5)    ;set vibrato depth
  365.         bra.w    synth_incwfc
  366. syw_f5:        move.b    -8(a0,d0.w),trk_synthvibspd+1(a5) ;set vibrato speed
  367.         addq.b    #1,trk_synthvibspd+1(a5)
  368.         bra.w    synth_incwfc
  369. syw_f2:        moveq    #0,d1            ;set slide down
  370.         move.b    -8(a0,d0.w),d1
  371. synth_setsld:    move.w    d1,trk_wfchgspd(a5)
  372.         bra.w    synth_incwfc
  373. syw_f3:        move.b    -8(a0,d0.w),d1        ;set slide up
  374.         neg.b    d1
  375.         ext.w    d1
  376.         bra.s    synth_setsld
  377. syw_f6:        clr.w    trk_perchg(a5)        ;reset period
  378.         move.w    trk_prevper(a5),ac_per(a3)
  379.         bra.w    synth_getwfcmd
  380. syw_fa:        move.b    -8(a0,d0.w),trk_volcmd+1(a5) ;JVS (jump volume sequence)
  381.         clr.b    trk_volwait(a5)
  382.         bra.w    synth_incwfc
  383. syw_ff:        subq.b    #1,d0        ;pointer = END - 1
  384. synth_wfend:    move.w    d0,trk_wfcmd(a5)
  385. synth_arpeggio:    move.w    trk_arpgoffs(a5),d0
  386.         beq.s    synth_vibrato
  387.         moveq    #0,d1
  388.         move.b    -8(a0,d0.w),d1
  389.         add.b    trk_prevnote2(a5),d1
  390.         movea.l    trk_periodtbl(a5),a1    ;get period table
  391.         add.w    d1,d1
  392.         move.w    0(a1,d1.w),d1
  393.         add.w    trk_perchg(a5),d1
  394.         move.w    d1,trk_prevper(a5)
  395.         move.w    d1,ac_per(a3)
  396.         addq.b    #1,d0
  397.         tst.b    -8(a0,d0.w)
  398.         bpl.s    synth_noarpres
  399.         move.w    trk_arpsoffs(a5),d0
  400. synth_noarpres:    move.w    d0,trk_arpgoffs(a5)
  401. synth_vibrato:    move.w    trk_synvibdep(a5),d1    ;get vibrato depth
  402.         beq.s    synth_rts        ;0 => no vibrato
  403.         move.w    trk_synviboffs(a5),d0    ;get offset
  404.         lsr.w    #4,d0            ;/ 16
  405.         and.w    #$1f,d0            ;sinetable offset (0-31)
  406.         move.b    sinetable(pc,d0.w),d0    ;get byte
  407.         ext.w    d0            ;to word
  408.         muls    d1,d0            ;amplify (* depth)
  409.         asr.w    #8,d0            ;and divide by 64
  410.         move.w    trk_prevper(a5),d1    ;get the old period
  411.         add.w    d0,d1            ;add vibrato...
  412.         add.w    trk_perchg(a5),d1    ;and pitch change...
  413.         move.w    d1,ac_per(a3)        ;change.
  414.         move.w    trk_synthvibspd(a5),d0    ;vibrato speed
  415.         add.w    d0,trk_synviboffs(a5)    ;add to offset
  416. synth_rts:    move.l    (sp)+,a3
  417.         rts
  418.     ENDC
  419. sinetable:    dc.b    0,25,49,71,90,106,117,125,127,125,117,106,90,71,49
  420.         dc.b    25,0,-25,-49,-71,-90,-106,-117,-125,-127,-125,-117
  421.         dc.b    -106,-90,-71,-49,-25,0
  422.  
  423. _Wait1line:    move.l    d0,-(sp)
  424.         moveq    #$79,d0
  425. wl0:        move.b    $dff007,d1
  426. wl1:        cmp.b    $dff007,d1
  427.         beq.s    wl1
  428.         dbf    d0,wl0
  429.         move.l    (sp)+,d0
  430.         rts
  431. pushnewvals:    movea.l    (a1)+,a5
  432.         lsr.b    #1,d0
  433.         bcc.s    rpnewv
  434.         move.l    trk_sampleptr(a5),d1
  435.         beq.s    rpnewv
  436.         movea.l    trk_audioaddr(a5),a0
  437.         move.l    d1,ac_ptr(a0)
  438.         move.w    trk_samplelen(a5),ac_len(a0)
  439. rpnewv:        rts
  440. _StartDMA:        ;This small routine turns on audio DMA
  441.         move.w    dmaonmsk(pc),d0    ;dmaonmsk contains the mask of
  442.         beq.s    rpnewv    ;the channels that must be turned on
  443.         bset    #15,d0    ;DMAF_SETCLR: set these bits in dmacon
  444.         bsr.s    _Wait1line
  445.         move.w    d0,$dff096    ;do that!!!
  446.         bsr.s    _Wait1line
  447.         lea    trackdataptrs(pc),a1
  448.         bsr.s    pushnewvals
  449.         bsr.s    pushnewvals
  450.         bsr.s    pushnewvals
  451.         bra.s    pushnewvals
  452.  
  453. dmaonmsk:    dc.w    0
  454.     IFNE    MIDI
  455. prevmidicpres:    dc.l    0,0,0,0 ; 16 bytes
  456. prevmidipbend:    dc.w    $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
  457.         dc.w    $2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
  458.     ENDC
  459. ; TRACK-data structures (see definitions at the end of this file)
  460. t03d:        ds.b    20
  461.         dc.l    $dff0a0
  462.         ds.b    50+20
  463.         dc.l    $dff0b0
  464.         ds.b    50+20
  465.         dc.l    $dff0c0
  466.         ds.b    50+20
  467.         dc.l    $dff0d0
  468.         ds.b    50
  469. t415d:        ds.b    4*T415SZ
  470. t815d:        ds.b    8*T415SZ    ;8 bytes * 12 tracks = 96 bytes
  471. trackdataptrs:    dc.l    t03d,t03d+T03SZ,t03d+2*T03SZ,t03d+3*T03SZ
  472.         dc.l    t415d,t415d+T415SZ,t415d+2*T415SZ,t415d+3*T415SZ
  473.         dc.l    t815d,t815d+T415SZ,t815d+2*T415SZ,t815d+3*T415SZ
  474.         dc.l    t815d+4*T415SZ,t815d+5*T415SZ,t815d+6*T415SZ
  475.         dc.l    t815d+7*T415SZ
  476. numtracks:    dc.w    0
  477. numlines:    dc.w    0
  478. _counter:    dc.b    0
  479. nextblock:    dc.b    0
  480.  
  481. _IntHandler:    movem.l    d2-d7/a2-a5,-(sp)
  482.         movea.l    _module(pc),a6    ;a6 = pointer of MMD0
  483.         move.l    a6,d0
  484.         beq.w    plr_exit
  485.         clr.w    dmaonmsk
  486.         movea.l    8(a6),a4    ;a4 = pointer of MMD0song
  487.         moveq    #0,d3
  488.         lea    _counter(pc),a0
  489.         move.b    (a0),d3
  490.         addq.b    #1,d3
  491.         cmp.b    769(a4),d3
  492.         bge.s    plr_pnewnote    ;play new note
  493.         move.b    d3,(a0)
  494.         bra.w    nonewnote    ;do just fx
  495. ; --- new note!! first get address of current block
  496. plr_pnewnote:    clr.b    (a0)        ;clear counter
  497. ; --- now start to play it
  498.         move.w    pblock(pc),d0
  499.         movea.l    16(a6),a0
  500.         lsl.w    #2,d0
  501.         movea.l    0(a0,d0.w),a2    ;block...
  502.         move.b    (a2)+,numtracks+1
  503.         move.b    (a2)+,numlines+1
  504.         move.w    pline(pc),d0
  505.         move.w    d0,d1
  506.         add.w    d0,d0    ;d0 * 2
  507.         add.w    d1,d0    ;+ d0 = d0 * 3
  508.         mulu    numtracks(pc),d0
  509.         adda.w    d0,a2        ;a2 => pointer of curr. note
  510.         moveq    #0,d7        ;number of track
  511.         pea    trackdataptrs(pc)
  512. plr_loop0:    moveq    #0,d5
  513.         move.l    (sp),a1
  514.         movea.l    (a1)+,a5    ;get address of this track's struct
  515.         move.l    a1,(sp)
  516. ; ---------------- get the note numbers
  517.         move.b    (a2)+,d5    ;get the number of this note
  518.         move.b    (a2)+,d6    ;and the 4 numbers containing fx
  519.         move.b    (a2)+,trk_cmdqual(a5)    ;get & save the fx numbers
  520. ; ---------------- clear some instrument # flags
  521.         moveq    #0,d4        ;d4 is a flag: if set, instr. is
  522.         moveq    #0,d3        ;in range G-V. If clr, it's 1-F.
  523. ; ---------------- and set them, if needed
  524.         bclr    #7,d5        ;d3 is also a flag. If it's set,
  525.         sne    d4        ;the instr. is in range 10 - 1V
  526.         bclr    #6,d5
  527.         sne    d3
  528. ; ---------------- check if there's an instrument number
  529.         move.b    d6,d0
  530.         and.w    #$f0,d0        ;d0 now contains only the # of instr
  531.         bne.s    instnum        ;instrument number is not 0
  532.         tst.b    d4        ;maybe it's G (instr. #0, d4 set)
  533.         bne.s    instnum        ;yes, it really was G!!
  534.         tst.b    d3
  535.         beq.s    noinstnum    ;it wasn't 10 - 1V either..
  536. ; ---------------- if there was, GET IT!!
  537. instnum:    lsr.b    #4,d0        ;shift it right to get number 0-F
  538.         tst.b    d4
  539.         beq.s    nogtov2
  540.         add.w    #16,d0        ;if G-V, add 16 to the number
  541. nogtov2:    tst.b    d3
  542.         beq.s    no10to1v
  543.         add.w    #32,d0
  544. ; ---------------- finally, save the number
  545. no10to1v:    subq.b    #1,d0
  546.         move.b    d0,trk_previnstr(a5) ;remember instr. number!
  547. ; ---------------- remember hold/decay values
  548.         lea    holdvals(pc),a0
  549.         move.b    0(a0,d0.w),trk_inithold(a5)
  550.         move.b    63(a0,d0.w),trk_initdecay(a5)
  551. ; ---------------- get the pointer of data's of this sample in Song-struct
  552.         lsl.w    #3,d0        ;* 8
  553.         lea    0(a4,d0.w),a3    ;a3 contains now address of it
  554.         move.l    a3,trk_previnstra(a5)
  555.         moveq    #0,d0
  556. ; ---------------- get volume and make it relative (0 - 100 %)
  557.     IFNE    RELVOL
  558.         move.b    6(a3),d0
  559.         mulu    trk_trackvol(a5),d0
  560.         lsr.w    #8,d0
  561.         move.b    d0,trk_prevvol(a5) ;vol of this instr
  562.     ENDC
  563.     IFEQ    RELVOL
  564.         move.b    6(a3),trk_prevvol(a5)
  565.     ENDC
  566. ; ---------------- remember transpose
  567.         move.b    7(a3),trk_stransp(a5)
  568. ; ---------------- check the commands
  569. noinstnum:    move.b    d6,d0        ;effect again...
  570.         and.b    #$0f,d0        ;now check only the effect part
  571.         move.b    d0,trk_cmd(a5)    ;save the effect number
  572.         beq.w    plr_nocmd    ;no effect
  573.         move.b    trk_cmdqual(a5),d6    ;get qualifier...
  574. ; ---------------- there was a command (effect), but which one??
  575.         cmp.b    #$0f,d0        ;yes effect...is it Tempo???
  576.         bne.w    not0f        ;not Tempo
  577. ; ---------------- it was tempo (F)
  578.         tst.b    d6        ;test effect qual..
  579.         beq.s    fx0fchgblck    ;if effect qualifier (last 2 #'s)..
  580.         cmp.b    #$f0,d6        ;..is zero, go to next block
  581.         bhi.s    fx0fspecial    ;if it's F1-FF something special
  582. ; ---------------- just an ordinary "change tempo"-request
  583.     IFNE    CIAB
  584.         moveq    #0,d0        ;will happen!!!
  585.         move.b    d6,d0
  586.         bsr    _SetTempo    ;change The Tempo
  587.     ENDC
  588.         bra.w    plr_nocmd
  589. ; ---------------- no, it was FFx, something special will happen!!
  590. fx0fspecial:    cmp.b    #$f2,d6    ; | rest - play | SpecialFX#2: no note..yet
  591.         bne.s    isfxfe    ;not SpecFX2
  592. ; ---------------- it was FF2, nothing to do now
  593.         move.b    d5,(a5)    ;Yes!!! Save the note number
  594.         moveq    #0,d5    ; clear the number for awhile
  595.         bra.w    plr_nocmd
  596. isfxfe:        cmp.b    #$fe,d6
  597.         bne.s    notcmdfe
  598. ; ---------------- it was FFE, stop playing
  599.         clr.w    pstate
  600.     IFNE    CIAB
  601.         movea.l    craddr(pc),a0
  602.         bclr    #0,(a0)        ;stop timer
  603.     ENDC
  604.         bsr.w    SoundOff
  605.         addq.l    #4,sp        ;trackdataptrs...
  606.         bra.w    plr_exit
  607. notcmdfe:    cmp.b    #$fd,d6 ;change period
  608.         bne.s    isfxff
  609. ; ---------------- FFD, change the period, don't replay the note
  610.     IFNE    CHECK
  611.         cmp.w    #4,d7 ;no tracks 4 - 15, thank you!!
  612.         bge.w    plr_nocmd
  613.     ENDC
  614.         movea.l    trk_periodtbl(a5),a0    ;period table
  615.         subq.b    #1,d5    ;sub 1 to make "real" note number
  616.         bmi.w    plr_endloop0    ;under zero, do nothing
  617.         add.b    d5,d5
  618.         move.w    0(a0,d5.w),d0 ;get the period
  619.         movea.l    trk_audioaddr(a5),a0
  620.         move.w    d0,ac_per(a0) ;push the period
  621.         moveq    #0,d5 ;and clear it so that it won't be replayed
  622.         bra.w    plr_nocmd    ;done!!
  623. isfxff:        cmp.b    #$ff,d6        ;note off??
  624.         bne.w    plr_nocmd
  625.         move.w    d7,d0
  626.         bsr.w    _ChannelOff
  627.         bra.w    plr_nocmd
  628. ; ---------------- F00, called Pattern Break in ST
  629. fx0fchgblck:    addq.b    #1,nextblock    ;next block????...YES!!!! (F00)
  630.         bra.w    plr_nocmd
  631. ; ---------------- was not Fxx, then it's something else!!
  632. not0f:        cmp.b    #$0e,d0
  633.         bne.s    not0e
  634.         move.b    d6,trk_wfcmd+1(a5) ;set waveform command position ptr
  635.         bra.w    plr_nocmd
  636. not0e:        cmp.b    #$0c,d0        ;new volume???
  637.         bne.s    not0c        ;NO!!!!!!!!!!!!!!!!!!!!!!
  638. ; ---------------- change volume
  639.         move.b    d6,d0
  640.         btst    #4,767(a4)    ;look at flags
  641.         bne.s    volhex
  642.         lsr.b    #4,d0        ;get number from left
  643.         mulu    #10,d0        ;number of tens
  644.         move.b    d6,d1        ;get again
  645.         and.b    #$0f,d1        ;this time don't get tens
  646.         add.b    d1,d0        ;add them
  647. volhex:
  648.     IFNE    CHECK
  649.         cmp.b    #64,d0
  650.         bls.s    novolov64
  651.         moveq    #64,d0
  652.     ENDC
  653. novolov64:
  654.     IFNE    RELVOL
  655.         mulu    trk_trackvol(a5),d0
  656.         lsr.w    #8,d0
  657.     ENDC
  658.         move.b    d0,trk_prevvol(a5)
  659.         bra.s    plr_nocmd
  660. ; ---------------- tempo2 change??
  661. not0c:        cmp.b    #$09,d0
  662.         bne.s    not09
  663.     IFNE    CHECK
  664.         and.b    #$1F,d6
  665.         bne.s    fx9chk
  666.         moveq    #$20,d6
  667.     ENDC
  668. fx9chk:        move.b    d6,769(a4)
  669.         bra.s    plr_nocmd
  670. ; ---------------- note off time set??
  671. not09:        cmp.b    #$08,d0
  672.         bne.s    not08
  673.         move.b    d6,d0
  674.         lsr.b    #4,d6        ;extract left  nibble
  675.         and.b    #$0f,d0        ; "   "  right  "  "
  676.         move.b    d6,trk_initdecay(a5)    ;left = decay
  677.         move.b    d0,trk_inithold(a5)    ;right = hold
  678.         bra.s    plr_nocmd
  679. ; ---------------- cmd Bxx, "position jump", like Goto, yäk!!
  680. not08:        cmp.b    #$0b,d0
  681.         bne.s    not0b
  682.         move.w    d6,d0
  683.         and.w    #$00ff,d0
  684.     IFNE    CHECK
  685.         cmp.w    506(a4),d0    ;test the song length
  686.         bhi.s    plr_nocmd
  687.     ENDC
  688.         move.w    d0,pseq
  689.         st    nextblock    ; = 1
  690.         bra.s    plr_nocmd
  691. ; ---------------- try portamento (3)
  692. not0b:        cmp.b    #$03,d0
  693.         bne.s    plr_nocmd
  694.         subq.b    #1,d5        ;subtract note number
  695.         bpl.s    plr_fx3note    ;there's a note...
  696.         tst.b    d6        ;qual??
  697.         beq.s    plr_endloop0    ;0 -> do nothing
  698.         bra.s    plr_setfx3spd    ;not 0 -> set new speed
  699. plr_fx3note:
  700.     IFNE    CHECK
  701.         cmp.w    #4,d7
  702.         bge.s    plr_endloop0    ;hey, what are you trying to do??
  703.     ENDC
  704.         movea.l    trk_periodtbl(a5),a0
  705.         add.b    766(a4),d5    ;play transpose
  706.         add.b    trk_stransp(a5),d5 ;and instrument transpose
  707.         bmi.s    plr_endloop0    ;again.. too low
  708.         add.w    d5,d5
  709.         move.w    0(a0,d5.w),trk_porttrgper(a5) ;period of this note is the target
  710. plr_setfx3spd:    move.b    d6,trk_prevportspd(a5)    ;remember size
  711.         moveq    #0,d5    ;don't play this one
  712. ; ---------------- everything is checked now: play or not to play??
  713. plr_nocmd:    tst.b    d5    ;Now we'll check if we have to play a note
  714.         beq.s    plr_endloop0    ;no.
  715. ; ---------------- we decided to play
  716.         move.b    d5,(a5)
  717.         move.w    d7,d0
  718.         move.w    d5,d1
  719.         moveq    #0,d2
  720.         move.b    trk_prevvol(a5),d2    ;get volume
  721.         moveq    #0,d3
  722.         move.b    trk_previnstr(a5),d3    ;instr #
  723.         movea.l    trk_previnstra(a5),a3    ;instr data address
  724. ; ---------------- does this instrument have holding??
  725.         move.b    trk_inithold(a5),trk_noteoffcnt(a5) ;initialize hold
  726.         bne.s    plr_holdok    ;not 0 -> OK
  727.         st    trk_noteoffcnt(a5)    ;0 -> hold = 0xff (-1)
  728. ; ---------------- and finally:
  729. plr_holdok:    bsr    _PlayNote    ;play it!!!!!!!!!!!
  730. ; ---------------- end of loop: handle next track, or quit
  731. plr_endloop0:    addq.b    #1,d7
  732.         cmp.w    numtracks(pc),d7
  733.         blt.w    plr_loop0
  734.         addq.l    #4,sp        ;trackdataptrs
  735.  
  736. ; and advance song pointers
  737.         lea    pline(pc),a3
  738.         move.w    (a3),d1        ;pline
  739.         addq.w    #1,d1        ;very important!!! advance line!!
  740.         cmp.w    numlines(pc),d1    ;important too!!! advance block??
  741.         bgt.s    plr_chgblock    ;yes!!!
  742.         tst.b    nextblock    ;command F00 ??
  743.         beq.s    plr_nochgblock    ;no, don't change block
  744. plr_chgblock:    moveq    #0,d1        ;clear line number
  745.         cmp.w    #2,6(a3)    ;play block/play song?
  746.         bne.s    plr_nonewseq    ;play block only...
  747.         move.w    4(a3),d0    ;get play sequence number
  748.         tst.b    nextblock
  749.         bmi.s    plr_noadvseq    ;Bxx sets nextblock to 0xff (= neg)
  750.         addq.w    #1,d0        ;advance sequence number
  751. plr_noadvseq:    cmp.w    506(a4),d0    ;is this the highest seq number??
  752.         blt.s    plr_notagain    ;no.
  753.         moveq    #0,d0        ;yes: play song again
  754.         moveq    #0,d1            ;...forever!!!
  755. plr_notagain:    move.b    d0,5(a3)    ;remember new playseq-#
  756.         lea    508(a4),a0    ;offset in sequence table
  757.         move.b    0(a0,d0.w),d0    ;get number of the block
  758.     IFNE    CHECK
  759.         cmp.b    505(a4),d0    ;beyond last block??
  760.         blt.s    plr_nolstblk    ;no..
  761.         moveq    #0,d0        ;play block 0
  762.     ENDC
  763. plr_nolstblk:    move.b    d0,3(a3)    ;store pblock
  764. plr_nonewseq:    clr.b    nextblock    ;clear this if F00 set it
  765. plr_nochgblock:    move.w    d1,(a3)        ;set new pline
  766.         movea.l    16(a6),a0
  767.         move.w    2(a3),d0    ;pblock
  768.         lsl.w    #2,d0
  769.         movea.l    0(a0,d0.w),a2    ;block...
  770.         move.b    (a2),d7        ;# of tracks
  771.         move.w    (a3),d0        ;play line
  772.         move.w    d0,d1
  773.         add.w    d0,d0    ;d0 * 2
  774.         add.w    d1,d0    ;+ d0 = d0 * 3
  775.         mulu    d7,d0
  776.         lea    2(a2,d0.w),a2
  777.         move.b    769(a4),d3    ;interrupts/note
  778.         lea    trackdataptrs(pc),a0
  779.         subq.b    #1,d7
  780. plr_chkhold:    movea.l    (a0)+,a1    ;track data
  781.         tst.b    trk_noteoffcnt(a1)    ;hold??
  782.         bmi.s    plr_holdend    ;no.
  783.         move.b    (a2),d1        ;get the 1st byte..
  784.         bne.s    plr_hold1
  785.         move.b    1(a2),d1
  786.         and.b    #$f0,d1
  787.         beq.s    plr_holdend    ;don't hold
  788.         bra.s    plr_hold2
  789. plr_hold1:    and.b    #$3f,d1        ;note??
  790.         beq.s    plr_hold2    ;no, cont hold..
  791.         move.b    1(a2),d1
  792.         and.b    #$0f,d1        ;get cmd
  793.         subq.b    #3,d1        ;is there command 3 (slide)
  794.         bne.s    plr_holdend    ;no -> end holding
  795. plr_hold2:    add.b    d3,trk_noteoffcnt(a1)    ;continue holding...
  796. plr_holdend:    addq.l    #3,a2        ;next note
  797.         dbf    d7,plr_chkhold
  798.         btst    #5,767(a4)    ;FLAG_STSLIDE??
  799.         bne.w    plr_endfx    ;yes, no effects this time...
  800.         moveq    #0,d3        ;counter = 0!!!
  801. nonewnote:
  802. ;    *********************** This code produces the effects **
  803.         moveq    #0,d7    ;clear track count
  804.         moveq    #0,d6
  805.         lea    trackdataptrs(pc),a2
  806. plr_loop1:    movea.l    (a2)+,a5
  807.         moveq    #0,d5
  808.         moveq    #0,d4
  809.         move.b    trk_cmd(a5),d6    ;get the fx number
  810.         move.b    trk_cmdqual(a5),d4    ;and the last 2 #'s
  811.     IFNE    MIDI
  812.         tst.b    trk_prevmidin(a5)    ;first: is it MIDI??
  813.         bne.w    midifx
  814.     ENDC
  815.         cmp.w    #4,d7
  816.         bge.w    endl    ;no non-MIDI effects in tracks 4 - 15
  817.         tst.b    trk_noteoffcnt(a5)
  818.         bmi.s    plr_nowaitoff
  819.         subq.b    #1,trk_noteoffcnt(a5)
  820.         bpl.s    plr_nowaitoff
  821.     IFNE    SYNTH
  822.         tst.l    trk_synthptr(a5)    ;synth/hybrid??
  823.         beq.s    plr_nosyndec
  824.         move.b    trk_decay(a5),trk_volcmd+1(a5)    ;set volume command pointer
  825.         clr.b    trk_volwait(a5)    ;abort WAI
  826.         bra.s    plr_gosynth
  827.     ENDC
  828. plr_nosyndec:    move.b    trk_decay(a5),trk_fadespd(a5)    ;set fade...
  829.         bne.s    plr_nowaitoff    ;if > 0, don't stop sound
  830.         bset    d7,d5
  831.         move.w    d5,$dff096    ;stop DMA...
  832.         moveq    #0,d5
  833. plr_nowaitoff:
  834.     IFNE    SYNTH
  835.         tst.l    trk_synthptr(a5)
  836.         beq.s    plr_nosynth
  837. plr_gosynth:    movea.l    trk_synthptr(a5),a0
  838.         bsr.w    synth_start
  839.     ENDC
  840. plr_nosynth:    move.b    trk_fadespd(a5),d0    ;fade??
  841.         beq.s    plr_nofade    ;no.
  842.         sub.b    d0,trk_prevvol(a5)
  843.         bpl.s    plr_nofade2low
  844.         clr.b    trk_prevvol(a5)
  845.         clr.b    trk_fadespd(a5)        ;fade no more
  846. plr_nofade2low:    movea.l    trk_audioaddr(a5),a1
  847.         move.b    trk_prevvol(a5),ac_vol+1(a1)
  848. plr_nofade:    add.b    d6,d6    ;* 2
  849.         move.w    fx_table(pc,d6.w),d0
  850.         jmp    fxs(pc,d0.w)
  851. fx_table:    dc.w    fx_00-fxs,fx_01-fxs,fx_02-fxs,fx_03-fxs,fx_04-fxs
  852.         dc.w    fx_05-fxs,fx_xx-fxs,fx_xx-fxs,fx_xx-fxs,fx_xx-fxs
  853.         dc.w    fx_0a-fxs,fx_xx-fxs,fx_0c-fxs,fx_0d-fxs,fx_xx-fxs
  854.         dc.w    fx_0f-fxs
  855. fxs:
  856. ;    **************************************** Effect 01 ******
  857. fx_01:        sub.w    d4,trk_prevper(a5)    ;slide it up!!!
  858.         move.w    trk_prevper(a5),d5
  859.         cmp.w    #113,d5        ;too high???
  860.         bge    newvals
  861.         move.w    #113,d5        ;yes, too high!!!
  862.         move.w    d5,trk_prevper(a5)
  863.         bra    newvals
  864. ;    **************************************** Effect 02 ******
  865. fx_02:        add.w    d4,trk_prevper(a5)    ;slide it down!!!!!!!!!
  866.         move.w    trk_prevper(a5),d5
  867.         bra.w    newvals
  868. ;    **************************************** Effect 00 ******
  869. fx_00:        tst.b    d4    ;both fxqualifiers are 0s: no arpeggio!!
  870.         beq.w    endl
  871.         move.l    d3,d0
  872.         divu    #3,d0
  873.         swap    d0
  874.         tst.w    d0
  875.         bne.s    fx_arp12
  876.         and.b    #$0f,d4
  877.         add.b    (a5),d4
  878.         bra.s    fx_doarp
  879. fx_arp12:    subq.b    #1,d0
  880.         bne.s    fx_arp2
  881.         lsr.b    #4,d4
  882.         add.b    (a5),d4
  883.         bra.s    fx_doarp
  884. fx_arp2:    move.b    (a5),d4
  885. fx_doarp:    subq.b    #1,d4        ;-1 to make it 0 - 127
  886.         add.b    766(a4),d4    ;add play transpose
  887.         add.b    trk_stransp(a5),d4    ;add instrument transpose
  888.         lsl.b    #1,d4        ;shift to make index for UWORD
  889.         movea.l    trk_periodtbl(a5),a1
  890.         move.w    0(a1,d4.w),d5
  891.         bra.w    newvals
  892. ;    **************************************** Effect 0D/0A ***
  893. fx_0a:
  894. fx_0d:        move.b    d4,d1
  895.         move.b    trk_prevvol(a5),d0    ;move previous vol to d0
  896.         and.b    #$f0,d1
  897.         bne.s    crescendo
  898.         sub.b    d4,d0    ;sub from prev. vol
  899.         bpl.s    novolund0
  900.         moveq    #0,d0    ;volumes under zero not accepted!!!
  901. novolund0:    move.b    d0,trk_prevvol(a5)    ;put new vol back
  902.         move.b    d0,d1
  903.         bra    dispvolchng
  904. crescendo:    lsr.b    #4,d1
  905.         add.b    d1,d0
  906.         cmp.b    #64,d0
  907.         ble.s    novolover64
  908.         moveq    #64,d0
  909. novolover64:    move.b    d0,trk_prevvol(a5)
  910.         move.b    d0,d1
  911.         bra.w    dispvolchng
  912. ;    **************************************** Effect 05 ******
  913. fx_05:        move.w    trk_prevper(a5),d5 ;this is very simple: get the old period
  914.         cmp.b    #3,d3        ;and..
  915.         bge.w    newvals        ;if counter < 3
  916.         sub.w    d4,d5    ;subtract effect qualifier
  917.         bra.w    newvals
  918. ;    **************************************** Effect 03 ******
  919. fx_03:        move.w    trk_porttrgper(a5),d0    ;d0 = target period
  920.         beq.w    newvals    ;no target period specified
  921.         move.w    trk_prevper(a5),d1    ;d1 = curr. period
  922.         move.b    trk_prevportspd(a5),d4    ;get prev. speed
  923.         cmp.w    d0,d1
  924.         bhi.s    subper    ;curr. period > target period
  925.         add.w    d4,d1    ;add the period
  926.         cmp.w    d0,d1
  927.         bge.s    targreached
  928.         bra.s    targnreach
  929. subper:        sub.w    d4,d1    ;subtract
  930.         cmp.w    d0,d1    ;compare current period to target period
  931.         bhi.s    targnreach
  932. targreached:    move.w    trk_porttrgper(a5),d1 ;eventually push target period
  933.         clr.w    trk_porttrgper(a5) ;now we can forget everything
  934. targnreach:    move.w    d1,trk_prevper(a5)
  935.         move.w    d1,d5
  936.         bra.w    newvals
  937. ;    *********************************************************
  938. fx_0c:        cmp.b    #1,d3
  939.         bne.w    newvals
  940.         move.b    trk_prevvol(a5),d1
  941. dispvolchng:    bra.w    newvals
  942. ;    **************************************** Effect 04 ******
  943. fx_04:        tst.b    d4
  944.         beq.s    nonvib
  945.         move.b    d4,trk_vibrspdsz(a5)
  946. nonvib:        move.b    trk_vibroffs(a5),d0
  947.         lsr.b    #2,d0
  948.         and.w    #$1f,d0
  949.         moveq    #0,d1
  950.         lea    sinetable(pc),a0
  951.         move.b    0(a0,d0.w),d5
  952.         ext.w    d5
  953.         move.b    trk_vibrspdsz(a5),d0
  954.         and.w    #$000f,d0
  955.         muls    d0,d5
  956.         asr.w    #5,d5
  957.         add.w    trk_prevper(a5),d5
  958.         move.b    trk_vibrspdsz(a5),d0
  959.         lsr.b    #3,d0
  960.         and.b    #$3e,d0
  961.         add.b    d0,trk_vibroffs(a5)
  962.         bra.s    newvals
  963. ;    **************************************** Effect 0F ******
  964. fx_0f:        cmp.b    #$f1,d4
  965.         bne.s    no0ff1
  966.         cmp.b    #3,d3
  967.         bne.w    endl
  968.         bra.s    playfxnote
  969. no0ff1:        cmp.b    #$f2,d4
  970.         bne.s    no0ff2
  971.         cmp.b    #3,d3
  972.         bne.w    endl
  973.         bra.s    playfxnote
  974. no0ff2:        cmp.b    #$f3,d4
  975.         bne.s    no0ff3
  976.         move.b    d3,d0
  977.         and.b    #2+4,d0        ;is 2 or 4
  978.         beq.w    endl
  979. playfxnote:    move.w    d7,d0        ;track # to d0...
  980.         moveq    #0,d1
  981.         move.b    (a5),d1        ;get note # of previous note
  982.         moveq    #0,d2
  983.         move.b    trk_prevvol(a5),d2    ;get previous volume
  984.         move.w    d3,-(sp)
  985.         moveq    #0,d3
  986.         move.b    trk_previnstr(a5),d3    ;and prev. sample #
  987.         movea.l    trk_previnstra(a5),a3
  988.         bsr    _PlayNote
  989.         move.w    (sp)+,d3
  990.         bra.s    endl
  991. no0ff3:        cmp.b    #$f8,d4        ;f8 = filter off
  992.         beq.s    plr_filteroff
  993.         cmp.b    #$f9,d4        ;f9 = filter on
  994.         bne.s    endl
  995.         bclr    #1,$bfe001
  996.         bra.s    endl
  997. plr_filteroff:    bset    #1,$bfe001
  998.         bra.s    endl
  999. ;    *********************************************************
  1000. newvals:    movea.l    trk_audioaddr(a5),a1    ;get channel address
  1001.         tst.w    d5    ;now: do the effects!!!
  1002.         beq.s    plr_oldper
  1003. plr_newper:    move.w    d5,ac_per(a1)    ;push period
  1004. plr_oldper:    move.b    trk_prevvol(a5),ac_vol+1(a1)    ;get volume & push it
  1005. fx_xx:
  1006. endl:        addq.b    #1,d7    ;increment channel number
  1007.         cmp.w    numtracks(pc),d7    ;all channels done???
  1008.         blt.w    plr_loop1    ;not yet!!!
  1009. plr_endfx:    bsr    _StartDMA    ;turn on DMA
  1010. plr_exit:    movem.l    (sp)+,d2-d7/a2-a5
  1011.         rts
  1012.  
  1013. pline:        dc.w    0
  1014. pblock:        dc.w    0
  1015. pseq:        dc.w    0
  1016. pstate:        dc.w    0
  1017.  
  1018. _SetTempo:
  1019.     IFNE    CIAB
  1020.         cmp.b    #10,d0    ;If tempo <= 10, use SoundTracker tempo
  1021.         bhi.s    calctempo
  1022.         subq.b    #1,d0
  1023.         lsl.w    #1,d0
  1024.         move.w    sttempo+2(pc,d0.w),d1
  1025.         bra.s    pushtempo
  1026. calctempo:    move.l    timerdiv(pc),d1
  1027.         divu    d0,d1
  1028. pushtempo:    movea.l    craddr+4(pc),a0
  1029.         move.b    d1,(a0)        ;and set the CIA timer
  1030.         lsr.w    #8,d1
  1031.         movea.l    craddr+8(pc),a0
  1032.         move.b    d1,(a0)
  1033.     ENDC
  1034.         rts ;   vv-- These values are the SoundTracker tempos (approx.)
  1035. sttempo:    dc.w    $0f00
  1036.     IFNE    CIAB
  1037.         dc.w    2417,4833,7250,9666,12083,14500,16916,19332,21436,24163
  1038. timerdiv:    dc.l    470000    ;this value for CIA freq 709 379 Hz (PAL..)
  1039.     ENDC
  1040.  
  1041.     IFNE    MIDI
  1042. midifx:        tst.b    trk_noteoffcnt(a5)
  1043.         bmi.s    midi_nowaitoff
  1044.         subq.b    #1,trk_noteoffcnt(a5)
  1045.         bpl.s    midi_nowaitoff
  1046.         move.l    a5,a1
  1047.         move.b    trk_prevmidin(a5),d1
  1048.         beq.s    midi_nowaitoff    ;no note
  1049.         bsr.w    choff_midi
  1050. midi_nowaitoff:    cmp.b    #1,d6
  1051.         bne.s    nomidi01fx
  1052.         lea    prevmidipbend(pc),a0
  1053.         moveq    #0,d1
  1054.         move.b    trk_prevmidich(a5),d1    ;get previous midi channel
  1055.         lsl.w    #1,d1        ;UWORD index
  1056.         tst.b    d4        ;x100??
  1057.         beq.s    resetpbend
  1058.         move.w    0(a0,d1.w),d0    ;get previous pitch bend
  1059.         lsl.w    #3,d4        ;multiply bend value by 8
  1060.         add.w    d4,d0
  1061.         cmp.w    #$3fff,d0
  1062.         bls.s    bendpitch
  1063.         move.w    #$3fff,d0
  1064. bendpitch:    move.w    d0,0(a0,d1.w)    ;save current pitch bend
  1065.         lsr.b    #1,d1        ;back to UBYTE
  1066.         or.b    #$e0,d1
  1067.         lea    noteondata(pc),a0
  1068.         move.b    d1,(a0)        ;midi command & channel
  1069.         move.b    d0,1(a0)    ;lower value
  1070.         and.b    #$7f,1(a0)    ;clear bit 7
  1071.         lsr.w    #7,d0
  1072.         and.b    #$7f,d0        ;clr bit 7
  1073.         move.b    d0,2(a0)    ;higher 7 bits
  1074.         moveq    #3,d0
  1075.         bsr.w    _AddMIDIData
  1076.         bra.w    endl
  1077. nomidi01fx:    cmp.b    #2,d6
  1078.         bne.s    nomidi02fx
  1079.         lea    prevmidipbend(pc),a0
  1080.         moveq    #0,d1
  1081.         move.b    trk_prevmidich(a5),d1
  1082.         lsl.w    #1,d1
  1083.         tst.b    d4
  1084.         beq.s    resetpbend    ;x200??
  1085.         move.w    0(a0,d1.w),d0
  1086.         lsl.w    #3,d4
  1087.         sub.w    d4,d0
  1088.         bpl.s    bendpitch    ;not under 0
  1089.         moveq    #0,d0
  1090.         bra.s    bendpitch
  1091. resetpbend:    tst.b    d3        ;d3 = counter (remember??)
  1092.         bne.w    endl
  1093.         move.w    #$2000,d0
  1094.         bra.s    bendpitch
  1095. nomidi02fx:    cmp.b    #$04,d6
  1096.         bne.s    nomidi04fx
  1097.         moveq    #$01,d0
  1098.         bra.s    pushctrldata
  1099. nomidi04fx:    cmp.b    #$0e,d6        ;with MIDI, this is "pan", when
  1100.         bne.s    nomidi0efx    ;values are 0 - $7f
  1101.         moveq    #$0a,d0
  1102. pushctrldata:    tst.b    d3        ;do it only once in a note
  1103.         bne.w    endl        ;(when counter = 0)
  1104.         lea    noteondata(pc),a0 ;push "control change" data,
  1105.         move.b    trk_prevmidich(a5),(a0)      ;d0 = 1. databyte, d4 = 2. db
  1106.         or.b    #$b0,(a0)
  1107.         move.b    d0,1(a0)
  1108.         move.b    d4,2(a0)
  1109.         bmi.w    endl    ;I said 0 - $7f!!! (for future compatibility)
  1110.         moveq    #3,d0
  1111.         bsr.w    _AddMIDIData
  1112.         bra.w    endl
  1113. nomidi0efx:    cmp.b    #$0f,d6
  1114.         bne.w    endl
  1115.         cmp.b    #$fa,d4        ;hold pedal ON
  1116.         bne.s    nomffa
  1117.         moveq    #$40,d0
  1118.         moveq    #$7f,d4
  1119.         bra.s    pushctrldata
  1120. nomffa:        cmp.b    #$fb,d4        ;hold pedal OFF
  1121.         bne.s    nomffb
  1122.         moveq    #$40,d0
  1123.         moveq    #$00,d4
  1124.         bra.s    pushctrldata
  1125. nomffb:        bra.w    fx_0f
  1126.  
  1127. _ResetMIDI:    movem.l    d2/a2,-(sp)
  1128.         lea    prevmidicpres(pc),a0
  1129.         clr.l    (a0)+    ;force presets to be set again
  1130.         clr.l    (a0)+    ;(clear prev. preset numbers)
  1131.         clr.l    (a0)+
  1132.         clr.l    (a0)+
  1133.         clr.b    lastcmdbyte
  1134.         lea    midiresd(pc),a2
  1135.         move.b    #$e0,(a2)    ;reset pitchbenders & mod. wheel
  1136.         move.b    #$b0,3(a2)
  1137.         moveq    #15,d2
  1138. respbendl:    movea.l    a2,a0
  1139.         moveq    #6,d0
  1140.         bsr.w    _AddMIDIData
  1141.         addq.b    #1,(a2)
  1142.         addq.b    #1,3(a2)
  1143.         dbf    d2,respbendl
  1144.         lea    prevmidipbend(pc),a2
  1145.         moveq    #15,d2
  1146. resprevpbends:    move.w    #$2000,(a2)+
  1147.         dbf    d2,resprevpbends
  1148.         movem.l    (sp)+,d2/a2
  1149.         rts
  1150. midiresd:    dc.b    $e0,$00,$40,$b0,$01,$00
  1151.     ENDC
  1152.  
  1153. getinsdata:    moveq    #0,d2
  1154.     IFNE    IFF53
  1155.         move.w    4(a0),d0    ;Soitin-struct in a0
  1156.         bne.s    iff5or3oct    ;note # in d1 (0 - ...)
  1157.     ENDC
  1158.         move.l    a0,d0
  1159.         lea    _periods(pc),a0
  1160.         move.l    a0,trk_periodtbl(a5)
  1161.         lsl.b    #1,d1
  1162.         move.w    0(a0,d1.w),d5 ;put period to d5
  1163.         move.l    d0,a0
  1164.         addq.l    #6,d0        ;Skip structure
  1165.         move.l    (a0),d1        ;length
  1166.         move.w    (a3),d2
  1167.         move.w    2(a3),d3
  1168.         rts
  1169.     IFNE    IFF53
  1170. iff5or3oct:    movem.l    d6-d7,-(sp)
  1171.         moveq    #0,d7
  1172.         move.w    d1,d7
  1173.         divu    #12,d7    ;octave #
  1174.         move.l    d7,d5
  1175.         swap    d5    ;note number in this oct (0-11) is in d5
  1176.         move.l    (a0),d1
  1177.         cmp.b    #2,d0
  1178.         bne.s    no3oct
  1179.         addq.l    #6,d7
  1180.         divu    #7,d1    ;get length of the 1st octave
  1181.         bra.s    no5oct
  1182. no3oct:        divu    #31,d1    ;get length of the 1st octave (5 octaves)
  1183. no5oct:        move.l    d1,d0        ;d0 and d1 = length of the 1st oct
  1184.         move.w    (a3),d2
  1185.         move.w    2(a3),d3
  1186.         moveq    #0,d6
  1187.         move.b    shiftcnt(pc,d7.w),d6
  1188.         lsl.w    d6,d2
  1189.         lsl.w    d6,d3
  1190.         lsl.w    d6,d1
  1191.         move.b    mullencnt(pc,d7.w),d6
  1192.         mulu    d6,d0        ;offset of this oct from 1st oct
  1193.         add.l    a0,d0        ;add base address to offset
  1194.         addq.l    #6,d0        ;skip structure
  1195.         lea    _periods(pc),a1
  1196.         add.b    octstart(pc,d7.w),d5
  1197.         lsl.b    #1,d5
  1198.         move.w    0(a1,d5.w),d5
  1199.         movem.l    (sp)+,d6-d7
  1200.         rts    ;returns period in d5
  1201. shiftcnt:    dc.b    4,3,2,1,1,0,2,2,1,1,0,0
  1202. mullencnt:    dc.b    15,7,3,1,1,0,3,3,1,1,0,0
  1203. octstart:    dc.b    12,12,12,12,24,24,0,12,12,24,24,36
  1204.     ENDC
  1205.  
  1206. ; *************************************************************************
  1207. ; *************************************************************************
  1208. ; ***********          P U B L I C   F U N C T I O N S          ***********
  1209. ; *************************************************************************
  1210. ; *************************************************************************
  1211.  
  1212.         xdef    _InitModule,_PlayModule,_PlayModule2
  1213.         xdef    _InitPlayer,_RemPlayer,_StopPlayer
  1214.         xdef    _SetTempo
  1215.  
  1216. ; *************************************************************************
  1217. ; InitModule(a0 = module) -- extract expansion data etc.. from V3.00 module
  1218. ; *************************************************************************
  1219.  
  1220. _InitModule:    movem.l    a2-a3/d2,-(sp)
  1221.         move.l    a0,d0
  1222.         beq.s    IM_exit        ;0 => xit
  1223.     IFNE    RELVOL
  1224.         movea.l    8(a0),a1    ;MMD0song
  1225.         move.b    786(a1),d0    ;d0 = mastervol
  1226.         ext.w    d0
  1227.         lea    770(a1),a1    ;a1 = trkvol
  1228.         lea    trackdataptrs(pc),a2
  1229.         moveq    #15,d1
  1230. IM_loop0    move.b    (a1)+,d2    ;get vol...
  1231.         ext.w    d2
  1232.         move.l    (a2)+,a3    ;pointer to track data
  1233.         mulu    d0,d2        ;mastervol * trackvol
  1234.         lsr.w    #4,d2
  1235.         move.w    d2,trk_trackvol(a3)
  1236.         dbf    d1,IM_loop0
  1237.     ENDC
  1238.         lea    holdvals(pc),a2
  1239.         move.l    32(a0),d0    ;expdata...
  1240.         beq.s    IM_clrhlddec    ;none here
  1241.         move.l    d0,a1
  1242.         move.l    4(a1),d0    ;exp_smp
  1243.         beq.s    IM_clrhlddec    ;again.. nothing
  1244.         move.l    d0,a0        ;InstrExt...
  1245.         move.w    8(a1),d2    ;# of entries
  1246.         beq.s    IM_clrhlddec
  1247.         subq.w    #1,d2        ;- 1 (for dbf)
  1248.         move.w    10(a1),d0    ;entry size
  1249. IM_loop1    move.b    1(a0),63(a2)    ;InstrExt.decay ->decay
  1250.         move.b    (a0),(a2)+    ;InstrExt.hold -> holdvals
  1251.         adda.w    d0,a0        ;ptr to next InstrExt
  1252.         dbf    d2,IM_loop1
  1253.         bra.s    IM_exit
  1254. IM_clrhlddec    moveq    #62,d0        ;no InstrExt => clear holdvals/decays
  1255. IM_loop2    clr.w    (a2)+
  1256.         dbf    d0,IM_loop2
  1257. IM_exit        movem.l    (sp)+,a2-a3/d2
  1258.         rts
  1259. ; *************************************************************************
  1260. ; InitPlayer() -- allocate interrupt, audio, serial port etc...
  1261. ; *************************************************************************
  1262. _InitPlayer:
  1263.     IFNE    MIDI
  1264.         bsr.w    _GetSerial
  1265.         tst.l    d0
  1266.         bne.s    IP_error
  1267.     ENDC
  1268.         bsr.w    _AudioInit
  1269.         tst.l    d0
  1270.         bne.s    IP_error
  1271.         moveq    #33,d0
  1272.         bsr.w    _SetTempo    ;set default tempo
  1273.         moveq    #0,d0
  1274.         rts
  1275. IP_error    bsr.w    _RemPlayer
  1276.         moveq    #-1,d0
  1277.         rts
  1278. ; *************************************************************************
  1279. ; RemPlayer() -- free interrupt, audio, serial port etc..
  1280. ; *************************************************************************
  1281. _RemPlayer:    move.b    _timeropen(pc),d0
  1282.         beq.s    RP_notimer    ;timer is not ours
  1283.         bsr.s    _StopPlayer
  1284. RP_notimer:    bsr.w    _AudioRem
  1285.     IFNE    MIDI
  1286.         bsr.w    _FreeSerial
  1287.     ENDC
  1288.         rts
  1289. ; *************************************************************************
  1290. ; PlayModule(a0 = module)  -- initialize & play it!!
  1291. ; PlayModule2(a0 = module) -- play module (must be initialized)
  1292. ; *************************************************************************
  1293. _PlayModule:    move.l    a0,-(sp)
  1294.         bsr    _InitModule
  1295.         move.l    (sp)+,a0
  1296. _PlayModule2:    move.b    _timeropen(pc),d0
  1297.         beq.s    PM_end        ;resource allocation failure
  1298.         move.l    a0,d0
  1299.         beq.s    PM_end        ;module failure
  1300.     IFNE    CIAB
  1301.         movea.l    craddr(pc),a1
  1302.         bclr    #0,(a1)        ;stop timer...
  1303.     ENDC
  1304.         clr.l    _module
  1305.     IFNE    MIDI
  1306.         clr.b    lastcmdbyte
  1307.     ENDC
  1308.         move.l    a0,-(sp)
  1309.         movea.l    8(a0),a0    ;song
  1310.         move.b    769(a0),_counter    ;init counter
  1311.         btst    #0,767(a0)
  1312.         bne.s    PM_filon
  1313.         bset    #1,$bfe001
  1314.         bra.s    PM_filset
  1315. PM_filon    bclr    #1,$bfe001
  1316. PM_filset    move.w    764(a0),d0    ;get default tempo
  1317.         moveq    #0,d1
  1318.         move.b    508(a0),d1    ;get first playseq entry
  1319.         lea    pline(pc),a0    ;clear pline etc..
  1320.         move.l    d1,(a0)+
  1321.         moveq    #2,d1
  1322.         move.l    d1,(a0)        ;pstate = 2 (play song)
  1323.         move.l    (sp)+,_module
  1324.     IFNE    CIAB
  1325.         bsr.w    _SetTempo    ;set default tempo
  1326.         bset    #0,(a1)        ;start timer => PLAY!!
  1327.     ENDC
  1328. PM_end        rts
  1329. ; *************************************************************************
  1330. ; StopPlayer() -- stop music
  1331. ; *************************************************************************
  1332. _StopPlayer:    move.b    _timeropen(pc),d0
  1333.         beq.s    SP_end        ;res. alloc fail.
  1334.     IFNE    CIAB
  1335.         movea.l    craddr(pc),a0
  1336.         bclr    #0,(a0)        ;stop timer
  1337.     ENDC
  1338.         clr.w    pstate
  1339.     IFNE    MIDI
  1340.         clr.b    lastcmdbyte
  1341.     ENDC
  1342.         bsr.w    SoundOff
  1343. SP_end        rts
  1344. ; *************************************************************************
  1345.  
  1346.  
  1347. _AudioInit:    movem.l    a4/a6/d2-d3,-(sp)
  1348.         moveq    #0,d2
  1349.         movea.l    4,a6
  1350. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ alloc signal bit
  1351.     IFNE    AUDDEV
  1352.         addq.l    #1,d2
  1353.         moveq    #-1,d0
  1354.         jsr    -$14a(a6)    ;AllocSignal()
  1355.         tst.b    d0
  1356.         bmi.w    initerr
  1357.         move.b    d0,sigbitnum
  1358. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ prepare IORequest
  1359.         lea    allocport(pc),a1
  1360.         move.b    d0,15(a1)    ;set mp_SigBit
  1361.         move.l    a1,-(sp)
  1362.         suba.l    a1,a1
  1363.         jsr    -$126(a6)    ;FindTask(0)
  1364.         move.l    (sp)+,a1
  1365.         move.l    d0,16(a1)    ;set mp_SigTask
  1366.         lea    reqlist(pc),a0
  1367.         move.l    a0,(a0)        ;NEWLIST begins...
  1368.         addq.l    #4,(a0)
  1369.         clr.l    4(a0)
  1370.         move.l    a0,8(a0)    ;NEWLIST ends...
  1371. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ open audio.device
  1372.         addq.l    #1,d2
  1373.         lea    allocreq(pc),a1
  1374.         lea    audiodevname(pc),a0
  1375.         moveq    #0,d0
  1376.         moveq    #0,d1
  1377.         jsr    -$1bc(a6)    ;OpenDevice()
  1378.         tst.b    d0
  1379.         bne.w    initerr
  1380.         st.b    audiodevopen
  1381. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ open ciaa.resource
  1382.         addq.l    #1,d2
  1383.     ENDC
  1384.     IFNE    CIAB
  1385.         cmp.b    #50,$212(a6)    ;ExecBase->VBlankFrequency
  1386.         beq.s    init_pal
  1387.         move.l    #474326,timerdiv ;Assume that CIA freq is 715 909 Hz
  1388. init_pal:    moveq    #0,d0
  1389.         lea    ciabname(pc),a1
  1390.         jsr    -$1f2(a6)    ;OpenResource()
  1391.         tst.l    d0
  1392.         beq.s    initerr
  1393.         move.l    d0,_ciaresource
  1394. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ attach interrupt
  1395.         addq.l    #1,d2
  1396.         moveq    #2,d3
  1397.         lea    craddr(pc),a4
  1398.         move.l    #$bfdf00,(a4)+    ;Initialize Timer B addresses
  1399.         move.l    #$bfd600,(a4)+
  1400.         move.l    #$bfd700,(a4)
  1401.         move.l    d0,a6
  1402.         lea    timerinterrupt(pc),a1    ;Attempt to get timer B
  1403.         clr.l    -4(a1)            ;clear module pointer
  1404.         moveq    #1,d0    ;Bit number 1: Timer B
  1405.         jsr    -$6(a6)    ;AddICRVector
  1406.         tst.l    d0
  1407.         beq.s    gotTimerB        ;succeeded!!
  1408.         moveq    #1,d3
  1409.         lea    timerinterrupt(pc),a1    ;no. Get timer A then...
  1410.         moveq    #0,d0    ;Bit number 0: Timer A
  1411.         jsr    -$6(a6)
  1412.         tst.l    d0
  1413.         bne.s    initerr
  1414.         move.l    #$bfd500,(a4)        ;Set Timer A addresses
  1415.         move.l    #$bfd400,-(a4)
  1416.         move.l    #$bfde00,-(a4)
  1417. gotTimerB:    movea.l    craddr(pc),a0    ;get Control Register address
  1418.         and.b    #%10000000,(a0) ;clear CtrlReg bits 0 - 6
  1419.         move.b    d3,_timeropen    ;d3: 1 = TimerA 2 = TimerB
  1420.     ENDC
  1421.     IFNE    VBLANK
  1422.         moveq    #5,d0        ;INTB_VERTB
  1423.         lea    timerinterrupt(pc),a1
  1424.         jsr    -$a8(a6)    ;AddIntServer
  1425.         st    _timeropen
  1426.     ENDC
  1427.         clr.w    pstate
  1428.         moveq    #0,d0
  1429. initret:    movem.l    (sp)+,a4/a6/d2-d3
  1430.         rts
  1431. initerr:    move.l    d2,d0
  1432.         bra.s    initret
  1433.  
  1434. _AudioRem:    move.l    a6,-(sp)
  1435.         moveq    #0,d0
  1436.         lea    _timeropen(pc),a0
  1437.         move.b    (a0),d0
  1438.         beq.s    rem1
  1439. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ remove interrupt
  1440.         clr.b    (a0)
  1441.     IFNE    CIAB
  1442.         move.l    _ciaresource(pc),a6
  1443.         lea    timerinterrupt(pc),a1
  1444.         subq.b    #1,d0
  1445.         jsr    -$c(a6)        ;RemICRVector
  1446.     ENDC
  1447.     IFNE    VBLANK
  1448.         movea.l    4,a6
  1449.         lea    timerinterrupt(pc),a1
  1450.         moveq    #5,d0
  1451.         jsr    -$ae(a6)    ;RemIntServer
  1452.     ENDC
  1453. rem1:    
  1454.     IFNE    AUDDEV
  1455.         movea.l    4,a6
  1456.         lea    audiodevopen(pc),a0
  1457.         tst.b    (a0)
  1458.         beq.s    rem2
  1459.         move.w    #$000f,$dff096    ;stop audio DMA
  1460. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ close audio.device
  1461.         clr.b    (a0)
  1462.         lea    allocreq(pc),a1
  1463.         jsr    -$1c2(a6)    ;CloseDevice()
  1464. rem2:        moveq    #0,d0
  1465.         move.b    sigbitnum(pc),d0
  1466.         bmi.s    rem3
  1467. ;    +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ free signal bit
  1468.         jsr    -$150(a6)    ;FreeSignal()
  1469.     ENDC
  1470. rem3:        move.l    (sp)+,a6
  1471.         rts
  1472.  
  1473.     IFNE    MIDI
  1474. _GetSerial:    move.l    a6,-(sp)    ;Get serial port for MIDI
  1475.         bsr.s    GetSer2
  1476.         tst.l    d0        ;got the port??
  1477.         beq.s    rgser        ;yes
  1478.         movea.l    4,a6        ;no..try to flush serial.device:
  1479.         jsr    -$84(a6)        ;Forbid
  1480.         lea    $15e(a6),a0        ;ExecBase->DeviceList
  1481.         lea    serdev(pc),a1        ;"serial.device"
  1482.         jsr    -$114(a6)        ;FindName
  1483.         tst.l    d0
  1484.         beq.s    serdnotf        ;no serial.device!!
  1485.         move.l    d0,a1
  1486.         jsr    -$1b6(a6)        ;RemDevice
  1487. serdnotf:    jsr    -$8a(a6)        ;and Permit
  1488.         bsr.s    GetSer2        ;now try it again...
  1489. rgser:        move.l    (sp)+,a6
  1490.         rts
  1491.  
  1492. GetSer2:    movea.l    4,a6
  1493.         moveq    #0,d0
  1494.         lea    miscresname(pc),a1
  1495.         jsr    -$1f2(a6)    ;OpenResource()
  1496.         move.l    d0,miscresbase
  1497.         tst.l    d0
  1498.         beq.s    gserror
  1499.         move.l    d0,a6
  1500.         lea    medname(pc),a1
  1501.         moveq    #0,d0        ;serial port
  1502.         jsr    -$6(a6)        ;AllocMiscResource()
  1503.         tst.l    d0
  1504.         bne.s    gserror
  1505.         st.b    serportalloc
  1506.         clr.w    intrson
  1507.         move.w    $dff01c,d0
  1508.         btst    #0,d0
  1509.         sne    intrson
  1510.         moveq    #0,d0        ;TBE
  1511.         lea    serinterrupt(pc),a1
  1512.         move.l    4,a6
  1513.         jsr    -$a2(a6)    ;SetIntVector()
  1514.         move.l    d0,prevtbe
  1515.         move.w    #$8001,$dff09a    ;TBE on!!
  1516.         move.w    #114,$dff032    ;set baud rate (SERPER)
  1517.         moveq    #0,d0
  1518.         rts
  1519. gserror:    moveq    #-1,d0
  1520.         rts
  1521.  
  1522. intrson:    dc.b    0,0
  1523.  
  1524. _FreeSerial:    move.l    a6,-(sp)
  1525.         tst.l    miscresbase
  1526.         beq.s    retfs
  1527.         tst.b    serportalloc
  1528.         beq.s    retfs
  1529.         move.w    #$0001,$dff09a    ;disable TBE
  1530.         movea.l    prevtbe(pc),a1
  1531.         moveq    #0,d0
  1532.         movea.l    4,a6
  1533.         jsr    -$a2(a6)    ;SetIntVector()
  1534.         tst.b    intrson
  1535.         beq.s    nofsstbe
  1536.         move.w    #$8001,$dff09a
  1537. nofsstbe:    movea.l    miscresbase(pc),a6
  1538.         moveq    #0,d0        ;serial port
  1539.         jsr    -$c(a6)        ;FreeMiscResource()
  1540.         clr.b    serportalloc
  1541.         clr.b    lastcmdbyte
  1542. retfs:        move.l    (sp)+,a6
  1543.         rts
  1544.  
  1545. prevtbe:    dc.l    0
  1546.  
  1547. SerIntHandler:    move.w    #$4000,$9a(a0)    ;disable...
  1548.         addq.b    #1,$126(a6)
  1549.         move.w    #1,$9c(a0)    ;clear intreq bit
  1550.         move.b    bytesinbuff(pc),d0
  1551.         beq.s    exsih        ;buffer empty
  1552.         movea.l    4(a1),a5    ;get buffer read pointer
  1553.         move.w    #$100,d1    ;Stop bit
  1554.         move.b    (a5),d1        ;get byte
  1555.         move.w    d1,$30(a0)    ;and push it out!! (SERDAT)
  1556.         addq.l    #1,a5        ;add 1
  1557.         cmpa.l    a1,a5        ;shall we reset ptr??
  1558.         bne.s    norrbuffptr    ;not yet..
  1559.         lea    sendbuffer(pc),a5
  1560. norrbuffptr:    subq.b    #1,d0        ;one less bytes in buffer
  1561.         move.b    d0,bytesinbuff    ;remember it
  1562.         move.l    a5,4(a1)    ;push new read pointer back
  1563. exsih:        subq.b    #1,$126(a6)
  1564.         bge.s    exsih0
  1565.         move.w    #$c000,$9a(a0)
  1566. exsih0:        rts
  1567.  
  1568. _AddMIDIData:    tst.b    serportalloc
  1569.         beq.s    retamd
  1570.         movem.l    a2/a6,-(sp)
  1571.         movea.l    4,a6
  1572.         move.w    #$4000,$dff09a    ;Disable interrupts
  1573.         addq.b    #1,$126(a6)    ;ExecBase->IDNestCnt
  1574.         move.b    bytesinbuff(pc),d1
  1575.         bne.s    noTBEreq
  1576.         move.w    #$8001,$dff09c    ;request TBE
  1577. noTBEreq:    lea    buffptr(pc),a2    ;end of buffer (ptr)
  1578.         movea.l    (a2),a1        ;buffer pointer
  1579. adddataloop:    move.b    (a0)+,d1    ;get byte
  1580.         bpl.s    norscheck    ;this isn't a status byte
  1581.         cmp.b    #$ef,d1        ;forget system messages
  1582.         bhi.s    norscheck
  1583.         cmp.b    lastcmdbyte(pc),d1 ;same as previos status byte??
  1584.         beq.s    samesb        ;yes, skip
  1585.         move.b    d1,lastcmdbyte    ;no, don't skip but remember!!
  1586. norscheck:    move.b    d1,(a1)+    ;push it to midi send buffer
  1587.         addq.b    #1,bytesinbuff
  1588. samesb:        cmpa.l    a2,a1    ;end of buffer??
  1589.         bne.s    noresbuffptr    ;no, no!!
  1590.         lea    sendbuffer(pc),a1 ;better reset it to avoid trashing
  1591. noresbuffptr:    subq.b    #1,d0
  1592.         bne.s    adddataloop
  1593.         move.l    a1,(a2)        ;push new buffer ptr back
  1594. overflow:    subq.b    #1,$126(a6)
  1595.         bge.s    retamd1
  1596.         move.w    #$c000,$dff09a    ;enable interrupts again
  1597. retamd1:    movem.l    (sp)+,a2/a6
  1598. retamd:        rts
  1599. sendbuffer:    ds.b    128
  1600. buffptr:    dc.l    sendbuffer
  1601. readbuffptr:    dc.l    sendbuffer
  1602. miscresbase:    dc.l    0
  1603. lastcmdbyte:    dc.b    0
  1604.     ENDC
  1605.         even
  1606.     IFNE    MIDI
  1607. preschgdata:    dc.b    0,0
  1608. noteondata:    dc.l    0
  1609. serportalloc:    dc.b    0
  1610. bytesinbuff:    dc.b    0
  1611.     ENDC
  1612.     IFNE    AUDDEV
  1613. audiodevopen:    dc.b    0
  1614. sigbitnum:    dc.b    -1
  1615.     ENDC
  1616. _timeropen:    dc.b    0
  1617.         even
  1618.     IFNE    CIAB
  1619. _ciaresource:    dc.l    0
  1620. craddr:        dc.l    0
  1621.         dc.l    0    ;tloaddr
  1622.         dc.l    0    ;thiaddr
  1623.     ENDC
  1624. _module:    dc.l    0
  1625. timerinterrupt:    dc.w    0,0,0,0,0
  1626.         dc.l    timerintname,0,_IntHandler
  1627.     IFNE    MIDI
  1628. serinterrupt:    dc.w    0,0,0,0,0
  1629.         dc.l    serintname,buffptr,SerIntHandler
  1630.     ENDC
  1631.     IFNE    AUDDEV
  1632. allocport:    dc.l    0,0    ;succ, pred
  1633.         dc.b    4,0    ;NT_MSGPORT
  1634.         dc.l    0    ;name
  1635.         dc.b    0,0    ;flags = PA_SIGNAL
  1636.         dc.l    0    ;task
  1637. reqlist:    dc.l    0,0,0    ;list head, tail and tailpred
  1638.         dc.b    5,0
  1639. allocreq:    dc.l    0,0
  1640.         dc.b    5,127    ;NT_MESSAGE, use maximum priority (127)
  1641.         dc.l    0,allocport    ;name, replyport
  1642.         dc.w    68        ;length
  1643.         dc.l    0    ;io_Device
  1644.         dc.l    0    ;io_Unit
  1645.         dc.w    0    ;io_Command
  1646.         dc.b    0,0    ;io_Flags, io_Error
  1647.         dc.w    0    ;ioa_AllocKey
  1648.         dc.l    sttempo    ;ioa_Data
  1649.         dc.l    1    ;ioa_Length
  1650.         dc.w    0,0,0    ;ioa_Period, Volume, Cycles
  1651.         dc.w    0,0,0,0,0,0,0,0,0,0    ;ioa_WriteMsg
  1652. audiodevname:    dc.b    'audio.device',0
  1653.     ENDC
  1654.     IFNE    CIAB
  1655. ciabname:    dc.b    'ciab.resource',0
  1656.     ENDC
  1657. timerintname:    dc.b    'MEDTimerInterrupt',0
  1658.     IFNE    MIDI
  1659. serintname:    dc.b    'MEDSerialInterrupt',0
  1660.     ENDC
  1661.     IFNE    MIDI
  1662. miscresname:    dc.b    'misc.resource',0
  1663. serdev:        dc.b    'serial.device',0
  1664.     ENDC
  1665. medname:    dc.b    'MED - Player routine',0 ;yeah, our name
  1666.         even
  1667.     IFNE    SYNTH
  1668. _synthper:    dc.w 3424,3232,3048,2880,2712,2560,2416,2280,2152,2032
  1669.         dc.w 1920,1812,1712,1616,1524,1440,1356,1280,1208,1140
  1670.         dc.w 1076,1016,960,906
  1671.     ENDC
  1672. _periods:    dc.w 856,808,762,720,678,640,604,570,538,508,480,453
  1673.         dc.w 428,404,381,360,339,320,302,285,269,254,240,226
  1674.         dc.w 214,202,190,180,170,160,151,143,135,127,120,113
  1675.         dc.w 214,202,190,180,170,160,151,143,135,127,120,113
  1676.         dc.w 214,202,190,180,170,160,151,143,135,127,120,113
  1677.         dc.w 214,202,190,180,170,160,151,143,135,127,120,113
  1678.  
  1679. holdvals:    ds.b 63
  1680. decays:        ds.b 63
  1681.  
  1682.     IFND    __G2
  1683.         section "datachip",data,chip ;for A68k
  1684.     ENDC
  1685.     IFD    __G2
  1686.         section "datachip",data_c ;this is for Devpac 2
  1687.     ENDC
  1688. _chipzero:    dc.l    0
  1689.  
  1690. ; the track-data structure definition:
  1691. trk_prevnote    equ    0    ;previous note number
  1692. trk_previnstr    equ    1    ;previous instrument number
  1693. trk_prevvol    equ    2    ;previous volume
  1694. trk_prevmidich    equ    3    ;previous MIDI channel
  1695. trk_cmd        equ    4    ;command (the 3rd number from right)
  1696. trk_cmdqual    equ    5    ;command qualifier (infobyte, databyte..)
  1697. trk_prevmidin    equ    6    ;previous MIDI note
  1698. trk_noteoffcnt    equ    7    ;note-off counter (hold)
  1699. trk_inithold    equ    8    ;default hold for this instrument
  1700. trk_initdecay    equ    9    ;default decay for....
  1701. trk_stransp    equ    10    ;instrument transpose
  1702. trk_pad        equ    11
  1703. trk_previnstra    equ    12    ;address of the previous instrument data
  1704. trk_trackvol    equ    16    ;relative volume of track (premultiplied)
  1705. ;    the following data only on tracks 0 - 3
  1706. trk_prevper    equ    18    ;previous period
  1707. trk_audioaddr    equ    20    ;hardware audio channel base address
  1708. trk_sampleptr    equ    24    ;pointer to sample
  1709. trk_samplelen    equ    28    ;length (>> 1)
  1710. trk_porttrgper    equ    30    ;portamento (cmd 3) target period
  1711. trk_vibroffs    equ    32    ;vibrato table offset
  1712. trk_vibrspdsz    equ    33    ;vibrato speed/size (cmd 4 qualifier)
  1713. trk_synthptr    equ    34    ;pointer to synthetic/hybrid instrument
  1714. trk_arpgoffs    equ    38    ;SYNTH: current arpeggio offset
  1715. trk_arpsoffs    equ    40    ;SYNTH: arpeggio restart offset
  1716. trk_volxcnt    equ    42    ;SYNTH: volume execute counter
  1717. trk_wfxcnt    equ    43    ;SYNTH: waveform execute counter
  1718. trk_volcmd    equ    44    ;SYNTH: volume command pointer
  1719. trk_wfcmd    equ    46    ;SYNTH: waveform command pointer
  1720. trk_volwait    equ    48    ;SYNTH: counter for WAI (volume list)
  1721. trk_wfwait    equ    49    ;SYNTH: counter for WAI (waveform list)
  1722. trk_synthvibspd    equ    50    ;SYNTH: vibrato speed
  1723. trk_wfchgspd    equ    52    ;SYNTH: period change
  1724. trk_volchgspd    equ    54    ;SYNTH: volume change
  1725. trk_prevnote2    equ    55    ;SYNTH: previous note
  1726. trk_initvolxspd    equ    56    ;SYNTH: volume execute speed
  1727. trk_initwfxspd    equ    57    ;SYNTH: waveform execute speed
  1728. trk_perchg    equ    58    ;SYNTH: curr. period change from trk_prevper
  1729. trk_synviboffs    equ    60    ;SYNTH: vibrato pointer
  1730. trk_synvibdep    equ    62    ;SYNTH: vibrato depth
  1731. trk_synvol    equ    64    ;SYNTH: current volume
  1732. trk_pad2    equ    65
  1733. trk_periodtbl    equ    66    ;pointer to period table
  1734. trk_prevportspd    equ    70    ;portamento (cmd 3) speed
  1735. trk_decay    equ    72    ;decay
  1736. trk_fadespd    equ    73    ;decay speed
  1737.         end
  1738.