* 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: misca.asm,v 5.1 92/09/14 18:40:10 BAF Exp $
*

        include "exec/types.i"
        include "exec/nodes.i"
        include "exec/interrupts.i"
        include "exec/funcdef.i"
        include "exec/execbase.i"
        include "exec/exec_lib.i"
        include "intuition/intuition_lib.i"
        include "intuition/intuitionbase.i"
        include "dos/dos.i"
        include "bry/macros.i"
        include "player.i"

        xref    _LinkerDB,_SysBase,_sysflags,_procpt,_songpos,_songlen
        xref    _curmod,_fadevol,_fadeinc,playervolume
        xref    _sysflags,_playing,_songtime,_songendtime
        xref    _spectrum,_flashactive,_flashytaskptr
        xref    scopechandata,notetab,scrollline,scrolllines,_scopeinterval

        xdef    intsongpos,intrepeat,intflashnote,intflashsample,intflashscroll,clearflash
        xdef    _vblankint,_scopeinterval

        code    text

        xref    _IntuitionBase

*** intsongpos - Set a new song position, callable from an interrupt
* d0.w = Position in song
* d1.w = Length of song
* Returns ALL registers saved (convenience for internal players)
intsongpos:
        movem.l d0-d1/a0-a1/a6,-(sp)
        lea     _LinkerDB,a1
        move.l  d0,_songpos(a1)         ; Store the new values
        move.l  d1,_songlen(a1)
        bset    #SB_TIMERUP,_sysflags(a1)
        bra.s   intsig

*** intrepeat - Signal the MultiPlayer task that the module is repeating
* Returns ALL registers saved (convenience for internal players)
intrepeat:
        movem.l d0-d1/a0-a1/a6,-(sp)
        lea     _LinkerDB,a1

        cmpi.b  #PM_OVEROVER,_playmode(a1)
        beq.b   intout

        bset    #SB_REPEAT,_sysflags(a1)

        move.l  _curmod(a1),d0
        bz.b    intsig
        move.l  d0,a0
        tst.w   mn_volume(a0)
        bmi.b   intsig
        btst    #MNB_ENDFADE,mn_flags(a0)
        bz.b    intsig
        move.w  #128,_fadevol(a1)
        move.w  #-1,_fadeinc(a1)
        bra.b   intout

intsig:
        move.l  _SysBase(a1),a6         ; Signal the main task
        move.l  _procpt(a1),a1
        move.l  #SIGBREAKF_CTRL_F,d0
        jsr     _LVOSignal(a6)
intout
        movem.l (sp)+,d0-d1/a0-a1/a6
        rts


*** vblankfunc - Vertical blank function
vblankfunc:
        move.l  a1,a5

        tst.b   _playing(a5)            ; Don't do anything unless we're playing something
        bz.b    \out

        move.w  _fadevol(a5),d0         ; Perform any fading in progress
        bgt     \fade
\fadeback

        movem.l _songtime(a5),d0/d1     ; Update the song time
        addq.l  #1,d0
        move.l  d0,_songtime(a5)
        tst.l   d1
        bz.b    \endback
        cmp.l   d1,d0
        bhs     \endhit
\endback

        subq.b  #1,seccnt(a5)           ; Signal the main task every second
        bz      \second
\secback

        subq.b  #1,flashycnt(a5)        ; Signal the main task every flash
        bnz.b   \flashback
        move.b  #FFperF,flashycnt(a5)
        tst.b   _flashactive(a5)        ; Only if flashy window is operative
        bnz     \flashy
\flashback

\out
        moveq   #0,d0
        rts

\fade
        add.w   _fadeinc(a5),d0
        bz.b    \fadedone
        cmp.w   #128,d0
        bls.b   \fadenotdone
        mq      #-1,d0
\fadedone
        move.w  d0,_fadevol(a5)
        bset    #SB_FADEDONE,_sysflags(a5)
        pea     \fadeback(pc)
        bra.b   \int
\fadenotdone
        move.w  d0,_fadevol(a5)
        exg     a4,a5
        bsr     playervolume
        exg     a4,a5
        bra.b   \fadeback

\second:                                ; Signal that a second has elapsed
        move.l  _SysBase(a5),a1
        move.b  VBlankFrequency(a1),seccnt(a5)
        bset    #SB_SECOND,_sysflags(a5)
        pea     \secback(pc)

\int:
        move.l  _procpt(a5),a1          ; Signal the main task
        move.l  #SIGBREAKF_CTRL_F,d0
        move.l  _SysBase(a5),a6
        jmp     _LVOSignal(a6)

\endhit:                                ; Signal that we (may be) repeating
        btst    #SB_REPEAT,_sysflags(a5)
        bnz     \endback
        pea     \endback(pc)
        bra     intrepeat

\flashy                                 ; Signal to update the flashy window
        mq      #4-1,d0                 ; Update the scope channels
        lea     scopechandata+scd_SIZEOF*4(a5),a0
\scopechan
        suba.w  #scd_SIZEOF,a0
        tst.w   scd_len(a0)
        bz.b    \scopechandone
        move.w  scd_pos(a0),d1
        add.w   scd_inc(a0),d1
        bcs.b   \scopechanovf
        move.w  d1,scd_pos(a0)
        add.w   #SCOPEWIDTH,d1
        cmp.w   scd_len(a0),d1
        bhi.b   \scopechanovf
\scopechandone
        dbra    d0,\scopechan

        move.l  _flashytaskptr(a5),d1   ; Signal the flashy task
        bz      \flashback
        move.l  d1,a1
        move.l  #SIGBREAKF_CTRL_F,d0
        move.l  _SysBase(a5),a6
        pea     \flashback(pc)
        jmp     _LVOSignal(a6)

\scopechanovf                           ; Got to the end of the sample
        move.w  scd_rep(a0),scd_pos(a0)
        bnz.b   \scopechandone
\scopechanoff                           ; Turn channel off
        clr.w   scd_len(a0)
        bra.b   \scopechandone


*** clearflash - Clear the flashy display
clearflash
        lea     _spectrum(a4),a0        ; Clear the spectrum display
        mq      #SPECTRUMRES/4-1,d0
1$      clr.l   (a0)+
        dbra    d0,1$
        clr.w   scopechandata+scd_len(a4) ; Stop the scope
        clr.w   scopechandata+scd_SIZEOF+scd_len(a4)
        clr.w   scopechandata+scd_SIZEOF*2+scd_len(a4)
        clr.w   scopechandata+scd_SIZEOF*3+scd_len(a4)
        clr.w   scrolllines(a4)         ; Clear the note scroller
        st.b    _flashactive(a4)
        rts

*** intflashnote - Start a new note in the spectrogram
* d0.b = Channel (0-4)
* d1.b = Note frequency (0-255)
* d2.b = Volume (0-64)
intflashnote
        push    d0-d2/a0/a4
        lea     _LinkerDB,a4

        tst.b   _flashflags(a4)
        bz.b    \out

        lsr.b   #4,d1                   ; Set the spectrogram
        ext.w   d1
        lsr.b   #1,d2
        lea     _spectrum(a4),a0
        bmi     \out
        cmp.b   0(a0,d1.w),d2
        bls.b   \nomiddle
        move.b  d2,0(a0,d1.w)
\nomiddle
        lsr.w   #1,d2
        cmp.b   -1(a0,d1.w),d2
        bls.b   \noleft
        move.b  d2,-1(a0,d1.w)
\noleft
        cmp.b   1(a0,d1.w),d2
        bls.b   \noright
        move.b  d2,1(a0,d1.w)
\noright

        st.b    _flashactive(a4)        ; There's now something to display
\out
        pop     d0-d2/a0/a4
        rts

*** intflashsample - Start a new note in the scope
* d0.w = Channel (0-4)
* a0 = Sample data pointer
* d1.w = Period at which this sample will play
* d2.w = Sample length in bytes (0 = turn channel off)
* d3.w = Repeat part length in bytes (0 = no repeat)
intflashsample
        push    d0-d4/a1/a4
        lea     _LinkerDB,a4

        tst.b   _flashflags(a4)
        bz.b    \outout

        ext.w   d0

        cmp.w   #4,d0                   ; Protection
        bhs.b   \out
        tst.w   d1
        bz.b    \out

        move.w  d0,d4                   ; Find the appropriate channel data structure
        lea     scopechandata(a4),a1
        lsl.w   #4,d4
        add.w   d4,a1

        move.w  d2,scd_len(a1)
        bz.b    \out
        move.l  a0,scd_sample(a1)
        clr.w   scd_pos(a1)
        sub.w   d3,d2
        bnz.b   \smallrep
        mq      #1,d2
\smallrep
        cmp.w   #2,d3
        bhi.b   \hasrep
        mq      #0,d2
\hasrep move.w  d2,scd_rep(a1)
        cmp.w   scd_per(a1),d1
        beq.b   \nodiv
        move.l  _scopeinterval(a4),d0
        divu.w  d1,d0
        move.w  d1,scd_per(a1)
        move.w  d0,scd_inc(a1)
\nodiv
*        mq      #SCOPEWIDTH,d0          ; Prevent static displays for short samples
*        add.w   scd_inc(a1),d0
*        cmp.w   scd_len(a1),d0
*        blo.b   \out
*        move.w  #SCOPEWIDTH,scd_inc(a1)
\out
        st.b    _flashactive(a4)
\outout
        pop     d0-d4/a1/a4
        rts

*** intflashscroll - Change note scroller position
* Must have already set notetab and scrollmod
* d0.w = Current line number
* d1.w = Number of lines in this pattern
intflashscroll
        move.w  d0,scrollline
        move.w  d1,scrolllines
        st.b    _flashactive
        rts

        data    __MERGED

        xdef    _prefs,_prefsend

_prefs                                  ; All the saved preferences variables
        dcxd.b  playmode,PM_SEQUENCE
        dcxd.b  showmode,SM_SEQUENCE0

        dcxd.w  zoomwinleft,$135
        dcxd.w  zoomwintop,$a

        dcxd.w  progwinleft,$13a
        dcxd.w  progwintop,$25

        dcxd.w  prefswinleft,$3
        dcxd.w  prefswintop,$23

        dcxd.w  spectrumwinleft,$5
        dcxd.w  spectrumwintop,$a

        dcxd.w  scopewinleft,$99
        dcxd.w  scopewintop,$a

        dcxd.w  channelwinleft,$135
        dcxd.w  channelwintop,$a

        dcxd.b  flashflags,0
        dcxd.b  keepprog,0

        dcxd.w  tinywinleft,-1
        dcxd.w  tinywintop,0

        dcxd.w  qscopewinleft,$99
        dcxd.w  qscopewintop,$42

        dcxd.w  notewinleft,$5
        dcxd.w  notewintop,$42

        dcxd.w  settingswinleft,$2
        dcxd.w  settingswintop,$3

        dcxd.b  pausefade,1

        dsxd.b  hotkey,30+1

        dcxd.w  mspeed,50
        dcxd.w  mvolume,100
        dcxd.w  mbalance,0

        dcxd.w  modfrleft,0
        dcxd.w  modfrtop,0
        dcxd.w  modfrwidth,0
        dcxd.w  modfrheight,0

        dcxd.w  progfrleft,0
        dcxd.w  progfrtop,0
        dcxd.w  progfrwidth,0
        dcxd.w  progfrheight,0

        dcxd.w  infowinleft,2
        dcxd.w  infowintop,80

        dcxd.b  appicon,0

        dsxd.b  mainfontname,0
        dc.b    "topaz.font",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0          ; 31 bytes
        dsxd.b  listfontname,0
        dc.b    "topaz.font",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0          ; 31 bytes
        dcxd.w  mainfontsize,8
        dcxd.w  listfontsize,8

        dcxd.w  fontreqleft,0
        dcxd.w  fontreqtop,0
        dcxd.w  fontreqwidth,0
        dcxd.w  fontreqheight,0

        dcxd.b  contprogonerr,0

        dcxd.b  appicona,0

* This setting is controlled by the Nasty Audio button on the Prefs window.  If set, audio channels
* are always allocated at maximum priority, disallowing any other programs from playing beeps and
* other sounds on top of the music.
        dcxd.b  nasty_audio,0

_prefsend

                even

rnd             ds.l    2

_vblankint:
                dc.l    0,0
                dc.b    NT_INTERRUPT,-10
                dc.l    intname
                dc.l    _LinkerDB
                dc.l    vblankfunc

intname         dc.b    "MultiPlayer VBlank",0

seccnt          dc.b    1
flashycnt       dc.b    1

        end
