* MultiPlayer
* Copyright (C) 1992 Bryan Ford
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* I (the author of MultiPlayer) can be contacted on the Internet at
* "bryan.ford@m.cc.utah.edu".  See "Player.doc" for other addresses.
*
* $Id: play8.asm,v 3.1 92/05/25 07:52:25 BAF Exp $
*

        include "exec/types.i"
        include "exec/execbase.i"
        include "hardware/custom.i"
        include "hardware/dmabits.i"
        include "hardware/intbits.i"
        include "bry/macros.i"

        ifnd    custom
custom  equ     $dff000
        endc

BUFLEN       equ     632

 STRUCTURE      VirtChan,0
        APTR    vc_sample
        UWORD   vc_subpos
        UWORD   vc_length
        LABEL   vc_pos
        UWORD   vc_posfrac
        UWORD   vc_posint
        LABEL   vc_inc
        UWORD   vc_incint
        UWORD   vc_incfrac
        APTR    vc_relsample
        UWORD   vc_rellength
        UWORD   vc_bufper
        LABEL   vc_SIZEOF

 STRUCTURE      HardwareChan,0
        APTR    hc_audcustom
        APTR    hc_playbuf
        APTR    hc_fillbuf
        LABEL   hc_DEFSIZEOF
        STRUCT  hc_virtchan0,vc_SIZEOF
        STRUCT  hc_virtchan1,vc_SIZEOF
        UWORD   hc_channum
        UWORD   hc_buflend2
        LABEL   hc_SIZEOF

        xref    _SysBase,intflashsample

        xdef    p8_Start,p8_Stop
        xdef    p8_SetPeriod,p8_SetVolume
        xdef    p8_PlaySample,p8_Release,p8_StopSample
        xdef    p8_AudioInt

        code    text

*** Initialize and start the audio engine
* d0 = Sampling period for combining channels (>= 127 FIXME???)
p8_Start:
        push    d2-d3

        ml      #3579545,d2
        divu.w  d0,d2
        cq      d3
        mw      d2,d3
        divu.w  #50*2,d3

        lea     hc0,a0                  ; Reset the data structures
        lea     custom+aud0,a1
        mw      d0,d1
        cq      d0
        bsr.b   \clrhc
        bsr.b   \clrhc
        bsr.b   \clrhc
        bsr.b   \clrhc

        bsr     p8_AudioInt             ; Prime the pump, clear everything out
        bsr     p8_AudioInt

        mw      #DMAF_SETCLR!DMAF_AUDIO,custom+dmacon   ; Start playing

        pop     d2-d3
        rts

\clrhc
        mw      d3,hc_buflend2(a0)
        clr.w   hc_virtchan0+vc_length(a0)
        mw      d1,hc_virtchan0+vc_bufper(a0)
        clr.w   hc_virtchan1+vc_length(a0)
        mw      d1,hc_virtchan1+vc_bufper(a0)
        mw      d0,hc_channum(a0)

        push    a0/d3                   ; Tell MultiPlayer where to find the data
        ml      hc_fillbuf(a0),a0
        add.w   d3,d3
        mw      d3,d2
        bsr     intflashsample
        pop     a0/d3

        addq.w  #1,d0
        lea     hc_SIZEOF(a0),a0
        mw      d1,ac_per(a1)
        mw      d3,ac_len(a1)
        mw      #$40,ac_vol(a1)
        lea     aud1-aud0(a1),a1
        rts

*** Stop the audio engine
p8_Stop:
        mw      #DMAF_AUDIO,custom+dmacon
        rts

findchan macro
        add.w   d0,d0
        add.w   d0,d0
        ml      virtchantab(pc,d0.w),a1
        endm

*** Set the period of a virtual channel
* d0 = Virtual channel number (0-7)
* d1 = Period (greater than bufper)
p8_SetPeriod:
        findchan
        tst.w   d1
        bz.s    9$
        cq      d0
        mw      vc_bufper(a1),d0
        divu.w  d1,d0
        mw      d0,vc_incint(a1)
        clr.w   d0
        divu.w  d1,d0
        mw      d0,vc_incfrac(a1)
9$      rts

virtchantab:
        dc.l    hc0+hc_virtchan0,hc0+hc_virtchan1
        dc.l    hc1+hc_virtchan0,hc1+hc_virtchan1
        dc.l    hc2+hc_virtchan0,hc2+hc_virtchan1
        dc.l    hc3+hc_virtchan0,hc3+hc_virtchan1

*** Start a new note/sample in a channel
* d0 = Virtual channel number (0-7)
* a0 = Sample (in fast memory if possible)
* d1 = Length of sample (not including 632 byte suffix)
* d2 = Length of repeat part of sample (0 = one-shot)
p8_PlaySample:
        findchan
        ml      a0,vc_sample(a1)
        mw      d1,vc_length(a1)
        mw      d2,d1
        bnz.b   1$
        mw      #$ffff,d1
1$      mw      d1,vc_subpos(a1)
        clr.l   vc_pos(a1)
        rts

*** Begin the release phase of a sample
* d0 = Virtual channel number (0-7)
* a0 = Release part of sample (just after 632 byte prefix)
* d1 = Length of repeat part (not including 632 byte prefix or 632 byte suffix)
p8_Release:
        findchan
        illegal

*** Stop a channel
* d0 = Virtual channel number (0-7)
p8_StopSample:
        findchan
        clr.w   vc_length(a1)
        rts

*** Set the volume of a virtual channel
*** Note: Setting the volume for one virtchan sets the volume for the entire hardchan.
* d0 = Virtual channel number (0-7)
* d1 = Volume ($00-$40)
p8_SetVolume:
        lsr.w   #1,d0
        lsl.w   #4,d0
        lea     custom+aud+ac_vol,a0
        adda.w  d0,a0
        mw      d1,(a0)
        rts

ld0     macro
        ml      hc_virtchan0+vc_sample(a6),a0
        suba.w  d7,a0
        ml      hc_virtchan0+vc_pos(a6),d2
        add.w   d7,d2
        ml      hc_virtchan0+vc_inc(a6),d4
        endm

ld1     macro
        ml      hc_virtchan1+vc_sample(a6),a1
        suba.w  d7,a1
        ml      hc_virtchan1+vc_pos(a6),d3
        add.w   d7,d3
        ml      hc_virtchan1+vc_inc(a6),d5
        endm

sv0     macro
        add.w   d7,d2
\svb0\@ cmp.w   hc_virtchan0+vc_length(a6),d2
        blo.b   \sv0\@
        sub.w   hc_virtchan0+vc_subpos(a6),d2
        bhs.b   \svb0\@
        clr.w   hc_virtchan0+vc_length(a6)
\sv0\@  ml      d2,hc_virtchan0+vc_pos(a6)
        endm

sv1     macro
        add.w   d7,d3
\svb1\@ cmp.w   hc_virtchan1+vc_length(a6),d3
        blo.b   \sv1\@
        sub.w   hc_virtchan1+vc_subpos(a6),d3
        bhs.b   \svb1\@
        clr.w   hc_virtchan1+vc_length(a6)
\sv1\@  ml      d3,hc_virtchan1+vc_pos(a6)
        endm

comb01  macro
        move.b  0(a1,d3.w),(a2)+
        swap    d3
        add.l   d5,d3
        swap    d3
        endm

comb10  macro
        move.b  0(a0,d2.w),(a2)+
        swap    d2
        add.l   d4,d2
        swap    d2
        endm

comb11  macro
        move.b  0(a0,d2.w),d0
        add.b   0(a1,d3.w),d0
        move.b  d0,(a2)+
        swap    d2
        swap    d3
        add.l   d4,d2
        add.l   d5,d3
        swap    d2
        swap    d3
        endm

*** Audio interrupt routine - call after updating song
p8_AudioInt:
        push    d2-d7/a2-a6
        lea     hc0,a6
        bsr.b   \upchan
        lea     hc_SIZEOF(a6),a6
        bsr.b   \upchan
        lea     hc_SIZEOF(a6),a6
        bsr.b   \upchan
        lea     hc_SIZEOF(a6),a6
        bsr.b   \upchan
        pop     d2-d7/a2-a6
        move.w  #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,custom+intreq
        rts

\upchan
        ml      hc_audcustom(a6),a5

        ml      hc_fillbuf(a6),d0
        ml      hc_playbuf(a6),a2
        ml      a2,ac_ptr(a5)
        ml      a2,hc_fillbuf(a6)
        ml      d0,hc_playbuf(a6)

        mw      #$8000,d7

        tst.w   hc_virtchan0+vc_length(a6)
        bz      \f0
\f1
        tst.w   hc_virtchan1+vc_length(a6)
        bz      \f1s0

\f1s1
        ld0
        ld1
        mw      hc_buflend2(a6),d1
        mw      d1,d6
        lsr.w   #2,d1
        bra     11$
1$      comb11
        comb11
        comb11
        comb11
        comb11
        comb11
        comb11
        comb11
11$     dbra    d1,1$
        andi.w  #3,d6
        bra     13$
12$     comb11
        comb11
13$     dbra    d6,12$
        sv0
        sv1
        rts

\f1s0
        ld0
        mw      hc_buflend2(a6),d1
        mw      d1,d6
        lsr.w   #2,d1
        bra     21$
2$      comb10
        comb10
        comb10
        comb10
        comb10
        comb10
        comb10
        comb10
21$     dbra    d1,2$
        andi.w  #3,d6
        bra     23$
22$     comb10
        comb10
23$     dbra    d6,22$
        sv0
        rts

\f0
        tst.w   hc_virtchan1+vc_length(a6)
        bz      \f0s0

\f0s1
        ld1
        mw      hc_buflend2(a6),d1
        mw      d1,d6
        lsr.w   #2,d1
        bra     51$
5$      comb01
        comb01
        comb01
        comb01
        comb01
        comb01
        comb01
        comb01
51$     dbra    d1,5$
        andi.w  #3,d6
        bra     53$
52$     comb01
        comb01
53$     dbra    d6,52$
        sv1
        rts

\f0s0
        mw      hc_buflend2(a6),d1
        add.w   d1,d1
        lea     0(a2,d1.w),a0
        cq      d2
        cq      d3
        cq      d4
        cq      d5
        ml      d2,a2
        ml      d3,a3
        ml      d4,a4
        ml      d5,a5
        mw      hc_buflend2(a6),d1
        mw      d1,d6
        andi.w  #15,d6
        bra     73$
72$     mw      d2,-(a0)
73$     dbra    d6,72$
        lsr.w   #4,d1
        bra     71$
7$      movem.l d2-d5/a2-a5,-(a0)
71$     dbra    d1,7$
        rts

        data    play8data

hc0     dc.l    custom+aud0,soundbuf0,soundbuf1
        ds.b    hc_SIZEOF-hc_DEFSIZEOF

hc1     dc.l    custom+aud1,soundbuf2,soundbuf3
        ds.b    hc_SIZEOF-hc_DEFSIZEOF

hc2     dc.l    custom+aud2,soundbuf4,soundbuf5
        ds.b    hc_SIZEOF-hc_DEFSIZEOF

hc3     dc.l    custom+aud3,soundbuf6,soundbuf7
        ds.b    hc_SIZEOF-hc_DEFSIZEOF

        bss     chip,chip

soundbuf0       ds.b    BUFLEN
                cnop    0,4
soundbuf1       ds.b    BUFLEN
                cnop    0,4
soundbuf2       ds.b    BUFLEN
                cnop    0,4
soundbuf3       ds.b    BUFLEN
                cnop    0,4
soundbuf4       ds.b    BUFLEN
                cnop    0,4
soundbuf5       ds.b    BUFLEN
                cnop    0,4
soundbuf6       ds.b    BUFLEN
                cnop    0,4
soundbuf7       ds.b    BUFLEN

        end
