* 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: soundplay.asm,v 4.1 92/06/21 11:15:00 BAF Exp Locker: BAF $
*


        include "exec/types.i"
        include "exec/interrupts.i"
        include "exec/funcdef.i"
        include "exec/exec_lib.i"
        include "hardware/intbits.i"
        include "hardware/dmabits.i"
        include "hardware/custom.i"
        include "bry/macros.i"
        include "player.i"

        xref    _LinkerDB

        xref    diecorrupt,diemes,intrepeat

        xref    sysbase,modmem,modsize

        xdef    soundstart

        code    text

 STRUCTURE      VHDR,0
        ULONG   OneShotHiSamples
        ULONG   RepeatHiSamples
        ULONG   SamplesPerHiCycle
        UWORD   SamplesPerSec
        UBYTE   NumOctaves
        UBYTE   Compression
        LONG    Volume

soundstart
        cmpi.l  #'FORM',(a0)            ; Make sure it's a FORM
        bne     diecorrupt

        move.l  #'VHDR',d0              ; Find the header chunk
        bsr     findiff
        bnz     diecorrupt
        move.l  a0,sndhdr(a4)
        tst.b   Compression(a0)
        bne     diecomp
        subq.b  #1,NumOctaves(a0)
        bne     dieinst

        move.l  #'BODY',d0              ; Find the body chunk
        bsr     findiff
        bnz     diecorrupt
        move.l  a0,sndbod(a4)

        move.l  #'SEQN',d0              ; Find the sequence block, if any
        clr.l   seqptr(a4)
        bsr     findiff
        bnz     19$
        move.l  a0,seqbeg(a4)
        move.l  a0,seqptr(a4)
        add.l   -4(a0),a0
        move.l  a0,seqend(a4)
19$
        plstartret 9$

        cnop    0,4
        dc.l    gmod_Jump
9$      gmodnop
        gmodbra soundinit               ; StartMusic
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodbra soundint                ; Channel0
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodbra maker                   ; GetMakerName
      	move.l	#GMODHF_REPEAT,d0	; Hook
	rts

maker:
        lea     soundname(a4),a0        ; GetMakerName
        tst.l   seqptr(a4)
        beq.s   1$
        lea     soundseqname(a4),a0
1$      move.l  a0,d0
        rts

soundinit:
        movem.l a3/a5/a6,-(sp)
        move.l  #CUSTOM,a3

        move.l  #CLOCK,d0               ; Setup the sound
        move.l  sndhdr(a4),a0
        divu.w  SamplesPerSec(a0),d0
        bvs     diecorrupt
        move.w  d0,aud0+ac_per(a3)
        move.w  d0,aud1+ac_per(a3)
        move.w  d0,aud2+ac_per(a3)
        move.w  d0,aud3+ac_per(a3)
        move.w  #64,aud0+ac_vol(a3)
        move.w  #64,aud1+ac_vol(a3)
        move.w  #64,aud2+ac_vol(a3)
        move.w  #64,aud3+ac_vol(a3)

        move.l  modmem(a4),a0           ; Prime the pump
        clr.l   (a0)
        move.l  a0,playptr(a4)
        moveq   #4/2,d0
        move.l  d0,playrem(a4)
        move.l  a3,a0
        clr.l   ends(a4)
        bsr     soundint

        move.w  #DMAF_SETCLR!DMAF_AUD0!DMAF_AUD1!DMAF_AUD2!DMAF_AUD3,dmacon(a3)

        movem.l (sp)+,a3/a5/a6
        rts

soundint:
        lea     _LinkerDB,a5

        tst.b   end1(a5)
        bz.s    2$
        jsr     intrepeat
        clr.l   ends(a5)
2$
        move.l  playptr(a5),a1          ; Play the next part of this section
        move.l  playrem(a5),d0
        moveq   #0,d1
        bset    #14,d1
        cmp.l   d0,d1
        ble.s   1$
        move.l  d0,d1
1$      move.l  a1,aud0+ac_ptr(a0)
        move.l  a1,aud1+ac_ptr(a0)
        move.l  a1,aud2+ac_ptr(a0)
        move.l  a1,aud3+ac_ptr(a0)
        move.w  d1,aud0+ac_len(a0)
        move.w  d1,aud1+ac_len(a0)
        move.w  d1,aud2+ac_len(a0)
        move.w  d1,aud3+ac_len(a0)
        move.b  end2(a5),end1(a5)
        add.l   d1,playptr(a5)
        add.l   d1,playptr(a5)
        sub.l   d1,playrem(a5)
        bne.s   9$

        move.b  end3(a5),end2(a5)

        move.l  sndbod(a5),a1           ; Ran out of section - get next in sequence
        move.l  seqptr(a5),d0
        bz      8$

        move.l  d0,a6                   ; Get ready for the next section
        move.l  (a6)+,d0
        add.l   d0,a1
        sub.l   (a6)+,d0
        neg.l   d0
        lsr.l   #1,d0
        move.l  a1,playptr(a5)
        move.l  d0,playrem(a5)

        cmpa.l  seqend(a5),a6           ; Find the next section after that
        blt.s   5$
        move.l  seqbeg(a5),a6
        st      end3(a5)
5$      move.l  a6,seqptr(a5)

        bra.s   9$

8$      move.l  -4(a1),d0               ; Simple sound - just replay the whole thing
        lsr.l   #1,d0
        move.l  a1,playptr(a5)
        move.l  d0,playrem(a5)
        st      end3(a5)

9$      move.w  #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,intreq(a0)

        moveq   #0,d0                   ; Keep going in the server chain
        rts


*** Find a chunk in an IFF file
* d0 = Chunk type to find
* Returns: a0 = Pointer to start of chunk's data, Z bit set if found
findiff:
        move.l  d2,-(sp)
        move.l  modmem(a4),a0
        moveq   #-12,d1
        sub.l   d1,a0
        add.l   modsize(a4),d1
1$      cmp.l   (a0),d0
        beq.s   8$
        move.l  4(a0),d2
        btst    #0,d2
        beq.s   5$
        addq.l  #1,d2
5$      addq.l  #8,d2
        add.l   d2,a0
        sub.l   d2,d1
        bhi.s   1$
        bne     diecorrupt
        moveq   #-1,d0
9$      movem.l (sp)+,d2/d2
        rts
8$      addq.l  #8,a0
        b.s     9$

*** Various ways to die
diecomp:
        lea     comptext(a4),a0
        bra     diemes

dieinst:
        lea     insttext(a4),a0
        bra     diemes

        data    __MERGED

soundname       dc.b    "IFF 8SVX sound",0
soundseqname    dc.b    "IFF 8SVX sequenced sound",0
comptext        dc.b    "Can't play compressed sounds",0
insttext        dc.b    "Can't play instruments",0

        bss     __MERGED

playptr         ds.l    1                       ; Pointer in the section we're playing
playrem         ds.l    1                       ; Words remaining in this section

seqbeg          ds.l    1                       ; Sequencing stuff
seqend          ds.l    1
seqptr          ds.l    1

sndhdr          ds.l    1                       ; Pointer to VHDR chunk
sndbod          ds.l    1                       ; Pointer to BODY chunk

*oldint         ds.l    1                       ; Old interrupt pointer
*olddmac        ds.w    1                       ; Old DMACON value
*oldinte        ds.w    1                       ; Old INTENA value

ends:
end1            dc.b    0                       ; When this sound finishes
end2            dc.b    0
end3            dc.b    0
end4            dc.b    0

        end
