*** Header file used for creating and calling GMOD modules ***
* Public domain by Bryan Ford

        ifnd    BRY_GMOD_I
BRY_GMOD_I      set     1

        ifnd    EXEC_TYPES_I
        include "exec/types.i"
        endc


*** This is the layout of the first part of every GMOD module.
 STRUCTURE      GMOD,0
        ; The first four longwords contain various important values.
        ULONG   gmod_ID                 ; Must be 'GMOD'
        ULONG   gmod_Maker              ; ID of creator program (ASCII, like IFF ID's)
        ULONG   gmod_LoadAddress        ; Address at which to load module (0L = any)
        ULONG   gmod_MaxVecOfs          ; Offset of end of vector table (numvecs+4)*4

        ; From here on are the entrypoints
        ; (actual instructions, not just vector pointers)
        LONG    gmod_InitMusic          ; Initialize the module
        LONG    gmod_StartMusic         ; Start playing (d0.l = song number)
        LONG    gmod_StopMusic          ; Stop playing
        LONG    gmod_EndMusic           ; Shut down the module
        LONG    gmod_NotePlayer         ; Tell the module to use a NotePlayer (a0 = NotePlayer)
        LONG    gmod_ContinueMusic      ; Restart after pause
        LONG    gmod_VBlank50           ; VBlank interrupt (50Hz)
        LONG    gmod_VBlank60           ; VBlank interrupt (60Hz)
        LONG    gmod_Audio0             ; Channel 0 audio interrupt
        LONG    gmod_Audio1             ; Channel 1 audio interrupt
        LONG    gmod_Audio2             ; Channel 2 audio interrupt
        LONG    gmod_Audio3             ; Channel 3 audio interrupt
        LONG    gmod_GetNumSongs        ; Get number of songs (d0.l)
        LONG    gmod_GetSongName        ; Get description of a song (d1.l) into (d0.p)
        LONG    gmod_GetSongAuthor      ; Get the name of a song's author (d1.l) into (d0.p)
        LONG    gmod_GetFrequency       ; Get the timing frequency for the song (d0.l)
        LONG    gmod_TimerTick          ; Routine to call at specified frequency
        LONG    gmod_GetMakerName       ; Get name of creator program
        LONG    gmod_Hook               ; Specify a Hook to call on various events
        LONG    gmod_Jump               ; Jump somewhere else in song
        LONG    gmod_SetVolume          ; Set master volume ($0-$100)
        LONG    gmod_GetScroll          ; Get scroll text
        LABEL   gmod_SIZEOF             ; This will grow!

        ; Flags for the gmod_Hook call - similar to Intuition's IDCMP flags
        BITDEF  GMODH,REPEAT,0          ; Call when music repeats
        BITDEF  GMODH,SEQUENCE,1        ; Call when sequence changes


*** Use these macros to help when playing GMOD modules.
*** All of them assume that the pointer to the GMOD module is in a5.

* Branch if a vector offset (gmod_xxx) is in range
gmodbin         macro   ; DReg,label
                cmp.l   gmod_MaxVecOfs(a5),\1
                bcs     \2
                endm

* Branch if a vector offset (gmod_xxx) is out of range
gmodbout        macro   ; DReg,label
                cmp.l   gmod_MaxVecOfs(a5),\1
                bcc     \2
                endm

* Call a GMOD vector WITHOUT checking - you must first make sure it's there!
gmodcall        macro   ; DReg
                jsr     0(a5,\1)
                endm

* Same as gmodcall, but with an immediate (as opposed to register) vector offset
gmodcalli       macro   ; Offset
                jsr     \1(a5)
                endm

* This is what you'll usually use when calling GMOD entrypoints -
* it first checks to make sure the entrypoint is available, THEN calls
* it.  The GMOD pointer must be in a5, and the vector offset must
* be in some data register.
gmodmaycall     macro   ; DReg
                cmp.l   gmod_MaxVecOfs(a5),\1
                dc.w    $6404           ; bra.s *+2
                gmodcall \1
                endm


*** Use these macros if you are DEFINING a GMOD header.  This makes it
*** easier if you don't happen to know the lengths of the various instructions
*** by memory.

* Do-nothing entrypoint - stick this in entrypoints you don't need or can't support
gmodnop         macro                   ; Do-nothing entry in a GMOD header
                rts
                nop
                endm

* Branch to some other location (makes the GMOD header act like a jump table)
gmodbra         macro   ; <label>       ; 4-byte branch.
                jmp     \1(pc)          ; (Some assemblers would optimize down a bra.w.)
                endm

* The following macro is useful for a few entrypoints like GetNumSongs
* where you just need to return a small constant value.
gmodq           macro   ; const         ; Return quick constant
                moveq   #\1,d0
                rts
                endm

        endc
