
************************************************************************
*                                                                      *
*   FUTURE.ASM                                                         *
*                                                                      *
*   Copyright (C) 1985, Commodore Amiga Inc.  All rights reserved.     *
*                                                                      *
*   Portions copyright 1986 Applied Visions, 15 Oak Ridge Road,        *
*           Medford, Mass. 02155  (617) 488-3602                       *
*                                                                      *
************************************************************************/

*************************************************************************
*
* future sound library source
*   based on mylib.asm, from RKM 1.1 Vol. 2 Appendix, and Errata 1.1 disk
*
*   V1.0 by John Foust, for Applied Visions, 22-Jun-86.
*
* Source Control
* ------ -------
* 
* $Header: amain.asm,v 31.3 86/06/20 18:58:00 jjf Exp $
*
* $Locker: john foust $
*
* $Log:   amain.asm,v $
*
************************************************************************/

   SECTION  text,CODE

   NOLIST
   include "exec/types.i"
   include "exec/nodes.i"
   include "exec/lists.i"
   include "exec/libraries.i"
   include "exec/alerts.i"
   include "exec/initializers.i"
   include "exec/resident.i"
   include "libraries/dos.i"

   include "asmsupp.i"

   include "future.i"

   LIST

   ;------ These don't have to be external, but it helps some
   ;------ debuggers to have them globally visible
   XDEF   Init
   XDEF   Open
   XDEF   Close
   XDEF   Expunge
   XDEF   Null
   XDEF   myName

; These are the external Lattice C functions for FutureSound
; They were compiled with stack checking off, with '-v' on lc2.

   XDEF   FSGetSize
   XDEF   FSLoadSound
   XDEF   FSPlaySound
   XDEF   FSStopSound

   XREF   _GetSize
   XREF   _LoadSound
   XREF   _PlaySound
   XREF   _StopSound

; These are used by the library for the startup code.

   XREF   _AbsExecBase

   XLIB   OpenLibrary
   XLIB   CloseLibrary
   XLIB   Alert
   XLIB   FreeMem
   XLIB   Remove


   ; The first executable location.  This should return an error
   ; in case someone tried to run you as a program (instead of
   ; loading you as a library).

Start:
   CLEAR   d0
   rts

;-----------------------------------------------------------------------
; A romtag structure.  Both "exec" and "ramlib" look for
; this structure to discover magic constants about you
; (such as where to start running you from...).
;-----------------------------------------------------------------------

   ; Most people will not need a priority and should leave it at zero.
   ; the RT_PRI field is used for configuring the roms.  Use "mods" from
   ; wack to look at the other romtags in the system
MYPRI   EQU   0

initDDescrip:
               ;STRUCTURE RT,0
     DC.W    RTC_MATCHWORD ; UWORD RT_MATCHWORD
     DC.L    initDDescrip  ; APTR  RT_MATCHTAG
     DC.L    EndCode       ; APTR  RT_ENDSKIP
     DC.B    RTF_AUTOINIT  ; UBYTE RT_FLAGS
     DC.B    VERSION       ; UBYTE RT_VERSION
     DC.B    NT_LIBRARY    ; UBYTE RT_TYPE
     DC.B    MYPRI         ; BYTE  RT_PRI
     DC.L    myName        ; APTR  RT_NAME
     DC.L    idString      ; APTR  RT_IDSTRING
     DC.L    Init          ; APTR  RT_INIT
               ; LABEL RT_SIZE


   ; this is the name that the library will have
myName:      FSLIBNAME

   ; a major version number.
VERSION:   EQU   1

   ; A particular revision.  This should uniquely identify the bits in the
   ; library.  I use a script that advances the revision number each time
   ; I recompile.  That way there is never a question of which library
   ; that really is.

REVISION:   EQU   1

   ; this is an identifier tag to help in supporting the library
   ; format is 'name version.revision (dd MON yyyy)',<cr>,<lf>,<null>
idString:   dc.b   'future 1.0 (20 JUN 1986)',13,10,0

dosName:   DOSNAME

   ; force word allignment
   ds.w   0


   ; The romtag specified that we were "RTF_AUTOINIT".  This means
   ; that the RT_INIT structure member points to one of these
   ; tables below.  If the AUTOINIT bit was not set then RT_INIT
   ; would point to a routine to run.

Init:
   DC.L   MyLib_Sizeof   ; data space size
   DC.L   funcTable      ; pointer to function initializers
   DC.L   dataTable      ; pointer to data initializers
   DC.L   initRoutine    ; routine to run


funcTable:

   ;------ standard system routines
   dc.l   Open
   dc.l   Close
   dc.l   Expunge
   dc.l   Null

   ;------ my library function table
   dc.l   FSGetSize
   dc.l   FSLoadSound
   dc.l   FSPlaySound
   dc.l   FSStopSound

   ;------ function table end marker
   dc.l   -1


   ; The data table initializes static data structures.
   ; The format is specified in exec/InitStruct routine's
   ; manual pages.  The INITBYTE/INITWORD/INITLONG routines
   ; are in the file "exec/initializers.i".  The first argument
   ; is the offset from the library base for this byte/word/long.
   ; The second argument is the value to put in that cell.
   ; The table is null terminated
dataTable:
   INITBYTE   LH_TYPE,NT_LIBRARY
   INITLONG   LN_NAME,myName
   INITBYTE   LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
   INITWORD   LIB_VERSION,VERSION
   INITWORD   LIB_REVISION,REVISION
   INITLONG   LIB_IDSTRING,idString
   DC.L   0


   ; This routine gets called after the library has been allocated.
   ; The library pointer is in D0.  The segment list is in A0.
   ; And A6 holds an exec pointer.
   ; If it returns non-zero then the library will be linked into
   ; the library list.
initRoutine:

   ;------ get the library pointer into a convenient A register, A5
   move.l   a5,-(sp)
   move.l   d0,a5

   ;------ save a pointer to exec
   move.l   a6,ml_SysLib(a5)

; and save an exec pointer for Lattice, too.
   move.l   a6,_SysBase

   ;------ save a pointer to our loaded code
   move.l   a0,ml_SegList(a5)

   ;------ open the dos library
   lea   dosName(pc),a1
   CLEAR   d0
   CALLSYS   OpenLibrary

   move.l   d0,ml_DosLib(a5)

; and save a Dos pointer for Lattice, too.
   move.l   d0,_DOSBase
   bne.s   1$

   ;------ can't open the dos!  what gives
   ALERT   AG_OpenLib!AO_DOSLib

1$:

; Build and initialize all application-specific data.

; Aside from having the _SysBase and _DOSBase variables set, Lattice
; code compiled with the '-v' option on pass 2 doesn't need any other
; setup - if you don't use any special Lattice functions.

; final library cleanup before exiting Init routine.
; restore A5 to be a pointer to our library, like what we got to start.
; Since this is non-zero, we will be added to the library list.
   move.l   a5,d0
   move.l   (sp)+,a5
   rts


;----------------------------------------------------------------------
; Here begins the system interface commands.  When the user calls
; OpenLibrary/CloseLibrary/RemoveLibrary, this eventually gets translated
; into a call to the following routines (Open/Close/Expunge).  Exec
; has already put our library pointer in A6 for us.  Exec has turned
; off task switching while in these routines (via Forbid/Permit), so
; we should not take too long in them.
;----------------------------------------------------------------------

   ; Open returns the library pointer in d0 if the open
   ; was successful.  If the open failed then null is returned.
   ; It might fail if we allocated memory on each open, or
   ; if only open application could have the library open
   ; at a time...

Open:      ; ( libptr:a6, version:d0 )

   ;------ mark us as having another opener
   addq.w   #1,LIB_OPENCNT(a6)

   ;------ prevent delayed expunges
   bclr   #LIBB_DELEXP,ml_Flags(a6)

   move.l   a6,d0
   rts

   ; There are two different things that might be returned from
   ; the Close routine.  If the library is no longer open and
   ; there is a delayed expunge then Close should return the
   ; segment list (as given to Init).  Otherwise close should
   ; return NULL.

Close:      ; ( libptr:a6 )
    
   ;------ set the return value
   CLEAR   d0

   ;------ mark us as having one fewer openers
   subq.w   #1,LIB_OPENCNT(a6)

   ;------ see if there is anyone left with us open
   bne.s   1$

   ;------ see if we have a delayed expunge pending
   btst   #LIBB_DELEXP,ml_Flags(a6)
   beq.s   1$

   ;------ do the expunge
   bsr   Expunge
1$:
   rts


   ; There are two different things that might be returned from
   ; the Expunge routine.  If the library is no longer open
   ; then Expunge should return the segment list (as given to
   ; Init).  Otherwise Expunge should set the delayed expunge
   ; flag and return NULL.
   ;
   ; One other important note: because Expunge is called from
   ; the memory allocator, it may NEVER Wait() or otherwise
   ; take long time to complete.

Expunge:   ; ( libptr: a6 )

   movem.l   d2/a5/a6,-(sp)
   move.l   a6,a5
   move.l   ml_SysLib(a5),a6
   
   ;------ see if anyone has us open
   tst.w   LIB_OPENCNT(a5)
   beq   1$

   ;------ it is still open.  set the delayed expunge flag
   bset   #LIBB_DELEXP,ml_Flags(a5)
   CLEAR   d0
   bra.s   Expunge_End

1$:
   ;------ go ahead and get rid of us.  Store our seglist in d2
   move.l   ml_SegList(a5),d2

   ;------ unlink from library list
   move.l   a5,a1
   CALLSYS   Remove
   
; now perform application-specific cleanup

; nothing to clean up from Lattice as specified above.

; continue the library cleanup

   ;------ close the dos library
   move.l   ml_DosLib(a5),a1
   CALLSYS   CloseLibrary

   ;------ free our memory
   CLEAR   d0
   move.l   a5,a1
   move.w   LIB_NEGSIZE(a5),d0

   sub.l   d0,a1
   add.w   LIB_POSSIZE(a5),d0

   CALLSYS   FreeMem

   ;------ set up our return value
   move.l   d2,d0

Expunge_End:
   movem.l   (sp)+,d2/a5/a6
   rts


Null:
   CLEAR   d0
   rts

;----------------------------------------------------------------------
; Here begins the library specific commands
;----------------------------------------------------------------------

; Lattice places the function arguments on the stack in right-to-left
; declaration order, so the CALLED function takes them off in natural
; order.  So, here we take the register values as specified in
; 'future_lib.fd,' and put them on the stack for Lattice.

; Lattice function return values are in D0 in these functions


; ULONG GetSize(filename)        (A0)
; char *filename;
;
; ULONG error code returned in D0.L

FSGetSize:
   move.l   a0,-(a7)
   jsr      _GetSize
   add.w     #4,a7
   rts

; UWORD LoadSound(filename,buffer)  (D0,A0)
; char *filename;
; char *buffer;
;
; recording rate returned in D0

FSLoadSound:
   move.l   a0,-(a7)
   move.l   d0,-(a7)
   jsr      _LoadSound
   add.w    #8,a7
   rts

; struct IOAudio *PlaySound(buffer,buflen,repeat,period,volume) (A0,D0-D3)
; BYTE *buffer;
; ULONG buflen;
; long repeat,
;      period,
;      volume;
; 
; struct IOAudio pointer returned in D0.L

FSPlaySound:
   movem.l  d0/d1/d2/d3,-(a7)    ; D3 is pushed first
   move.l   a0,-(a7)
   jsr      _PlaySound
   add.w    #20,a7
   rts


; StopSound(ioa)        (A0)
; struct IOAudio *ioa;
;
; no return value

FSStopSound:
   move.l   a0,-(a7)
   jsr      _StopSound
   moveq    #0,d0
   add.w    #4,a7
   rts

; Lattice data for these functions.

   XDEF   _DOSBase,_SysBase

_SysBase     DC.L 0
_DOSBase     DC.L 0   

   ; EndCode is a marker that show the end of your code.
   ; Make sure it does not span sections nor is before the
   ; rom tag in memory!  It is ok to put it right after
   ; the rom tag -- that way you are always safe.  I put
   ; it here because it happens to be the "right" thing
   ; to do, and I know that it is safe in this case.
EndCode:

   END

