* 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: okta8play.asm,v 3.1 92/05/25 07:51:48 BAF Exp $
*

        include "exec/types.i"
        include "exec/memory.i"
        include "exec/libraries.i"
        include "exec/execbase.i"
        include "exec/funcdef.i"
        include "exec/exec_lib.i"
        include "intuition/intuition_lib.i"
        include "player.i"
        include "bry/macros.i"

BUFLEN  equ     632
MINPER  equ     113

        code    text

        xref    modspec,modmem,modend,intsongpos,intrepeat,getfreqmodspeed
        xref    unloadfile,_IntuitionBase,intflashnote

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

        xdef    okta8start

okta8start:
        plstartret 9$

1$      lea     name(pc),a0
        ml      a0,d0
        rts

2$      ml      4,a1
        mw      #227,d0
        btst    #AFB_68020,AttnFlags+1(a1)
        bz      p8_Start
        mw      #127,d0
        bra     p8_Start

        dc.l    gmod_SetVolume+4
9$      gmodbra rs_init
        gmodbra 2$                      ; StartMusic
        gmodbra p8_Stop
        gmodbra rs_free
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodbra rs_int
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodnop
        gmodbra 1$                      ; GetMakerName
        gmodbra \hook                   ; Hook
        gmodnop
        gmodbra \vol                    ; SetVolume

\hook
        move.l  #GMODHF_REPEAT!GMODHF_SEQUENCE,d0
        rts

\vol
        move.w  d0,leftvol
        move.w  d1,rightvol
        rts

 STRUCTURE      sample,0
        STRUCT  sm_name,20
        ULONG   sm_length
        UWORD   sm_rep24
        UWORD   sm_rep26
        UBYTE   sm_b
        UBYTE   sm_vol
        UWORD   sm_playmode
        LABEL   sm_SIZEOF

 STRUCTURE      mysample,0
        APTR    msm_ptr
        UWORD   msm_len
        UWORD   msm_replen
        APTR    msm_relptr
        UWORD   msm_rellen
msm_SIZEOF      equ     sm_SIZEOF

 STRUCTURE      pbuff,0
        APTR    pb_relptr               ; 6
        UWORD   pb_rellen               ; 10
        UWORD   pb_note                 ; 12
        UWORD   pb_period               ; 14
        UBYTE   pb_active
        UBYTE   pb_pad
        LABEL   pb_SIZEOF

**********************************
* OKTALYZER V1.1 REPLAYER SOURCE *
**********************************

;by A.Sander with Defpac2
;(C) 1989 VERLAG MAYER
;- only for 4-Channels

* init ********************************

p:

rs_init         bsr     rs_free

                push    d2-d3/d7/a2-a3/a5-a6
                ml      sp,d7

                move.l  modmem,a5
                cmp.l   #'OKTA',(a5)+
                bne     rs_error2
                cmp.l   #'SONG',(a5)+
                bne     rs_error2
                move.l  a5,a0
                lea     rs_cmformat(pc),a1
                bsr     rs_search
                move.l  a5,a0
                lea     rs_extformat(pc),a1
                bsr     rs_search
                bsr     rs_getpatts
                bsr     rs_getsamples

                lea     rs_pbuffs(pc),a0
                moveq   #pb_SIZEOF*8/4-1,d0
rs_loop4        clr.l   (a0)+
                dbf     d0,rs_loop4

                lea     rs_channelmodes(pc),a0
                lea     rs_pbuffs+pb_active(pc),a1
                moveq   #4-1,d0
                cq      d3
1$              move.w  (a0)+,d1
                st      (a1)
                move.b  d1,pb_SIZEOF(a1)
                lea     pb_SIZEOF*2(a1),a1
                moveq   #1,d2
                lsl.w   d1,d2
                add.w   d2,d3
                dbra    d0,1$
                move.w  d3,rs_channels
                lsl.w   #2,d3
                move.w  d3,rs_pattlinelen

                clr.w   rs_pointer
                bsr     rs_gettrkpos
                sub.l   d3,rs_trkpos
                subq.w  #1,rs_patty

                move.l  #$40404040,rs_vol
                clr.w   rs_filter
                move.w  rs_speed,rs_actspeed
                clr.w   rs_actcyc
                move.w  #-1,rs_nextpt

                lea     rs_pattline(pc),a0
                moveq   #8-1,d0
rs_loop5        clr.l   (a0)+
                dbf     d0,rs_loop5

                cq      d0
                cq      d1
                mw      rs_len(pc),d1
                jsr     intsongpos

                lea     modspec,a0
                jsr     unloadfile

                moveq   #0,d0
rs_initout      ml      d7,sp
                pop     d2-d3/d7/a2-a3/a5-a6
                rts
rs_error2       lea     errmes(pc),a0
                ml      a0,d0
                b       rs_initout
rs_nomem        lea     errnomem(pc),a0
                ml      a0,d0
                b       rs_initout

* format search ***********************

;a0 fpt
;a1 format list

rs_search       move.l  a0,a2
                move.l  (a1)+,d0
                beq.s   rs_ex
rs_loop         cmp.l   modend,a2
                bhs.s   rs_ex
                cmp.l   (a2)+,d0
                bne.s   rs_next
                move.l  (a1)+,d0
                cmp.l   (a2)+,d0
                ble.s   rs_nocorrect
                move.l  -4(a2),d0
rs_nocorrect    move.l  (a1)+,a3
rs_copy         subq.l  #1,d0
                bmi.s   rs_search
                move.b  (a2)+,(a3)+
                bra.s   rs_copy
rs_next         add.l   (a2)+,a2
                bra.s   rs_loop
rs_ex           rts

* pattern descriptor ******************

rs_getpatts     lea     rs_pattpts(pc),a2
                move.l  a5,a3
                move.l  #'PBOD',d3
rs_loop2        cmp.l   modend,a3
                bhs.s   rs_ready
                movem.l (a3)+,d1-d2
                cmp.l   d3,d1
                beq.s   rs_got
                add.l   d2,a3
                bra.s   rs_loop2
rs_got          ml      d2,d0
                bsr     alloc
                ml      d0,(a2)+

                ml      d0,a1
                ml      a3,a0
                ml      d2,d0
                ml      4,a6
                jl      CopyMem

                add.l   d2,a3
                bra.s   rs_loop2
rs_ready        rts

* sample descriptor *******************

rs_getsamples   lea     rs_samples(pc),a2
                move.l  a5,a3
                move.l  #'SBOD',d3
rs_loop2a       cmp.l   modend,a3
                bhs     rs_sready
                movem.l (a3)+,d1-d2
                cmp.l   d3,d1
                beq.s   rs_gots
                add.l   d2,a3
                bra.s   rs_loop2a

rs_gots         tst.l   20(a2)
                bne.s   rs_setsample
                clr.l   msm_ptr(a2)
                lea     sm_SIZEOF(a2),a2
                bra.s   rs_gots

rs_setsample
        tst.w   26(a2)
        bz      \norep

        tst.w   24(a2)
        bz      \releaseonly

        ml      a3,a0
        cq      d0
        mw      24(a2),d0
        add.w   26(a2),d0
        add.l   d0,d0
        cq      d1
        mw      26(a2),d1
        add.l   d1,d1
        bsr     \repeat

        b       \release

\releaseonly
        ml      a3,a0
        cq      d0
        mw      26(a2),d0
        add.l   d0,d0
        ml      d0,d1
        bsr     \repeat

\release
        ml      a3,a0
        cq      d1
        mw      msm_len(a2),d1
        adda.l  d1,a0
        ml      d2,d0
        sub.l   d1,d0
        lea     msm_relptr(a2),a2
        bsr     \oneshot
        lea     -msm_relptr(a2),a2
        b       \done
\norep
        clr.w   msm_replen(a2)
        clr.l   msm_relptr(a2)
        clr.w   msm_rellen(a2)
        ml      a3,a0
        cq      d0
        mw      d2,d0
        bsr     \oneshot

\done
        lea     sm_SIZEOF(a2),a2
        add.l   d2,a3
        bra     rs_loop2a

\oneshot
        bsr     \getit

        cq      d1
\oneshot_clr
        mw      d1,(a1)+
        dbra    d0,\oneshot_clr
        rts

\repeat
        cmp.w   #2,d1                   ; Forget these stupid little pseudo-repeats
        bhi.b   \repeat_notone
        clr.w   msm_replen(a2)
        b       \oneshot
\repeat_notone
        mw      d1,msm_replen(a2)

        bsr     \getit

        ml      a1,a0
        cq      d1
        mw      msm_replen(a2),d1
        sub.l   d1,a0
\repeat_cpy
        mw      (a0)+,(a1)+
        dbra    d0,\repeat_cpy
        rts

\getit
        mw      d0,msm_len(a2)
        bz      \getnothing
        add.l   #BUFLEN,d0
        bsr     alloc
        move.l  d0,msm_ptr(a2)

        ml      d0,a1
        cq      d0
        mw      msm_len(a2),d0
        ml      4,a6
        jl      CopyMem

        ml      msm_ptr(a2),a1
        cq      d1
        mw      msm_len(a2),d1
        add.l   d1,a1
        mw      #BUFLEN/2-1,d0
        rts

\getnothing
        clr.l   msm_ptr(a2)
        clr.w   msm_len(a2)
        addq    #4,sp
        rts

rs_sready       rts

alloc
        push    d1/a0-a1
        ml      #MEMF_PUBLIC,d1
        lea     rs_remember(pc),a0
        ml      _IntuitionBase,a6
        jl      AllocRemember
        tst.l   d0
        bz      rs_nomem
        pop     d1/a0-a1
        rts

* exit ********************************

rs_free
        push    a6
        ml      _IntuitionBase,a6
        lea     rs_remember(pc),a0
        mq      #1,d0
        jl      FreeRemember
        pop     a6
        rts

* interrupt ***************************

rs_int          movem.l d2-d7/a2-a6,-(sp)
                bsr.b   rs_rh
                movem.l (sp)+,d2-d7/a2-a6
                bra     p8_AudioInt

rs_rh           bsr     rs_p8
                addq.w  #1,rs_actcyc
                move.w  rs_actspeed,d0
                cmp.w   rs_actcyc,d0
                ble.s   rs_addcyc
                rts

rs_addcyc       clr.w   rs_actcyc
                cq      d0
                mw      rs_pattlinelen(pc),d0
                add.l   d0,rs_trkpos
                addq.w  #1,rs_patty
                bsr     rs_getppatt
                tst.w   rs_nextpt
                bpl.s   rs_pattend
                cmp.w   rs_patty,d0
                bgt.s   rs_nonew
rs_pattend      clr.w   rs_patty
                tst.w   rs_nextpt
                bmi     rs_nonextpt
                move.w  rs_nextpt,rs_pointer
                bra.s   rs_newpos
rs_nonextpt     addq.w  #1,rs_pointer
rs_newpos       move.w  rs_pointer(pc),d0
                cmp.w   rs_len,d0
                bne.s   rs_nonewinit
                clr.w   rs_pointer
                move.w  rs_speed(pc),rs_actspeed
                jsr     intrepeat
rs_nonewinit    mw      rs_pointer(pc),d0
                mw      rs_len(pc),d1
                jsr     intsongpos
                bsr     rs_gettrkpos
rs_nonew        move.l  rs_trkpos(pc),a0
                lea     rs_pattline,a1
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.l  (a0)+,(a1)+
                move.w  #-1,rs_nextpt
                rts

rs_p8           tst.w   rs_actcyc
                bnz.s   rs_effects

                bsr     rs_set
                bsr     rs_setperiods ;FIXME - put in rs_set

rs_effects      bsr     rs_effect
                lea     rs_vol,a0

                lea     $dff0a9,a1      ; Questionable conduct when using play8,
                cq      d0              ; but it works fine...
                move.b  (a0)+,d0
                mulu.w  leftvol(pc),d0
                lsr.w   #8,d0
                move.b  d0,(a1)
                cq      d0
                move.b  (a0)+,d0
                mulu.w  rightvol(pc),d0
                lsr.w   #8,d0
                move.b  d0,$10(a1)
                cq      d0
                move.b  (a0)+,d0
                mulu.w  rightvol(pc),d0
                lsr.w   #8,d0
                move.b  d0,$20(a1)
                cq      d0
                move.b  (a0),d0
                mulu.w  leftvol(pc),d0
                lsr.w   #8,d0
                move.b  d0,$30(a1)

                tst.b   rs_filter
                bz.b    rs_blink
                bclr    #1,$bfe001
                rts
rs_blink        bset    #1,$bfe001
                rts

rs_set          lea     rs_pattline(pc),a2
                lea     rs_pbuffs(pc),a3
                lea     rs_samples(pc),a4
                lea     rs_periods(pc),a6

                moveq   #8-1,d7

rs_ploop        tst.b   pb_active(a3)
                bz.b    1$
                bsr.s   rs_set8
                addq.w  #4,a2
1$              lea     pb_SIZEOF(a3),a3
                dbf     d7,rs_ploop
                rts

rs_set8         moveq   #0,d3
                move.b  (a2),d3
                bz      rs_noset
                subq.w  #1,d3

                moveq   #0,d0
                move.b  1(a2),d0
                lsl.w   #5,d0
                lea     0(a4,d0.w),a1

                tst.l   sm_length(a1)
                bz      rs_noset

                push    d0-d2           ; BAF - Flash the note on the display
                mb      d7,d0
                mb      rs_flashnotes(pc,d3.w),d1
                mb      sm_vol(a1),d2
                bsr     intflashnote
                pop     d0-d2

                move.w  d3,pb_note(a3)
                add.w   d3,d3
                move.w  0(a6,d3.w),pb_period(a3)

                lea     rs_vol(pc),a0
                mw      d7,d0
                lsr.b   #1,d0
                move.b  sm_vol(a1),0(a0,d0.w)

                ml      msm_relptr(a1),pb_relptr(a3)
                mw      msm_rellen(a3),pb_rellen(a3)

                mw      d7,d0
                ml      msm_ptr(a1),a0
                mw      msm_len(a1),d1
                mw      msm_replen(a1),d2
                bra     p8_PlaySample

rs_noset        rts

rs_flashnotes   dc.b    0,7,14,21,28,35,42,49,56,64
                dc.b    71,78,85,92,99,106,113,120,128,135
                dc.b    142,149,156,163,170,177,184,192,199,206
                dc.b    213,220,227,234,241,248

rs_setperiods   lea     rs_pbuffs,a3
                mq      #8-1,d7
1$              mw      pb_period(a3),d1
                mw      d7,d0
                bsr     p8_SetPeriod
                lea     pb_SIZEOF(a3),a3
                dbra    d7,1$
                rts

rs_effect       lea     rs_pattline(pc),a2
                lea     rs_pbuffs(pc),a3
                lea     p(pc),a4
                lea     rs_periods(pc),a6
                moveq   #8-1,d7
rs_eloop        tst.b   pb_active(a3)
                bz.b    1$
                bsr     rs_doeff
                addq.w  #4,a2
1$              lea     pb_SIZEOF(a3),a3
                dbf     d7,rs_eloop
                rts

rs_doeff        moveq   #0,d0
                move.b  2(a2),d0
                add.w   d0,d0
                moveq   #0,d1
                move.b  3(a2),d1

                move.w  rs_effecttab(pc,d0.w),d0
                beq.s   rs_noeff
                bmi.s   rs_1eff

                jmp     0(a4,d0.w)

rs_1eff         tst.w   rs_actcyc
                bne.s   rs_noeff
                neg.w   d0
                jmp     0(a4,d0.w)

rs_noeff        rts

rs_effecttab    dc.w    0,rs_portd-p,rs_portu-p,0,0,0
                dc.w    0,0,0,0,rs_arp-p,rs_arp2-p
                dc.w    0,rs_slided-p,0,p-rs_filt,0,p-rs_slideu
                dc.w    0,0,0,p-rs_slided,0,0
                dc.w    0,p-rs_posjmp,0,p-rs_release,p-rs_cspeed,0
                dc.w    rs_slideu-p,rs_volume-p,0,0,0,0

rs_portd        mw      pb_period(a3),d0
                sub.w   d1,d0
                cmp.w   #MINPER,d0
                bhs.b   1$
                mw      #MINPER,d0
1$              mw      d0,pb_period(a3)
                mw      d0,d1
                mw      d7,d0
                bra     p8_SetPeriod

rs_portu        add.w   pb_period(a3),d1
                move.w  d1,pb_period(a3)
                mw      d7,d0
                bra     p8_SetPeriod

rs_arp          move.w  pb_note(a3),d2
                move.w  rs_actcyc,d0
                move.b  rs_divtab(pc,d0.w),d0
                bnz.s   rs_val1
                and.w   #$f0,d1         ;runter
                lsr.w   #4,d1
                sub.w   d1,d2
                bra.s   rs_setarp

rs_val1         subq.b  #1,d0
                bnz.s   rs_val2
                bra.s   rs_setarp

rs_val2         and.w   #$0f,d1
                add.w   d1,d2
                bra.s   rs_setarp

rs_divtab       dc.b    0,1,2,0,1,2,0,1,2,0,1,2,0,1,2,0,1,2

rs_arp2         move.w  pb_note(a3),d2
                move.w  rs_actcyc,d0
                and.w   #3,d0
                bnz.s   rs_val3
                bra.s   rs_setarp

rs_val3         subq.b  #1,d0
                bnz.s   rs_val4
                and.w   #$f,d1
                add.w   d1,d2
                bra.s   rs_setarp

rs_val4         subq.b  #1,d0
                bz.s    rs_setarp
                and.w   #$f0,d1
                lsr.w   #4,d1
                sub.w   d1,d2

rs_setarp       tst.w   d2
                bpl.s   rs_arpok1
                moveq   #0,d2
rs_arpok1       cmp.w   #35,d2
                ble.s   rs_arpok2
                moveq   #35,d2
rs_arpok2       add.w   d2,d2
                move.w  0(a6,d2.w),d1
                move.w  d1,pb_period(a3)
                mw      d7,d0
                bra     p8_SetPeriod

rs_slided       move.w  pb_note(a3),d2
                sub.w   d1,d2
                move.w  d2,pb_note(a3)
                bra.s   rs_setarp

rs_slideu       move.w  pb_note(a3),d2
                add.w   d1,d2
                move.w  d2,pb_note(a3)
                bra.s   rs_setarp

rs_cspeed       and.w   #$f,d1
                beq.s   rs_nochange
                move.w  d1,rs_actspeed
rs_nochange     rts

rs_filt         tst.b   d1
                sne     rs_filter
                rts

rs_volume       lea     rs_vol,a0
                mw      d7,d0
                lsr.w   #1,d0
                add.w   d0,a0
                cmp.w   #$40,d1
                bgt.s   rs_4567
                move.b  d1,(a0)
rs_vex          rts

rs_4567         sub.b   #$40,d1
                cmp.b   #$10,d1
                blt.s   rs_4
                sub.b   #$10,d1
                cmp.b   #$10,d1
                blt.s   rs_5
                sub.b   #$10,d1
                cmp.b   #$10,d1
                blt.s   rs_6
                sub.b   #$10,d1
                cmp.b   #$10,d1
                blt.s   rs_7
                bra.s   rs_vex

rs_6            tst.w   rs_actcyc
                bne.s   rs_vex

rs_4            sub.b   d1,(a0)
                bcc.s   rs_vex
                clr.b   (a0)
                bra.s   rs_vex

rs_7            tst.w   rs_actcyc
                bne.s   rs_vex

rs_5            add.b   d1,(a0)
                cmp.b   #$40,(a0)
                ble.s   rs_vex
                move.b  #$40,(a0)
                bra.s   rs_vex

rs_release      mw      pb_rellen(a3),d1
                bz      rs_rex
                ml      pb_relptr(a3),a0
                cq      d2
                mw      d7,d0
                bra     p8_PlaySample
rs_rex          rts

rs_posjmp       move.w  d1,d0
                and.w   #$f,d0
                lsr.w   #4,d1
                mulu    #10,d1
                add.w   d1,d0
                cmp.w   rs_len,d0
                bge.s   rs_nojmp
                move.w  d0,rs_nextpt
                jsr     intrepeat
rs_nojmp        rts

rs_gettrkpos    lea     rs_patterns(pc),a0
                add.w   rs_pointer(pc),a0
                moveq   #0,d0
                move.b  (a0),d0
                bsr.s   rs_getpattern
                move.l  a0,rs_trkpos
                clr.w   rs_patty
                rts

rs_getppatt     lea     rs_patterns(pc),a0
                add.w   rs_pointer(pc),a0
                moveq   #0,d0
                move.b  (a0),d0
rs_getpattern   lea     rs_pattpts,a0
                add.w   d0,d0
                add.w   d0,d0
                move.l  0(a0,d0.w),a0
                move.w  (a0)+,d0
                rts

                cnop    0,4

rs_remember     dc.l    0
rs_cmformat     dc.l    'CMOD',8,rs_channelmodes
rs_extformat    dc.l    'SAMP',36*32,rs_samples
                dc.l    'SPEE',2,rs_speed
                dc.l    'PLEN',2,rs_len
                dc.l    'PATT',128,rs_patterns,0
rs_channelmodes ds.w    4
rs_channels     ds.w    1
rs_samples      ds.b    36*32
rs_speed        dc.w    6
rs_len          dc.w    1
rs_patterns     ds.b    128
rs_pattpts      ds.l    64
rs_patty        ds.w    1
rs_trkpos       ds.l    1
rs_pbuffs       ds.b    pb_SIZEOF*8
rs_pattline     ds.l    8
rs_pattlinelen  ds.w    1
rs_actspeed     ds.w    1
rs_actcyc       ds.w    1
rs_nextpt       ds.w    1
rs_pointer      ds.w    1
rs_vol          ds.b    4
rs_filter       ds.w    1
rs_oldaud       ds.l    1
rs_periods      dc.w    $358,$328,$2FA,$2D0,$2A6,$280,$25C,$23A,$21A
                dc.w    $1FC,$1E0,$1C5,$1AC,$194,$17D,$168,$153,$140
                dc.w    $12E,$11D,$10D,$FE,$F0,$E2,$D6,$CA,$BE
                dc.w    $B4,$AA,$A0,$97,$8F,$87,$7F,$78,$71

leftvol         dc.w    $100
rightvol        dc.w    $100

name            dc.b    "Oktalyzer (8 channel)",0

errmes          dc.b    "Unknown Oktalyzer module variation",0
errnomem        dc.b    "Not enough memory",0

        end
