*** ScR ***

*** NOTES ***

*  InputGain not supported

DMA_LENGTH	EQU	2021

;------------
	auto	wo AHI:user/devs/ahi/wavetools.audio\

	incdir	include:

	include	exec/exec.i
	include	dos/dos.i
	include	dos/dostags.i
	include	utility/utility.i
	include	utility/hooks.i

	include	lvo/exec_lib.i
	include	lvo/dos_lib.i
	include	lvo/utility_lib.i

	include	devices/ahi.i
	include	libraries/ahi_sub.i
	include	AHI:Developer/drivers/wavetools/dad_audio.i
	include	macros.i

 * wtBase (private)
	STRUCTURE wtBase,LIB_SIZE
	UBYTE	wtb_Flags
	UBYTE	wtb_Pad1
	UWORD	wtb_Pad2
	APTR	wtb_SysLib
	ULONG	wtb_SegList
	APTR	wtb_DosLib
	APTR	wtb_UtilLib
	LABEL	wtBase_SIZEOF

 * wavetools (private) ahiac_DriverData points to this structure.
	STRUCTURE wavetools,0
	UBYTE	wt_Flags
	UBYTE	wt_Pad1
	BYTE	wt_MasterSignal
	BYTE	wt_RecMasterSignal
	BYTE	wt_SlaveSignal
	BYTE	wt_RecSlaveSignal
	UWORD	wt_Pad2
	APTR	wt_MasterTask
	APTR	wt_RecMasterTask
	APTR	wt_SlaveTask
	APTR	wt_RecSlaveTask
	APTR	wt_dadport
	APTR	wt_recdadport
	APTR	wt_dadioreq
	APTR	wt_recdadioreq
	ULONG	wt_daddev
	ULONG	wt_recdaddev
	APTR	wt_RecBuffer
	APTR	wt_RecordMsg
	APTR	wt_DMAbuffer1
	APTR	wt_DMAbuffer2
	LONG	wt_InputVolume
	LONG	wt_OutputVolume
	LONG	wt_InputGain		;not supported yet

	ULONG	wt_DBflag

	APTR	wt_SoftInt

	LABEL	wt_SoftIntData
	APTR	wt_PlayerHook
	ULONG	wt_Reserved
	APTR	wt_AudioCtrlP
	FPTR	wt_PlayerEntry		;wt_PlayerHook->h_Entry

	ULONG	wt_LoopTimes
	APTR	wt_MixHook
	APTR	wt_Mixbuffer
	APTR	wt_AudioCtrlM
	FPTR	wt_MixEntry		;wt_MixHook->h_Entry

	APTR	wt_DMAbuffer		;current buffer
	APTR	wt_DMAlength		;length

	LABEL	wavetools_SIZEOF

Start:
	moveq	#-1,d0
	rts

VERSION		EQU	2
REVISION	EQU	0
DATE	MACRO	
		dc.b	"21.5.96"
	ENDM
VERS	MACRO
		dc.b	"wavetools 2.0"
	ENDM
VSTRING	MACRO
		VERS
		dc.b	" ("
		DATE
		dc.b	")",13,10,0
	ENDM
VERSTAG	MACRO
		dc.b	0,"$VER: "
		VERS
		dc.b	" ("
		DATE
		dc.b	")",0
	ENDM

RomTag:
	DC.W	RTC_MATCHWORD
	DC.L	RomTag
	DC.L	EndCode
	DC.B	RTF_AUTOINIT
	DC.B	VERSION		;version
	DC.B	NT_LIBRARY
	DC.B	0		;pri
	DC.L	LibName
	DC.L	IDString
	DC.L	InitTable

LibName:	dc.b	"wavetools.audio",0
IDString:	VSTRING
dosName:	DOSNAME
utilName:	UTILITYNAME

	cnop	0,2

InitTable:
	DC.L	wtBase_SIZEOF
	DC.L	funcTable
	DC.L	dataTable
	DC.L	initRoutine

funcTable:
	dc.l	Open
	dc.l	Close
	dc.l	Expunge
	dc.l	Null
*
	dc.l	AHIsub_AllocAudio
	dc.l	AHIsub_FreeAudio
	dc.l	AHIsub_Disable
	dc.l	AHIsub_Enable
	dc.l	AHIsub_Start
	dc.l	AHIsub_Update
	dc.l	AHIsub_Stop
	dc.l	AHIsub_SetVol
	dc.l	AHIsub_SetFreq
	dc.l	AHIsub_SetSound
	dc.l	AHIsub_SetEffect
	dc.l	AHIsub_LoadSound
	dc.l	AHIsub_UnloadSound
	dc.l	AHIsub_GetAttr
	dc.l	AHIsub_HardwareControl
	dc.l	-1

dataTable:
	INITBYTE	LN_TYPE,NT_LIBRARY
	INITLONG	LN_NAME,LibName
	INITBYTE	LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
	INITWORD	LIB_VERSION,VERSION
	INITWORD	LIB_REVISION,REVISION
	INITLONG	LIB_IDSTRING,IDString
	DC.L		0

initRoutine:
	movem.l	d1/a0/a1/a5/a6,-(sp)
	move.l	d0,a5
	move.l	a6,wtb_SysLib(a5)
	move.l	a0,wtb_SegList(a5)
	lea	dosName(pc),a1
	moveq	#37,d0
	call	OpenLibrary
	move.l	d0,wtb_DosLib(a5)
	bne.b	.dosOK
	ALERT	AG_OpenLib!AO_DOSLib
	moveq	#0,d0
	bra.b	.exit
.dosOK
	lea	utilName(pc),a1
	moveq	#37,d0
	call	OpenLibrary
	move.l	d0,wtb_UtilLib(a5)
	bne.b	.utilOK
	ALERT	AG_OpenLib!AO_UtilityLib
	moveq	#0,d0
	bra.b	.exit
.utilOK
	move.l	a5,d0
.exit
	movem.l	(sp)+,d1/a0/a1/a5/a6
	rts

Open:
	addq.w	#1,LIB_OPENCNT(a6)
	bclr.b	#LIBB_DELEXP,wtb_Flags(a6)
	move.l	a6,d0
	rts

Close:
	moveq	#0,d0
	subq.w	#1,LIB_OPENCNT(a6)
	bne.b	.exit
	btst.b	#LIBB_DELEXP,wtb_Flags(a6)
	beq.b	.exit
	bsr.b	Expunge
.exit
	rts

Expunge:
	movem.l	d1/d2/a0/a1/a5/a6,-(sp)
	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6
	tst.w	LIB_OPENCNT(a5)
	beq.b	.notopen
	bset.b	#LIBB_DELEXP,wtb_Flags(a5)
	moveq	#0,d0
	bra.b	.Expunge_end
.notopen
	move.l	wtb_DosLib(a5),a1
	call	CloseLibrary
	move.l	wtb_UtilLib(a5),a1
	call	CloseLibrary

	move.l	wtb_SegList(a5),d2
	move.l	a5,a1
	call	Remove

	moveq	#0,d0
	move.l	a5,a1
	move.w	LIB_NEGSIZE(a5),d0
	sub.l	d0,a1
	add.w	LIB_POSSIZE(a5),d0
	call	FreeMem
	move.l	d2,d0
.Expunge_end
	movem.l	(sp)+,d1/d2/a0/a1/a5/a6
	rts

Null:
	moveq	#0,d0
	rts

*       result = AHIsub_AllocAudio( tagList, AudioCtrl );
*       D0                          A1       A2

AHIsub_AllocAudio:
	pushm	d2-d7/a2-a6
	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6

	move.l	#wavetools_SIZEOF,d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,ahiac_DriverData(a2)
	beq.w	.error_nowavetools
	move.l	d0,a3

* try allocate dad_audio.device
	moveq	#0,d2
	moveq	#0,d3
	moveq	#-1,d4
	call	CreateMsgPort
	move.l	d0,d2
	beq.b	.err2
	move.l	d0,a0
	moveq	#IOSTD_SIZE,d0
	call	CreateIORequest
	move.l	d0,d3
	beq.b	.err1
	lea	dadname(pc),a0
	moveq	#0,d0
	move.l	d3,a1
	moveq	#0,d1
	call	OpenDevice
	move.l	d0,d4
	move.l	d3,a1
	call	CloseDevice
	move.l	d3,a0
	call	DeleteIORequest
.err1
	move.l	d2,a0
	call	DeleteMsgPort
.err2
	tst.l	d4
	bne.w	.error_nodevice

	move.l	#-1,wt_daddev(a3)
	move.b	#-1,wt_MasterSignal(a3)
	move.b	#-1,wt_SlaveSignal(a3)
	move.l	a2,wt_AudioCtrlP(a3)		;player Hook
	move.l	a2,wt_AudioCtrlM(a3)		;mixer Hook

* find closest frequency
	move.l	ahiac_MixFreq(a2),d0
	bsr.b	findfreq
	move.l	d0,ahiac_MixFreq(a2)		;store actual freq

	moveq	#IS_SIZE,d0
	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,wt_SoftInt(a3)
	beq.b	.error_nointmem

	move.l	d0,a0
	move.b	#NT_INTERRUPT,LN_TYPE(a0)
	lea	LibName(pc),a1
	move.l	a1,LN_NAME(a0)
	lea	SoftInt_Dummy(pc),a1
	move.l	a1,IS_CODE(a0)
	lea	wt_SoftIntData(a3),a1
	move.l	a1,IS_DATA(a0)

* Set default output volume
	move.l	#$10000,wt_OutputVolume(a3)

	moveq	#AHISF_CANRECORD|AHISF_KNOWSTEREO|AHISF_MIXING|AHISF_TIMING,d0
.exit
	popm	d2-d7/a2-a6
	rts
.error_nointmem
.error_nodevice
.error_nowavetools
	moveq	#AHISF_ERROR,d0
	bra.b	.exit

;in:
* d0	Frequency
;out:
* d0	New frequency
findfreq:
	lea	freqlist(pc),a0
	cmp.l	(a0),d0
	bhi.b	.findfreq
	move.l	(a0),d0
	bra.b	.2
.findfreq
	cmp.l	(a0)+,d0
	bhi.b	.findfreq
	move.l	-4(a0),d1
	sub.l	d0,d1
	sub.l	-8(a0),d0
	cmp.l	d1,d0
	bhs.b	.1
	move.l	-8(a0),d0
	bra.b	.2
.1
	move.l	-4(a0),d0
.2
	rts

freqlist:
	dc.l	DADFREQ_17640
	dc.l	DADFREQ_19200
	dc.l	DADFREQ_22050
	dc.l	DADFREQ_24000
	dc.l	DADFREQ_29400
	dc.l	DADFREQ_32000
	dc.l	DADFREQ_44100
	dc.l	DADFREQ_48000
	dc.l	-1

*       AHIsub_FreeAudio( AudioCtrl );
*                         A2

AHIsub_FreeAudio:
	pushm	d2-d7/a2-a6

	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6

	move.l	ahiac_DriverData(a2),d0
	beq.b	.nodriverdata
	move.l	d0,a3

	move.l	wt_SoftInt(a3),a1
	clr.l	wt_SoftInt(a3)
	call	FreeVec

	move.l	ahiac_DriverData(a2),a1
	clr.l	ahiac_DriverData(a2)
	call	FreeVec
.nodriverdata
	moveq	#0,d0
	popm	d2-d7/a2-a6
	rts


*       AHIsub_Disable( AudioCtrl );
*                       A2

AHIsub_Disable:
	pushm	a5-a6
	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6
	call	Forbid				; Lame, but it works.
	popm	a5-a6
	rts

*       AHIsub_Enable( AudioCtrl );
*                      A2

AHIsub_Enable:
	pushm	a5-a6
	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6
	call	Permit				; Lame, but it works.
	popm	a5-a6
	rts

*       error = AHIsub_Start( Flags, AudioCtrl );
*       D0                    D0     A2

AHIsub_Start:
	pushm	d2-d7/a2-a6

	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6
	move.l	ahiac_DriverData(a2),a3

	move.l	d0,d7
	btst	#AHISB_PLAY,d7
	beq.b	.noplay

	exg.l	a5,a6
	moveq	#AHISF_PLAY,d0
	call	AHIsub_Stop
	call	AHIsub_Update			;fill variables
	exg.l	a5,a6

	move.l	ahiac_BuffSize(a2),d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,wt_Mixbuffer(a3)
	beq.b	.error_nomixmem

	move.l	ahiac_MaxBuffSamples(a2),d0
	lsl.l	#2,d0				;16bit+Stereo
	move.l	d0,d2
	move.l	#MEMF_24BITDMA!MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,wt_DMAbuffer1(a3)
	beq.b	.error_nodmamem

	move.l	d2,d0
	move.l	#MEMF_24BITDMA!MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,wt_DMAbuffer2(a3)
	beq.b	.error_nodmamem

	bsr.b	PlayStart
	tst.l	d0
	bne.b	.error

.noplay
	btst	#AHISB_RECORD,d7
	beq.b	.norecord
	moveq	#AHISF_PLAY,d0

	exg.l	a5,a6
	moveq	#AHISF_PLAY|AHISF_RECORD,d0
	call	AHIsub_Stop
	exg.l	a5,a6

	bsr.w	RecStart
	tst.l	d0
	bne.b	.error

.norecord
	moveq	#AHIE_OK,d0
.exit
	popm	d2-d7/a2-a6
	rts
.error_nodmamem
.error_nomixmem
	moveq	#AHIE_NOMEM,d0
.error
	bra.b	.exit

PlayStart:
* create audio playback process
	moveq	#-1,d0
	call	AllocSignal
	move.b	d0,wt_MasterSignal(a3)
	cmp.b	#-1,d0
	beq.w	.error_nosignal
	suba.l	a1,a1
	call	FindTask
	move.l	d0,wt_MasterTask(a3)

* This is just a trick to make it possible to send the slave an argument.
	moveq	#.size,d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	tst.l	d0
	beq.b	.error_noaudioproc
	move.l	d0,a1

	lea	.kicker(pc),a0
	moveq	#.size-1,d1
.copykicker	
	move.b	(a0)+,(a1)+
	dbf	d1,.copykicker

	move.l	d0,a1
	move.l	a2,.audioctrl(a1)
	lea	.codestart(a1),a0
	move.l	a0,.entry(a1)

	move.l	wt_SoftInt(a3),a0
	move.l	ahiac_Flags(a2),d0
	and.l	#AHIACF_STEREO,d0
	beq.b	.mono
	move.l	#SoftInt_Stereo,IS_CODE(a0)
	bra.b	.1
.mono
	move.l	#SoftInt_Mono,IS_CODE(a0)
.1

	push	a1
	call	CacheClearU
	pop	a1

	move.l	wtb_DosLib(a5),a6
	move.l	a1,d1
	call	CreateNewProc
	move.l	d0,wt_SlaveTask(a3)
	beq.b	.error_noaudioproc

; Wait for slave to allocate and store a signal (or die if error).
	move.l	wtb_SysLib(a5),a6
	moveq	#0,d0
	move.b	wt_MasterSignal(a3),d1
	bset	d1,d0
	call	Wait
	moveq	#AHIE_OK,d0
	rts
.error_noaudioproc
.error_nolocalvar
.error_nosignal
	moveq	#AHIE_NOMEM,d0
	rts

.kicker:
	dc.l	NP_Entry
.entry		EQU	*-.kicker
	dc.l	Dummy
	dc.l	NP_Priority,127
	dc.l	NP_Name,LibName
	dc.l	TAG_DONE

.codestart	EQU	*-.kicker
	lea	.kicker(pc),a1			;a1 points to allocated kicker
.audioctrl	EQU	*+2-.kicker
	lea	Dummy,a2			;a2 points to current AudioCtrl structure
	jmp	audioproc_play
.size		EQU	*-.kicker

RecStart:
* create audio record process
	moveq	#-1,d0
	call	AllocSignal
	move.b	d0,wt_RecMasterSignal(a3)
	cmp.b	#-1,d0
	beq.b	.error_nosignal
	suba.l	a1,a1
	call	FindTask
	move.l	d0,wt_RecMasterTask(a3)

* This is just a trick to make it possible to send the slave an argument.
	moveq	#.size,d0
	move.l	#MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	tst.l	d0
	beq.b	.error_noaudioproc
	move.l	d0,a1

	lea	.kicker(pc),a0
	moveq	#.size-1,d1
.copykicker	
	move.b	(a0)+,(a1)+
	dbf	d1,.copykicker

	move.l	d0,a1
	move.l	a2,.audioctrl(a1)
	lea	.codestart(a1),a0
	move.l	a0,.entry(a1)

	push	a1
	call	CacheClearU
	pop	a1

	move.l	wtb_DosLib(a5),a6
	move.l	a1,d1
	call	CreateNewProc
	move.l	d0,wt_RecSlaveTask(a3)
	beq.b	.error_noaudioproc

; Wait for slave to allocate and store a signal (or die if error).
	move.l	wtb_SysLib(a5),a6
	moveq	#0,d0
	move.b	wt_RecMasterSignal(a3),d1
	bset	d1,d0
	call	Wait
	moveq	#AHIE_OK,d0
	rts
.error_noaudioproc
.error_nolocalvar
.error_nosignal
	moveq	#AHIE_NOMEM,d0
	rts

*** 'kicker'
.kicker:
	dc.l	NP_Entry
.entry		EQU	*-.kicker
	dc.l	Dummy
	dc.l	NP_Priority,127
	dc.l	NP_Name,LibName
	dc.l	TAG_DONE

.codestart	EQU	*-.kicker
	lea	.kicker(pc),a1			;a1 points to allocated kicker
.audioctrl	EQU	*+2-.kicker
	lea	Dummy,a2			;a2 points to current AudioCtrl structure
	jmp	audioproc_record
.size		EQU	*-.kicker


Dummy:
	rts

*       AHIsub_Update( flags, audioctrl );
*                      D0     A2

AHIsub_Update:
	pushm	d2-d7/a2-a6

	call	AHIsub_Disable		;make sure we don't get an interrupt
					;while updating our local variables
	move.l	ahiac_DriverData(a2),a3

	move.l	ahiac_PlayerFunc(a2),a0
	move.l	a0,wt_PlayerHook(a3)
	move.l	h_Entry(a0),wt_PlayerEntry(a3)

	move.l	ahiac_BuffSamples(a2),d0
	move.l	d0,wt_LoopTimes(a3)		;See audioproc.
	lsl.l	#2,d0
	move.l	d0,wt_DMAlength(a3)

	move.l	ahiac_MixerFunc(a2),a0
	move.l	a0,wt_MixHook(a3)
	move.l	h_Entry(a0),wt_MixEntry(a3)

	call	AHIsub_Enable
	moveq	#0,d0
	popm	d2-d7/a2-a6
	rts


*       AHIsub_Stop(Flags, AudioCtrl );
*                   D0     A2

AHIsub_Stop:
	pushm	d2-d7/a2-a6

	move.l	a6,a5
	move.l	wtb_SysLib(a5),a6
	move.l	ahiac_DriverData(a2),a3

	move.l	d0,d7					;save flags
	btst	#AHISB_PLAY,d7
	beq.b	.noplaystop

; Signal slave to quit
	move.l	wt_SlaveTask(a3),d0
	beq.b	.noslave
	move.l	d0,a1
	moveq	#0,d0
	move.b	wt_SlaveSignal(a3),d1
	bset	d1,d0
	call	Signal
; Wait for slave to die
	moveq	#0,d0
	move.b	wt_MasterSignal(a3),d1
	bset	d1,d0
	call	Wait
.noslave
	moveq	#0,d0
	move.b	wt_MasterSignal(a3),d0			;-1 is ok
	move.b	#-1,wt_MasterSignal(a3)
	call	FreeSignal

	move.l	wt_DMAbuffer1(a3),d0
	beq.b	.nodmamem1
	move.l	d0,a1
	call	FreeVec
	clr.l	wt_DMAbuffer1(a3)
.nodmamem1
	move.l	wt_DMAbuffer2(a3),d0
	beq.b	.nodmamem2
	move.l	d0,a1
	call	FreeVec
	clr.l	wt_DMAbuffer2(a3)
.nodmamem2
	move.l	wt_Mixbuffer(a3),d0
	beq.b	.nomixmem
	move.l	d0,a1
	call	FreeVec
	clr.l	wt_Mixbuffer(a3)
.nomixmem

.noplaystop
	btst	#AHISB_RECORD,d7
	beq.b	.norecstop

; Signal record slave to quit
	move.l	wt_RecSlaveTask(a3),d0
	beq.b	.norecslave
	move.l	d0,a1
	moveq	#0,d0
	move.b	wt_RecSlaveSignal(a3),d1
	bset	d1,d0
	call	Signal
; Wait for record slave to die
	moveq	#0,d0
	move.b	wt_RecMasterSignal(a3),d1
	bset	d1,d0
	call	Wait
.norecslave
	moveq	#0,d0
	move.b	wt_RecMasterSignal(a3),d0		;-1 is ok
	move.b	#-1,wt_RecMasterSignal(a3)
	call	FreeSignal
.norecstop
	moveq	#0,d0
	popm	d2-d7/a2-a6
	rts

AHIsub_SetVol:
AHIsub_SetFreq:
AHIsub_SetSound:
AHIsub_SetEffect:
AHIsub_LoadSound:
AHIsub_UnloadSound:
	moveq	#AHIS_UNKNOWN,d0
	rts

;in:
* a2	audioctrl
;out:
* d0	Wavetools outout damp value
volume2damp:
* translate linear to wavetools output damp value

	moveq	#31,d0				;DADCONST_MAXDAMP
	lea	.volumelist(pc),a0
.loop
	cmp.l	(a0)+,d1
	bls.b	.exit
	subq.l	#1,d0
	bpl.b	.loop
.exit
	and.l	#31,d0				;just security
	rts

.volumelist
	dc.l	1,2,3,4,6,8,12,16,23,33,46,66,93,131,185,261,369,521,735,1039
	dc.l	1467,2072,2927,4135,5841,8250,11654,16462,23253,32846,46396
	dc.l	65536



*       AHIsub_GetAttr( attribute, argument, default, taglist, audioctrl );
*       D0              D0         D1        D2       A1       a2

AHIsub_GetAttr:
	cmp.l	#AHIDB_Bits,d0
	bne.b	.not_bits
	moveq	#16,d0
	bra.w	.exit
.not_bits
	cmp.l	#AHIDB_Frequencies,d0
	bne.b	.not_freqs
	moveq	#8,d0
	bra.w	.exit
.not_freqs
	cmp.l	#AHIDB_Frequency,d0
	bne.b	.not_freq
	add.l	d1,d1
	add.l	d1,d1
	lea	freqlist(pc),a0
	move.l	(a0,d1.l),d0
	bra.w	.exit
.not_freq
	cmp.l	#AHIDB_Index,d0
	bne.b	.not_index
	move.l	d1,d0
	bsr.w	findfreq
	move.l	d0,d1
	moveq	#0,d0
	lea	freqlist(pc),a0
.index_loop
	cmp.l	(a0)+,d1
	beq.w	.exit
	addq.l	#1,d0
	bra.b	.index_loop
.not_index
	cmp.l	#AHIDB_Author,d0
	bne.b	.not_author
	lea	.author(pc),a0
	move.l	a0,d0
	bra.w	.exit
.not_author
	cmp.l	#AHIDB_Copyright,d0
	bne.b	.not_copyright
	lea	.copyright(pc),a0
	move.l	a0,d0
	bra.w	.exit
.not_copyright
	cmp.l	#AHIDB_Version,d0
	bne.b	.not_version
	lea	IDString(pc),a0
	move.l	a0,d0
	bra.w	.exit
.not_version
	cmp.l	#AHIDB_MaxRecordSamples,d0
	bne.b	.not_maxrecsamples
	move.l	#DMA_LENGTH,d0
	bra.w	.exit
.not_maxrecsamples
	cmp.l	#AHIDB_Realtime,d0
	bne.b	.not_realtime
	moveq	#TRUE,d0
	bra.w	.exit
.not_realtime
	cmp.l	#AHIDB_Record,d0
	bne.b	.not_record
	moveq	#TRUE,d0
	bra.b	.exit
.not_record
	cmp.l	#AHIDB_FullDuplex,d0
	bne.b	.not_fullduplex
	moveq	#FALSE,d0
	bra.b	.exit
.not_fullduplex
	cmp.l	#AHIDB_Inputs,d0
	bne.b	.not_inputs
	moveq	#1,d0
	bra.b	.exit
.not_inputs
	cmp.l	#AHIDB_Input,d0
	bne.b	.not_input
	lea	.line(pc),a0			;only one source
	move.l	a0,d0
	bra.b	.exit
.not_input
	cmp.l	#AHIDB_Outputs,d0
	bne.b	.not_outputs
	moveq	#1,d0
	bra.b	.exit
.not_outputs
	cmp.l	#AHIDB_Output,d0
	bne.b	.not_output
	lea	.line(pc),a0			;only one destination
	move.l	a0,d0
	bra.b	.exit
.not_output
	cmp.l	#AHIDB_MinMonitorVolume,d0
	bne.b	.not_minmonvol
	moveq	#0,d0
	bra.b	.exit
.not_minmonvol
	cmp.l	#AHIDB_MaxMonitorVolume,d0
	bne.b	.not_maxmonvol
	move.l	#$10000,d0
	bra.b	.exit
.not_maxmonvol
	cmp.l	#AHIDB_MinOutputVolume,d0
	bne.b	.not_minoutvol
	moveq	#0,d0
	bra.b	.exit
.not_minoutvol
	cmp.l	#AHIDB_MaxOutputVolume,d0
	bne.b	.not_maxoutvol
	move.l	#$10000,d0
	bra.b	.exit
.not_maxoutvol

* Unknown attribute, return default.
	move.l	d2,d0
.exit
	rts
.author
	dc.b	"Martin 'Leviticus' Blom",0
.copyright
	dc.b	"Public Domain",0
.line
	dc.b	"Line",0
	even


*       AHIsub_HardwareControl( attribute,  argument, audioctrl );
*       D0                      D0          D1        A2

AHIsub_HardwareControl:
	cmp.l	#AHIC_MonitorVolume,d0
	bne.b	.dontsetmonvol
	move.l	ahiac_DriverData(a2),a1
	move.l	d1,wt_InputVolume(a1)
	bra.b	.exit
.dontsetmonvol
	cmp.l	#AHIC_MonitorVolume_Query,d0
	bne.b	.dontgetmonvol
	move.l	ahiac_DriverData(a2),a1
	move.l	wt_InputVolume(a1),d0
	bra.b	.quit
.dontgetmonvol
	cmp.l	#AHIC_OutputVolume,d0
	bne.b	.dontsetvol
	move.l	ahiac_DriverData(a2),a1
	move.l	d1,wt_OutputVolume(a1)
	bra.b	.exit
.dontsetvol
	cmp.l	#AHIC_OutputVolume_Query,d0
	bne.b	.dontgetvol
	move.l	ahiac_DriverData(a2),a1
	move.l	wt_OutputVolume(a1),d0
	bra.b	.quit
.dontgetvol
	moveq	#FALSE,d0
.quit
	rts
.exit
	moveq	#TRUE,d0
	rts
*****************************************************************************

;in:
* a1	ptr to 'kicker'
* a2	AudioCtrl
audioproc_play:
	move.l	ahiac_DriverData(a2),a5
	move.l	4.w,a6
	call	FreeVec

	moveq	#-1,d0
	call	AllocSignal
	move.b	d0,wt_SlaveSignal(a5)
	cmp.b	#-1,d0
	beq.w	.error_nosignal

* allocate dad_audio.device
	call	CreateMsgPort
	move.l	d0,wt_dadport(a5)
	beq.w	.error_noport
	move.l	d0,a0
	moveq	#IOSTD_SIZE,d0

	call	CreateIORequest
	move.l	d0,wt_dadioreq(a5)
	beq.w	.error_noioreq

	lea	dadname(pc),a0
	moveq	#0,d0
	move.l	wt_dadioreq(a5),a1
	moveq	#0,d1
	call	OpenDevice
	move.l	d0,wt_daddev(a5)
	bne.w	.error_nodaddev

* initialize the board
	move.l	wt_dadioreq(a5),a1
	move.l	#DADF_SETFLAG|DADF_INIT,IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_INIT2,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_dadioreq(a5),a1
	move.l	ahiac_MixFreq(a2),IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_REPLAYFREQ,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_MasterTask(a5),a1
	moveq	#0,d0
	move.b	wt_MasterSignal(a5),d1
	bset	d1,d0
	call	Signal			;Tell master we're alive and kicking!

.again
*** Set Volume
	move.l	wt_OutputVolume(a5),d1		;default is $10000 (see alloc function)
	bsr.w	volume2damp
	move.l	wt_dadioreq(a5),a1
	move.l	d0,IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_OUTPUTDAMP,IO_COMMAND(a1)
	call	DoIO

	not.l	wt_DBflag(a5)
	beq.b	.1
	move.l	wt_DMAbuffer1(a5),wt_DMAbuffer(a5)
	bra.b	.2
.1
	move.l	wt_DMAbuffer2(a5),wt_DMAbuffer(a5)
.2

	move.l	wt_SoftInt(a5),a1
	call	Cause

	move.l	wt_dadioreq(a5),a1
	call	WaitIO

	moveq	#0,d0
	moveq	#0,d1
	call	SetSignal
	move.b	wt_SlaveSignal(a5),d1
	btst	d1,d0
	bne.b	.quit

	move.l	wt_dadioreq(a5),a1
	move.l	wt_DMAbuffer(a5),IO_DATA(a1)
	move.l	wt_DMAlength(a5),IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#CMD_WRITE,IO_COMMAND(a1)
	call	SendIO
	bra.b	.again
.quit
.error_noport
.error_noioreq
.error_nodaddev
.error_nosignal
	clr.l	wt_SlaveTask(a5)
	moveq	#0,d0
	move.b	wt_SlaveSignal(a5),d0			;-1 is ok
	move.b	#-1,wt_SlaveSignal(a5)
	call	FreeSignal

	tst.l	wt_daddev(a5)
	bne.b	.nodaddev

	move.l	wt_dadioreq(a5),a1
	move.l	#DADCONST_MAXDAMP,IO_DATA(a1)		;zero volume
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_OUTPUTDAMP,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_dadioreq(a5),a1
	move.l	#-1,wt_daddev(a5)
	call	CloseDevice
.nodaddev
	move.l	wt_dadioreq(a5),a0
	clr.l	wt_dadioreq(a5)
	call	DeleteIORequest
.noaudioreq
	move.l	wt_dadport(a5),a0
	clr.l	wt_dadport(a5)
	call	DeleteMsgPort
.noaudioport
	move.l	wt_MasterTask(a5),a1
	moveq	#0,d0
	move.b	wt_MasterSignal(a5),d1
	bset	d1,d0
	call	Signal
	rts


SoftInt_Dummy:
	rts

* d0	scratch
* d1	scratch
* a0	scratch
* a1	wt_SoftIntData
* a5	scratch
SoftInt_Mono:
	pushm	a2/a3
	move.l	a1,a5
	movem.l	(a5)+,a0/a1/a2/a3
	jsr	(a3)				;call Player Hook
	movem.l	(a5),d0/a0/a1/a2/a3/a5
	jsr	(a3)				;call Mixer Hook

* transfer buffer (unrolled)
	lsr.w	#1,d0
	bcs.b	.3
	subq.w	#1,d0
.loop
	move.w	(a1),(a5)+
	move.w	(a1)+,(a5)+
.3
	move.w	(a1),(a5)+
	move.w	(a1)+,(a5)+
	dbf	d0,.loop
	popm	a2/a3
	rts

* d0	scratch
* d1	scratch
* a0	scratch
* a1	wt_SoftIntData
* a5	scratch
SoftInt_Stereo:
	pushm	a2/a3
	move.l	a1,a5
	movem.l	(a5)+,a0/a1/a2/a3
	jsr	(a3)				;call Player Hook
	movem.l	(a5),d0/a0/a1/a2/a3/a5
	jsr	(a3)				;call Mixer Hook

* transfer buffer (unrolled)
	lsr.w	#1,d0
	bcs.b	.3
	subq.w	#1,d0
.loop
	move.l	(a1)+,(a5)+
.3
	move.l	(a1)+,(a5)+
	dbf	d0,.loop
	popm	a2/a3
	rts

;in:
* a1	ptr to 'kicker'
* a2	AudioCtrl
audioproc_record:
	move.l	ahiac_DriverData(a2),a5
	move.l	4.w,a6
	call	FreeVec

	moveq	#-1,d0
	call	AllocSignal
	move.b	d0,wt_RecSlaveSignal(a5)
	cmp.b	#-1,d0
	beq.w	.error

	moveq	#AHIRecordMessage_SIZEOF,d0
	move.l	#MEMF_24BITDMA|MEMF_PUBLIC|MEMF_CLEAR,d1
	call	AllocVec
	move.l	d0,wt_RecordMsg(a5)
	beq.w	.error

* allocate dad_audio.device
	call	CreateMsgPort
	move.l	d0,wt_recdadport(a5)
	beq.w	.error
	move.l	d0,a0
	moveq	#IOSTD_SIZE,d0

	call	CreateIORequest
	move.l	d0,wt_recdadioreq(a5)
	beq.w	.error

	lea	dadname(pc),a0
	moveq	#0,d0
	move.l	wt_recdadioreq(a5),a1
	moveq	#0,d1
	call	OpenDevice
	move.l	d0,wt_recdaddev(a5)
	bne.w	.error

* initialize the board
	move.l	wt_recdadioreq(a5),a1
	move.l	#DADF_SETFLAG|DADF_INIT,IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_INIT2,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_recdadioreq(a5),a1
	move.l	ahiac_MixFreq(a2),IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_SAMPLEFREQ,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_recdadioreq(a5),a1
	move.l	ahiac_MixFreq(a2),IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_REPLAYFREQ,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_recdadioreq(a5),a1
	clr.l	IO_DATA(a1)				;no gain
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_INPUTGAIN,IO_COMMAND(a1)
	call	DoIO

	move.l	wt_recdadioreq(a5),a1
	clr.l	IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	move.l	#DAD_BUFFER_SETUP,IO_OFFSET(a1)
	move.w	#DADCMD_BUFFER,IO_COMMAND(a1)
	call	DoIO
; Hardcoded value used, since ahi.device must know the size
;of the record buffer.
;	move.l	IO_ACTUAL(a1),d7			;dma length
	move.l	#DMA_LENGTH*4,d7
	move.l	d7,d0
	move.l	#MEMF_CLEAR|MEMF_CHIP|MEMF_PUBLIC,d1
	call	AllocVec
	move.l	d0,wt_RecBuffer(a5)
	beq.w	.error

	move.l	wt_RecMasterTask(a5),a1
	moveq	#0,d0
	move.b	wt_RecMasterSignal(a5),d1
	bset	d1,d0
	call	Signal			;Tell Master we're alive and kicking!

.again
*** Set Volume
	move.l	wt_InputVolume(a5),d1
	bsr.w	volume2damp
	move.l	wt_recdadioreq(a5),a1
	move.l	d0,IO_DATA(a1)
	clr.l	IO_LENGTH(a1)
	clr.l	IO_OFFSET(a1)
	move.w	#DADCMD_OUTPUTDAMP,IO_COMMAND(a1)
	call	DoIO

*** Read
	move.l	wt_recdadioreq(a5),a1
	move.l	wt_RecBuffer(a5),IO_DATA(a1)
	move.l	d7,IO_LENGTH(a1)
	move.l	#-1,IO_OFFSET(a1)
	move.w	#CMD_READ,IO_COMMAND(a1)
	call	DoIO			;copy internal buffer to RecBuffer

	move.l	wt_recdadioreq(a5),a1
	clr.l	IO_DATA(a1)
	move.l	IO_ACTUAL(a1),IO_LENGTH(a1)
	move.l	#DAD_BUFFER_SWITCH,IO_OFFSET(a1)
	move.w	#DADCMD_BUFFER,IO_COMMAND(a1)
	call	DoIO			;swap internal buffers

*** Call Hook
	move.l	ahiac_SamplerFunc(a2),a0
	move.l	h_Entry(a0),a3
	move.l	wt_RecordMsg(a5),a1
	move.l	wt_RecBuffer(a5),ahirm_Buffer(a1)
	move.l	d7,d0
	lsr.l	#2,d0
	move.l	d0,ahirm_Length(a1)
	move.l	#AHIST_S16S,ahirm_Type(a1)
	jsr	(a3)

*** Exit?
	moveq	#0,d0
	moveq	#0,d1
	call	SetSignal
	move.b	wt_RecSlaveSignal(a5),d1
	btst	d1,d0
	beq.w	.again
.error
	move.l	wt_RecBuffer(a5),d0
	beq.b	.nobuffer
	move.l	d0,a1
	clr.l	wt_RecBuffer(a5)
	call	FreeVec
.nobuffer
	clr.l	wt_RecSlaveTask(a5)
	moveq	#0,d0
	move.b	wt_RecSlaveSignal(a5),d0		;-1 is ok
	move.b	#-1,wt_RecSlaveSignal(a5)
	call	FreeSignal

	tst.l	wt_recdaddev(a5)
	bne.b	.nodaddev

	move.l	wt_recdadioreq(a5),a1
	move.l	#-1,wt_recdaddev(a5)
	call	CloseDevice
.nodaddev
	move.l	wt_recdadioreq(a5),a0
	clr.l	wt_recdadioreq(a5)
	call	DeleteIORequest
.noaudioreq
	move.l	wt_recdadport(a5),a0
	clr.l	wt_recdadport(a5)
	call	DeleteMsgPort
.noaudioport
	move.l	wt_RecMasterTask(a5),a1
	moveq	#0,d0
	move.b	wt_RecMasterSignal(a5),d1
	bset	d1,d0
	call	Signal
	rts
dadname:
	DAD_DEVICENAME
	even
EndCode:
