*****************************************************************************
**                                                                         **
** Internal Amplifier Modules                                              **
**                                                                         **
** Project: Eagleplayer 2.04                                               **
** Authors: Jan Blumenthal & Henryk Richter                                **
** Start  : 1993/01/09                                                     **
** $Header$                                                                **
**                                                                         **
*****************************************************************************
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program (See the included file COPYING);
** if not, write to the Free Software Foundation, Inc.,
** 675 Mass Ave, Cambridge, MA 02139, USA.
**
*****************************************************************************

FirstAmplifier:
ChipRamAmiplifier:
	dc.l	0		;bra.w
	dc.l	.fastram ;ACHTUNG wird benutzt
	dc.l	0
	*dc.w	0
	dc.l	0		;eus_next
	dc.w	0		;eus_Usernr
	dc.l	0		;eus_EPBase
	dc.l	0		;eus_Freetable
	dc.l	0		;eus_Taskadr
	dc.l	0		;eus_unused1
	dc.l	0		;eus_unused2
	dc.l	.chipramjumptab	;EUS_Specialjumptab
	dc.l	0		;EUS_Taglist
	dc.w	0		;eus_ticks
	dc.w	0		;eus_tickcounter
	dc.l	0		;eus_tickflags
	dc.l	0		;eus_msgflags
	dc.l	0		;eus_PName
	dc.l	.chipname	;eus_CName <- Name des Amplifier
	dc.l	0 .myinfoC
	dc.w	0		;eus_Kickstart
	dc.l	8		;eus_EPVersion
	dc.w	0,25		;eus_version,revision
	dc.l	.chipname	;eus_username
	dc.w	0		;eus_winx
	dc.w	0		;eus_winy
	dc.w	0;EUSB_disable	;Amplifier disabled ?
	dc.w	0		;EUS_AMPriority

	dc.w	ENPB_NoWindow	;EUS_AMFlags -> no show/hide gadgets
	dc.l	0		;EUS_Special2
	dc.l	0		;EUS_Special3
	dc.b	CD_Tag,CD_Monat	;\ EUS_Creatordate
	dc.w	CD_Jahr		;/ EUS_Creatordate
	dc.b	0		;EUS_Priority
	dc.b	EUTY_Amplifier	;EUS_Type
	dc.w	0		;EUS_Reserved2
	dc.l	0		;EUS_Reserved3
	dc.l	0		;EUS_Reserved4
	dc.l	MyUPSStruct	;EUS_Reserved5
	dc.l	0		;EUS_Reserved6

		ifne	(*-ChipRamAmiplifier)-EUS_SizeOF
		Aber Hallo
		endc

.fastram:
	dc.l	0		;bra.w
	dc.l	0		;next Amplifier
	dc.l	0
	*dc.w	0
	dc.l	0		;eus_next
	dc.w	0		;eus_Usernr
	dc.l	0		;eus_EPBase
	dc.l	0		;eus_Freetable
	dc.l	0		;eus_Taskadr
	dc.l	0		;eus_unused1
	dc.l	0		;eus_unused2
	dc.l	.fastramjumptab	;EUS_Specialjumptab
	dc.l	0		;EUS_Taglist
	dc.w	0		;eus_ticks
	dc.w	0		;eus_tickcounter
	dc.l	0		;eus_tickflags
	dc.l	0		;eus_msgflags
	dc.l	0		;eus_PName
	dc.l	.fastname	;eus_username
	dc.l	0 .myinfoF
	dc.w	0		;eus_Kickstart
	dc.l	8		;eus_EPVersion
	dc.w	0,25		;eus_version,revision
	dc.l	.fastname	;eus_username
	dc.w	0		;eus_winx
	dc.w	0		;eus_winy

	dc.w	0;EUSB_disable	;Amplifier disabled ?
	dc.w	0		;EUS_AMPriority

	dc.w	ENPB_NoWindow	;EUS_AMFlags -> no show/hide gadgets
	dc.l	0		;EUS_Special2
	dc.l	0		;EUS_Special3
	dc.b	CD_Tag,CD_Monat	;\ EUS_Creatordate
	dc.w	CD_Jahr		;/ EUS_Creatordate
	dc.b	0		;EUS_Priority
	dc.b	EUTY_Amplifier	;EUS_Type
	dc.w	0		;EUS_Reserved2
	dc.l	`4CHN`		;EUS_Reserved3;EUS_AMIDNr
	dc.l	0		;EUS_Reserved4
	dc.l	MyUPSStruct	;EUS_Reserved5
	dc.l	0		;EUS_Reserved6

		ifne	(*-.Fastram)-EUS_SizeOF
		Aber Hallo
		endc

.fastname
	dc.b	`4ch. FastRam Amplifier`,0
.chipname
	dc.b	`4ch. ChipRam Amplifier`,0
.mybuggsname
	dc.b	`Buggs/Defect`,0
*.myinfoC
*	dc.b	`This Amplifier supports`,10
*	dc.b	`up to 4 voices to be played`,10
*	dc.b	`directly by the hardware.`,10
*	dc.b	`Therefore it requires the`,10
*	dc.b	`modules to be loaded into`,10
*	dc.b	`chip memory.`,10
*	dc.b	`It was written by Buggs`,10
*	dc.b	`of Defect.`,0
*.myinfoF
*	dc.b	`This Amplifier supports`,10
*	dc.b	`up to 4 voices. It is able`,10
*	dc.b	`to play modules from fast`,10
*	dc.b	`memory without any quality`,10
*	dc.b	`loss.`,10
*	dc.b	`It was written by Buggs`,10
*	dc.b	`of Defect.`,0

	even
.chipramjumptab
	dc.l	0		;AMJ_CheckFeatures
	dc.l	Chipraminit	;AMJ_Init
	dc.l	ChipRamStartInt	;AMJ_StartInt
	dc.l	ChipRamStopInt	;AMJ_StopInt
	dc.l	ChipramEND	;AMJ_End
	dc.l	0		;AMJ_Amplifier

	dc.l	Chip_Adr;AMJ_PokeAdr
	dc.l	Chip_Len;AMJ_PokeLen
	dc.l	Chip_Per;AMJ_PokePer
	dc.l	Chip_Vol;AMJ_PokeVol
	dc.l	Chip_DMA;AMJ_DMABit
	dc.l	0	;AMJ_Command
.fastramjumptab
	dc.l	0			;AMJ_CheckFeatures
	dc.l	FastRamInit		;AMJ_Init
	dc.l	FastRamStartInt		;AMJ_StartInt
	dc.l	FastRamStopInt		;AMJ_StopInt
	dc.l	FastRamEND		;AMJ_End
	dc.l	0		;AMJ_Amplifier

	dc.l	0	;AMJ_PokeAdr
	dc.l	0	;AMJ_PokeLen
	dc.l	Fast_Per;AMJ_PokePer
	dc.l	Fast_Vol;AMJ_PokeVol
	dc.l	Fast_DMA;AMJ_DMABit
	dc.l	0	;AMJ_Command
		even
;---------------- Routinen für den 4 Stimmen ChipRamPlayer --------------------
; Init/End:
;          - Initplayer -> Übergabe A0: Tagliste
;                                   A5: EP Globals
;                       -> zurück   D0: 0=OK, <>0=Error
;
; Start-Stop: Startint (keine Übergabeargumente)
;
;             Stopint  (keine Übergabeargumente)
;
ChipRamInit:
	move.l	#EPAMT_Flags,d0
	jsr	ENPP_FindTag(A5)
	beq	.err

	;------- ausmaskieren, was nicht unterstützt wird --------------
	move.l	#EPAMB_8BitUnsigned!EPAMB_16Bit!EPAMB_PingPongLoops!EPAMB_AudioInts,d1
	and.l	d0,d1
	bne	.err

	;------- ausmaskieren, was auf jeden Fall gebraucht wird -------
	and.l	#EPAMB_Direct!EPAMB_8Bit!EPAMB_ChipRam,d0
	cmp.l	#EPAMB_Direct!EPAMB_8Bit!EPAMB_ChipRam,d0
	bne	.err

	move.l	#EPAMT_Audiostructs,d0
	jsr	ENPP_FindTag(A5)
	beq	.err
	move.l	d0,d7

	move.l	#EPAMT_NumStructs,d0
	jsr	ENPP_FindTag(A5)
	beq	.err
	cmp.w	#4,d0
	bne	.err

	move.l	d7,a0

	cmp.w	#01,AS_Leftright(a0)			;1. Kanal links
	bne	.err
	cmp.w	#-1,AS_Leftright+as_sizeof*1(a0)	;2. Kanal rechts
	bne	.err
	cmp.w	#-1,AS_Leftright+as_sizeof*2(a0)	;3. Kanal rechts
	bne	.err
	cmp.w	#01,AS_Leftright+as_sizeof*3(a0)	;4. Kanal links
	bne	.err

	move.l	a0,epg_audiostruct(A5)			;Audiostruct setzen

	moveq	#0,d0
	move.w	d0,savedma				;DMA nicht sofort wieder
							;starten
	lea	MyUPSStruct,a1
	move.w	#UPSB_Adr!UPSB_LEN!UPSB_Per!UPSB_Vol!UPSB_DMACON,ups_flags(a1)
	clr.w	UPS_DmaCon(a1)
	clr.w	UPS_Enabled(a1)
	rts
.err
	moveq	#-1,d0
	rts
ChipramEND
	rts
;	move.w	#15,$dff096
;	clr.w	$dff0a8
;	clr.w	$dff0b8
;	clr.w	$dff0c8
;	clr.w	$dff0d8
;	rts

ChipRamStartInt
	jsr	AllocAudio2
	bne.w	.err

	move.w	savedma(pc),d0
	or.w	#$8000,d0
	move.w	d0,$dff096
	move.w	#$ff,$dff09e

	bset	#1,$bfe001			;Filter off
;	move.l	EPG_SomePrefs(a5),d0
;	btst	#EGPRF_Filter,d0
;	beq.s	.Off
	tst.b	DTG_LED(a5)
	beq.s	.off

	bclr	#1,$bfe001			;Filter on
.off
	moveq	#0,d0
.err	rts

ChipRamStopInt
	move.w	$dff002,d0
	and.w	#15,d0
	move.w	d0,savedma
	move.w	#15,$dff096

	jsr	FreeAudio
	rts
saveDMA	dc.w	0

Chip_DMA:		;alle Register sind bereits gesichert !
	tst.w	d0
	bpl.s	.set2
	or.w	#$8000,d1
.set2
	move.w	d1,$dff096
	jsr	DTWaitAudioDma

	lea	MyUPSStruct+UPS_Modulo*3,a1

	lea	BSSMerkPuffer,a0
	move.l	epg_audiostruct(a0),a0
	lea	AS_Sizeof*3(a0),a0

	moveq	#3,d0
	moveq	#0,d2
.makeUPS
	lsl	#1,d2

	move.w	AS_LeftVolume(A0),UPS_Voice1Vol(a1)
	move	AS_Period(a0),d1
	lsr	#2,d1
	move	d1,UPS_Voice1Per(a1)
	move.l	AS_CurrentAdr(a0),UPS_Voice1Adr(a1)
	move.l	AS_SampleSize(a0),d1
	lsr	#1,d1
	move.w	d1,UPS_Voice1Len(a1)

	tst.w	AS_DmaBit(a0)
	beq.s	.noadd
	or.w	#1,d2
.noadd
	lea	-UPS_Modulo(a1),a1
	lea	-AS_Sizeof(a0),a0
	dbf	d0,.makeUPS

	lea	MyUPSStruct,a1
	move	d2,UPS_DmaCon(a1)
	rts
Chip_Vol:
	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	add.w	d2,d2			;mal 2
	move.w	d2,d3
	add.w	#EPG_Voice1Vol,d3
	lsl.w	#3,d2			;mal 16/2
	mulu	(a5,d3.w),d0
	lsr.w	#6,d0

	add.w	d2,a0
	move.w	d0,8(a0)
	rts
Chip_Per
	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	lsl.w	#4,d2
	add.w	d2,a0
	lsr	#2,d0
	move.w	d0,6(a0)
	rts
Chip_Len
	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	lsl.w	#4,d2
	add.w	d2,a0
	tst.w	d0
	bne.s	.nozero
	moveq	#1,d0
.nozero
	move.w	d0,4(a0)
	rts
Chip_Adr
	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	lsl.w	#4,d2
	add.w	d2,a0
	move.l	d0,(a0)
	rts

Fast_OLDDMA	dc.w	0

SamLEN		equ	128
NumChipBuffers	equ	2

;---------------- Routinen für den 4 Stimmen FastRamPlayer --------------------
; Init/End:
;          - Initplayer -> Übergabe A0: Tagliste
;                                   A5: EP Globals
;                       -> zurück   D0: 0=OK, <>0=Error
;
; Start-Stop: Startint (keine Übergabeargumente)
;
;             Stopint  (keine Übergabeargumente)
;
FastRamInit:
	move.l	#EPAMT_Flags,d0
	jsr	ENPP_FindTag(A5)
	beq	.err

	;------- ausmaskieren, was nicht unterstützt wird --------------
	move.l	#EPAMB_8BitUnsigned!EPAMB_16Bit!EPAMB_PingPongLoops,d1
	and.l	d0,d1
	bne	.err

	;------- ausmaskieren, was auf jeden Fall gebraucht wird -------
	and.l	#EPAMB_8Bit!EPAMB_Direct,d0
	beq	.err

	move.l	#EPAMT_Audiostructs,d0
	jsr	ENPP_FindTag(A5)
	beq	.err
	move.l	d0,d7

	move.l	#EPAMT_NumStructs,d0
	jsr	ENPP_FindTag(A5)
	beq	.err
	move.l	d7,a0

	subq.w	#1,d0			;Anzahl der Audio-Strukturen
	blt	.err

	moveq	#0,d1
	moveq	#0,d2
	lea	(a0),a2
.countvoc
	tst.w	AS_LeftRight(a2)
	bpl.s	.addL
	bmi.s	.addR
	bra.s	.noADD
.addL
	cmp.w	#2,AS_Leftright(a2)
	beq	.err
	addq.w	#1,d1
	bra.s	.noADD
.addR
	addq.w	#1,d2
.noadd
	lea	as_sizeof(a2),a2
	dbf	d0,.countvoc

	cmp.w	#2,d1			;max. 2 links
	bhi	.err
	cmp.w	#2,d2			;max. 2 rechts
	bhi	.err

	move.w	d2,d0
	add.w	d1,d0
	beq	.err			;wie, was, gar nichts ?

	lea	ChannelStruct0(pc),a1
	clr.l	4(a1)
	clr.l	8(a1)
	clr.l	4+22(a1)
	clr.l	8+22(a1)
	clr.l	4+44(a1)
	clr.l	8+44(a1)
	clr.l	4+66(a1)
	clr.l	8+66(a1)

	subq.w	#1,d1
	bmi.w	.noneleft

	lea	ChannelStruct0(pc),a1
	lea	(a0),a2
	sub.w	#AS_Sizeof,a2
.leftloop
	add.w	#AS_Sizeof,a2

	tst.w	AS_LeftRight(a2)
	ble.s	.leftloop

	move.l	a2,8(a1)
	lea	ChannelStruct3(pc),a1	;2. linker Kanal (da ja eh nur 2 sind, kann man das schon so seltsam machen)

	dbf	d1,.leftloop
.noneleft
	subq.w	#1,d2
	bmi.w	.noneright
	lea	(a0),a2

	lea	ChannelStruct1(pc),a1
	lea	(a0),a2
	sub.w	#AS_Sizeof,a2
.rightloop
	add.w	#AS_Sizeof,a2

	tst.w	AS_LeftRight(a2)
	bge.s	.rightloop

	move.l	a2,8(a1)
	lea	ChannelStruct2(pc),a1	;2. linker Kanal (da ja eh nur 2 sind, kann man das schon so seltsam machen)

	dbf	d2,.rightloop
.noneright
	move.l	a0,epg_audiostruct(A5)			;Audiostruct setzen

	clr	Fast_OLDDMA
	moveq	#0,d0
	rts
.err
	moveq	#-1,d0
	rts
	;-------------------- (noch) keine Funktion -------------------
FastramEND
	move.w	#15,$dff096
	clr.w	$dff0a8
	clr.w	$dff0b8
	clr.w	$dff0c8
	clr.w	$dff0d8
	rts

FastRamStartInt
	lea	OLDINT0(pc),a0
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+
	clr.l	(a0)+

	;-------------------- hier alloc Audio -------------------------
	jsr	AllocAudio2
	bne.w	.err
	;---------------------------------------------------------------

	bset	#1,$bfe001			;Filter off
;	move.l	EPG_SomePrefs(a5),d0
;	btst	#EGPRF_Filter,d0
;	beq.s	.Off
	tst.b	DTG_LED(a5)
	beq.s	.Off
	bclr	#1,$bfe001			;Filter on
.Off
					;Audio Interrupt disable
	move.w	#$780,$dff09c		;Interrupt Request Hardwarehack
	move.w	#$ff,$dff09e

	movem.l	d0-a6,-(sp)		;Audio Interrupt handler durch
					;eigene ersetzen
	lea	AudInts,a3		;Audio Interrupt Strukturen


	lea	(a3),a1			;Interrupt Strukturen vorbereiten
	moveq	#4-1,d0
	lea	HardInt0(pc),a0
	lea	INT_Name1(pc),a2
.initInts1
	move.l	a0,18(a1)		;IS_Code
	move.w	#$027f,8(a1)		;type+Pri
	move.l	a2,10(a1)		;Nodename

	add.l	#HardInt1-Hardint0,a0	;nächste Routine
	add.w	#22,a1			;IS_SIZE
	dbf	d0,.initInts1
	
	moveq	#4-1,d0
	lea	INT_Loop0(pc),a0
	lea	INT_Name1(pc),a2
.initInts2
	move.l	a0,18(a1)		;IS_Code
	move.w	#$0220,8(a1)		;type+Pri
	move.l	a2,10(a1)		;Nodename

	add.l	#Int_loop1-Int_loop0,a0	;nächste Routine
	add.w	#22,a1			;IS_SIZE
	dbf	d0,.initInts2

	move.l	4,a6
	lea	(a3),a1
	moveq	#7,d0
	jsr	-162(a6)			;Setintvektor
	move.l	d0,Oldint0

	lea	22(a3),a1
	moveq	#8,d0
	jsr	-162(a6)			;Setintvektor
	move.l	d0,Oldint1
	
	lea	44(a3),a1
	moveq	#9,d0
	jsr	-162(a6)			;Setintvektor
	move.l	d0,Oldint2

	lea	66(a3),a1
	moveq	#10,d0
	jsr	-162(a6)			;Setintvektor
	move.l	d0,Oldint3

	lea	MyUPSStruct,a1
	move.w	#UPSB_Adr!UPSB_LEN!UPSB_Per!UPSB_Vol!UPSB_DMACON,ups_flags(a1)
	clr.w	UPS_DmaCon(a1)
	clr.w	UPS_Enabled(a1)

	movem.l	(sp)+,d0-a6

	move.w	#$8780,$dff09a			;Interrupt Enable Hardwarehack

	bsr	StartDMA
	moveq	#0,d0
	rts
.err
	moveq	#EPR_CantAllocAudio,d0
	rts

FastRamStopInt
	move	$dff002,d0
	and	#15,d0
	move	d0,Fast_OLDDMA

	jsr	FreeAudio

	move.l	Oldint0(pc),d0
	beq.s	.empty

	move.w	#$780,$dff09a
	move.w	#$f,$dff096			;DMA Stoppen

	move.l	4,a6
	move.l	Oldint0(pc),a1
	moveq	#7,d0
	jsr	-162(a6)			;Setintvektor

	move.l	Oldint1(pc),a1
	moveq	#8,d0
	jsr	-162(a6)			;Setintvektor
	
	move.l	Oldint2(pc),a1
	moveq	#9,d0
	jsr	-162(a6)			;Setintvektor

	move.l	Oldint3(pc),a1
	moveq	#10,d0
	jmp	-162(a6)			;Setintvektor

	move.w	#$780,$dff09a

	lea	Oldint0(pc),a1
	clr.l	(a1)+
	clr.l	(a1)+
	clr.l	(a1)+
	clr.l	(a1)+
.empty
	rts
;============ Puffer löschen und DMA starten =============================
StartDMA
	lea	Buffer0a,a0
	move.w	#[ENDBUFFER-Buffer0a]/2-1,d0
.clr
	clr.w	(A0)+
	dbf	d0,.clr

	move.w	#$f,$dff096		;DMA Stop

					;Anfangsadressen setzen
	lea	$dff0a0,a5
	move.w	#SamLEN,d0
	lea	channelstruct0+4(pc),a1	;auf Offset für Pufferadr

	lea	Buffer0a,a0
	move.l	a0,(a5)
	move.w	d0,4(A5)
	clr.l	(a1)
	move.w	#$78,6(a5)

	lea	$10(a5),a5	
	lea	22(a1),a1
	lea	Buffer1a,a0
	move.l	a0,(a5)
	move.w	d0,4(A5)
	clr.l	(a1)
	move.w	#$78,6(a5)

	lea	$10(a5),a5	
	lea	22(a1),a1
	lea	Buffer2a,a0
	move.l	a0,(a5)
	move.w	d0,4(A5)
	clr.l	(a1)
	move.w	#$78,6(a5)

	lea	$10(a5),a5	
	lea	22(a1),a1
	lea	Buffer3a,a0
	move.l	a0,(a5)
	move.w	d0,4(A5)
	clr.l	(a1)
	move.w	#$78,6(a5)

	bsr	CH_DMAWait		;warten bis DMA wirklich gestoppt

	move	Fast_OLDDMA(pc),d0
	or	#$8000,d0
	move	d0,$dff096

;	move.w	#$800f,$dff096		;DMA Start


CH_DMAWait
	movem.w	d0/d1,-(SP)
	moveq	#16,d0
.wart2
	move.b	$dff006,d1
.wart
	cmp.b	$dff006,d1
	beq	.wart
	dbf	d0,.wart2
	movem.w	(sp)+,d0/d1
	rts

Fast_DMA:		;alle Register sind bereits gesichert !
	move.l	Oldint0(pc),d2		;läuft Fastramplayer ??
	beq.w	.end			;nö, raus...

	tst.w	d0
	bpl.w	.set2

	lea	$dff000,a0

	btst	#0,d1
	beq.s	.no0

	moveq	#0,d0
	bsr	IntSetAdrs
	bsr	Int_Call0
	clr.w	$dff0aa
.no0
	btst	#1,d1
	beq.s	.no1

	moveq	#1*22,d0
	bsr	IntSetAdrs
	bsr	Int_Call1
	clr.w	$dff0ba
.no1
	btst	#2,d1
	beq.s	.no2

	moveq	#2*22,d0
	bsr	IntSetAdrs
	bsr	Int_Call2
	clr.w	$dff0ca
.no2
	btst	#3,d1
	beq.s	.no3

	moveq	#3*22,d0
	bsr	IntSetAdrs
	bsr	Int_Call3
	clr.w	$dff0da
.no3
	jsr	DTWaitAudioDma

	move.w	d1,d2
	lsl	#7,d2			;Interruptbits
	move.w	d2,$9c(a0)		;Kein Interrupt Request
	
	or.w	#$8000,d1
	move.w	d1,$96(a0)

	lea	MyUPSStruct,a1
	move	UPS_DmaCon(a1),d0
	or.b	d1,d0			;$8000 nicht mit reinnehmen
	move	d0,UPS_DmaCon(a1)

	or.w	#$8000,d2
	move.w	d2,$9a(a0)		;Ints erlauben
	
	jsr	DTWaitAudioDMA
.end
	rts
.set2
	and.w	#15,d1
	move	d1,d2
	lsl	#7,d1			;keine Ints jetzt
	move.w	d1,$dff09a		;Interrupt Enable
	move.w	d1,$dff09c		;Interrupt Request
	
	move.w	d2,$dff096

	lea	MyUPSStruct,a1
	move	UPS_DmaCon(a1),d0
	not	d2
	and	d2,d0
	move	d0,UPS_DmaCon(a1)
	rts
Fast_Per
	lea	MyUPSStruct,a1
	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	move	d2,d1
	lsl.w	#4,d2
	add.w	d2,a0
	mulu	#UPS_Modulo,d1
	add.l	d1,a1
	lsr	#2,d0
	beq.s	.skip
	move.w	d0,6(a0)
	move	d0,UPS_Voice1Per(a1)
.skip	rts
Fast_Vol
	lea	MyUPSStruct,a1
	lea	BSSMerkPuffer,a5
	move.l	EPG_AudioStruct(A5),d2
	beq.s	.skip
	move.l	d2,a0

	moveq	#$3f,d2			;max. 64
	and.w	d1,d2
	mulu	#AS_Sizeof,d2
	lea	(A0,d2.w),a0		;Audstruct 0-n

	move.w	AS_LeftVolume(A0),d0

	lea	$dff0a0,a0
	moveq	#3,d2
	and.w	d1,d2
	move	d2,d1
	mulu	#UPS_Modulo,d1
	add.l	d1,a1
	move	d0,UPS_Voice1Vol(a1)	;Lautstärkekorrektur nicht einrechnen

	add.w	d2,d2			;mal 2
	move.w	d2,d3
	add.w	#EPG_Voice1Vol,d3
	lsl.w	#3,d2			;mal 16/2
	mulu	(a5,d3.w),d0
	lsr.w	#6,d0

	add.w	d2,a0
	move.w	d0,8(a0)
.skip
	rts
;=========================================================================

IntSetAdrs:
	movem.l	d1-a6,-(sp)
	lea	channelstruct0(pc),a0
	add.l	d0,a0		;genau wie Interrupt auch 22 Bytes lang

	;erstmal nächsten Puffer schreiben, damit das Thema erledigt ist
	move.l	(a0),a1		;Dff0a0/b0/c0/0d0

	move.l	4(a0),d1
	eor.l	#SAMLEN*2,d1	;128 Worte
	move.l	d1,4(A0)

	move.l	12(a0),a2	;Puffer-Basisadresse
	add.l	d1,a2
	move.l	a2,(a1)		;dff0a0/b0/c0/0d0

				;A2 ist nun der Puffer, der gefüllt werden
				;soll
	move.w	#SAMLEN,4(a1)	;Länge immer 128 Worte

;	move.l	12(a0),a2
;	move.w	#SamLen-1,d1
;.c
;	clr.l	(a2)+
;	dbf	d1,.c

	movem.l	(sp)+,d1-a6
	rts

CauseInt:
	movem.l	d1-a6,-(sp)

	lea	channelstruct0(pc),a0
	add.l	d0,a0		;genau wie Interrupt auch 22 Bytes lang

	;erstmal nächsten Puffer schreiben, damit das Thema erledigt ist
	move.l	(a0),a1		;Dff0a0/b0/c0/0d0

	move.l	4(a0),d1
	eor.l	#SAMLEN*2,d1	;128 Worte
	move.l	d1,4(A0)

	move.l	12(a0),a2	;Puffer-Basisadresse
	add.l	d1,a2
	move.l	a2,(a1)		;dff0a0/b0/c0/0d0

				;A2 ist nun der Puffer, der gefüllt werden
				;soll
	move.w	#SAMLEN,4(a1)	;Länge immer 128 Worte

	lea	AudInts+22*4,a1		;Audio Interrupt Struktur Nr. 5 ist
					;der erste Softint
	add.l	d0,a1
	move.l	4.w,a6
	jsr	_LVOCause(a6)
	movem.l	(sp)+,d1-a6
	rts

;------------------------------------------------------------------------------
;---------Vorsicht! Die  HardInts/Int_Loops werden relativ angesprochen -------
;---------und müssen jeweils exakt gleich lang sein !!!                 -------
;------------------------------------------------------------------------------
HardInt0:
	move.w	#1<<7,$dff09c
	moveq	#0*22,d0		;Nummer dr Struktur * IS_Size
	bra.s	Causeint
HardInt1:
	move.w	#1<<8,$dff09c
	moveq	#1*22,d0
	bra.s	Causeint
HardInt2:
	move.w	#1<<9,$dff09c
	moveq	#2*22,d0
	bra.s	Causeint
HardInt3:
	move.w	#1<<10,$dff09c
	moveq	#3*22,d0
	bra.s	Causeint
INT_Loop0:
Int_Call0:
	movem.l d1/a0/a3,-(sp)
	lea	channelstruct0(pc),a0
	tst.l	8(a0)			;Kanal an ?
	beq.s	.skipvoice
	move.w	BSSMerkPuffer+EPG_Voice1Vol,d1
	lea	MyUPSStruct+UPS_Modulo*0,a3
	bsr	doit2
.skipvoice
	movem.l	(sp)+,d1/a0/a3
	rts
INT_Loop1:
Int_Call1:
	movem.l d1/a0/a3,-(sp)
	lea	channelstruct1(pc),a0
	tst.l	8(a0)			;Kanal an ?
	beq.s	.skipvoice
	move.w	BSSMerkPuffer+EPG_Voice2Vol,d1
	lea	MyUPSStruct+UPS_Modulo*1,a3
	bsr	doit
.skipvoice
	movem.l	(sp)+,d1/a0/a3
	rts
INT_Loop2:
Int_Call2:
	movem.l d1/a0/a3,-(sp)
	lea	channelstruct2(pc),a0
	tst.l	8(a0)			;Kanal an ?
	beq.s	.skipvoice
	move.w	BSSMerkPuffer+EPG_Voice3Vol,d1
	lea	MyUPSStruct+UPS_Modulo*2,a3
	bsr	doit
.skipvoice
	movem.l	(sp)+,d1/a0/a3
	rts
INT_Loop3:
Int_Call3:
	movem.l d1/a0/a3,-(sp)
	lea	channelstruct3(pc),a0
	tst.l	8(a0)			;Kanal an ?
	beq.s	.skipvoice
	lea	MyUPSStruct+UPS_Modulo*3,a3
	move.w	BSSMerkPuffer+EPG_Voice4Vol,d1
	bsr	doit
.skipvoice
	movem.l	(sp)+,d1/a0/a3
	rts
;-------------------------------------------------------------------------------
DoIt:
;	rts
doit2:
	movem.l	d0-a6,-(Sp)
	move.l	(a0),a1		;Dff0a0/b0/c0/d0

	move.l	4(a0),d0
	move.l	12(a0),a2	;Puffer-Basisadresse
	add.l	d0,a2
				;A2 ist nun der Puffer, der gefüllt werden soll

	;nun folgt die Hauptroutine: das Kopieren

	move.l	8(a0),a0	;Audiostruktur
	move.b	AS_LoopFlag(a0),d0
	seq	d0
	ext.w	d0
	move	d0,UPS_Voice1Repeat(a3)

	move.w	AS_LeftVolume(a0),d0
	mulu	d0,d1
	lsr.w	#6,d1
	move.w	d1,8(A1)

	move.w	AS_Period(a0),d0
	lsr	#2,d0		;!!!
	beq.s	.skip
	move.w	d0,6(A1)	;Periode sichern
.skip
	tst.w	AS_DMABit(a0)	;Kanal eingeschaltet ?
	beq	.clearbuf	;nein, Puffer löschen

	tst.b	AS_noloop(a0)	;Sample zu Ende gespielt ?
	bne	.clearbuf

	tst.l	AS_Currentadr(A0)	;überhaupt Sample da ?
	beq	.clearbuf_special	;nein, Puffer löschen, aber wie
					;normal behandeln

	move.l	AS_Currentpos(a0),d1	;Aktuelle Adresse
	add.l	AS_CurrentAdr(a0),d1
	bra.s	.isset			;was neues ?
.newcurr
	move.l	AS_Currentadr(a0),d1	;yep
.isset
	move.l	d1,a1
	move.l	a1,UPS_Voice1Adr(a3)	;Current Position

	move.l	AS_Samplesize(a0),d0
	beq	.clearbuf

	st	AS_AmplifierPrivate3(a0);Counter für Lösch = -1 (+2 = >0)

	sub.l	AS_Currentadr(a0),d1	;gespielte Länge in Bytes
	blt.s	.newcurr
	
	sub.l	d1,d0		;Samplelänge - gespielte Länge
	blt	.doless

	cmp.l	#SAMLEN*2,d0		;weniger als 128 Worte noch ?
	blo.s	.doless

	lsr	#1,d0			;in Bytes umrechnen
	move.w	d0,UPS_Voice1Len(a3)
	

	if	samlen=128

	moveq	#44,d0

	rept	5			;220 Bytes
	movem.l	(a1)+,d1-d7/a3-a6
	movem.l	d1-d7/a3-a6,(a2)
	add.l	d0,a2
	endr
					;+36 Bytes = 256 Bytes
	movem.l	(a1)+,d1-d7/a3-a4
	movem.l	d1-d7/a3-a4,(a2)

	else
	move.w	#SAMLEN-1,d1
.copy
	move.w	(a1)+,(a2)+
	dbf	d1,.copy
	endc

	sub.l	AS_CurrentAdr(a0),a1
	move.l	a1,AS_Currentpos(a0)
	movem.l	(sp)+,d0-a6
	rts
.doless
	move	d0,d1
	lsr	#1,d1
	move	d1,UPS_Voice1Len(a3)

	move.w	#SAMLEN-1,d1	;egal was kommt, 128 Worte müssen kopiert
				;werden
.loop
	tst.l	d0
	bgt.s	.nonew

	tst.b	AS_LoopFlag(a0)
	beq.s	.noloop
	move.l	AS_RepeatAdr(A0),a1
	move.l	a1,AS_Currentadr(A0)

	move.l	AS_RepeatSize(A0),d0
	move.l	d0,AS_Samplesize(A0)
.loop_normal				;<<--- hier von Spezialroutine zurück
	tst.l	AS_Int(a0)		;"Interrupt" bei neuem Sample ?
	beq.s	.noInt
	movem.l	d0-a6,-(sp)		;nur zur Sicherheit
	move.l	AS_Int(A0),a1
	move.l	4.w,a6
	jsr	_LVOCause(a6)
	movem.l	(sp)+,d0-a6		;man weiss ja nie...
.noINT
	tst.l	d0
.noloop
	seq	AS_noloop(a0)
	beq.w	.clearbuf2			;Replen=0 -> nur löschen
.nonew
	move.w	(a1)+,(a2)+
	subq.l	#2,d0
	dbf	d1,.loop

	tst.l	d0
	bgt.s	.nonew2

	move.l	AS_RepeatAdr(A0),a1
	move.l	a1,AS_Currentadr(A0)
	move.l	AS_RepeatSize(A0),d0
	move.l	d0,AS_Samplesize(A0)

	tst.l	AS_Int(a0)		;"Interrupt" bei neuem Sample ?
	beq.s	.noInt_2
	movem.l	d0-a6,-(sp)		;nur zur Sicherheit
	move.l	AS_Int(A0),a1
	move.l	4.w,a6
	jsr	_LVOCause(a6)
	movem.l	(sp)+,d0-a6		;man weiss ja nie...
.noINT_2

.nonew2
	sub.l	AS_CurrentAdr(a0),a1
	move.l	a1,AS_Currentpos(a0)

	movem.l	(sp)+,d0-a6
	rts
	
	;------- wenn DMABit nicht gesetzt, Puffer löschen und fertig ------
.clearbuf
	tst.b	AS_AmplifierPrivate3(a0)
	bgt.s	.skipLOE

	addq.b	#1,AS_AmplifierPrivate3(a0)

	if	samlen=128
	moveq	#0,d0
	moveq	#0,d1
	moveq	#0,d2
	moveq	#0,d3
	add.w	#256,a2

	movem.l	d0-d3,-(a2)
	movem.l	d0-d3,-(a2)
	movem.l	(a2),d4-d7

	rept	7		;weil schon 32 Bytes fertig, s.o.
	movem.l	d0-d7,-(a2)
	endr
	movem.l	(sp)+,d0-a6
	rts

	endc
	move.w	#Samlen-1,d1
.clearbuf2
	clr.w	(A2)+
	dbf	d1,.clearbuf2
.skipLOE
	movem.l	(sp)+,d0-a6
	rts
.clearbuf_special
	move.l	AS_Samplesize(a0),d0
	beq	.clearbuf

	st	AS_AmplifierPrivate3(a0);Counter für Lösch = -1 (+2 = >0)

	move.l	AS_Currentpos(a0),d1	;Aktuelle Adresse
	add.l	AS_Currentadr(a0),d1
;					;was neues ?
;	move.l	AS_Currentadr(a0),d1	;yep
;.isset_2
	move.l	d1,a1

	sub.l	AS_Currentadr(a0),d1	;gespielte Länge in Bytes
	
	sub.l	d1,d0		;Samplelänge - gespielte Länge

	move.w	#SAMLEN-1,d1	;egal was kommt, 128 Worte müssen kopiert
				;werden
.loop_spe
	tst.l	d0
	bgt.s	.nonew_spe

	tst.b	AS_LoopFlag(a0)
	beq.s	.noloop_spe

	move.l	AS_RepeatAdr(A0),a1
	move.l	a1,AS_Currentadr(A0)
	move.l	a1,d2
	bne	.loop_normal		;<<--- hier in Normalroutine zurück

	move.l	AS_RepeatSize(A0),d0
	move.l	d0,AS_Samplesize(A0)

	tst.l	AS_Int(a0)		;"Interrupt" bei neuem Sample ?
	beq.s	.noInt_3
	movem.l	d0-a6,-(sp)		;nur zur Sicherheit
	move.l	AS_Int(A0),a1
	move.l	4.w,a6
	jsr	_LVOCause(a6)
	movem.l	(sp)+,d0-a6		;man weiss ja nie...
.noINT_3
	tst.l	d0
.noloop_spe
	seq	AS_noloop(a0)
	beq.s	.clearbuf2			;Replen=0 -> nur löschen
.nonew_spe
	clr.w	(a2)+
;	move.w	(a1)+,(A2)+
;	addq.l	#2,a1
	subq.l	#2,d0
	dbf	d1,.loop_spe

	tst.l	d0
	bgt.s	.nonew2_spe

	move.l	AS_RepeatAdr(A0),a1
	move.l	a1,AS_Currentadr(A0)
	move.l	AS_RepeatSize(A0),d0
	move.l	d0,AS_Samplesize(A0)

	tst.l	AS_Int(a0)		;"Interrupt" bei neuem Sample ?
	beq.s	.noInt_4
	movem.l	d0-a6,-(sp)		;nur zur Sicherheit
	move.l	AS_Int(A0),a1
	move.l	4.w,a6
	jsr	_LVOCause(a6)
	movem.l	(sp)+,d0-a6		;man weiss ja nie...
.noINT_4

.nonew2_spe
	sub.l	AS_CurrentAdr(a0),a1
	move.l	a1,AS_Currentpos(A0)
	movem.l	(sp)+,d0-a6
	rts

;----------------- hier nun die Daten für den FastRamPlayer ----------------
ChannelStruct0:
	dc.l	$dff0a0			;Basisadresse
	dc.l	0			;zuletzt geschriebener Puffer
	dc.l	0
	dc.l	Buffer0a
	dc.l	0			;6 Bytes reine Verschwendung
	dc.w	0
ChannelStruct1:
	dc.l	$dff0b0			;Basisadresse
	dc.l	0			;zuletzt geschriebener Puffer
	dc.l	0
	dc.l	Buffer1a
	dc.l	0
	dc.w	0
ChannelStruct2:
	dc.l	$dff0c0			;Basisadresse
	dc.l	0			;zuletzt geschriebener Puffer
	dc.l	0
	dc.l	Buffer2a
	dc.l	0
	dc.w	0
ChannelStruct3:
	dc.l	$dff0d0			;Basisadresse
	dc.l	0			;zuletzt geschriebener Puffer
	dc.l	0
	dc.l	Buffer3a

OLDINT0:	dc.l	0	;diese 4 zusammen lassen !
OLDINT1:	dc.l	0
OLDINT2:	dc.l	0
OLDINT3:	dc.l	0

INT_Name1:	dc.b	`EP_FastRam-Amplifier`,0
	even
;;

