; $VER: SoundMon20.library 2.11
;

	INCDIR	"Includes3.0:Include3.0/"
	INCLUDE	"Exec/Types.i"
	INCLUDE	"Own/SystemBases.i"
	INCLUDE	"Own/SystemStructures.i"
	INCLUDE	"Own/SystemOffsets.i"
	INCLUDE	"Own/AccessiblePlayer.i"


VERSION		=	2
REVISION	=	11

TRUE		=	-1
FALSE		=	0

; Library Data

LN_Name		=	10
LN_Type		=	8
NT_Library	=	9

LIBB_Summing	=	0
LIBB_Changed	=	1
LIBB_SumUsed	=	2
LIBB_DelExp	=	3

LIBF_Summing	=	1<<LIBB_Summing
LIBF_Changed	=	1<<LIBB_Changed
LIBF_SumUsed	=	1<<LIBB_SumUsed
LIBF_DelExp	=	1<<LIBB_DelExp

; Macros

INBYTE	MACRO
	dc.b	%11100000,0
	dc.w	\1
	dc.b	\2,0
	ENDM

INWORD	MACRO
	dc.b	%11010000,0
	dc.w	\1,\2
	ENDM

INLONG	MACRO
	dc.b	%11000000,0
	dc.w	\1
	dc.l	\2
	ENDM

; Library Base Structure

	STRUCTURE LibraryStruct,0
	STRUCT	LIB_Node,14
	UBYTE	LIB_Flags
	UBYTE	LIB_Pad
	UWORD	LIB_NegSize
	UWORD	LIB_PosSize
	UWORD	LIB_Version
	UWORD	LIB_Revision
	APTR	LIB_IDString
	ULONG	LIB_Sum
	UWORD	LIB_OpenCnt

	LONG	LIB_SegList
	LABEL	LibraryStruct_SIZEOF


	SECTION	SoundMon20.library,CODE

START	moveq	#0,d0
	rts
;------------------------------------------------------------------------------
LIBNAME	dc.b	"apSoundMon20.library",0

LIBID	dc.b	"SoundMon20.library 2.11 (23-September-1994)",0
	even
;------------------------------------------------------------------------------
; ROMTAG Structure
;

ROMTAG	dc.w	$4afc			;ROMTAG Indentifier
	dc.l	romtag
	dc.l	slut
	dc.b	$80			;Flags
	dc.b	version
	dc.b	$09			;Type Of Module
	dc.b	$00			;Initialization Priority
	dc.l	libname
	dc.l	libid
	dc.l	autinit			;Pointer To AUTOINIT Table
;------------------------------------------------------------------------------
; AUTOINIT Table
;

AUTINIT	dc.l	LibraryStruct_SIZEOF	;Size Of Structure AFTER Base Address
	dc.l	vector			;Pointer To Vector Table
	dc.l	inittab			;Pointer To Init Structure
	dc.l	init			;Pointer To Init Routine
;------------------------------------------------------------------------------
; Init Table
;

INITTAB	INBYTE	LN_Type,NT_Library
	INBYTE	LIB_Flags,LIBF_SumUsed!LIBF_Changed
	INWORD	LIB_Version,version
	INWORD	LIB_Revision,revision
	INLONG	LN_Name,libname
	INLONG	LIB_IDString,libid
	dc.l	0
;------------------------------------------------------------------------------
; Vector Table
;

VECTOR	dc.w	-1
	dc.w	opnlib-vector,clslib-vector,expunge-vector,extfunc-vector
	dc.w	SM_GetTags-vector
	dc.w	-1
;------------------------------------------------------------------------------
; Init Routine
;

INIT	movem.l	d1-d7/a0-a6,-(sp)
	move.l	d0,a4			;Base Address
	move.l	a0,LIB_SegList(a4)

	move.l	a4,d0
	movem.l	(sp)+,d1-d7/a0-a6
	rts
;------------------------------------------------------------------------------
; Offset  -6: Open Library
;

OPNLIB	addq.w	#1,LIB_OpenCnt(a6)
	bclr	#LIBB_DelExp,LIB_Flags(a6)
	move.l	a6,d0
	rts
;------------------------------------------------------------------------------
; Offset -12: Close Library
;

CLSLIB	moveq	#0,d0
	subq.w	#1,LIB_OpenCnt(a6)
	bne.b	clslibo
	btst	#LIBB_DelExp,LIB_Flags(a6)
	bne.b	expunge
CLSLIBO	rts
;------------------------------------------------------------------------------
; Offset -18: Expunge
;

EXPUNGE	movem.l	d1-d7/a0-a6,-(sp)
	move.l	a6,a4
	tst.w	LIB_OpenCnt(a4)
	beq.b	exp1
	bset	#LIBB_DelExp,LIB_Flags(a4)
	moveq	#0,d0
	bra.b	expungo

EXP1	move.l	4.w,a6
	move.l	LIB_SegList(a4),d2
	move.l	a4,a1
	jsr	Remove(a6)

	move.l	a4,a1
	moveq	#0,d0
	move.w	LIB_NegSize(a4),d0
	sub.l	d0,a1
	add.w	LIB_PosSize(a4),d0
	jsr	FreeMem(a6)
	move.l	d2,d0

EXPUNGO	movem.l	(sp)+,d1-d7/a0-a6
	rts
;------------------------------------------------------------------------------
; Offset -24: ExtFunc
;

EXTFUNC	moveq	#0,d0
	rts
;------------------------------------------------------------------------------
;******************************************************************************
;* Sound Monitor 2.0 Player
;******************************************************************************
;------------------------------------------------------------------------------
; Structure
;

	STRUCTURE SoundMonStruct,0
	APTR	SMON_Global
	APTR	SMON_Module
	APTR	SMON_Tables
	UWORD	SMON_DMA
	UWORD	SMON_BPStep
	UBYTE	SMON_NumTables
	UBYTE	SMON_ArpCount
	UBYTE	SMON_BPCount
	UBYTE	SMON_BPDelay
	UBYTE	SMON_ST
	UBYTE	SMON_TR
	UBYTE	SMON_BPPatCount
	UBYTE	SMON_BPRepCount
	STRUCT	SMON_Samples,15*4
	STRUCT	SMON_BPCurrent,14+18+32*3
	STRUCT	SMON_BPBuffer,144
	LABEL	SoundMonStruct_SIZEOF
;------------------------------------------------------------------------------
; Offset -30: GetTags
;
; IN :	Nothing
;
; OUT:	A0 = Pointer To A TagList
;

SM_GetTags
	lea	SM_Tags(pc),a0
	rts

SM_Tags	dc.l	APT_RequestVersion,2
	dc.l	APT_EarlyCheck,SM_TestModule

	dc.l	APT_InitPlayer,SM_InitPlayer
	dc.l	APT_EndPlayer,SM_EndPlayer
	dc.l	APT_InitSound,SM_InitSound
	dc.l	APT_EndSound,SM_EndSound
	dc.l	APT_Interrupt,SM_PlayModule

	dc.l	APT_PlayerName,smname
	dc.l	APT_Description,smdes
	dc.l	APT_ModuleName,SM_ModuleName

	dc.l	APT_Volume,TRUE
	dc.l	APT_Pause,TRUE

	dc.l	APT_GetMaxPattern,SM_GetMaxPattern
	dc.l	APT_GetMaxSample,SM_GetMaxSample
	dc.l	APT_GetSongLength,SM_GetSongLength

	dc.l	APT_GetSongPos,SM_GetSongPos
	dc.l	APT_Rewind,SM_Rewind
	dc.l	APT_Forward,SM_Forward
	dc.l	TAG_END

SMNAME	dc.b	"Sound Monitor 2.0",0
SMDES	dc.b	"Original player by Brian Postma.",10
	dc.b	"Adapted by Tax.",0
	even
;------------------------------------------------------------------------------
; TestModule
;
; IN :	Nothing
;
; OUT:	D0 = Success (0=Unknown, 1=Ok, 2=Error)
;

SM_TestModule
	movem.l	d1-d2/a0/a4-a5,-(sp)

	subq.l	#4,sp
	moveq	#$1a,d1
	moveq	#4,d2
	move.l	sp,a0
	move.l	APG_CheckLoad(a5),a4
	jsr	(a4)			;Read Mark
	move.l	(sp)+,d1
	tst.l	d0
	beq.b	.tsmod1

	moveq	#0,d0			;Unknown
	lsr.l	#8,d1
	cmp.l	#"V.2",d1
	bne.b	.tsmodo
	moveq	#1,d0			;Ok
	bra.b	.tsmodo

.TSMOD1	moveq	#2,d0			;Error
.TSMODO	movem.l	(sp)+,d1-d2/a0/a4-a5
	rts
;------------------------------------------------------------------------------
; InitPlayer
;
; IN :	A1 = Address
;
; OUT:	D1 = Success (0=Error)
;

SM_InitPlayer
	movem.l	d0/a0,-(sp)
	move.l	APG_AllocChannels(a5),a0
	jsr	(a0)
	move.l	d0,d1
	movem.l	(sp)+,d0/a0
	rts
;------------------------------------------------------------------------------
; EndPlayer
;
; IN :	A1 = Address
;
; OUT:	Nothing
;

SM_EndPlayer
	move.l	a0,-(sp)
	move.l	APG_FreeChannels(a5),a0
	jsr	(a0)
	move.l	(sp)+,a0
	rts
;------------------------------------------------------------------------------
; InitSound
;
; IN :	A1 = Address
;
; OUT:	Nothing
;

SM_InitSound	movem.l	d0-d2/a0-a1/a4,-(sp)
		lea	SM_DataArea,a4
		move.l	a1,SMON_Module(a4)
		move.l	a5,SMON_Global(a4)

		move.b	#1,SMON_ArpCount(a4)
		move.b	#1,SMON_BPCount(a4)
		move.b	#6,SMON_BPDelay(a4)
		move.b	#1,SMON_BPRepCount(a4)

		clr.w	SMON_DMA(a4)
		clr.w	SMON_BPStep(a4)
		clr.b	SMON_BPPatCount(a4)
		clr.b	SMON_ST(a4)
		clr.b	SMON_TR(a4)

		lea	SMON_BPCurrent(a4),a0
		lea	null,a1
		clr.l	(a0)+
		move.l	a1,(a0)+
		move.w	#1,(a0)+
		clr.l	(a0)+

		clr.l	(a0)+
		clr.l	(a0)+
		clr.l	(a0)+
		clr.w	(a0)+
		clr.w	(a0)+
		clr.w	(a0)+

		moveq	#3-1,d0
.initloop	clr.l	(a0)+
		move.l	a1,(a0)+
		move.w	#1,(a0)+
		clr.l	(a0)+
		clr.l	(a0)+
		clr.l	(a0)+
		clr.l	(a0)+
		clr.l	(a0)+
		clr.w	(a0)+
		dbra	d0,.initloop

		lea	SMON_BPBuffer(a4),a0
		moveq	#(144/2)-1,d0
.initloop1	clr.w	(a0)+
		dbra	d0,.initloop1

		lea	SMON_Samples(a4),a0
		move.l	SMON_Module(a4),a1

		clr.b	SMON_NumTables(a4)
		cmp.w	#'V.',26(a1)
		bne.b	bpnotv2
		cmp.b	#'2',28(a1)
		bne.b	bpnotv2
		move.b	29(a1),SMON_NumTables(a4)

bpnotv2		move.l	#512,d0
		move.w	30(a1),d1	;d1 now contains length in steps
		moveq	#1,d2		;1 is highest pattern number
		mulu	#4,d1		;4 voices per step
		subq.w	#1,d1		;correction for DBRA
findhighest	cmp.w	(a1,d0),d2	;Is it higher
		bge.b	nothigher	;No
		move.w	(a1,d0),d2	;Yes, so let D2 be highest
nothigher	addq.l	#4,d0		;Next Voice
		dbra	d1,findhighest	;And search

		move.w	30(a1),d1
		lsl.w	#4,d1		;16 bytes per step
		move.l	#512,d0		;header is 512 bytes
		mulu	#48,d2		;48 bytes per pattern
		add.l	d2,d0
		add.l	d1,d0		;offset for samples
		add.l	SMON_Module(a4),d0
		move.l	d0,SMON_Tables(a4)
		moveq	#0,d1
		move.b	SMON_NumTables(a4),d1	;Number of tables
		lsl.l	#6,d1			;x 64
		add.l	d1,d0

		moveq	#15-1,d1	;15 samples
		lea	32(a1),a1
initloop	move.l	d0,(a0)+
		cmp.b	#$ff,(a1)
		beq.b	bpissynth
		move.w	24(a1),d2
		add.w	d2,d2
		add.l	d2,d0		;offset next sample
bpissynth	lea	32(a1),a1	;Length of Sample Part in header
		dbra	d1,initloop

		movem.l	(sp)+,d0-d2/a0-a1/a4
		rts
;------------------------------------------------------------------------------
; EndSound
;
; IN :	A1 = Address
;
; OUT:	Nothing
;

SM_EndSound
	move.l	d0,-(sp)
	moveq	#0,d0
	move.w	d0,$dff0a8
	move.w	d0,$dff0b8
	move.w	d0,$dff0c8
	move.w	d0,$dff0d8
	move.w	#$000f,$dff096
	move.l	(sp)+,d0
	rts
;------------------------------------------------------------------------------
; PlayModule
;
; IN :	A1 = Address
;	D1 = VBlank/Cia (0=CIA)
;
; OUT:	Nothing
;

SM_PlayModule	movem.l	d0-d7/a0-a6,-(sp)
		lea	SM_DataArea,a5
		bsr.b	bpmusic
		movem.l	(sp)+,d0-d7/a0-a6
		rts

bpmusic		bsr.w	bpsynth
		subq.b	#1,SMON_ArpCount(a5)
		moveq	#3,d0
		lea	SMON_BPCurrent(a5),a0
		lea	$dff0a0,a1
bploop1		move.b	12(a0),d4
		ext.w	d4
		add.w	d4,(a0)
		tst.b	$1e(a0)
		bne.b	bplfo
		move.w	(a0),6(a1)
bplfo		move.l	4(a0),(a1)
		move.w	8(a0),4(a1)
		tst.b	11(a0)
		bne.b	bpdoarp
		tst.b	13(a0)
		beq.b	not2
bpdoarp		tst.b	SMON_ArpCount(a5)
		bne.b	not0
		move.b	11(a0),d3
		move.b	13(a0),d4
		and.w	#240,d4
		and.w	#240,d3
		lsr.w	#4,d3
		lsr.w	#4,d4
		add.w	d3,d4
		add.b	10(a0),d4
		bsr.w	bpplayarp
		bra.b	not2

not0		cmpi.b	#1,SMON_ArpCount(a5)
		bne.b	not1
		move.b	11(a0),d3
		move.b	13(a0),d4
		and.w	#15,d3
		and.w	#15,d4
		add.w	d3,d4
		add.b	10(a0),d4
		bsr.w	bpplayarp
		bra.b	not2

not1		move.b	10(a0),d4
		bsr.w	bpplayarp
not2		lea	$10(a1),a1
		lea	$20(a0),a0
		dbra	d0,bploop1

		tst.b	SMON_ArpCount(a5)
		bne.b	arpnotzero
		move.b	#3,SMON_ArpCount(a5)
arpnotzero	subq.b	#1,SMON_BPCount(a5)
		beq.b	bpskip1
		rts

bpskip1		move.b	SMON_BPDelay(a5),SMON_BPCount(a5)
bpplay		bsr.b	bpnext
		move.w	SMON_DMA(a5),$dff096

		move.l	SMON_Global(a5),a1
		move.l	APG_WaitDma(a1),a1
		jsr	(a1)			;Wait For DMA

		moveq	#3,d0
		lea	$dff0a0,a1
		moveq	#1,d1
		move.l	a5,-(sp)
		lea	SMON_BPCurrent(a5),a2
		lea	SMON_BPBuffer(a5),a5
bploop2		btst	#15,(a2)
		beq.b	bpskip7
		bsr.w	bpplayit
bpskip7		asl.w	#1,d1
		lea	$10(a1),a1
		lea	$20(a2),a2
		lea	$24(a5),a5
		dbra	d0,bploop2
		move.l	(sp)+,a5
		rts

bpnext		clr.w	SMON_DMA(a5)
		move.l	SMON_Module(a5),a0
		lea	$dff0a0,a3
		moveq	#3,d0
		moveq	#1,d7
		lea	SMON_BPCurrent(a5),a1
bploop3		moveq	#0,d1
		move.w	SMON_BPStep(a5),d1
		lsl.w	#4,d1
		move.l	d0,d2
		lsl.l	#2,d2
		add.l	d2,d1
		add.l	#512,d1
		move.w	(a0,d1),d2
		move.b	2(a0,d1),SMON_ST(a5)
		move.b	3(a0,d1),SMON_TR(a5)
		subq.w	#1,d2
		mulu	#48,d2
		moveq	#0,d3
		move.w	30(a0),d3
		lsl.w	#4,d3
		add.l	d2,d3
		move.l	#$00000200,d4
		move.b	SMON_BPPatCount(a5),d4
		add.l	d3,d4
		move.l	d4,a2
		add.l	a0,a2
		moveq	#0,d3 
		move.b	(a2),d3
		tst.b	d3
		bne.b	bpskip4
		bra.w	bpoptionals

bpskip4		clr.w	12(a1)			;Clear autoslide/autoarpeggio
		move.b	1(a2),d4
		and.b	#15,d4
		cmpi.b	#10,d4    		;Option 10->transposes off
		bne.b	bp_do1
		move.b	2(a2),d4
		and.b	#240,d4	  		;Higher nibble=transpose
		bne.b	bp_not1
bp_do1		add.b	SMON_TR(a5),d3
		ext.w	d3
bp_not1		move.b	d3,10(a1) 		;Voor Arpeggio's
		lea	bpper(pc),a4
		lsl.w	#1,d3
		move.w	-2(a4,d3.w),(a1)
		bset	#15,(a1)
		move.b	#$ff,2(a1)
		moveq	#0,d3
		move.b	1(a2),d3
		lsr.b	#4,d3
		and.b	#15,d3
		tst.b	d3
		bne.b	bpskip5
		move.b	3(a1),d3 
bpskip5 	move.b	1(a2),d4
		and.b	#15,d4
		cmpi.b	#10,d4 			;option 10
		bne.b	bp_do2
		move.b	2(a2),d4
		and.b	#15,d4
		bne.b	bp_not2
bp_do2		add.b	SMON_ST(a5),d3
bp_not2		cmpi.w	#1,8(a1)
		beq.b	bpsamplechange
		cmp.b	3(a1),d3
		beq.b	bpoptionals
bpsamplechange	move.b	d3,3(a1)
		or.w	d7,SMON_DMA(a5)
bpoptionals 	moveq	#0,d3
		moveq	#0,d4
		move.b	1(a2),d3
		and.b	#15,d3
		move.b	2(a2),d4

		cmpi.b	#0,d3			; Optionals Here
		bne.b	notopt0
		move.b	d4,11(a1)

notopt0		cmpi.b	#1,d3
		bne.b	bpskip3
		move.l	d0,-(sp)
		move.b	d4,2(a1) 		; Volume ook in BPCurrent
		move.b	d4,d0
		bsr.w	calvol
		move.w	d0,8(a3)
		move.l	(sp)+,d0

bpskip3		cmpi.b	#2,d3  			; Set Speed
		bne.b	bpskip9
		move.b	d4,SMON_BPCount(a5)
		move.b	d4,SMON_BPDelay(a5)

bpskip9		cmpi.b	#3,d3 			; Filter = LED control
		bne.b	bpskipa
		tst.b	d4
		bne.b	bpskipb
		bset	#1,$bfe001
		bra.b	bpskip2
bpskipb		bclr	#1,$bfe001

bpskipa		cmpi.b	#4,d3 			; PortUp
		bne.b	noportup
		sub.w	d4,(a1)			; Slide data in BPCurrent
		clr.b	11(a1) 			; Arpeggio's uit

noportup	cmpi.b	#5,d3 			; PortDown
		bne.b	noportdn
		add.w	d4,(a1)			; Slide down
		clr.b	11(a1)

noportdn	cmpi.b	#6,d3			; SetRepCount
		bne.b	notopt6
		move.b	d4,SMON_BPRepCount(a5)

notopt6		cmpi.b	#7,d3			; DBRA repcount
		bne.b	notopt7
		subq.b	#1,SMON_BPRepCount(a5)
		beq.b	notopt7
		cmp.w	SMON_BPStep(a5),d4
		bge.b	jump
		move.l	SMON_Global(a5),a2
		move.l	APG_SendMsg(a2),a2
		move.w	#MSG_NextMod,d2
		jsr	(a2)
jump		move.w	d4,SMON_BPStep(a5)

notopt7		cmpi.b	#8,d3			;Set AutoSlide
		bne.b	notopt8
		move.b	d4,12(a1)

notopt8		cmpi.b	#9,d3			;Set AutoArpeggio
		bne.b	notopt9
		move.b	d4,13(a1)

notopt9
bpskip2		lea	$10(a3),a3
		lea	$20(a1),a1
		asl.w	#1,d7
		dbra	d0,bploop3

		addq.b	#3,SMON_BPPatCount(a5)
		cmpi.b	#48,SMON_BPPatCount(a5)
		bne.b	bpskip8
		move.b	#0,SMON_BPPatCount(a5)
		addq.w	#1,SMON_BPStep(a5)

		move.l	SMON_Global(a5),a2
		move.l	APG_SendMsg(a2),a2
		move.w	#MSG_NextPos,d2
		jsr	(a2)

		move.l	SMON_Module(a5),a0
		move.w	30(a0),d1
		cmp.w	SMON_BPStep(a5),d1
		bne.b	bpskip8
		move.w	#0,SMON_BPStep(a5)

		move.l	SMON_Global(a5),a2
		move.l	APG_SendMsg(a2),a2
		move.w	#MSG_NextMod,d2
		jsr	(a2)
bpskip8		rts

bpplayit	bclr	#15,(a2)
		tst.l	(a5) 			;Was EG used
		beq.b	noeg1 			;No ??
		moveq	#0,d3 			;Well then copy
		move.l	(a5),a4			;Old waveform back
		moveq	#7,d7 			;to waveform tables
eg1loop		move.l	4(a5,d3.w),(a4)+	;Copy...
		addq.w	#4,d3 			;Copy...
		dbra	d7,eg1loop		;Copy...

noeg1		move.w	(a2),6(a1)		;Period from bpcurrent
		moveq	#0,d7
		move.b	3(a2),d7		;Instrument number
		move.l	d7,d6 			;Also in d6
		lsl.l	#5,d7 			;Header offset
		move.l	4(sp),a3
		move.l	SMON_Module(a3),a3
		cmpi.b	#$ff,(a3,d7.w)		;Is synthetic
		beq.w	bpplaysynthetic		;Yes ??
		clr.l	(a5) 			;EG Off
		clr.b	$1a(a2)			;Synthetic mode off
		clr.w	$1e(a2)			;Lfo Off
		add.l	#24,d7 			;24 is name->ignore
		lsl.l	#2,d6 			;x4 for sample offset
		move.l	4(sp),a4
		lea	SMON_Samples(a4),a4
		move.l	-4(a4,d6),d4		;Fetch sample pointer
		beq.b	bp_nosamp		;is zero->no sample
		move.l	d4,(a1) 		;Sample pointer in hardware
		move.w	(a3,d7),4(a1)		;length in hardware

		movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.b	2(a2),d0
		bsr.w	calvol
		movem.l	(sp)+,d0/a5

		cmpi.b	#$ff,2(a2)		;Use default volume
		bne.b	skipxx 			;No ??

		movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.w	6(a3,d7),d0
		bsr.w	calvol
		move.w	d0,8(a1)
		movem.l	(sp)+,d0/a5

skipxx	 	move.w	4(a3,d7),8(a2)		;Length in bpcurrent
		moveq	#0,d6
		move.w	2(a3,d7),d6		;Calculate repeat
		add.l	d6,d4
		move.l	d4,4(a2)		;sample start in bpcurrent
		cmpi.w	#1,8(a2)		;has sample repeat part
		bne.b	bpskip6			;Yes ??
bp_nosamp	move.l	#null,4(a2)		;Play no sample
		bra.b	bpskip10

bpskip6		move.w	8(a2),4(a1)		;Length to hardware
		move.l	4(a2),(a1)		;pointer to hardware
bpskip10	or.w	#$8000,d1		;Turn on DMA for this voice
		move.w	d1,$dff096		;Yeah, do it
		rts

bpplaysynthetic	move.b	#$1,$1a(a2)		;Synthetic mode on
		clr.w	$e(a2) 			;EG Pointer restart
		clr.w	$10(a2) 		;LFO Pointer restart
		clr.w	$12(a2) 		;ADSR Pointer restart
		move.w	22(a3,d7.w),$14(a2)	;EG Delay
		addq.w	#1,$14(a2)		;0 is nodelay
		move.w	14(a3,d7.w),$16(a2)	;LFO Delay
		addq.w	#1,$16(a2)		;So I need correction
		move.w	#1,$18(a2)		;ADSR Delay->Start immediate
		move.b	17(a3,d7.w),$1d(a2)	;EG OOC
		move.b	9(a3,d7.w),$1e(a2)	;LFO OOC
		move.b	4(a3,d7.w),$1f(a2)	;ADSR OOC
		move.b	19(a3,d7.w),$1c(a2)	;Current EG Value
		move.l	4(sp),a4
		move.l	SMON_Tables(a4),a4	; so far so good,now what ??
		moveq	#0,d3			;Pointer to waveform tables
		move.b	1(a3,d7.w),d3		;Which waveform
		lsl.l	#6,d3 			;x64 is length waveform table
		add.l	d3,a4
		move.l	a4,(a1) 		;Sample Pointer
		move.l	a4,4(a2)		;In bpcurrent
		move.w	2(a3,d7.w),4(a1)	;Length in words
		move.w	2(a3,d7.w),8(a2)	;Length in bpcurrent
		tst.b	4(a3,d7.w)		;Is ADSR on
		beq.b	bpadsroff		;No ??
		move.l	4(sp),a4
		move.l	SMON_Tables(a4),a4	;Tables
		moveq	#0,d3
		move.b	5(a3,d7.w),d3		;ADSR table number
		lsl.l	#6,d3 			;x64 for length
		add.l	d3,a4 			;Add it
		moveq	#0,d3
		move.b	(a4),d3 		;Get table value
		add.b	#128,d3 		;I want it from 0..255
		lsr.w	#2,d3 			;Divide by 4->0..63
		cmpi.b	#$ff,2(a2)
		bne.b	bpskip99
		move.b	25(a3,d7.w),2(a2)
bpskip99	moveq	#0,d4
		move.b	2(a2),d4		;Default volume
		mulu	d4,d3 			;default maal init volume
		lsr.w	#6,d3 			;divide by 64

		movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.w	d3,d0
		bsr.w	calvol
		move.w	d0,8(a1)		;is new volume
		movem.l	(sp)+,d0/a5
		bra.b	bpflipper

bpadsroff	movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.b	2(a2),d0
		bsr.w	calvol
		move.w	d0,8(a1)		;is new volume
		movem.l	(sp)+,d0/a5

		cmpi.b	#$ff,2(a2)
		bne.b	bpflipper		;No ADSR
		movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.b	25(a3,d7.w),d0
		bsr.w	calvol
		move.w	d0,8(a1)		;So use default volume
		movem.l	(sp)+,d0/a5

bpflipper	move.l	4(a2),a4		;Pointer on waveform
		move.l	a4,(a5)			;Save it
		moveq	#0,d3 			;Save Old waveform
		moveq	#7,d4 			;data in bpbuffer
eg2loop		move.l	(a4,d3.w),4(a5,d3.w)
		addq.w	#4,d3 			;Copy 		
		dbra	d4,eg2loop

		tst.b	17(a3,d7.w)		;EG off
		beq.w	bpskip10		;Yes ??
		tst.b	19(a3,d7.w)		;Is there an init value for EG
		beq.w	bpskip10		;No ??
		moveq	#0,d3
		move.b	19(a3,d7.w),d3
		lsr.l	#3,d3 			;Divide by 8 ->0..31
		move.b	d3,$1c(a2)		;Current EG Value
		subq.l	#1,d3 			;-1,DBRA correction
eg3loop		neg.b	(a4)+
		dbra	d3,eg3loop
		bra.w	bpskip10

bpplayarp	lea	bpper(pc),a4
		ext.w	d4
		asl.w	#1,d4
		move.w	-2(a4,d4.w),6(a1)
		rts

bpsynth		move.l	a5,-(sp)
		moveq	#3,d0
		lea	SMON_BPCurrent(a5),a2
		lea	$dff0a0,a1
		move.l	SMON_Module(a5),a3
		lea	SMON_BPBuffer(a5),a5
bpsynthloop	tst.b	$1a(a2)			;Is synthetic sound
		beq.b	bpnosynth		;No ??
		bsr.b	bpyessynth		;Yes 		
bpnosynth	lea	$24(a5),a5
		lea	$20(a2),a2
		lea	$10(a1),a1
		dbra	d0,bpsynthloop
		move.l	(sp)+,a5
		rts

bpyessynth	moveq	#0,d7
		move.b	3(a2),d7		;Which instr. was I playing
		lsl.w	#5,d7 			;x32, is length of instr.
		tst.b	$1f(a2) 		;ADSR off
		beq.b	bpendadsr		;Yes ??
		subq.w	#1,$18(a2)		;Delay,May I
		bne.b	bpendadsr		;No ??
		moveq	#0,d3
		move.b	8(a3,d7.w),d3
		move.w	d3,$18(a2)		;Reset Delay Counter
		move.l	4(sp),a4
		move.l	SMON_Tables(a4),a4
		move.b	5(a3,d7.w),d3		;Which ADSR table
		lsl.l	#6,d3 			;x64
		add.l	d3,a4 			;This is my table
		move.w	$12(a2),d3		;Get ADSR table pointer
		moveq	#0,d4
		move.b	(a4,d3.w),d4		;Value from table
		add.b	#128,d4 		;Want it from 0..255
		lsr.w	#2,d4 			;And now from 0..63
		moveq	#0,d3
		move.b	2(a2),d3		;Current Volume
		mulu	d3,d4 			;MultiPly with table volume
		lsr.w	#6,d4 			;Divide by 64=New volume

		movem.l	d0/a5,-(sp)
		move.l	12(sp),a5
		move.w	d4,d0
		bsr.w	calvol
		move.w	d0,8(a1)		;Volume in hardware
		movem.l	(sp)+,d0/a5

		addq.w	#1,$12(a2)		;Increment of ADSR pointer
		move.w	6(a3,d7.w),d4		;Length of adsr table
		cmp.w	$12(a2),d4		;End of table reached
		bne.b	bpendadsr		;No ??
		clr.w	$12(a2) 		;Clear ADSR Pointer
		cmpi.b	#1,$1f(a2)		;Once
		bne.b	bpendadsr		;No ??
		clr.b	$1f(a2)			;ADSR off
bpendadsr	tst.b	$1e(a2)			;LFO On
		beq.b	bpendlfo		;No ??
		subq.w	#1,$16(a2)		;LFO delay,May I
		bne.b	bpendlfo		;No
		moveq	#0,d3
		move.b	16(a3,d7.w),d3
		move.w	d3,$16(a2)		;Set LFO Count
		move.l	4(sp),a4
		move.l	SMON_Tables(a4),a4
		move.b	10(a3,d7.w),d3		;Which LFO table
		lsl.l	#6,d3 			;x64
		add.l	d3,a4
		move.w	$10(a2),d3		;LFO pointer
		moveq	#0,d4
		move.b	(a4,d3.w),d4		;That's my value
		ext.w	d4 			;Make it a word
		ext.l	d4 			;And a longword
		moveq	#0,d5
		move.b	11(a3,d7.w),d5		;LFO depth
		tst.b	d5
		beq.b	bpnotx
		divs	d5,d4 			;Calculate it
bpnotx		move.w	(a2),d5 		;Period
		add.w	d4,d5 			;New Period
		move.w	d5,6(a1)		;In hardware
		addq.w	#1,$10(a2)		;Next position
		move.w	12(a3,d7.w),d3		;LFO table Length
		cmp.w	$10(a2),d3		;End Reached
		bne.b	bpendlfo		;NO ??
		clr.w	$10(a2)		 	;Reset LFO Pointer
		cmpi.b	#1,$1e(a2)		;Once LFO
		bne.b	bpendlfo		;NO ??
		clr.b	$1e(a2) 		;LFO Off
bpendlfo	tst.b	$1d(a2) 		;EG On
		beq.w	bpendeg			;No ??
		subq.w	#1,$14(a2)		;EG delay,May I
		bne.w	bpendeg 		;No
		tst.l	(a5)
		beq.b	bpendeg
		moveq	#0,d3
		move.b	24(a3,d7.w),d3
		move.w	d3,$14(a2)		;Set EG Count
		move.l	4(sp),a4
		move.l	SMON_Tables(a4),a4
		move.b	18(a3,d7.w),d3		;Which EG table
		lsl.l	#6,d3 			;x64
		add.l	d3,a4
		move.w	$e(a2),d3		;EG pointer
		moveq	#0,d4
		move.b	(a4,d3.w),d4		;That's my value
		move.l	(a5),a4 		;Pointer to waveform
		add.b	#128,d4 		;0..255
		lsr.l	#3,d4 			;0..31
		moveq	#0,d3
		move.b	$1c(a2),d3		;Old EG Value
		move.b	d4,$1c(a2)
		add.l	d3,a4 			;WaveForm Position
		move.l	a5,a6 			;Buffer
		add.l	d3,a6 			;Position
		addq.l	#4,a6 			;For adress in buffer
		cmp.b	d3,d4 			;Compare old with new value
		beq.b	bpnexteg		;no change ??
		bgt.b	bpishigh		;new value is higher
bpislow		sub.l	d4,d3 			;oldvalue-newvalue
		subq.l	#1,d3 			;Correction for DBRA
bpegloop1a	move.b	-(a6),d4
		move.b	d4,-(a4)
		dbra	d3,bpegloop1a
		bra.b	bpnexteg

bpishigh	sub.l	d3,d4 			;Newvalue-oldvalue
		subq.l	#1,d4 			;Correction for DBRA
bpegloop1b	move.b	(a6)+,d3
		neg.b	d3
		move.b	d3,(a4)+		;DoIt
		dbra	d4,bpegloop1b

bpnexteg	addq.w	#1,$e(a2)		;Next position
		move.w	20(a3,d7.w),d3		;EG table Length
		cmp.w	$e(a2),d3		;End Reached
		bne.b	bpendeg			;NO ??
		clr.w	$e(a2) 			;Reset EG Pointer
		cmpi.b	#1,$1d(a2)		;Once EG
		bne.b	bpendeg 		;NO ??
		clr.b	$1d(a2) 		;EG Off
bpendeg		rts
;------------------------------------------------------------------------------
; Calculate New Volume
;
; IN :	D0 = Volume
;	A5 = SMON Structure
;
; OUT:	D0 = New Volume
;

CALVOL	move.l	a5,-(sp)
	move.l	SMON_Global(a5),a5
	move.l	APG_CalcVolume(a5),a5
	jsr	(a5)
	move.l	(sp)+,a5
	rts
;------------------------------------------------------------------------------
	dc.w 6848,6464,6080,5760,5440,5120,4832,4576,4320,4064,3840,3616
	dc.w 3424,3232,3040,2880,2720,2560,2416,2288,2160,2032,1920,1808
	dc.w 1712,1616,1520,1440,1360,1280,1208,1144,1080,1016,0960,0904
bpper	dc.w 0856,0808,0760,0720,0680,0640,0604,0572,0540,0508,0480,0452
	dc.w 0428,0404,0380,0360,0340,0320,0302,0286,0270,0254,0240,0226
	dc.w 0214,0202,0190,0180,0170,0160,0151,0143,0135,0127,0120,0113
	dc.w 0107,0101,0095,0090,0085,0080,0076,0072,0068,0064,0060,0057
;------------------------------------------------------------------------------
; ModuleName
;
; IN :	A1 = Address
;
; OUT:	A0 = Pointer To The Name
;

SM_ModuleName
	move.l	a1,a0
	rts
;------------------------------------------------------------------------------
; GetMaxPattern
;
; IN :	A1 = Address
;
; OUT:	D1 = Number Of Patterns
;

SM_GetMaxPattern
	movem.l	d0/d2/a1,-(sp)

	move.w	30(a1),d0		;d1 now contains length in steps
	move.l	#512,d2
	moveq	#1,d1			;1 is highest pattern number
	mulu	#4,d0 			;4 voices per step
	subq.w	#1,d0 			;correction for DBRA
.GTMAX1	cmp.w	(a1,d2.l),d1		;Is it higher
	bge.b	.gtmax2			;No
	move.w	(a1,d2.l),d1		;Yes, so let D2 be highest
.GTMAX2	addq.l	#4,d2 			;Next Voice
	dbra	d0,.gtmax1		;And search

	movem.l	(sp)+,d0/d2/a1
	rts
;------------------------------------------------------------------------------
; GetMaxSample
;
; IN :	A1 = Address
;
; OUT:	D1 = Number Of Samples
;

SM_GetMaxSample
	moveq	#15,d1
	rts
;------------------------------------------------------------------------------
; GetSongLength
;
; IN :	A1 = Address
;
; OUT:	D1 = Length
;

SM_GetSongLength
	move.w	30(a1),d1
	rts
;------------------------------------------------------------------------------
; GetSongPos
;
; IN :	A1 = Address
;
; OUT:	D1 = Position (0-x)
;

SM_GetSongPos
	move.l	a0,-(sp)
	lea	SM_DataArea,a0
	move.w	SMON_BPStep(a0),d1
	move.l	(sp)+,a0
	rts
;------------------------------------------------------------------------------
; Rewind
;
; IN :	A1 = Address
;
; OUT:	D1 = New Position
;

SM_Rewind
	movem.l	a0-a1,-(sp)
	lea	SM_DataArea,a0

	move.w	SMON_BPStep(a0),d1
	beq.b	sforwa1
	subq.w	#1,d1
	bra.b	sforwa1
;------------------------------------------------------------------------------
; Forward
;
; IN :	A1 = Address
;
; OUT:	D1 = New Position
;

SM_Forward
	movem.l	a0-a1,-(sp)
	lea	SM_DataArea,a0

	move.w	SMON_BPStep(a0),d1
	addq.w	#1,d1
	cmp.w	30(a1),d1
	blt.b	sforwa1
	moveq	#0,d1

SFORWA1	move.w	d1,SMON_BPStep(a0)
	clr.b	SMON_BPPatCount(a0)

	movem.l	(sp)+,a0-a1
	rts
;------------------------------------------------------------------------------
	SECTION	NullSample,DATA_C

NULL	dc.l	0
;------------------------------------------------------------------------------
	SECTION	SM_DataArea,BSS

SM_DataArea
	ds.b	SoundMonStruct_SIZEOF
;------------------------------------------------------------------------------
SLUT
