* 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.
*
* Note:  This playroutine was not originally written by me.  In general
* these playroutines are public domain, so I am bringing the versions
* modified for MultiPlayer under the General Public License.  In the
* few cases of already-copyrighted playroutines, the above copyright
* notice applies only to the parts of the file written by me.
*
* $Id: jamplay.asm,v 4.1 92/06/21 11:14:19 BAF Exp Locker: BAF $
*

        include "exec/types.i"
        include "bry/macros.i"
        include "player.i"

        xref    modmem,getfreqmodspeed,intrepeat,intsongpos,dmawait

        xdef    jamstart

        code    text

jamstart
        plstartret 9$

        cnop    0,4
        dc.l    gmod_Jump
9$      gmodnop
        gmodbra _pp_init                ; StartMusic
        gmodbra _pp_end                 ; StopMusic
        gmodnop
        gmodnop
        gmodq   1                       ; ContinueMusic
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodbra getfreqmodspeed         ; GetFrequency
        gmodbra _pp_music               ; TimerTick
        gmodbra 2$                      ; GetMakerName
        move.l  #GMODHF_REPEAT!GMODHF_SEQUENCE,d0       ; Hook
        rts

2$      lea     name(pc),a0
        move.l  a0,d0
        rts




*                  ****************************************
*                  *** JamCrackerPro V1.0a play-routine ***
*                  ***   Originally coded by M. Gemmel  ***
*                  ***           Code optimised         ***
*                  ***         by Xag of Betrayal       ***
*                  ***    See docs for important info   ***
*                  ****************************************

*** Relative offset definitions ***

 STRUCTURE Instrument,0         ;Instrument info structure
        STRUCT  it_name,31
        BYTE    it_flags
        LONG    it_size
        LONG    it_address
        LABEL   it_sizeof

 STRUCTURE Pattern,0            ;Pattern info structure
        WORD    pt_size
        LONG    pt_address
        LABEL   pt_sizeof

 STRUCTURE Note,0               ;Note info structure
        BYTE    nt_period
        BYTE    nt_instr
        BYTE    nt_speed
        BYTE    nt_arpeggio
        BYTE    nt_vibrato
        BYTE    nt_phase
        BYTE    nt_volume
        BYTE    nt_porta
        LABEL   nt_sizeof

 STRUCTURE Voice,0              ;Voice info structure
        WORD    pv_waveoffset
        WORD    pv_dmacon
        LONG    pv_custbase
        WORD    pv_inslen
        LONG    pv_insaddress
        LONG    pv_peraddress
        STRUCT  pv_pers,3*2
        WORD    pv_por
        WORD    pv_deltapor
        WORD    pv_porlevel
        WORD    pv_vib
        WORD    pv_deltavib
        WORD    pv_vol
        WORD    pv_deltavol
        WORD    pv_vollevel
        WORD    pv_phase
        WORD    pv_deltaphase
        BYTE    pv_vibcnt
        BYTE    pv_vibmax
        BYTE    pv_flags
        BYTE    pv_pad
        LABEL   pv_sizeof

*** Initialise routine ***

_pp_init:
; !!!!
                push.l  d0-d7/a0-a6
                move.l  modmem,a0
; !!!!
                addq.w  #4,a0
                move.w  (a0)+,d0
                move.w  d0,d1
                move.l  a0,instable
                mulu    #it_sizeof,d0
                add.w   d0,a0

                move.w  (a0)+,d0
                move.w  d0,d2
                move.l  a0,patttable
                mulu    #pt_sizeof,d0
                add.w   d0,a0

                move.w  (a0)+,d0
                move.w  d0,songlen
                move.l  a0,songtable
                add.w   d0,d0
                add.w   d0,a0

                move.l  patttable(PC),a1
                move.w  d2,d0
                subq.w  #1,d0
.l0:            move.l  a0,pt_address(a1)
                move.w  (a1),d3         ;pt_size
                mulu    #nt_sizeof*4,d3
                add.w   d3,a0
                addq.w  #pt_sizeof,a1
                dbra    d0,.l0

                move.l  instable(PC),a1
                move.w  d1,d0
                subq.w  #1,d0
.l1:            move.l  a0,it_address(a1)
                move.l  it_size(a1),d2
                add.l   d2,a0
                add.w   #it_sizeof,a1
                dbra    d0,.l1

                movem.l d0-d1,-(sp)     ; BAF
                clr.l   songpos
                moveq   #0,d0
                moveq   #0,d1
                move.w  songlen(pc),d1
                jsr     intsongpos
                movem.l (sp)+,d0-d1

                move.l  songtable(PC),pp_songptr
                move.w  songlen(PC),pp_songcnt
                move.l  pp_songptr(PC),a0
                move.w  (a0),d0
                mulu    #pt_sizeof,d0
                add.l   patttable(PC),d0
                move.l  d0,a0
                move.l  a0,pp_pattentry
                move.b  pt_size+1(a0),pp_notecnt
                move.l  pt_address(a0),pp_address
                move.b  #6,pp_wait
                move.b  #1,pp_waitcnt
                clr.w   pp_nullwave
                move.w  #$000F,$DFF096

                lea     pp_variables(PC),a0
                lea     $DFF0A0,a1
                moveq   #1,d1
                move.w  #$80,d2
                moveq   #4-1,d0
.l2:            move.w  #0,8(a1)
                move.w  d2,(a0)         ;pv_waveoffset
                move.w  d1,pv_dmacon(a0)
                move.l  a1,pv_custbase(a0)
                move.l  #pp_periods,pv_peraddress(a0)
                move.w  #1019,pv_pers(a0)
                clr.w   pv_pers+2(a0)
                clr.w   pv_pers+4(a0)
                clr.l   pv_por(a0)
                clr.w   pv_porlevel(a0)
                clr.l   pv_vib(a0)
                clr.l   pv_vol(a0)
                move.w  #$40,pv_vollevel(a0)
                clr.l   pv_phase(a0)
                clr.w   pv_vibcnt(a0)
                clr.b   pv_flags(a0)
                add.w   #pv_sizeof,a0
                add.w   #$10,a1
                add.w   d1,d1
                add.w   #$40,d2
                dbra    d0,.l2

; !!!!
                pop.l   d0-d7/a0-a6
; !!!!
                rts

*** Clean-up routine ***

_pp_end:
; !!!!
                push.l  d0-d7/a0-a6
; !!!!
                moveq   #0,d0
                lea     $DFF000,a0
                move.w  d0,$A8(a0)
                move.w  d0,$B8(a0)
                move.w  d0,$C8(a0)
                move.w  d0,$D8(a0)
                move.w  #$000F,$96(a0)
; !!!!
        pop.l   d0-d7/a0-a6
        moveq.l #0,d0
; !!!!
                rts
_pp_music:
        push.l  d0-d7/a0-a6
        bsr.s   pp_play
        pop.l   d0-d7/a0-a6
        rts

*** Play routine ***

pp_play:                lea     $DFF000,a6
                subq.b  #1,pp_waitcnt
                bne.s   \l0
                bsr     pp_nwnt
                move.b  pp_wait(PC),pp_waitcnt

\l0:            lea     pp_variables(PC),a1
                bsr.s   pp_uvs
                lea     pp_variables+pv_sizeof(PC),a1
                bsr.s   pp_uvs
                lea     pp_variables+2*pv_sizeof(PC),a1
                bsr.s   pp_uvs
                lea     pp_variables+3*pv_sizeof(PC),a1

pp_uvs:         move.l  pv_custbase(a1),a0

\l0:            move.w  pv_pers(a1),d0
                bne.s   \l1
                bsr     pp_rot
                bra.s   \l0
\l1:            add.w   pv_por(a1),d0
                tst.w   pv_por(a1)
                beq.s   \l1c
                bpl.s   \l1a
                cmp.w   pv_porlevel(a1),d0
                bge.s   \l1c
                bra.s   \l1b
\l1a:           cmp.w   pv_porlevel(a1),d0
                ble.s   \l1c
\l1b:           move.w  pv_porlevel(a1),d0

\l1c:           add.w   pv_vib(a1),d0
                cmp.w   #135,d0
                bge.s   \l1d
                move.w  #135,d0
                bra.s   \l1e
\l1d:           cmp.w   #1019,d0
                ble.s   \l1e
                move.w  #1019,d0
\l1e:           move.w  d0,6(a0)
                bsr     pp_rot

                move.w  pv_deltapor(a1),d0
                add.w   d0,pv_por(a1)
                cmp.w   #-1019,pv_por(a1)
                bge.s   \l3
                move.w  #-1019,pv_por(a1)
                bra.s   \l5
\l3:            cmp.w   #1019,pv_por(a1)
                ble.s   \l5
                move.w  #1019,pv_por(a1)

\l5:            tst.b   pv_vibcnt(a1)
                beq.s   \l7
                move.w  pv_deltavib(a1),d0
                add.w   d0,pv_vib(a1)
                subq.b  #1,pv_vibcnt(a1)
                bne.s   \l7
                neg.w   pv_deltavib(a1)
                move.b  pv_vibmax(a1),pv_vibcnt(a1)

\l7:            move.w  pv_dmacon(a1),d0
                move.w  pv_vol(a1),8(a0)
                move.w  pv_deltavol(a1),d0
                add.w   d0,pv_vol(a1)
                tst.w   pv_vol(a1)
                bpl.s   \l8
                clr.w   pv_vol(a1)
                bra.s   \la
\l8:            cmp.w   #$40,pv_vol(a1)
                ble.s   \la
                move.w  #$40,pv_vol(a1)

\la:            btst    #1,pv_flags(a1)
                beq.s   \l10
                tst.w   pv_deltaphase(a1)
                beq.s   \l10
                bpl.s   \sk
                clr.w   pv_deltaphase(a1)
\sk:            move.l  pv_insaddress(a1),a0
                move.w  (a1),d0         ;pv_waveoffset
                neg.w   d0
                lea     0(a0,d0.w),a2
                move.l  a2,a3
                move.w  pv_phase(a1),d0
                lsr.w   #2,d0
                add.w   d0,a3

                moveq   #$40-1,d0
\lb:            move.b  (a2)+,d1
                ext.w   d1
                move.b  (a3)+,d2
                ext.w   d2
                add.w   d1,d2
                asr.w   #1,d2
                move.b  d2,(a0)+
                dbra    d0,\lb

                move.w  pv_deltaphase(a1),d0
                add.w   d0,pv_phase(a1)
                cmp.w   #$100,pv_phase(a1)
                blt.s   \l10
                sub.w   #$100,pv_phase(a1)

\l10:           rts

pp_rot:         move.w  pv_pers(a1),d0
                move.w  pv_pers+2(a1),pv_pers(a1)
                move.w  pv_pers+4(a1),pv_pers+2(a1)
                move.w  d0,pv_pers+4(a1)
                rts

pp_nwnt:                move.l  pp_address(PC),a0
                add.l   #4*nt_sizeof,pp_address
                subq.b  #1,pp_notecnt
                bne.s   \l5

\l0:            movem.l d0-d1,-(sp)     ; BAF
                move.l  songpos(pc),d0
                addq.l  #1,d0
                move.l  d0,songpos
                moveq   #0,d1
                move.w  songlen(pc),d1
                jsr     intsongpos
                movem.l (sp)+,d0-d1

                addq.l  #2,pp_songptr
                subq.w  #1,pp_songcnt
                bne.s   \l1
                move.l  songtable(PC),pp_songptr
                move.w  songlen(PC),pp_songcnt

                jsr     intrepeat       ; BAF

\l1:            move.l  pp_songptr(PC),a1
                move.w  (a1),d0
                mulu    #pt_sizeof,d0
                add.l   patttable(PC),d0
                move.l  d0,a1
                move.b  pt_size+1(a1),pp_notecnt
                move.l  pt_address(a1),pp_address

\l5:            clr.w   pp_tmpdmacon
                lea     pp_variables(PC),a1
                bsr     pp_nnt
                addq.w  #nt_sizeof,a0
                lea     pp_variables+pv_sizeof(PC),a1
                bsr     pp_nnt
                addq.w  #nt_sizeof,a0
                lea     pp_variables+2*pv_sizeof(PC),a1
                bsr     pp_nnt
                addq.w  #nt_sizeof,a0
                lea     pp_variables+3*pv_sizeof(PC),a1
                bsr     pp_nnt

                move.w  pp_tmpdmacon(PC),$96(a6)

                jsr     dmawait

                lea     pp_variables(PC),a1
                bsr.s   pp_scr
                lea     pp_variables+pv_sizeof(PC),a1
                bsr.s   pp_scr
                lea     pp_variables+2*pv_sizeof(PC),a1
                bsr.s   pp_scr
                lea     pp_variables+3*pv_sizeof(PC),a1
                bsr.s   pp_scr

                bset    #7,pp_tmpdmacon
                move.w  pp_tmpdmacon(PC),$96(a6)

                jsr     dmawait

                move.l  pp_variables+pv_insaddress(PC),$A0(a6)
                move.w  pp_variables+pv_inslen(PC),$A4(a6)
                move.l  pp_variables+pv_sizeof+pv_insaddress(PC),$B0(a6)
                move.w  pp_variables+pv_sizeof+pv_inslen(PC),$B4(a6)
                move.l  pp_variables+2*pv_sizeof+pv_insaddress(PC),$C0(a6)
                move.w  pp_variables+2*pv_sizeof+pv_inslen(PC),$C4(a6)
                move.l  pp_variables+3*pv_sizeof+pv_insaddress(PC),$D0(a6)
                move.w  pp_variables+3*pv_sizeof+pv_inslen(PC),$D4(a6)

                rts

pp_scr:         move.w  pp_tmpdmacon(PC),d0
                and.w   pv_dmacon(a1),d0
                beq.s   \l5

                move.l  pv_custbase(a1),a0
                move.l  pv_insaddress(a1),(a0)
                move.w  pv_inslen(a1),4(a0)
                move.w  pv_pers(a1),6(a0)
                btst    #0,pv_flags(a1)
                bne.s   \l5
                move.l  #pp_nullwave,pv_insaddress(a1)
                move.w  #1,pv_inslen(a1)

\l5:            rts

pp_nnt:         move.b  (a0),d1         ;nt_period
                beq     \l5

                and.l   #$000000FF,d1
                add.w   d1,d1
                add.l   #pp_periods-2,d1
                move.l  d1,a2

                btst    #6,nt_speed(a0)
                beq.s   \l2
                move.w  (a2),pv_porlevel(a1)
                bra.s   \l5

\l2:            move.w  pv_dmacon(a1),d0
                or.w    d0,pp_tmpdmacon

                move.l  a2,pv_peraddress(a1)
                move.w  (a2),pv_pers(a1)
                move.w  (a2),pv_pers+2(a1)
                move.w  (a2),pv_pers+4(a1)

                clr.w   pv_por(a1)

                move.b  nt_instr(a0),d0
                ext.w   d0
                mulu    #it_sizeof,d0
                add.l   instable(PC),d0
                move.l  d0,a2
                tst.l   it_address(a2)
                bne.s   \l1
                move.l  #pp_nullwave,pv_insaddress(a1)
                move.w  #1,pv_inslen(a1)
                clr.b   pv_flags(a1)
                bra.s   \l5

\l1:            move.l  it_address(a2),a3
                btst    #1,it_flags(a2)
                bne.s   \l0a
                move.l  it_size(a2),d0
                lsr.l   #1,d0
                move.w  d0,pv_inslen(a1)
                bra.s   \l0
\l0a:           move.w  (a1),d0         ;pv_waveoffset
                add.w   d0,a3
                move.w  #$20,pv_inslen(a1)
\l0:            move.l  a3,pv_insaddress(a1)
                move.b  it_flags(a2),pv_flags(a1)
                move.w  pv_vollevel(a1),pv_vol(a1)

\l5:            move.b  nt_speed(a0),d0
                and.b   #$0F,d0
                beq.s   \l6
                move.b  d0,pp_wait

\l6:            move.l  pv_peraddress(a1),a2
                move.b  nt_arpeggio(a0),d0
                beq.s   \l9
                cmp.b   #$FF,d0
                bne.s   \l7
                move.w  (a2),pv_pers(a1)
                move.w  (a2),pv_pers+2(a1)
                move.w  (a2),pv_pers+4(a1)
                bra.s   \l9

\l7:            and.b   #$0F,d0
                add.b   d0,d0
                ext.w   d0
                move.w  0(a2,d0.w),pv_pers+4(a1)
                move.b  nt_arpeggio(a0),d0
                lsr.b   #4,d0
                add.b   d0,d0
                ext.w   d0
                move.w  0(a2,d0.w),pv_pers+2(a1)
                move.w  (a2),pv_pers(a1)

\l9:            move.b  nt_vibrato(a0),d0
                beq.s   \ld
                cmp.b   #$FF,d0
                bne.s   \la
                clr.l   pv_vib(a1)
                clr.b   pv_vibcnt(a1)
                bra.s   \ld
\la:            clr.w   pv_vib(a1)
                and.b   #$0F,d0
                ext.w   d0
                move.w  d0,pv_deltavib(a1)
                move.b  nt_vibrato(a0),d0
                lsr.b   #4,d0
                move.b  d0,pv_vibmax(a1)
                lsr.b   #1,d0
                move.b  d0,pv_vibcnt(a1)

\ld:            move.b  nt_phase(a0),d0
                beq.s   \l10
                cmp.b   #$FF,d0
                bne.s   \le
                clr.w   pv_phase(a1)
                move.w  #$FFFF,pv_deltaphase(a1)
                bra.s   \l10
\le:            and.b   #$0F,d0
                ext.w   d0
                move.w  d0,pv_deltaphase(a1)
                clr.w   pv_phase(a1)

\l10:           move.b  nt_volume(a0),d0
                bne.s   \l10a
                btst    #7,nt_speed(a0)
                beq.s   \l16
                bra.s   \l11a
\l10a:          cmp.b   #$FF,d0
                bne.s   \l11
                clr.w   pv_deltavol(a1)
                bra.s   \l16
\l11:           btst    #7,nt_speed(a0)
                beq.s   \l12
\l11a:          move.b  d0,pv_vol+1(a1)
                move.b  d0,pv_vollevel+1(a1)
                clr.w   pv_deltavol(a1)
                bra.s   \l16
\l12:           bclr    #7,d0
                beq.s   \l13
                neg.b   d0
\l13:           ext.w   d0
                move.w  d0,pv_deltavol(a1)

\l16:           move.b  nt_porta(a0),d0
                beq.s   \l1a
                cmp.b   #$FF,d0
                bne.s   \l17
                clr.l   pv_por(a1)
                bra.s   \l1a
\l17:           clr.w   pv_por(a1)
                btst    #6,nt_speed(a0)
                beq.s   \l17a
                move.w  pv_porlevel(a1),d1
                cmp.w   pv_pers(a1),d1
                bgt.s   \l17c
                neg.b   d0
                bra.s   \l17c

\l17a:          bclr    #7,d0
                bne.s   \l18
                neg.b   d0
                move.w  #135,pv_porlevel(a1)
                bra.s   \l17c

\l18:           move.w  #1019,pv_porlevel(a1)
\l17c:          ext.w   d0
\l18a:          move.w  d0,pv_deltapor(a1)

\l1a:           rts

*** Data section ***

pp_periods:     DC.W    1019,962,908,857,809,763,720,680,642,606,572,540
                DC.W    509,481,454,428,404,381,360,340,321,303,286,270
                DC.W    254,240,227,214,202,190,180,170,160,151,143,135
                DC.W    135,135,135,135,135,135,135,135,135
                DC.W    135,135,135,135,135,135

songlen:                DS.W    1
songtable:      DS.L    1
instable:               DS.L    1
patttable:      DS.L    1

pp_wait:                DS.B    1
pp_waitcnt:     DS.B    1
pp_notecnt:     DS.B    1
pp_address:     DS.L    1
pp_songptr:     DS.L    1
pp_songcnt:     DS.W    1
pp_pattentry:   DS.L    1
pp_tmpdmacon:   DS.W    1
pp_variables:   DS.B    4*48

songpos         ds.l    1

name            dc.b    "JamCracker",0

        section "chip",data,chip ; FIXME: This doesn't seem to work

pp_nullwave:    DS.W    1

        end
