home *** CD-ROM | disk | FTP | other *** search
- * 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: player.asm,v 5.1 92/09/14 18:43:30 BAF Exp $
- *
-
- * System includes
- include "exec/types.i"
- include "exec/nodes.i"
- include "exec/memory.i"
- include "exec/interrupts.i"
- include "exec/funcdef.i"
- include "exec/exec_lib.i"
- include "exec/execbase.i"
- include "exec/ables.i"
- include "hardware/cia.i"
- include "hardware/intbits.i"
- include "hardware/dmabits.i"
- include "hardware/custom.i"
- include "resources/cia.i"
- include "dos/dos.i"
- include "dos/dos_lib.i"
- include "intuition/intuition_lib.i"
- include "libraries/xpk.i"
- include "bry/macros.i"
- _LVOAddICRVector equ -$06 ; LVO offsets for ciab.resource
- _LVORemICRVector equ -$0c
- _LVOAbleICR equ -$12
- _LVOSetICR equ -$18
-
-
- include "player.i"
-
- code text
-
- xref toupper,toupperlong,stripblanks,isalpha
- xref allocaudio,freeaudio,intsongpos,intrepeat,clearflash
- xref _progload,_progstart
- xref NoteSys,NoteSysMasterVolBal
-
- xref ntstart,trekstart,ntpackstart,ststart,npstart
- xref fcostart,fc14start,dssstart
- xref jamstart,soundmonstart
- xref oktastart,medstart
- xref soundstart
-
- xref _LinkerDB,_SysBase,_DOSBase,_IntuitionBase,_BattMemBase,_XpkBase
- xref _sysflags,_playmode,_flashflags
- xref GlobSetByte,GlobSetWord,GlobSetLong
- xref mvolume,mbalance,mspeed,volume,balance,speed,modflags,filter
- xref _infowinattach,_infowindetach
-
- xdef loadfile,unloadfile
- xdef loadmod,startmod,playmod,stopmod,endmod,contmod,contplaymod,setsong
- xdef _loadmod,_startmod,_playmod,_stopmod,_endmod,_contmod,_contplaymod,_setsong,_iscantcont
- xdef dienomem,diecorrupt,dieerrplay,diemes
- xdef settint,setnormtint,stoptint,hookfunc,dmawait
- xdef getfreqmodspeed,ntgetsongname,ntgetsongauthor,parseauthor,prepstring,addinfo
- xdef changetint,changetintcia
- xdef playervolume,playerspeed,_playervolume,_playerspeed
- xdef addinfo,addinfopad
- xdef allocmod,allocmodchip
-
- xdef modtype,numsongs,cursong
- xdef modspec,modmem,modsize,modend
- xdef suppmem,suppsize,suppend
- xdef modname,authorname,modtypename,songcatalog
- xdef jumpforward,jumpback
- xdef _modtype,_modname,_authorname,_modtypename,_songcatalog,_playing,_infolist
- xdef _numsongs,_cursong,_songtime,_songendtime,_songpos,_songlen
- xdef _fadevol,_fadeinc
- xdef nocontinue ; For rexxcont's benefit
- xdef nomemtext
-
- *** gmodcheck - Check to see if a particular entry in the GMOD header is used
- * d0 = Offset of entrypoint
- * a5 = GMOD header
- * Returns: NZ if entrypoint is used, Z if it is nonexistent or do-nothing
- gmodcheck:
- gmodbout d0,9$
- cmp.w #RTSINST,0(a5,d0.l)
- rts
- 9$ cmp.l d0,d0
- rts
-
- *** closeloadhan - Close any currently opened loadhan
- closeloadhan:
- move.l loadhan(a4),d1 ; Close the loading handle if opened
- beq.s 1$
- move.l a6,-(sp)
- move.l _DOSBase(a4),a6
- jsr _LVOClose(a6)
- clr.l loadhan(a4)
- move.l (sp)+,a6
- 1$ rts
-
-
- *** allocmod/allocmodchip - Allocate memory attached to this module (freed when module is unloaded)
- * d0 = Amount of memory to allocate
- * Returns: d0 = Memory block, NULL on failure
- allocmodchip
- move.l #MEMF_CHIP,d0
- bra allocmod_in
- allocmod
- moveq #0,d1
- allocmod_in
- move.l a6,-(sp)
- move.l _IntuitionBase(a4),a6
- jsr _LVOAllocRemember(a6)
- move.l (sp)+,a6
- rts
-
-
- *** loadfile - Load a file into a memory filespec
- * a0 = Pointer to filename
- * a1 = Pointer to filespec
- * Returns: NE if successful, EQ if file not found, die if other error
- loadfile:
- apush
- move.l a1,a2
-
- tst.l fs_Mem(a2) ; See if we can decompress
- bne.s 1$ ; Can't decompress on a reload
- move.l _XpkBase(a4),d0
- bne 5$
- 1$
- move.l a0,d1 ; Open module
- move.l #MODE_OLDFILE,d2
- move.l _DOSBase(a4),a6
- jsr _LVOOpen(a6)
- move.l d0,loadhan(a4)
- move.l d0,d7
- beq 99$
-
- move.l d7,d1 ; Seek to end of module
- moveq #0,d2
- move.l #OFFSET_END,d3
- jsr _LVOSeek(a6)
- tst.l d0
- bne dienofile
-
- move.l d7,d1 ; Seek back to beginning and find size
- moveq #0,d2
- move.l #OFFSET_BEGINNING,d3
- jsr _LVOSeek(a6)
- move.l d0,d6
- ble dienofile
-
- move.l fs_Mem(a2),d0 ; See if the memory is already allocated
- beq.s 2$
- cmp.l fs_FileSize(a2),d6 ; Make sure the file wasn't compressed
- beq.s 3$
- bra diedontcompress
- 2$
- move.l _SysBase(a4),a6 ; Allocate memory
- move.l d6,d0
- moveq #MEMF_CHIP!MEMF_PUBLIC,d1
- jsr _LVOAllocMem(a6)
- move.l d0,fs_Mem(a2)
- beq dienocmem
- move.l d6,fs_FileSize(a2)
- move.l d6,fs_AllocSize(a2)
- 3$ move.l d0,d2
- add.l d6,d0
- move.l d0,fs_EndMem(a2)
-
- move.l _DOSBase(a4),a6 ; Load module
- move.l d7,d1
- move.l d6,d3
- jsr _LVORead(a6)
- cmp.l d0,d6
- bne dienofile
-
- bsr closeloadhan ; Close module
-
- bra 9$
-
- 5$ move.l d0,a6
-
- clr.l -(sp) ; Set up the TagList
- lea xpkerrmsg(a4),a1
- move.l a1,-(sp)
- move.l #XPK_GetError,-(sp)
- moveq #1,d1
- move.l d1,-(sp)
- move.l #XPK_PassThru,-(sp)
- moveq #MEMF_CHIP,d1
- move.l d1,-(sp)
- move.l #XPK_OutMemType,-(sp)
- lea fs_FileSize(a2),a1
- move.l a1,-(sp)
- move.l #XPK_GetOutLen,-(sp)
- lea fs_AllocSize(a2),a1
- move.l a1,-(sp)
- move.l #XPK_GetOutBufLen,-(sp)
- move.l a2,-(sp)
- move.l #XPK_GetOutBuf,-(sp)
- move.l a0,-(sp)
- move.l #XPK_InName,-(sp)
-
- move.l sp,a0 ; Try to load the module
- jsr _LVOXpkUnpack(a6)
- adda.w #7*8+4,sp ; Pop the TagList off the stack
- tst.l d0
- bne.s 88$
-
- move.l fs_Mem(a2),d0 ; Calculate the module end position
- add.l fs_FileSize(a2),d0
- move.l d0,fs_EndMem(a2)
-
- 9$ moveq #1,d0
- 99$ apop
- rts
-
- 88$ moveq #XPKERR_IOERRIN,d1 ; See if it was a DOS error
- cmp.l d0,d1
- beq 99$
- moveq #XPKERR_NOMEM,d1 ; See if it was not enough memory
- cmp.l d0,d1
- beq dienocmem
- lea xpkerrmsg(a4),a0 ; Use XPK's error message
- bra diemes
-
- *** unloadfile - Unload a file (if loaded)
- * a0 = Pointer to filespec
- unloadfile:
- move.l fs_Mem(a0),a1
- clr.l fs_Mem(a0)
- move.l a1,d0
- beq.s 9$
- move.l fs_AllocSize(a0),d0
- move.l a6,-(sp)
- move.l _SysBase(a4),a6
- jsr _LVOFreeMem(a6)
- move.l (sp)+,a6
- 9$ rts
-
-
-
- *** findauthor - Find the author of the current song (into authorname)
- * a5 = Pointer to GMOD header
- findauthor:
- moveq #0,d0
- move.l cursong(a4),d1
- movea.w #gmod_GetSongAuthor,a1
- gmodmaycall a1
- move.l d0,authorname(a4)
- bne.s 9$
- lea unknowntxt(a4),a0
- move.l a0,authorname(a4)
- 9$ rts
-
- *** findcursong - Find the song to start playing, adjusting if necessary
- * Returns: d0 = Adjusted song number
- findcursong:
- move.l cursong(a4),d0 ; Check the "recommended" song number
-
- bpl.s 19$ ; See if it's the user's option
- cmp.b #PM_RANDOM,_playmode(a4)
- bne.s 15$
- moveq #0,d0 ; FIXME: Select random song
- bra.s 19$
- 15$ moveq #0,d0
- 19$
- cmp.l numsongs(a4),d0 ; Make sure it's under the maximum
- bcs.s 49$
- moveq #0,d0 ; Always wrap around to song 0
- 49$
- move.l d0,cursong(a4) ; Store it back into cursong
-
- rts
-
- *** setsong - Start playing a different song in the current module
- * d0 = Song number to start playing
- _setsong
- move.l 4(sp),d0
- setsong
- move.l numsongs(a4),d1 ; Make sure there are at least two songs
- subq.l #1,d1
- beq.s 99$
-
- move.l d0,cursong(a4) ; Save new song number
-
- movem.l a5-a6,-(sp)
- move.l gmodptr(a4),a5
- move.l _SysBase(a4),a6
- * DISABLE ; No interrupts while song is stopped
-
- moveq #gmod_StopMusic,d0 ; Stop the current song
- gmodmaycall d0
-
- bsr findcursong ; Find/adjust the song to play
-
- moveq #gmod_StartMusic,d1 ; Start the new music
- gmodmaycall d1
-
- clr.l _songtime(a4) ; Clear the song timer
-
- 9$ bsr findauthor ; See who wrote this song
-
- * ENABLE
- movem.l (sp)+,a5-a6
-
- 99$ bset #SB_WINDOWUP,_sysflags(a4)
- rts
-
- *** catalogsongs - Create a catalog of songs for the current module
- * a5 = GMOD pointer
- catalogsongs:
- apush4
-
- lea modremember(a4),a0 ; Allocate memory for catalog
- move.l numsongs(a4),d0
- move.l d0,d2
- addq.l #1,d0
- lsl.l #2,d0
- bsr allocmod
- move.l d0,songcatalog(a4)
- beq dienomem
-
- move.l d0,a2 ; Create the song list
- movea.w #gmod_GetSongName,a6
- moveq #0,d3
- 11$ move.l d3,d1
- moveq #0,d0
- gmodmaycall a6
- move.l d0,(a2)+
- bne.s 15$
- lea unknowntxt(a4),a0
- move.l a0,-4(a2)
- 15$ addq.l #1,d3
- subq.l #1,d2
- bne.s 11$
- clr.l (a2)
-
- apop4
- rts
-
-
-
- *** freemodfile - Free the modfile string
- freemodfile:
- move.l modfile(a4),d0
- beq.s 9$
- move.l a6,-(sp)
- move.l d0,a1
- move.l modfilesize(a4),d0
- move.l _SysBase(a4),a6
- jsr _LVOFreeMem(a6)
- clr.l modfile(a4)
- move.l (sp)+,a6
- 9$ rts
-
- *** setmodfile - Copy a filename into the modfile buffer
- * a0 = Pointer to filename to copy
- setmodfile:
- movem.l a2/a6,-(sp)
- move.l a0,a2
- bsr freemodfile
-
- move.l a2,a0 ; Find the string length
- moveq #0,d0
- 1$ addq.l #1,d0
- tst.b (a0)+
- bne.s 1$
- move.l d0,modfilesize(a4)
-
- moveq #0,d1 ; Allocate the modfile buffer
- move.l _SysBase(a4),a6
- jsr _LVOAllocMem(a6)
- move.l d0,modfile(a4)
- beq dienomem
-
- move.l d0,a0 ; Copy the buffer
- 2$ move.b (a2)+,(a0)+
- bne.s 2$
-
- movem.l (sp)+,a2/a6
- rts
-
-
- *** addinfopad - Add a pad line to the info list (only if the list is already started)
- addinfopad
- tst.l infolist(a4)
- bz addinfo_rts
- lea nulllab(a4),a0
- ; Fall through...
- *** addinfo - Add a string to the info list (allocate a new info list if necessary)
- * a0 = Text
- addinfo
- apush4
- move.l a0,a3
- move.l _IntuitionBase(a4),a6
-
- bsr _infowindetach
-
- tst.l infolist(a4) ; Make sure we have a list to put things on
- bnz.b \gotlist
- lea modremember(a4),a0
- moveq #MLH_SIZE,d0
- moveq #0,d1
- jl AllocRemember
- move.l d0,infolist(a4)
- bz \out
- move.l d0,a1
- NEWLIST a1
- \gotlist
-
- \lloop
- move.l a3,a2
- moveq #-1,d2
- \loop
- addq.w #1,d2 ; Search for a null in this line
- move.b (a3)+,d0
- bz.b \add
- cmp.b #10,d0
- beq.b \add
- cmp.w #INFOCOLS,d2
- blo.b \loop
-
- move.l a3,a1 ; Search backwards for a word break
- move.w d2,d1
- \bloop
- subq.w #1,d2
- cmp.w #INFOCOLS/2,d2 ; Fill at least half a line
- beq.b \lbreak
- cmp.b #' ',-(a3)
- bne.b \bloop
- addq.w #1,d2
- addq #1,a3
- bra.b \add
-
- \lbreak
- lea -1(a1),a3 ; Break without regard to words
- move.w d1,d2
- \add
- lea modremember(a4),a0 ; Allocate a new info node
- moveq #LN_SIZE+1,d0
- add.w d2,d0
- moveq #0,d1
- jl AllocRemember
- tst.l d0
- bz.b \out
-
- move.l d0,a1 ; Add it to the list
- move.l infolist(a4),a0
- ADDTAIL
-
- lea LN_SIZE(a1),a1 ; Copy the string into it
- move.l a1,LN_NAME-LN_SIZE(a1)
- bra.b \copyin
- \copy
- move.b (a2)+,(a1)+
- \copyin
- dbra d2,\copy
- clr.b (a1)
-
- tst.b -1(a3) ; Next line
- bnz.b \lloop
- \out
- bsr _infowinattach
-
- apop4
- addinfo_rts
- rts
-
-
- *** ldmod - (Internal) - Load module used by loadmod and startmod
- * a0 = Pointer to filename
- * Returns: CCR, d0 = progload()+1, 0 if everything successful, dies on failure
- ldmod:
- move.l modfile(a4),a0 ; Find the filename to display
- move.l (a0),d0
- bsr toupperlong
- cmpi.l #'MOD.',d0
- bne.s 19$
- addq.l #4,a0
- 19$ move.l a0,modname(a4)
-
- lea modspec(a4),a1 ; Load the module
- move.l modfile(a4),a0
- bsr loadfile
- beq dienofile
-
- move.l modmem(a4),a0 ; See if this is a program
- cmpi.l #'PROG',(a0)
- beq \isprog
-
- ; FIXME: Load mod prefs
-
- move.l modmem(a4),a0
- pea 5$
-
- move.l (a0),d0 ; Modules IDable in first long
- cmpi.l #'GMOD',d0 ; General executable module
- beq gmodstart
- cmpi.l #'XMOD',d0 ; Executable module
- beq xmodstart
- cmpi.l #'AMOD',d0 ; Absolute executable module
- beq amodstart
- cmpi.l #'BeEp',d0 ; JamCracker module
- beq jamstart
- cmpi.l #'SMOD',d0 ; Future Composer old module
- beq fcostart
- cmpi.l #'FC14',d0 ; Future Composer 1.4 module
- beq fc14start
- cmpi.l #'OKTA',d0 ; Oktalyzer module
- beq oktastart
- cmpi.l #'MMD0',d0 ; MED 3.xx module
- beq medstart
- cmpi.l #'MMD1',d0 ; OctaMED Pro module
- beq medstart
- cmpi.l #'MMU2',d0 ; Digital Sound Studio module
- beq dssstart
- cmpi.l #$48e7f1fe,d0 ; Dave Whittaker module
- beq whitstart
- cmpi.l #$08f90001,d0 ; SidMon 2.1 module
- beq sid2start
- cmpi.l #$48e700f0,d0 ; Mark II module
- beq markiistart
-
- clr.b d0 ; Face The Music module
- cmpi.l #'FTM'<<8,d0
- beq ftmstart
-
- cmpi.l #'8SVX',$8(a0) ; 8SVX sounds (possibly sequenced)
- beq soundstart
-
- move.l $1a(a0),d0 ; SoundMonitor module
- clr.b d0
- cmpi.l #'V.2'<<8,d0
- beq soundmonstart
-
- cmpi.l #$4eaefeda,$80(a0) ; SoundFX executable module
- beq fxstart
-
- cmpi.l #'PATT',$1f6(a0) ; NoiseTracker packed module
- beq ntpackstart
-
- move.l $438(a0),d0 ; NoiseTrackerish module
- cmpi.l #'M.K.',d0
- beq ntststart
- cmpi.l #'FLT4',d0
- beq ntststart
- cmpi.l #'EXO4',d0
- beq ntststart
-
- cmpi.l #'MTN'<<8,$5b8(a0) ; SoundTracker 2.0-2.6 module
- beq ststart
-
- cmpi.l #'TA1A',$51c(a0) ; Delta Music module
- beq deltastart
- cmpi.l #'TA1A',$27c(a0) ; Delta Music module
- beq delta2start
-
- cmpi.w #$4efa,(a0) ; Generic embedded module
- beq genembstart
-
- move.l a0,a1 ; NoisePacker module
- move.w (a1),d0
- cmp.w #$1c,d0
- blo \notnp
- lea -4(a1,d0.w),a2
- tst.l (a1)+
- bz \notnp
- tst.l (a1)+
- bz \notnp
- \nptest
- cmp.l a2,a1
- bhs npstart
- tst.l (a1)+
- bnz \notnp
- tst.l (a1)+
- bnz \nptest
- \notnp
-
- moveq #$60,d1 ; ST/NT module
- move.b (a0),d0 ; FIXME: Need better detection here
- and.b d1,d0
- beq.s 51$
- move.b $13(a0),d0
- and.b d1,d0
- beq ntstart
-
- 51$ bra dieunkmod ; Doesn't match anything we know of
-
- 5$ move.l d0,gmodptr(a4) ; Save the GMOD header pointer
- move.l d0,a5
-
- moveq #gmod_NotePlayer,d1 ; Give the module our NotePlayer
- moveq #0,d0
- lea NoteSys,a0
- gmodmaycall d1
- tst.l d0
- sne portablemodule(a4)
-
- moveq #gmod_InitMusic,d1 ; Call the initialization vector
- moveq #0,d0
- gmodmaycall d1
- tst.l d0
- beq.s 39$
- move.l d0,a0
- bra diemes
- 39$
- moveq #gmod_GetNumSongs,d1 ; Find the number of songs
- moveq #0,d0
- gmodmaycall d1
- tst.l d0
- bne.s 7$
- moveq #1,d0
- 7$ move.l d0,numsongs(a4)
-
- moveq #gmod_GetMakerName,d1 ; Find the module type
- moveq #0,d0
- gmodmaycall d1
- move.l d0,modtypename(a4)
- bne.s 61$
- lea gmodname(a4),a0
- move.l a0,modtypename(a4)
- 61$
- bsr catalogsongs ; Catalog the songs in the module
-
- bsr findauthor ; See who wrote this song
-
- moveq #0,d0 ; Put the scrolltext into the info window
- moveq #gmod_GetScroll,d1
- gmodmaycall d1
- tst.l d0
- bz.b \noscroll
- move.l d0,-(sp)
- bsr addinfopad
- move.l (sp)+,a0
- bsr addinfo
- \noscroll
-
- moveq #gmod_Hook,d7 ; Give the module our Hook
- lea playerhook(a4),a0
- move.l #GMODHF_REPEAT!GMODHF_SEQUENCE,d1
- moveq #0,d0
- gmodmaycall d7
- btst #GMODHB_SEQUENCE,d0
- bz.s \nohookseq
- bset #MTB_SEQUENCE,modtype(a4)
- \nohookseq:
- btst #GMODHB_REPEAT,d0
- bz.s \nohookrepeat
- bset #MTB_REPEAT,modtype(a4)
- \nohookrepeat:
-
- btst.b #MTB_FILTER,modtype(a4) ; See if we can control the filter
- bnz.b \hasfilt
- lea filter(a4),a0
- sub.l a1,a1
- moveq #-1,d0
- bsr GlobSetByte
- \hasfilt
-
- btst.b #MTB_PROTRACKER,modtype(a4) ; See if it's the Protracker player
- bnz.b \ispt
- lea modflags(a4),a0
- move.b (a0),d0
- bset.b #MNB_NOTPROTRACKER,d0
- bnz.b \ispt
- sub.l a1,a1
- bsr GlobSetByte
- \ispt
-
- btst #MTB_SEQUENCE,modtype(a4) ; See if the player can jump around
- bz.b \nojump
- moveq #gmod_Jump,d0
- bsr gmodcheck
- bz.b \nojump
- bset.b #MTB_JUMP,modtype(a4)
- \nojump
-
- moveq #0,d0
- rts
-
- \isprog: ; We found a module program!
- clr.l -(sp) ; Load the program
- move.l modfile(a4),-(sp)
- clr.l -(sp)
- bsr _progload
- lea 12(sp),sp
- move.l d0,d2
- bsr endmod ; Unload what we loaded
- move.l d2,d0
- addq.l #1,d0
- rts
-
- *** plmod - (Internal) - Play module used by playmod and startmod
- * d0 = 0 to start, 1 to continue
- * Returns 0 if successful, 1 if couldn't continue, dies on other errors
- plmod:
- move.l d0,d7 ; Save start/continue flag
-
- tst.b _playing(a4) ; Don't restart if already playing
- bne 9$
-
- move.l gmodptr(a4),d0 ; Make sure a module is loaded
- beq dienotloaded
- move.l d0,a5
-
- move.b noaudalloc(a4),d0
- or.b portablemodule(a4),d0
- bnz \noalloc
- bsr allocaudio ; Allocate the audio.device
- \noalloc
-
- tst.l d7 ; Start or continue?
- bne.s 15$
-
- move.l _SysBase(a4),a1 ; Find the clock frequency
- move.l #715909,d0
- cmp.b #50,PowerSupplyFrequency(a1)
- bne.s \ntsc
- move.l #709379,d0
- \ntsc move.l d0,clockfreq(a4)
-
- bsr findcursong ; Find the song to start playing
-
- moveq #gmod_StartMusic,d1 ; Start playing the music
- move.l modmem(a4),a0 ; Convenience for built-in players
- gmodmaycall d1
-
- clr.l _songtime(a4) ; Clear the song timer
-
- bclr.b #SB_REPEAT,_sysflags(a4) ; Kill any stray repeat flags
-
- bra.s 19$
- 15$
- moveq #gmod_ContinueMusic,d1 ; Try to continue the music
- moveq #0,d0
- gmodmaycall d1
- tst.l d0
- beq 7$
- 19$
- tst.b portablemodule(a4) ; Set the module's master volume
- bnz \hasvol
- moveq #gmod_SetVolume,d0
- bsr gmodcheck
- bz.b \novol
- \hasvol
- st.b _playing(a4)
- bsr playervolume
- clr.b _playing(a4)
- bra.b \finvol
- \novol
- lea volume(a4),a0 ; Disable the volume control
- sub.l a1,a1
- moveq #-1,d0
- bsr GlobSetWord
- \finvol
-
- lea audisave(a4),a3 ; Set the audio channel interrupts
- lea audints(a4),a2
- moveq #gmod_Audio0,d2
- moveq #INTB_AUD0,d3
- move.w #INTF_SETCLR,d4
- bsr 88$
- bsr 88$
- bsr 88$
- bsr 88$
- move.w d4,CUSTOM+intena
-
- moveq #gmod_VBlank50,d0 ; Set the timing interrupt
- bsr gmodcheck
- beq.s 21$
- moveq #50,d0
- lea gmod_VBlank50(a5),a0
- bra.s 28$
- 21$ moveq #gmod_VBlank60,d0
- bsr gmodcheck
- beq.s 22$
- moveq #60,d0
- lea gmod_VBlank60(a5),a0
- bra.s 28$
- 22$ moveq #gmod_TimerTick,d0
- bsr gmodcheck
- beq.s 29$
- moveq #0,d0
- jsr gmod_GetFrequency(a5)
- tst.l d0
- beq.s 29$
- bpl.s 27$ ; Convenience for internal players
- moveq #50,d0
- bset #MTB_MODSPEED,modtype(a4)
- 27$ lea gmod_TimerTick(a5),a0
- 28$ move.l modmem(a4),a1 ; a1 = module pointer (for our players)
- bsr settint
- bra.b \speeddone
- 29$
- lea speed(a4),a0 ; No speed control - disable the speed gadget
- sub.l a1,a1
- moveq #0,d0
- bsr GlobSetWord
- \speeddone
-
- cmp.b #2,filter(a4) ; Set the filter
- bne.b \filtoff
- \filton
- bclr.b #CIAB_LED,CIAA+ciapra
- bra.b \filtdone
- \filtoff
- bset.b #CIAB_LED,CIAA+ciapra
- \filtdone
-
- st.b _playing(a4) ; Set playing flag
- 9$ moveq #0,d0 ; Return success code
- rts
-
- 88$ move.l a2,a1
- move.l d2,d0
- bsr gmodcheck
- beq.s 89$
- move.b #NT_INTERRUPT,LN_TYPE(a1) ; Set the interrupt vector
- lea audiointname(a4),a0
- move.l a0,LN_NAME(a1)
- lea 0(a5,d2.w),a0
- move.l a0,IS_CODE(a1)
- move.l a4,IS_DATA(a1)
- move.l d3,d0
- move.l _SysBase(a4),a6
- jsr _LVOSetIntVector(a6)
- move.l d0,(a3)
- bset d3,d4 ; Turn on the interrupt later
- 89$ addq.l #4,d2
- addq.l #4,a3
- addq.l #1,d3
- adda.w #IS_SIZE,a2
- rts
-
- 7$ bsr stpmod ; Stop whatever was started
-
- moveq #1,d0 ; Return can't continue error code
- rts
-
- *** stpmod - (Internal) - Stop a playing module
- stpmod:
- tst.b _playing(a4) ; Turn the LED back on
- bz.b \noled
- bclr.b #CIAB_LED,CIAA+ciapra
- \noled
-
- clr.b _playing(a4) ; Clear the playing flag
-
- bsr stoptint ; Stop timer interrupts
-
- lea audisave(a4),a2 ; Stop audio channel interrupts
- moveq #INTB_AUD0,d2
- move.w #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,CUSTOM+intena
- move.w #INTF_AUD0!INTF_AUD1!INTF_AUD2!INTF_AUD3,CUSTOM+intreq
- bsr.s 88$
- bsr.s 88$
- bsr.s 88$
- bsr.s 88$
- bra.s 85$
- 88$ move.l d2,d0
- addq.l #1,d2
- move.l (a2)+,d1
- beq.s 89$
- clr.l -4(a2)
- move.l d1,a1
- move.l _SysBase(a4),a6
- jmp _LVOSetIntVector(a6)
- 89$ rts
- 85$
- move.l gmodptr(a4),d0 ; Stop playing the music
- beq.s 29$
- move.l d0,a5
- moveq #gmod_StopMusic,d0
- gmodmaycall d0
- 29$
- bsr clearflash
-
- bra freeaudio ; Free the audio channels
-
-
- *** loadmod - Load a module without playing it
- * a0 = Pointer to filename
- * Returns: d0 = Null if successful, pointer to error message if failed
- _loadmod
- move.l 4(sp),a0
- loadmod
- movem.l d2-d7/a2-a6,-(sp)
- move.l a0,a2
-
- bsr endmod ; First make sure nothing is playing
-
- move.l sp,stackpt(a4) ; Save the stack pointer in case we die
-
- move.l a2,a0 ; Set/allocate the modfile string
- bsr setmodfile
-
- bsr ldmod ; Load the module
- bz.s 9$
- subq.l #1,d0 ; Find the real return code
-
- 9$ bset #SB_WINDOWUP,_sysflags(a4)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
-
- *** playmod - Play an already-loaded module
- * d0 = Song number (-1 = user's choice)
- * Returns: d0 = Null if successful, pointer to error message if failed
- _playmod
- move.l 4(sp),d0
- playmod
- movem.l d2-d7/a2-a6,-(sp)
- tst.l d0 ; Only change songs if it's specified
- bmi.s 1$
- move.l d0,cursong(a4) ; Save the song number
- 1$
- bsr stpmod ; Stop any previously playing song
-
- move.l sp,stackpt(a4) ; Save the stack pointer in case we die
-
- moveq #0,d0 ; Start playing the module
- bsr plmod
-
- bset #SB_WINDOWUP,_sysflags(a4)
-
- moveq #0,d0 ; Return a success code
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- *** startmod - Load a module and start it playing
- * a0 = Pointer to filename
- * d0 = Song number (-1 = user's choice)
- * Returns: d0 = Null if successful, pointer to error message if failed
- _startmod
- move.l 4(sp),a0
- move.l 8(sp),d0
- startmod
- movem.l d2-d7/a2-a6,-(sp)
- move.l d0,cursong(a4) ; Save the song number
- move.l a0,a2
-
- bsr endmod ; First make sure nothing is playing
-
- move.l sp,stackpt(a4) ; Save the stack pointer in case we die
-
- move.l a2,a0 ; Set/allocate the modfile string
- bsr setmodfile
-
- bsr ldmod ; Load the module
- bz.s 5$
- subq.l #1,d0
- bnz.s 9$
- move.l d0,-(sp)
- move.l a0,-(sp)
- bsr _progstart ; Start the program too
- addq #8,sp
- bra.s 9$
-
- 5$ moveq #0,d0 ; Play the module
- bsr plmod
-
- moveq #0,d0
- 9$ bset #SB_WINDOWUP,_sysflags(a4)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- *** contmod - Continue a module from where it left off
- * Returns: d0 = Null if successful, error message if failed
- contmod
- _contmod
- tst.b _playing(a4) ; See if it's already playing
- bne.s 99$
-
- movem.l d2-d7/a2-a6,-(sp)
- move.l sp,stackpt(a4) ; Save the stack pointer in case we die
-
- moveq #1,d0 ; Continue the module
- bsr plmod
- beq.s 19$
- lea nocontinue(a4),a0 ; Can't continue - error message
- move.l a0,d0
- 19$
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- bset #SB_WINDOWUP,_sysflags(a4)
-
- 99$ moveq #0,d0 ; Return a success code immediately
- rts
-
- *** contplaymod - Continue current module if possible, otherwise restart it
- * Returns: d0 = Null if successful, error message if failed
- contplaymod:
- _contplaymod:
- bsr contmod
- lea nocontinue(a4),a0
- cmp.l a0,d0
- bne.s 9$
- moveq #-1,d0
- bsr playmod
- 9$ rts
-
- *** stopmod - Stop a playing module
- * Returns: d0 = NULL
- stopmod:
- _stopmod:
- movem.l d2-d7/a2-a6,-(sp) ; Stop the module
- bsr stpmod
- movem.l (sp)+,d2-d7/a2-a6
-
- bset #SB_WINDOWUP,_sysflags(a4)
-
- moveq #0,d0
- rts
-
- *** endmod - Stop and unload a module
- * Returns: d0 = NULL
- endmod:
- _endmod:
- movem.l d2-d7/a2-a6,-(sp)
- move.l sp,stackpt(a4)
- moveq #0,d3
- bra.s die
-
- *** die - and other forms of death (from the module player only)
- dienotloaded: ; No module loaded
- lea notloaded(a4),a0
- bra.s diemes
- diedontcompress: ; Reloaded compressed module
- lea dontcompress(a4),a0
- bra.s diemes
- dienofile: ; File not found
- lea nofile(a4),a0
- bra.s diemes
- dieunkmod: ; File is not a module
- lea unkmod(a4),a0
- bra.s diemes
- diecorrupt: ; Module is corrupt
- lea cormod(a4),a0
- bra.s diemes
- dieerrplay: ; Error playing module
- lea errplay(a4),a0
- bra.s diemes
- dienoabs:
- lea noabs(a4),a0 ; Couldn't allocate absolute memory
- bra.s diemes
- dienotimer:
- lea notimer(a4),a0 ; Couldn't allocate either CIAB timer
- bra.s diemes
- dienocmem: ; Not enough memory
- lea nocmem(a4),a0
- bra.s diemes
- dienomem: ; Not enough memory
- lea nomemtext(a4),a0
- diemes:
- move.l a0,d3
- die:
- bsr stpmod ; Stop playing the module
-
- move.l gmodptr(a4),d0 ; Prepare to unload
- beq.s 29$
- move.l d0,a5
- moveq #gmod_EndMusic,d0
- gmodmaycall d0
- clr.l gmodptr(a4)
- 29$
- clr.l songcatalog(a4) ; Erase all pointers to memory we are about to free
- clr.l infolist(a4)
-
- bsr _infowinattach ; Clear out the info window
-
- lea modremember(a4),a0 ; Free any miscellaneous memory we allocated for the module
- moveq #1,d0
- move.l _IntuitionBase(a4),a6
- jl FreeRemember
-
- bsr closeloadhan ; Close any handle we were trying to load with
-
- lea modspec(a4),a0 ; Free the module memory
- bsr unloadfile
-
- lea suppspec(a4),a0 ; Free any secondary data file
- bsr unloadfile
-
- moveq #1,d0 ; Default to one song
- move.l d0,numsongs(a4)
- clr.l cursong(a4)
-
- clr.b modtype(a4) ; Default no special module type
-
- clr.l authorname(a4) ; Control-panel text fields
- clr.l modtypename(a4)
- clr.l modname(a4)
-
- clr.l ntauthor(a4)
-
- clr.b noaudalloc(a4)
-
- moveq #-1,d0
- move.l d0,_songlen(a4)
-
- move.w d0,_fadevol(a4)
-
- bset #SB_WINDOWUP,_sysflags(a4)
-
- bsr freemodfile ; Free the modfile buffer
-
- move.l stackpt(a4),sp ; Return to caller
- move.l d3,d0
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
-
- *** moveabs - Move the module to an absolute position in memory (reload if necessary)
- * a0 = Position to move module to
- * Returns: a0 = New module position
- moveabs:
- apush4
-
- move.l modsize(a4),d0 ; Allocate the required memory
- move.l d0,d2
- move.l a0,a1
- move.l a0,a2
- move.l _SysBase(a4),a6
- jl AllocAbs
- tst.l d0
- bz.b 1$
-
- move.l modmem(a4),a0 ; Copy the module to the final location
- move.l a2,a1
- move.l d2,d0
- jl CopyMem
-
- move.l modmem(a4),a1 ; Free the old memory block
- move.l modalloc(a4),d0
- jl FreeMem
-
- move.l a2,modmem(a4) ; Point to the new block
- move.l d2,modalloc(a4)
- add.l d2,a2
- move.l a2,modend(a4)
-
- bra 9$
-
- 1$ move.l modmem(a4),a1 ; First free the old block
- move.l modalloc(a4),d0
- jl FreeMem
- clr.l modmem(a4)
-
- move.l a2,a1 ; Now see if we can allocate the memory
- move.l d2,d0
- jl AllocAbs
- tst.l d0
- bz dienoabs
-
- move.l a2,modmem(a4) ; Point to the new memory block
- move.l d2,modalloc(a4)
- add.l d2,a2
- move.l a2,modend(a4)
-
- lea modspec(a4),a1 ; Re-load the file at the required address
- move.l modfile(a4),a0
- bsr loadfile
- beq dienofile
-
- 9$ move.l modmem(a4),a0
- apop4
- rts
-
-
- *** hookfunc - Hook function called by modules
- * a1 = Parameter packet
- hookfunc:
- move.l (a1)+,d0
- cmpi.l #GMODHF_SEQUENCE,d0
- beq.s \sequence
- cmpi.l #GMODHF_REPEAT,d0
- beq intrepeat
- moveq #0,d0
- rts
-
- \sequence:
- move.l (a1)+,d0
- move.l (a1)+,d1
- bra intsongpos
-
-
- *** getfreqmodspeed - Get the default module speed and set the MODSPEED flag
- getfreqmodspeed:
- moveq #50,d0
- bset #MTB_MODSPEED,modtype(a4)
- rts
-
-
- *** parseauthor - Find the author name in a string which potentially contains one
- * a0 = Pointer to string
- * Returns:
- * a0 = Pointer to beginning of author name or NULL if none found
- * a1 = Pointer to first character relating to the author name (<= a0)
- parseauthor:
- move.l a0,a1
- bra.s 11$ ; Search for 'by' keyword
- 1$ move.l a0,a1
- move.b (a0)+,d0
- bz.s 9$
- cmp.b #$a9,d0 ; Check for "⌐"
- beq 99$
- bsr isalpha
- bnz.s 1$
- 11$ move.b (a0),d0
- bsr toupper
- cmp.b #'C',d0 ; Check for "(C)"
- bne.s 12$
- cmp.b #'(',-1(a0)
- bne.s 12$
- cmp.b #')',1(a0)
- beq.s 92$
- 12$ cmp.b #'B',d0 ; Check for "BY"
- bne.s 1$
- move.b 1(a0),d0
- bsr toupper
- cmp.b #'Y',d0
- bne.s 1$
- move.b 2(a0),d0
- bsr isalpha
- bnz.s 1$
- 92$ addq.l #2,a0
- 99$ rts
-
- 9$ sub.l a0,a0 ; Return null for both strings
- move.w a0,a1
- rts
-
- *** prepstring - Prepare author/song name string for display - chop puctuation, etc.
- * a0 = String to prepare
- * Returns:
- * a0 = New pointer to string
- prepstring:
- move.l a2,-(sp)
-
- bsr stripblanks ; Strip leading and trailing blanks
- bz.s 9$
-
- move.l a0,a1 ; Hunt down and eliminate EdPlayer junk
- 1$ move.b (a1)+,d0
- bz.s 19$
- cmp.b #'`',d0
- bne.s 1$
- lea -1(a1),a2
- move.l a2,-(sp)
- cmp.b #'`',(a1)+
- bne.s 13$
- subq.l #1,a1
- addq.l #1,(sp)
- 13$ move.b (a1)+,(a2)+
- bne.s 13$
- move.l (sp)+,a1
- bra.s 1$
- 19$
- subq.l #1,a1 ; Eliminate some punctuation at the end
- 21$ cmp.l a0,a1
- beq.s \empty
- cmp.b #'.',-(a1)
- beq.s 25$
- cmp.b #',',(a1)
- bne.s 29$
- 25$ clr.b (a1)
- bra.s 21$
- 29$
- 9$ move.l (sp)+,a2
- rts
- \empty:
- sub.l a0,a0
- bra.s 9$
-
-
- *** ntgetsongname - Get song name (and possibly author) from a NoiseTracker module
- ntgetsongname:
- move.l modmem(a4),a0 ; See if the author's name is in the title
- bsr parseauthor
- move.l a0,d0
- bz.s 9$
-
- clr.b (a1) ; Separate it from the title
- bsr prepstring
- move.l a0,ntauthor(a4)
-
- 9$ move.l modmem(a4),a0 ; Return the title
- bsr prepstring
- move.l a0,d0
- rts
-
- *** ntgetsongauthor - Get author name from a NoiseTracker module
- ntgetsongauthor:
- movem.l a2-a3,-(sp)
-
- move.l ntauthor(a4),d0 ; See if we already found the author
- bnz 9$
-
- bsr addinfopad ; Display the instrument list verbatim
- move.l modmem(a4),a0
- lea 20(a0),a2
- lea 31*30(a2),a3
- \info
- tst.b (a2)
- bz.b \noinfo
- move.l a2,a0
- bsr addinfo
- \noinfo
- lea 30(a2),a2
- cmp.l a3,a2
- bne.b \info
-
- move.l modmem(a4),a0 ; Find an entry with author keywords
- lea 20(a0),a2
- lea 31*30(a2),a3
- 1$ move.l a2,a0
- bsr parseauthor
- move.l a0,d0
- bnz.s 2$
- lea 30(a2),a2
- cmp.l a3,a2
- bne.s 1$
-
- move.l modmem(a4),a0 ; Find an IntuiTracker scroll line
- lea 20(a0),a0
- lea 31*30(a0),a3
- 3$ cmp.b #'#',(a0)+
- beq.s 4$
- lea 30-1(a0),a0
- cmp.l a3,a0
- bne.s 3$
-
- moveq #0,d0 ; Nothing found at all
- bra.s 9$
-
- 2$ bsr prepstring ; Strip leading and trailing blanks
- move.l a0,d0
- bnz.s 9$
-
- lea 30(a2),a0 ; Nothing on that line - use the next line
- cmp.b #'#',(a0) ; Skip leading IntuiTracker junk
- bne.s 4$
- addq.l #1,a0
- cmp.b #'#',(a0) ; If there are *two*, it's probably decoration
- bne.s 4$
- subq.l #1,a0
- 4$ bsr prepstring
- move.l a0,d0
-
- 9$ movem.l (sp)+,a2-a3
- rts
-
-
- *** gmodstart - Code for general modules (GMOD's)
- gmodstart:
- move.l gmod_LoadAddress(a0),d1 ; Move the module if necessary
- beq.s 19$
- move.l d1,a0
- bsr moveabs
- 19$ move.l a0,d0
- move.l gmod_Maker(a0),gmodnametype(a4) ; Find the module's maker ID
- rts
-
- *** amodstart - Code for Absolute Executable modules (AMOD's)
- amodloc equ $10
-
- amodstart:
- move.l amodloc(a0),a0 ; Move to the required position
- bsr moveabs
- ; Fall through and execute like an XMOD...
- *** xmodstart - Code for Executable modules (XMOD's)
- xminitentry equ $4
- xmvbentry equ $8
- xmendentry equ $c
-
- xmodstart:
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodbra 3$ ; StopMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- jmp xmvbentry(a1) ; TimerTick
- lea xmodname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ move.l modmem(a4),a0
- jmp xminitentry(a0)
-
- 3$ move.l modmem(a4),a0
- jmp xmendentry(a0)
-
- *** ntstart - Code to differentiate between ST/NT/PT and StarTrekker
- ntststart:
- move.l modfile(a4),a0 ; Check for a StarTrekker ".NT" file
- move.l sp,a2
- moveq #4,d0
- 11$ addq.l #1,d0
- tst.b (a0)+
- bne.s 11$
- bclr #0,d0
- sub.l d0,sp
- move.l sp,a1
- move.l modfile(a4),a0
- bra.s 13$
- 12$ move.b d0,(a1)+
- 13$ move.b (a0)+,d0
- bne.s 12$
- move.b #'.',(a1)+
- move.b #'N',(a1)+
- move.b #'T',(a1)+
- clr.b (a1)
- move.l sp,a0
- lea suppspec(a4),a1
- bsr loadfile
- move.l a2,sp
- bnz trekstart ; Go to appropriate startup
- bra ntstart
-
- *** genembstart - Code for generic embedded-player modules (such as NoiseTracker packed w/player)
- genembstart:
- cmpi.w #$4efa,4(a0) ; Make sure the other two JMP's exist
- bne diecorrupt
- cmpi.w #$4efa,8(a0)
- bne diecorrupt
-
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodbra 3$ ; StopMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- gmodbra 5$ ; TimerTick
- lea genembname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ movem.l d2-d7/a2-a6,-(sp)
- moveq #0,d0
- move.l modmem(a4),a5
- jsr (a5)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- 3$ movem.l d2-d7/a2-a6,-(sp)
- move.l modmem(a4),a5
- jsr 8(a5)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- 5$ movem.l d2-d7/a2-a6,-(sp)
- jsr 4(a1)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- *** fxstart - Code for SoundFX modules
- fxstart:
- movem.l a5/a6,-(sp)
- move.l modmem(a4),a5
- move.l _SysBase(a4),a6
-
- lea $80(a5),a0 ; Make sure it's a SoundFX module
- move.w #($a20-$80)/4-1,d0
- moveq #0,d1
- 1$ add.l (a0)+,d1
- dbra d0,1$
- cmpi.l #$97adddd8,d1
- bne diecorrupt
-
- move.l $20(a5),d0 ; Relocate the player
- add.l d0,d0
- add.l d0,d0
- cmp.l modsize(a4),d0
- bge diecorrupt
- lea $30(a5,d0.l),a0
- cmpi.l #$3ec,-$c(a0)
- bne diecorrupt
- moveq #49-1,d0
- lea $24(a5),a1
- move.l a1,d2
- 12$ move.l (a0)+,d1
- add.l d2,0(a1,d1.l)
- dbra d0,12$
-
- move.l #$4e714e71,$196(a5) ; NOP out AddICRVector
- move.l #$4e714e71,$1a8(a5) ; NOP out call to set CIA stuff
-
- bsr clearcache
-
- movem.l (sp)+,a5/a6
- plstartret 9$
-
- 2$ movem.l d2-d7/a2-a6,-(sp) ; Jump into player start code
- move.l modmem(a4),a0
- jsr $13e(a0)
- movem.l (sp)+,d2-d7/a2-a6
- rts
-
- 5$ move.l modmem(a4),a0 ; Calculate interrupt frequency
- move.l #715909,d0
- divu.w $a64(a0),d0
- ext.l d0
- rts
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodnop
- gmodnop
- gmodnop
- gmodq 1
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra 5$ ; GetFrequency
- jmp $466(a1) ; TimerTick
- lea fxname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- *** whitstart - Code for Dave Whittaker modules
- dwinitentry equ $00
- dwvbentry equ $0e
- dwendentry equ $1c
-
- whitstart:
- moveq #6-1,d0 ; Make sure it's really a DW module
- 1$ move.w $0(a0),d1
- add.w $4(a0),d1
- add.w $8(a0),d1
- add.w $c(a0),d1
- cmpi.w #$453b,d1
- bne diecorrupt
- adda.w #$e,a0
- dbra d0,1$
-
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodbra 3$ ; StopMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- jmp dwvbentry(a1) ; TimerTick
- lea whitname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ move.l modmem(a4),a0
- jmp dwinitentry(a0)
-
- 3$ move.l modmem(a4),a0
- jmp dwendentry(a0)
-
- *** deltastart - Code for Delta Music modules
- deltastart:
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- gmodbra 4$ ; TimerTick
- lea deltaname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ push d2-d7/a2-a6
- move.l modmem(a4),a0
- moveq #1,d0
- jsr (a0)
- pop d2-d7/a2-a6
- rts
-
- 4$ push d2-d7/a2-a6
- moveq #0,d0
- jsr (a1)
- pop d2-d7/a2-a6
- rts
-
- delta2start: ; Different version (older probably)
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- gmodbra 4$ ; TimerTick
- lea deltaname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ push d2-d7/a2-a6
- move.l modmem(a4),a0
- jsr (a0)
- pop d2-d7/a2-a6
- rts
-
- 4$ push d2-d7/a2-a6
- jsr $17c(a1)
- pop d2-d7/a2-a6
- rts
-
- *** sid2start - Code for SidMon modules
- sid2start:
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- jmp $16a(a1) ; TimerTick
- lea sidname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ move.l modmem(a4),a0 ; Put an RTS after the interrupt routine
- move.w #$4e75,$25c(a0)
- bsr clearcache
-
- move.l modmem(a4),a0 ; Call the initialization routine
- push d2-d7/a2-a6
- jsr $2c(a0)
- pop d2-d7/a2-a6
- rts
-
- *** markiistart - Code for Mark II modules
- markiistart:
- cmpi.l #$41fa035e,4(a0) ; Check a little more...
- bne diecorrupt
-
- plstartret 9$
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra 2$ ; StartMusic
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodbra getfreqmodspeed ; GetFrequency
- gmodbra 3$ ; TimerTick
- lea markiiname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- 2$ move.l modmem(a4),a0
- moveq #-1,d0
- push d2-d7/a2-a6
- jsr (a0)
- pop d2-d7/a2-a6
- rts
-
- 3$ moveq #0,d0
- push d2-d7/a2-a6
- jsr (a1)
- pop d2-d7/a2-a6
- rts
-
- *** ftmstart - Code for Face The Music modules
-
- ftm_init equ 4
- ftm_end equ 8
- ftm_load equ 12 ; d0 = filename, returns nonzero = success
- ftm_unload equ 16
- ftm_play equ 20
- ftm_stop equ 24
- ftm_set1 equ 28
- ftm_set2 equ 32
- ftm_get1 equ 36
- ftm_get2 equ 40
- ftm_waitdone equ 44
- ftm_get3 equ 48
- ftm_ccall equ 52
-
- ftmstart:
- apush4
-
- st.b noaudalloc(a4)
-
- lea modspec(a4),a0 ; We can't use the already-loaded module!
- bsr unloadfile
-
- move.l _DOSBase(a4),a6 ; Load PlayFTM
- lea playftmname(a4),a0
- move.l a0,d1
- jl LoadSeg
- move.l d0,ftmseg(a4)
- bz.b \noplayer
-
- lsl.l #2,d0 ; Find jump table (a5, ftmtab)
- addq.l #4,d0
- move.l d0,ftmtab(a4)
- move.l d0,a5
-
- jsr ftm_init(a5) ; Initialize PlayFTM
-
- move.l modfile(a4),d0 ; Re-load the module through PlayFTM
- jsr ftm_load(a5)
- tst.l d0
- bz \corrupt
-
- apop4
- plstartret 9$
-
- \noplayer
- lea ftmnoplayer(a4),a0
- bra diemes
-
- \corrupt
- lea corrcomp(a4),a0
- bra diemes
-
- \start
- moveq #0,d0 ; Start playing
- moveq #0,d1
- moveq #0,d2
- moveq #0,d3
- move.l ftmtab(a4),a0
- jmp ftm_play(a0)
-
- \stop
- move.l ftmtab(a4),a0
- jmp ftm_stop(a0)
-
- \end
- move.l ftmtab(a4),a0
- jsr ftm_unload(a0)
- jmp ftm_end(a0)
-
- cnop 0,4
- dc.l gmod_Hook
- 9$ gmodnop
- gmodbra \start
- gmodbra \stop
- gmodbra \end
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- gmodnop
- lea ftmname(a4),a0 ; GetMakerName
- move.l a0,d0
- rts
-
- *** unloadftm - FIXME - KLUDGE - unload the FTM player (called by main.c)
- xdef _unloadftm
- _unloadftm
- apush4
- move.l _DOSBase(a4),a6
- move.l ftmseg(a4),d1
- bz.b 1$
- jl UnLoadSeg
- 1$ apop4
- rts
-
-
- *** setnormtint - Set the timer interrupt using the current module's default speed
- * a0 = Pointer to interrupt routine to be called on interrupts
- * a1 = Data that should appear in register a1 on interrupt calls
- setnormtint:
- moveq #50,d0
- ; fall through...
- *** settint - Set the timer interrupt
- * a0 = Pointer to interrupt routine to be called on interrupts
- * a1 = Data that should appear in register a1 on interrupt calls
- * d0 = Number of ticks per second (frequency) to call interrupt routine
- settint:
- movem.l a2/a3,-(sp)
-
- move.l a0,sint+IS_CODE(a4) ; Initialize the timer interrupt
- move.l a1,sint+IS_DATA(a4)
- move.b #NT_INTERRUPT,d1
- move.b d1,sint+LN_TYPE(a4)
- move.b d1,tint+LN_TYPE(a4)
- lea sint(a4),a0
- move.l a0,tint+IS_DATA(a4)
- move.l _SysBase(a4),a0
- lea _LVOCause(a0),a0
- move.l a0,tint+IS_CODE(a4)
-
- move.w d0,-(sp)
-
- move.l _BattMemBase(a4),a6
- lea tint(a4),a1 ; First try to get timer B
- moveq #CIAICRB_TB,d0
- move.b d0,timernum(a4)
- move.l #CIAB+ciatblo,a2
- move.l a2,timerlo(a4)
- move.l #CIAB+ciacrb,a3
- jsr _LVOAddICRVector(a6)
- tst.l d0
- beq.s 1$
-
- lea tint(a4),a1 ; Already taken - try timer A
- moveq #CIAICRB_TA,d0
- move.b d0,timernum(a4)
- move.l #CIAB+ciatalo,a2
- move.l a2,timerlo(a4)
- move.l #CIAB+ciacra,a3
- jsr _LVOAddICRVector(a6)
- tst.l d0
- bne dienotimer
- 1$
- and.b #%11000000,(a3) ; Set the control register
- tst.b timernum(a4)
- beq.s 3$
- bclr #6,(a3)
- 3$
- move.w (sp)+,d0 ; Set the timer frequency
- bsr changetint
-
- bset #0,(a3) ; Start the timer
-
- movem.l (sp)+,a2-a3
-
- move.b timernum(a4),d1 ; Enable the timer interrupt
- moveq #-$80,d0
- bset d1,d0
- jmp _LVOAbleICR(a6)
-
- *** changetint - Change the timer interrupt speed (callable from an interrupt)
- * d0 = New frequency (Hz)
- * All registers saved
- changetint:
- tst.l tint+IS_CODE
- bz.b 9$
- push d0-d1/a0-a1
- lea _LinkerDB,a1
-
- move.w d0,tintfreq(a1) ; Store the new frequency
-
- tst.l tint+IS_CODE(a1)
- bz.b 9$
-
- mulu.w mastfreq(a1),d0
- lsr.l #8,d0
- bz.b \zero
-
- move.l clockfreq(a1),d1 ; Poke the new timer value
- divu.w d0,d1
- move.l timerlo(a1),a0
- move.b d1,(a0)
- lsr.w #8,d1
- move.b d1,$100(a0)
- \zero
- pop d0-d1/a0-a1
- 9$ rts
-
- *** changetintcia - Change the timer interrupt speed (callable from an interrupt)
- * d0 = CIA speed value
- * All registers saved
- changetintcia:
- push d0-d1/a0-a1
- lea _LinkerDB,a1
-
- tst.l tint+IS_CODE(a1)
- bz.b 9$
-
- move.l timerlo(a1),a0 ; Poke the new timer value
- moveq #0,d1
- move.w d0,d1
- lsl.l #8,d1
- divu.w mastfreq(a1),d1
- move.b d1,(a0)
- lsr.w #8,d1
- move.b d1,$100(a0)
-
- move.l clockfreq(a1),d1 ; Find the new frequency to display
- divu.w d0,d1
- move.w d1,tintfreq(a1)
-
- 9$ pop d0-d1/a0-a1
- rts
-
- *** stoptint - Stop the timer interrupt if it was installed
- stoptint:
- tst.l tint+IS_CODE(a4) ; Make sure it was installed
- beq.s 9$
- moveq #0,d0 ; Remove the interrupt handler
- move.b timernum(a4),d0
- lea tint(a4),a1
- move.l _BattMemBase(a4),a6
- jsr _LVORemICRVector(a6)
- clr.l tint+IS_CODE(a4)
- 9$ rts
-
-
-
- *** playervolume - Update the master volume for the currently playing module
- playervolume
- _playervolume
- apush4
-
- tst.b _playing(a4) ; Make sure we're playing something
- bz \out
-
- move.w mbalance(a4),d2 ; Find the new overall volume (d0)
- move.w balance(a4),d3
- move.w mvolume(a4),d1
- move.w volume(a4),d0
- bpl.b \hasvol
- moveq #100,d0
- moveq #100,d1
- moveq #0,d2
- moveq #0,d3
- \hasvol
- mulu.w d1,d0
- lsl.l #8,d0
- divu.w #10000,d0
- move.w d0,d1
-
- tst.w d2 ; Adjust for master balance
- bz.b \mgot
- bmi.b \mmoreleft
- \mmoreright
- neg.w d2
- add.w #50,d2
- mulu.w d2,d0
- divu.w #50,d0
- bra.b \mgot
- \mmoreleft
- add.w #50,d2
- mulu.w d2,d1
- divu.w #50,d1
- \mgot
-
- tst.w d3 ; Adjust for module balance
- bz.b \got
- bmi.b \moreleft
- \moreright
- neg.w d3
- add.w #50,d3
- mulu.w d3,d0
- divu.w #50,d0
- bra.b \got
- \moreleft
- add.w #50,d3
- mulu.w d3,d1
- divu.w #50,d1
- \got
-
- move.w _fadevol(a4),d2 ; Adjust for fading
- bmi.b \nofade
- mulu.w d2,d0
- lsr.w #7,d0
- mulu.w d2,d1
- lsr.w #7,d1
- \nofade
-
- tst.b portablemodule(a4) ; Tell the module about the new volume
- bnz \portavol
- move.l gmodptr(a4),a5
- moveq #gmod_SetVolume,d2
- gmodmaycall d2
- bra \out
- \portavol
- bsr NoteSysMasterVolBal
- \out
- apop4
- rts
-
- *** playerspeed - Update the master speed
- playerspeed
- _playerspeed
- push a6
-
- move.w speed(a4),d0 ; Calculate the new relative speed
- bnz.b \ok
- moveq #50,d0
- \ok
- move.w mspeed(a4),d1
- mulu.w d1,d0
- lsl.l #8,d0
- divu.w #50*50,d0
- move.w d0,mastfreq(a4)
-
- move.l _SysBase(a4),a6 ; Set the new speed
- jl Disable
- move.w tintfreq(a4),d0
- bsr changetint
- jl Enable
-
- pop a6
- rts
-
-
- *** jumpforward - Jump one sequence forward in the module
- jumpforward
- move.l gmodptr(a4),d0
- bz \out
- push d5/a5
- move.l d0,a5
- moveq #0,d0
- move.l songpos(a4),d1
- addq.l #1,d1
- moveq #gmod_Jump,d5
- gmodmaycall d5
- pop d5/a5
- \out
- rts
-
- *** jumpback - Jump one sequence backward in the module
- jumpback
- move.l gmodptr(a4),d0
- bz \out
- push d5/a5
- move.l d0,a5
- moveq #0,d0
- move.l songpos(a4),d1
- bz.b \out1
- subq.l #1,d1
- moveq #gmod_Jump,d5
- gmodmaycall d5
- \out1
- pop d5/a5
- \out
- rts
-
-
- *** iscantcont - See if an error is a 'can't continue' error
- * a0 = Pointer to message in question
- * Returns: d0 = nonzero if a0 is a can't continue error
- _iscantcont
- move.l 4(sp),a0
- iscantcont
- moveq #0,d0
- lea nocontinue(a4),a1
- cmp.l a1,a0
- seq d0
- rts
-
- *** dmawait - DMA delay wait
- dmawait:
- movem.l d0-d1,-(sp)
- moveq #7-1,d1
- 1$ move.b $dff006,d0
- 2$ cmp.b $dff006,d0
- beq.s 2$
- dbf d1,1$
- movem.l (sp)+,d0-d1
- rts
-
-
- *** clearcache - Clear the code cache
- clearcache:
- move.l a6,-(sp)
- move.l 4,a6
- cmpi.w #36,LIB_VERSION(a6)
- bcs.s 13$
- jsr _LVOCacheClearU(a6)
- 13$ move.l (sp)+,a6
- rts
-
-
- data __MERGED
-
- _numsongs:
- numsongs dc.l 1 ; Number of songs in this module
- _cursong:
- cursong dc.l 0 ; Current song number
-
- playerhook dc.l 0,0,hookfunc ; Hook to send to modules
-
- mastfreq dc.w $100 ; Master relative frequency ($100=normal)
-
- _fadevol dc.w -1 ; Current fade volume
-
- even
- gmodname dc.b "GMOD ("
- gmodnametype dc.l 0
- dc.b ")",0
-
- nocmem dc.b "Not enough chip memory",0
- nomemtext dc.b "Not enough memory",0
- unkmod dc.b "Unknown module type",0
- cormod dc.b "Corrupt module",0
- errplay dc.b "Error playing module",0
- nofile dc.b "Can't load module",0
- noabs dc.b "Required memory occupied",0
- notimer dc.b "No CIAB timers available",0
- dontcompress dc.b "Please decompress this module",0
- genembname dc.b "Generic embedded-player",0
- xmodname dc.b "XMOD/AMOD",0
- whitname dc.b "Dave Whittaker",0
- deltaname dc.b "Delta Music",0
- sidname dc.b "SidMon",0
- markiiname dc.b "Mark II",0
- fxname dc.b "SoundFX",0
- unknowntxt dc.b "Unknown",0
- notloaded dc.b "No module loaded",0
- nocontinue dc.b "Module cannot continue",0
- audiointname dc.b "MultiPlayer audio interrupt",0
- playftmname dc.b "PlayFTM:",0
- ftmnoplayer dc.b "Can't load Face The Music player",0
- corrcomp dc.b "Corrupt (or compressed) FTM module",0
- ftmname dc.b "Face The Music"
- nulllab dc.b 0
-
- bss __MERGED
-
- stackpt ds.l 1 ; Stack pointer when we die while loading
- loadhan ds.l 1 ; Handle currently being loaded
- gmodptr ds.l 1 ; Pointer to real or fake GMOD structure
-
- modspec: ; Currently loaded module
- modmem ds.l 1
- modsize ds.l 1
- modend ds.l 1
- modalloc ds.l 1
-
- suppspec: ; Supplemental data file (Startrekker, TFMX)
- suppmem ds.l 1
- suppsize ds.l 1
- suppend ds.l 1
- suppalloc ds.l 1
-
- modfile ds.l 1 ; Filename of module
- _modname:
- modname ds.l 1 ; Displayed name of module
- modfilesize ds.l 1 ; Allocated size of modfile
-
- _authorname:
- authorname ds.l 1 ; Name of song's author
- _modtypename:
- modtypename ds.l 1 ; Type of module
- _songcatalog:
- songcatalog ds.l 1 ; Catalog of song names for current module
- _infolist:
- infolist ds.l 1 ; List of information lines for Info window
-
- cursongprefs ds.l 1 ; Pointer into songprefs for current song
-
- clockfreq ds.l 1 ; CIA clock frequency
-
- _songtime ds.l 1 ; Number of VBlanks this song has played
- _songendtime ds.l 1 ; When this song should end
-
- _songpos
- songpos ds.l 1 ; Current sequence number
- _songlen
- songlen ds.l 1 ; Total number of sequences in song
-
- ntauthor ds.l 1 ; Author name from NoiseTracker modules
-
- ftmseg ds.l 1 ; SegList of PlayFTM
- ftmtab ds.l 1 ; FTM jump table
-
- timerlo ds.l 1 ; Address of CIA timer low counter register
-
- audints ds.b IS_SIZE*4 ; Audio channel interrupts
- audisave ds.l 4 ; Previous interrupt vectors
-
- modremember ds.l 1 ; Remember list attached to this module
-
- tint ds.b IS_SIZE
- sint ds.b IS_SIZE
-
- tintfreq ds.w 1 ; Timer interrupt frequency (un-user-adjusted)
-
- _fadeinc ds.w 1 ; +1 or -1 - which way to fade
-
- xpkerrmsg ds.b 80 ; Buffer for XPK error messages
-
- _playing ds.b 1 ; Module is currently playing
- noaudalloc ds.b 1 ; Don't allocate the audio hardware
-
- timernum ds.b 1 ; Which CIAB timer we got
-
- _modtype
- modtype ds.b 1 ; Module type flags
-
- portablemodule ds.b 1 ; Nonzero if we're playing a portable module
-
- end
-