**************************************************
********** MusicMon 2.5 Replay Routine ***********
**********                             ***********
********** a short HowTo               ***********
**************************************************

replay.inl is the actual replay routine. The new replay will not play back old modules
created with versions < V2.5.

Changes to the interface since MM2.0:

INIT1 call (Base+4) now expects a so called 'Timer-Use-Mask' by that 
you can control which timers the routine allocates for playing Digis 
and SIDs. The specified timers are assigned dynamically to the channels
as needed. 

Changes to the interface since MM2.1:

The INIT2 call is now obsolete and accordingly also the need to copy 
modules with digi sounds in memory. You can still call the function, 
it will just return without doing anything. Accordingly the ASK call 
is now obsolete. Also this function can still be called, will have 
no harm.

Another change is that some of the calls now return an error code in D0
to inform the caller about the success.

-------------------------------------------------------------------------

There are two different ways of using the replay routine:

The first one is using the so called "comfort header" which is basically 
good for integration into high level languages. On using the comfort-header 
patching of Timer C, ACIA and spurious IRQ as well as restauration work is
done for you automatically as well as according clean up on calling the 
DEINIT function. All parameters are handed over on the stack. 

The second way is the "foot way" where you have to establish your own interrupt
handler from that you are calling te soundroutine frequently. Any patching 
and restauration work you have to do also explicitely. Fortunately there are
some sub-routines supporting you in that (see below). The advantage of this 
method is to be more flexible.

Attention: Do not mix up the two variants! Either you are doing anything via
the comfort-header (routbase+32), OR you are doing anything on the footway 
calling the other routines but not routbase+32!

There are two example sources showing both variants:

* MODPLAY.GFA shows use of the comfort-header
* EXAMPLE.S   shows how to do it the footway

Note: The replay routine makes use of the reset resident memory space
      Range from $200 to $2CC is reserved!

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Following the jump-in offsets including parameter description:

routbase = Address where you loaded replay.inl to.

; -----------------------------------------------------------------------------
; I. routbase+0      ASK, routine to query the new overall length of a Digi-Module
;                    after conversion by INIT2

;    OBSOLETE!!! Will always provide -1 in A0!
;    
;    OUT : A0 = -1 (originally meant : not a digi module)
;
; -----------------------------------------------------------------------------
; II. routbase+4     INIT1, Initialization for all kind of modules
;                    Can be called multiple times to restart replay
;

;    IN:       A0 = Baseadress of the module
;              D0 = Timer-Use-Mask (SID+DIGI+Sync-Buzzer)
;                   (Bit 0 = Timer A, Bit 1 = Timer B, Bit 2 = Timer C, Bit 3 = Timer D)
;
;   OUT:       A0 = Address of Info-Block (see below for details)
;            D0.l = 0 ok, -1 unkown format, -2 wrong version
; ------------------------------------------------------------------------------------
; III. routbase+8    INIT2
;
;    OBSOLETE!!!
;
; ------------------------------------------------------------------------------
; IV. routbase+12    SOUND, actual replay routine for modules without sounds
;                    with 100 oder 200Hz
;                    Call with 50Hz !!!
; ------------------------------------------------------------------------------
; V. routbase+16     SOUND2, also actual replay routine, but for modules
;                    using sounds with 100 or 200Hz
;                    Call with 200Hz !!!
; ------------------------------------------------------------------------------
; VI. routbase+20    FAST-DIGI on/off

;
; NO MORE SUPPORTED SINCE V 2.1  
;
; -------------------------------------------------------------------------------
; VII. routbase+24   VOLUME CONTROL

;     IN:            D0.b = set mastervolume (0-15) or -1, if not to modify
;                           0 means maximum volume, 15 means minimum volume!
;                    D1.b = fade in (pos. values), fade out (neg. values)
;                           The value determines the fading speed, the
;                           closer to 0, the faster it is
;                           In case of D1.b=0, no fading at all!
; -----------------------------------------------------------------------------
; VIII routbase+28   ASKING FOR MODUL TYPE

;       IN:          A0   = Baseadress of the module
;      OUT:          D0.l =     Bit 0 - set, if this is a digi module
;                               Bit 1 - set, if module uses sounds >50HZ
;                               Bit 2 - set, if module uses SID-Voices
;				Bit 3 - set, if module uses Sync Buzzer Voices
;                               -1 = unkown format
;                               -2 = wrong version
; -----------------------------------------------------------------------------
; IX routbase+32 COMFORT-HEADER

; good for integrating in high level languages since it comes with
; an own interrupt driver (VBL and Timer C) and applies according patches
; to ACIA and Timer C in the context of digis and SIDs
; Also spurious interrupt is already respected
;
; all parameters are handed over on stack, see below for Details
; return-values in D0, if applicable

; -----------------------------------------------------------------------------
; X routbase+36 Timer-INTERRUPTS OFF

; stops the timers used for Digis, SIDs and Sync Buzzers (according to 
; Timer-Use-Mask set on INIT1)
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XI mod.base+40 SOUNDS OFF

; clears any sound output
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XII mod.base+44 PATCH ACIA

; Patches the Acia Interrupt so that it does not distrubr digis, SIDs and Sync-Buzzers
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XIII mod.base+48 UNPATCH ACIA

; Undos ACIA patching
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XIV mod.base+52 PATCH TIMER C

; Patches Timer C Interrupt so that it does not distrubr digis, SIDs and Sync-Buzzers
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XV mod.base+56 UNPATCH TIMER C

; Undos Timer C patching
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XVI mod.base+60 PATCH SPURIOUS INTERRUPT

; Patches Spurious interrupt
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XVII mod.base+64 UNPATCH SPURIOUS INTERRUPT

; Undos Spurious interrupt patching
;
; no parameters, no return-value
; ----------------------------------------------------------------------------
; XVIII mod.base+68 Create SNDH Header

; Will create a sndh header followed by the actual replay at the given address
; Just stitch a MOD behind it and save all that stuff to disc to get a ready to use
; SNDH file.
;
; IN:  4(sp) = (L) Targetaddress
;      8(sp) = (L) Title (zero terminated string)
;     12(sp) = (L) Composer (zero terminated string)
;     16(sp) = (L) Year (zero terminated string)
;     20(sp) = (L) Ripper (zero terminated string)
;     24(sp) = (W) Playtime in seconds
; 
; Put all the stuff on the stack, starting with playtime, ending with targetaddress
;
; OUT: d0.l = number of bytes written
; ----------------------------------------------------------------------------


; ***************************************************
; *****            The Comfort-Header          ******
; ***************************************************
; ***** Parameters on the stack!               ******
; *****                                        ******
; ***** +++ ASK FOR MODULE TYPE +++            ******
; *****                      L: Modul Baseadr. ******
; *****                      W: Funct.No. #0   ******
; ***** Return in D0.b :                       ******
; *****                     Bit 0 - Digis      ******
; *****                     Bit 1 - >50Hz      ******
; *****                     Bit 2 - SID        ******
; *****                     Bit 3 - Sync-Buzz  ******
; *****                     -1 unknown format  ******
; *****                     -2 wrong version   ******
; *****                                        ******
; ***** +++ ASK FOR NEW LENGTH (DIGI-MODULE) + ******
; *****                                        ******
; ***** OBSOLETE!!!                            ******
; *****                                        ******
; ***** +++ INIT 1 (all  modules) +++          ******
; *****                L: Module Baseadr.      ******
; *****                W: Timer-Use-Mask       ******
; *****                   Bit 0 : Timer A      ******
; *****                   Bit 1 : Timer B      ******
; *****                   Bit 2 : IGNORED      ******
; *****                   Bit 3 : Timer D      ******
; *****                                        ******
; *****                W: Funct.No #2          ******
; *****                                        ******
; ***** Return in D0.L :		       ****** 
; *****                x Adress of infoblock   ******
; *****               -1 unkown format         ******
; *****               -2 wrong version         ******
; *****                                        ******
; ***** +++ INIT 2 (OSOLETE!!!)		       ******
; *****                                        ******
; ***** +++ START INTERRUPT +++                ******
; *****                W: Integration Method   ******
; *****                                        ******
; ***** 0 = VBL-QUEUE                          ******
; ***** 1 = VBL direct (System-routine in)     ******
; ***** 2 = VBL direct ("     "        out)    ******
; ***** 3 = TIMER C (System-routine in)        ******
; ***** 4 = TIMER C (System-routine out)       ******
; *****                                        ******
; *****                W: Funct.No #4          ******
; *****                                        ******
; ***** +++ DEINIT +++                         ******
; ***** (stops Timers, stops sound-routine,    ******
; *****  removes patches, etc.)                ******
; *****                                        ******
; *****                W: Funct.No. #5         ******
; *****                                        ******
; ***** +++ VOLUME SET / FADER +++             ******
; *****                                        ******
; *****                B: MASTERVOLUME         ******
; *****                   0 = max., 15 = min.  ******
; *****                   -1 = no effect       ******
; *****                B: Fadespeed (+ or -)   ******
; *****                   + fades in           ******
; *****                   - fades out          ******
; *****                W: Funct.No. #6         ******
; *****                                        ******
; ***************************************************

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Description of the infoblock:

A call to INIT1 provides the address of the infoblock. The information 
this data structure provides can be used to create e.g. fancy jukeboxes.

This is the structure :

infoblock:      dc.b 0             ; [0]  Loop Counter
                dc.b 0             ; [1]  reserved
                dc.w 0             ; [2]  reserved
                dc.l 0             ; [4]  Pointer to the names of the synth sounds
					  (NULL in case of not stored in the module)
                dc.l 0             ; [8]  Pointer to the names of the synth sounds
					  (NULL in case of not stored in the module)
                dc.l 0             ; [12] reserved

                rept 3

; 16 Bytes per channel:

                dc.b $FF           ; (0) current note ($FF = not any yet)
                dc.b $FF           ; (1) current Sound# ($FF = not any yet)
                dc.b 0             ; (2) current Sound-Type (0 = PSG, 1 = Digi, 2 = SID, 3 = SyncB)
                dc.b 0             ; (3) reserved
                dc.l 0             ; (4) Pointer to Digi Sample Pointer (Channel A + B only)
                dc.b 0             ; (8) Current Value of Timer Control-Register 
                dc.b 0             ; (9) Current Value of Timer Data-Register 
                dc.w 0             ; (10) reserved
                dc.l 0             ; (12) reserved

                endr

; A reflection of the current values of the first 14 PSG registers:

register:       ds.b 14		   ; (Volume registers are only valid for sounds of type PSG)


Note : The pointers to the sound names point to the first sound name. All sound names are
       zero terminated strings stored one after the other. After the last synth sound name 
       an end mark $FF is stored. Directly after that the digi names follow also with a $FF mark
       at the end.


The demo module player written in GFA-Basic demonstrates how to handle the infoblock and 
the sound name lists.

