home *** CD-ROM | disk | FTP | other *** search
/ Da Capo / da_capo_vol1.bin / programs / amiga / edit / octamedv2 / programmers / modplayer / modplayer.a < prev    next >
Text File  |  1993-03-13  |  58KB  |  2,103 lines

  1. ;    modplayer.a
  2. ;    ~~~~~~~~~~~
  3. ; The music player routine for OctaMED V2.00 four channel/MIDI songs.
  4. ; Written by Teijo Kinnunen.
  5.  
  6. ;============================================================================
  7.  
  8. MIDI    EQU    0    ;1 = include MIDI code
  9. AUDDEV    EQU    1    ;1 = allocate channels using audio.device
  10. SYNTH    EQU    1    ;1 = include synth-sound handler
  11. CHECK    EQU    1    ;1 = do range checkings (track, sample in mem etc.)
  12. RELVOL    EQU    1    ;1 = include relative volume handling code
  13. IFF53    EQU    1    ;1 = play IFF 3- and 5-octave samples correctly
  14. HOLD    EQU    1    ;1 = handle hold/decay
  15. ;****** Timing control ******
  16. VBLANK    EQU    0    ;1 = use VBlank interrupt (when absolutely necessary)
  17. CIAB    EQU    1    ;1 = use CIAB timers (default)
  18. ; Please use CIAB whenever possible to avoid problems with variable
  19. ; VBlank speeds and to allow the use of command F01 - FF0 (set tempo)
  20. ; If both are set to 0, the timing is left for you (never set both to 1!!),
  21. ; then you just call _IntHandler for each timing pulse.
  22.  
  23. ;============================================================================
  24.  
  25. ;If you are making a demo/game with only a single tune you'd like to
  26. ;incorporate in the code (like "easyplayer.a" of MED V3), set the following
  27. ;flag to 1. This requires an assembler with INCBIN (or equivalent) directive.
  28. ;You have to type the module name into the INCBIN statement (located near the
  29. ;end of this file, on line 2045).
  30.  
  31. EASY    EQU    0
  32.  
  33. ;Call _startmusic to play the music, and _endmusic to stop it (before
  34. ;exiting). Note: don't call _startmusic twice!! This would cause the module
  35. ;to be relocated twice (= Guru). If you need to stop and continue playing,
  36. ;don't use the EASY routines, use PlayModule/StopPlayer... instead.
  37.  
  38. ;============================================================================
  39.  
  40. ;the MMD0 structure offsets
  41. mmd_id        EQU    0
  42. mmd_modlen    EQU    4
  43. mmd_songinfo    EQU    8
  44. mmd_songlen    EQU    12    ;currently unused
  45. mmd_blockarr    EQU    16
  46. mmd_blockarrlen    EQU    20
  47. mmd_smplarr    EQU    24
  48. mmd_smplarrlen    EQU    28
  49. mmd_expdata    EQU    32
  50. mmd_expsize    EQU    36
  51. mmd_pstate    EQU    40 ; <0 = play song, 0 = don't play, >0 = play block
  52. mmd_pblock    EQU    42
  53. mmd_pline    EQU    44
  54. mmd_pseqnum    EQU    46
  55. mmd_actplayline    EQU    48
  56. mmd_counter    EQU    50
  57. mmd_songsleft    EQU    51
  58.  
  59. ;the MMD0song structure
  60. ;Instrument data here (504 bytes = 63 * 8)
  61. msng_numblocks    EQU    504
  62. msng_songlen    EQU    506
  63. msng_playseq    EQU    508
  64. msng_deftempo    EQU    764
  65. msng_playtransp    EQU    766
  66. msng_flags    EQU    767
  67. msng_reserved    EQU    768
  68. msng_tempo2    EQU    769
  69. msng_trkvol    EQU    770
  70. msng_mastervol    EQU    786
  71. msng_numsamples    EQU    787
  72.  
  73. ;Instrument data
  74. inst_repeat    EQU    0
  75. inst_replen    EQU    2
  76. inst_midich    EQU    4
  77. inst_midipreset    EQU    5
  78. inst_svol    EQU    6
  79. inst_strans    EQU    7
  80.  
  81. ;Audio hardware offsets
  82. ac_ptr    EQU    $00
  83. ac_len    EQU    $04
  84. ac_per    EQU    $06
  85. ac_vol    EQU    $08
  86.  
  87. ;Trackdata sizes
  88. T03SZ    EQU    88
  89. T415SZ    EQU    18
  90.  
  91.         section    "text",code
  92.  
  93.     IFNE    EASY
  94.  
  95.         xdef    _startmusic,_endmusic
  96.  
  97. _startmusic    lea    easymod,a0
  98.         bsr.w    _RelocModule
  99.         bsr.w    _InitPlayer
  100.         lea    easymod,a0
  101.         bra.w    _PlayModule
  102.  
  103. _endmusic    bra.w    _RemPlayer
  104.     ENDC
  105.  
  106.  
  107.  
  108. _ChannelOff:    ;d0 = channel #
  109.         lea    trackdataptrs(pc),a1
  110.         lsl.b    #2,d0
  111.         adda.w    d0,a1
  112.         lsr.b    #2,d0
  113.         movea.l    (a1),a1
  114.     IFNE    MIDI
  115.         move.b    trk_prevmidin(a1),d1    ;is it MIDI??
  116.         beq.s    notcomidi        ;not a MIDI note
  117. choff_midi:    clr.b    trk_prevmidin(a1)
  118.         lea    noteondata(pc),a0
  119.         move.b    d1,1(a0)
  120.         move.b    trk_prevmidich(a1),(a0)    ;prev MIDI channel
  121.         clr.b    2(a0)
  122.         or.b    #$90,(a0)        ;note off
  123.         moveq    #3,d0
  124.         bra.w    _AddMIDIData
  125.     ENDC
  126. notcomidi:    cmp.b    #4,d0
  127.         bge.s    notamigatrk
  128.     IFNE    SYNTH
  129.         clr.l    trk_synthptr(a1)
  130.         clr.b    trk_synthtype(a1)
  131.     ENDC
  132.         moveq    #1,d1
  133.         lsl.w    d0,d1
  134.         move.w    d1,$dff096
  135. notamigatrk:    rts
  136.  
  137. SoundOff:    move.l    d2,-(sp)
  138.         moveq    #15,d2
  139. SO_loop0    move.l    d2,d0
  140.         bsr.s    _ChannelOff
  141.         dbf    d2,SO_loop0
  142.         lea    _module(pc),a0
  143.         clr.l    (a0)        ;play nothing
  144.         move.l    (sp)+,d2
  145.         rts
  146.  
  147. _PlayNote:    ;d0(w) = trk #, d1 = note #, d2 = vol, d3(w) = instr # a3 = addr of instr
  148.         moveq    #0,d4
  149.         bset    d0,d4    ;d4 is mask for this channel
  150.         movea.l    mmd_smplarr(a6),a0
  151.         add.w    d3,d3            ;d3 = instr.num << 2
  152.         add.w    d3,d3
  153.         move.l    0(a0,d3.w),d5        ;get address of instrument
  154.     IFNE    MIDI
  155.         bne.s    inmem
  156.         tst.b    inst_midich(a3)        ;is MIDI channel set
  157.     ENDC
  158.     IFNE    CHECK
  159.         beq.w    pnote_rts        ; NO!!!
  160.     ENDC
  161. inmem:        add.b    msng_playtransp(a4),d1    ;add play transpose
  162.         add.b    inst_strans(a3),d1    ;and instr. transpose
  163.         cmp.b    #4,d0
  164.         bge.s    nodmaoff    ;track # >= 4: not an Amiga channel
  165.         move.l    d5,a1
  166.     IFNE    SYNTH
  167.         tst.l    d5
  168.         beq.s    stpdma
  169.         tst.b    trk_synthtype(a5)
  170.         ble.s    stpdma        ;prev. type = sample/hybrid
  171.         cmp.w    #-1,4(a1)    ;type == SYNTHETIC??
  172.         beq.s    nostpdma
  173.     ENDC
  174. stpdma:        move.w    d4,$dff096        ;stop this channel (dmacon)
  175. nostpdma:
  176.     IFNE    SYNTH
  177.         clr.l    trk_synthptr(a5)
  178.     ENDC
  179. nodmaoff:
  180.     IFNE    MIDI
  181.         move.b    trk_prevmidin(a5),d3    ;get prev. midi note
  182.         beq.s    noprevmidi
  183.         clr.b    trk_prevmidin(a5)
  184.         lea    noteondata+2(pc),a0
  185.         clr.b    (a0)                ;volume = 0
  186.         move.b    d3,-(a0)
  187.         move.b    trk_prevmidich(a5),-(a0)    ;prev midi channel
  188.         or.b    #$90,(a0)            ;note off
  189.         movem.w    d0-d1,-(sp)
  190.         moveq    #3,d0
  191.         bsr.w    _AddMIDIData
  192.         movem.w    (sp)+,d0-d1
  193. noprevmidi:    tst.b    inst_midich(a3)
  194.         bne.w    handleMIDInote
  195.     ENDC
  196.     IFNE    CHECK
  197.         cmp.w    #4,d0        ;track > 3???
  198.         bge.w    pnote_rts    ;no Amiga instruments here!!!
  199.     ENDC
  200. ; handle decay (for tracks 0 - 3 only!!)
  201.     IFNE    HOLD
  202.         clr.b    trk_fadespd(a5)        ;no fade yet..
  203.         move.b    trk_initdecay(a5),trk_decay(a5)    ;set decay
  204.     ENDC
  205.         clr.b    trk_vibroffs(a5)    ;clr vibrato offset
  206.         or.w    d4,dmaonmsk
  207.         move.l    d5,a0
  208.         subq.b    #1,d1
  209.     IFNE    SYNTH
  210.         tst.w    4(a0)
  211.         bmi.w    handleSynthnote
  212.         clr.b    trk_synthtype(a5)
  213.     ENDC
  214. tlwtst0:    tst.b    d1
  215.         bpl.s    notenot2low
  216.         add.b    #12,d1    ;note was too low, octave up
  217.         bra.s    tlwtst0
  218. notenot2low:    cmp.b    #62,d1
  219.         ble.s    endpttest
  220.         sub.b    #12,d1    ;note was too high, octave down
  221. endpttest:
  222.         moveq    #0,d4
  223.     IFNE    IFF53
  224.         move.w    4(a0),d0    ;Soitin-struct in a0
  225.         bne.s    iff5or3oct    ;note # in d1 (0 - ...)
  226.     ENDC
  227.         move.l    a0,d0
  228.         lea    _periods(pc),a0
  229.         move.l    a0,trk_periodtbl(a5)
  230.         add.b    d1,d1
  231.         move.w    0(a0,d1.w),d5 ;put period to d5
  232.         move.l    d0,a0
  233.         addq.l    #6,d0        ;Skip structure
  234.         move.l    (a0),d1        ;length
  235.         move.w    (a3),d4        ;inst_repeat
  236.         move.w    inst_replen(a3),d3
  237.     IFNE    IFF53
  238.         bra.s    end_getdata
  239. shiftcnt    dc.b    4,3,2,1,1,0,2,2,1,1,0,0
  240. mullencnt    dc.b    15,7,3,1,1,0,3,3,1,1,0,0
  241. octstart    dc.b    12,12,12,12,24,24,0,12,12,24,24,36
  242. iff5or3oct:    movem.l    d6-d7,-(sp)
  243.         moveq    #0,d7
  244.         move.w    d1,d7
  245.         divu    #12,d7    ;octave #
  246.         move.l    d7,d5
  247.         swap    d5    ;note number in this oct (0-11) is in d5
  248.         move.l    (a0),d1
  249.         cmp.b    #2,d0
  250.         bne.s    no3oct
  251.         addq.l    #6,d7
  252.         divu    #7,d1    ;get length of the 1st octave
  253.         bra.s    no5oct
  254. no3oct:        divu    #31,d1    ;get length of the 1st octave (5 octaves)
  255. no5oct:        move.l    d1,d0        ;d0 and d1 = length of the 1st oct
  256.         move.w    (a3),d4        ;inst_repeat
  257.         move.w    inst_replen(a3),d3
  258.         moveq    #0,d6
  259.         move.b    shiftcnt(pc,d7.w),d6
  260.         lsl.w    d6,d4
  261.         lsl.w    d6,d3
  262.         lsl.w    d6,d1
  263.         move.b    mullencnt(pc,d7.w),d6
  264.         mulu    d6,d0        ;offset of this oct from 1st oct
  265.         add.l    a0,d0        ;add base address to offset
  266.         addq.l    #6,d0        ;skip structure
  267.         lea    _periods(pc),a1
  268.         add.b    octstart(pc,d7.w),d5
  269.         add.b    d5,d5
  270.         move.w    0(a1,d5.w),d5
  271.         movem.l    (sp)+,d6-d7
  272.     ENDC
  273. end_getdata    movea.l    trk_audioaddr(a5),a1 ;base of this channel's regs
  274.         move.l    d0,(a1)+        ;put it in ac_ptr (= 0)
  275.         cmp.w    #1,d3
  276.         bhi.s    repeat
  277.         
  278.         move.l    #_chipzero,trk_sampleptr(a5) ;pointer of zero word
  279.         move.w    #1,trk_samplelen(a5)    ;length: 1 word
  280.         lsr.l    #1,d1            ;shift length right
  281.         move.w    d1,(a1)+    ;and put to custom chip (ac_len)
  282.         bra.s    retsn1
  283.  
  284. repeat:        tst.w    d4
  285.         beq.s    begin0        ;rep. start < 2
  286.         move.w    d4,(a1)+    ;move repeat to hardware
  287.         bra.s    beginn0
  288. begin0:        move.w    d3,(a1)+    ;ac_len
  289. beginn0:    add.l    d4,d4        ;shift
  290.         add.l    d4,d0        ;d0 = starting address of repeat
  291.         move.l    d0,trk_sampleptr(a5)    ;remember rep. start
  292.         move.w    d3,trk_samplelen(a5)    ;remember rep. length
  293.                 
  294. retsn1:        move.w    d5,(a1)+ ;getinsdata puts period to d5 (a1 = ac_per)
  295.         move.w    d2,(a1)    ;a1 = ac_vol
  296.         move.w    d5,trk_prevper(a5)
  297.     IFNE    SYNTH
  298.         tst.b    trk_synthtype(a5)
  299.         bne.w    hSn2
  300.     ENDC
  301. pnote_rts    rts
  302.  
  303.     IFNE    MIDI
  304. handleMIDInote:    add.b    #23,d1        ;2 octaves higher and -1
  305.         bpl.s    hmn_not2low    ;note number not too low
  306. hmn_2low    add.b    #12,d1        ;it was too low, 1 octave up
  307.         bmi.s    hmn_2low
  308. hmn_not2low
  309.         add.b    d2,d2        ;volume 0 - 63 => 0 - 127
  310.         subq.b    #1,d2        ;if 128 => 127
  311.         bpl.s    hmn_notvolu0
  312.         moveq    #0,d2
  313. hmn_notvolu0
  314.         moveq    #0,d5
  315.         move.b    inst_midich(a3),d5    ;