
; Listing14-7a2:	** MODULATION DER AMPLITUDE EINER HARMONISCHEN IN STEREO**

	SECTION	MODULATION,CODE

Start:
	lea	ModVol1,a0
	moveq	#0,d0
	moveq	#65-1,d7
.Lp1:	
	move.w	d0,(a0)+
	addq.w	#1,d0
	dbra	d7,.Lp1
	subq.w	#1,d0
.Lp2:	
	move.w	d0,(a0)+
	dbra	d0,.Lp2

	lea	ModVol2,a0
	moveq	#65,d0
	moveq	#65-1,d7
.Lp3:	
	subq.w	#1,d0
	move.w	d0,(a0)+
	dbra	d7,.Lp3
	moveq	#65-1,d7
.Lp4:	
	move.w	d0,(a0)+
	addq.w	#1,d0
	dbra	d7,.Lp4

_LVODisable	equ	-120
_LVOEnable	equ	-126

	move.l	4.w,a6
	jsr	_LVODisable(a6)

	bset	#1,$bfe001			; schaltet den Tiefpassfilter aus

	lea	$dff000,a6
	move.w	$2(a6),d7			; speichern DMA von OS
	move.w	$10(a6),d6			; speichern ADKCON von OS

CLOCK equ 3546895
	
	move.l	#Harmonic,$b0(a6)							; AUD1LCH
	move.w	#16/2,$b4(a6)								; AUD1LEN (in word)
	move.w	#CLOCK/(16*440),$b6(a6)						; AUD1PER - LA2
	move.l	#Harmonic,$d0(a6)							; AUD3LCH	
	move.w	#16/2,$d4(a6)								; AUD3LEN (in word)
	move.w	#CLOCK/(16*440),$d6(a6)						; AUD3PER - LA2

	move.l	#ModVol1,$a0(a6)							; AUD0LCH
	move.w	#(ModVol1End-ModVol1)/2,$a4(a6)				; AUD0LEN (in word)
	move.w	#CLOCK/((ModVol1End-ModVol1)/2),$a6(a6)		; AUD0PER	
	move.l	#ModVol2,$c0(a6)							; AUD2LCH
	move.w	#(ModVol2End-ModVol2)/2,$c4(a6)				; AUD2LEN (in word)
	move.w	#CLOCK/((ModVol2End-ModVol2)/2),$c6(a6)		; AUD2PER

	move.w	#$8005,$9e(a6)		; einschalten USE0V1 und USE2V3
	move.w	#$820f,$96(a6)		; einschalten AUD0-AUD3 in DMACONW

Mouse:	
	btst	#6,$bfe001			; linke Maustaste gedrückt?
	bne.s	Mouse

	move.w	#$0005,$9e(a6)		; ausschalten USE0V1 und USE2V3
	or.w	#$8000,d6			; Bit 15 schaltet ein (SET/CLR)
	move.w	d6,$9e(a6)			; rücksetzen ADKCON von OS
	move.w	#$000f,$96(a6)		; ausschalten AUD0-AUD3
	or.w	#$8000,d7			; Bit 15 schaltet ein (SET/CLR)
	move.w	d7,$96(a6)			; rücksetzen DMA von OS
	move.l	4.w,a6
	jsr	_LVOEnable(a6)
	rts

	SECTION	SAMPLE,DATA_C	; Wird es von der DMA gelesen, muss es sich im CHIP befinden

Harmonic:	; Harmonische von 16 Werten, die mit dem IC des Trash'm-One erzeugt wurden
	dc.b	$19,$46,$69,$7c,$7d,$6a,$47,$1a,$e8,$bb,$97,$84,$83,$95,$b8,$e5
ModVol1:
	blk.w	65*2
ModVol1End:
ModVol2:
	blk.w	65*2
ModVol2End:
	end


Diesmal haben wir 2 "gestaffelte" Tabellen erstellt: die erste, gelesen von	
Kanal 0, moduliert die Lautstärke von Kanal 1 von 0 bis 64 und von 64 bis 0.
Die zweite, gelesen von Kanal 2 moduliert auch die Amplitude von Kanal 3 von
64 bis 0 und von 0 bis 64.
Dies verursacht einen offensichtlichen "Verschiebungsseffekt" der Tonausgabe
in einem STEREO-System.

Hier erfolgt das Lesen der Tabellen mit der Frequenz von "halben" Hz, da
die Hälfte der Tabelle mit 1 Hz gelesen wird.

N.B.:	Wenn Sie ein MONO-System haben, sollten Sie eine fortlaufende Note
	ohne Modulation hören hinsichtlich der Abnahme des Volumens eines Falles
	der andere steigt und kompensiert seine Leistung.
                                                                                                                                                                                                                 AUD3
	move.l	$70(a0),oldlv4		; speichern des Eigenvektor von Level 4
	move.l	#lv4irq,$70(a0)		; neuen Eigenvektor setzen
	move.w	d2,$a8(a6)			; einstellen AUD0VOL
	move.w	d2,$b8(a6)			; einstellen AUD1VOL
	move.w	d2,$c8(a6)			; einstellen AUD2VOL
	move.w	d2,$d8(a6)			; einstellen AUD3VOL
	move.l	#CLOCK,d2
	divu.w	d1,d2				; d2.w=clock/freq = Periode
	move.w	d2,$a6(a6)			; einstellen AUD0PER
	move.w	d2,$b6(a6)			; einstellen AUD1PER
	move.w	d2,$c6(a6)			; einstellen AUD2PER
	move.w	d2,$d6(a6)			; einstellen AUD3PER
	move.w	$2(a6),olddma		; speichern DMACON von OS
	move.w	#$c400,$9a(a6)		; AUD3 IRQ einschalten - nur den...
	move.w	#$8400,$9c(a6)		; den Start des IRQ erzwingen...
	movem.l	(sp)+,d0-d2/a0-a1/a5-a6
.Bye:	rts
;--------------------------------------
GetVBR:
	dc.l	$4e7a8801			; movec	vbr,a0	; Basis der Ausnahmevektoren
	rte
;--------------------------------------
PlayLongSample_restore:
	movem.l	d0-d2/a0-a1/a5-a6,-(sp)
	sub.l	a0,a0
	move.l	4.w,a6
	btst	#afb_68010,attnflags+1(a6)
	beq.s	.no010
	lea	getvbr(pc),a5
	jsr	_LVOSupervisor(a6)
.No010:	lea	$dff000,a6
	move.w	#$0780,$9c(a6)		; lösche Anfragen von allen Kanälen
	move.w	#$0400,$9a(a6)		; maskiere INT AUD3
	move.l	oldlv4(pc),$70(a0)	; zurücksetzen Eigenvektor 4 von OS
	move.w	#$000f,$96(a6)		; ausschalten alle DMA audio
	move.w	oldint(pc),d0
	or.w	#$8000,d0			; setze SET/CLR welches in INTENAR 0 ist
	move.w	d0,$9a(a6)			; zurücksetzen INTENA von OS
	move.w	olddma(pc),d0
	or.w	#$8000,d0			; setze SET/CLR welches in DMACONR 0 ist
	move.w	d0,$96(a6)			; zurücksetzen DMACON von OS
	move.l	4.w,a6
	movem.l	plsregs+4*4(pc),d0/a1
	jsr	_LVOFreeMem(a6)			; RAM der ERSTEN Bank freigeben
	movem.l	plsregs+4*6(pc),d0/a1
	jsr	_LVOFreeMem(a6)			; RAM der ZWEITEN Bank freigeben
	movem.l	(sp)+,d0-d2/a0-a1/a5-a6
	rts
;--------------------------------------
PlayLongSample_IRQ:
	movem.l	d0-d2/a0-a1/a5-a6,-(sp)
	lea	$dff000,a6
	lea	plsregs(pc),a5
	movem.l	4*2(a5),d0/a0		; d0.l=Länge fehlt/a0=Basis sample
	movem.l	4*4(a5),d1/a1		; d1.l=Länge Bank/a1=Basis Bank
	move.l	a1,$a0(a6)			; einstellen AUDLC
	move.l	a1,$b0(a6)
	move.l	a1,$c0(a6)
	move.l	a1,$d0(a6)
	cmp.l	d0,d1				; Bank <= Länge fehlt?
	bls.s	.longc
	move.l	d0,d1				; wenn nein: Kopieren und spielen fehlende Länge
.LongC:	move.l	d1,d2
	lsr.l	#1,d1				; dividieren durch 2 für AUDLEN in word
	move.w	d1,$a4(a6)			; einstellen AUDLEN
	move.w	d1,$b4(a6)
	move.w	d1,$c4(a6)
	move.w	d1,$d4(a6)
	lsr.l	#1,d1				; dividieren durch 2 um das Langwort zu kopieren
	subq.w	#1,d1
	move.w	#$007,$180(a6)		; blau, wenn er anfängt zu kopieren
.CopyLp:move.l	(a0)+,(a1)+
	dbra	d1,.copylp
	move.w	#$000,$180(a6)		; schwarz wenn es endet
	move.l	4*3(a5),a0
	add.l	d2,a0				; a0 zeigt auf den nächsten Block
	sub.l	d2,d0				; Länge WENIGER Länge gespielt
	bhi.s	.noloop				; d0 => 1 ? (MINDESTENS 1 Byte fehlt noch)
	movem.l	(a5),d0/a0			; wenn nein: wiederherstellen Originalregister
.NoLoop:movem.l	d0/a0,4*2(a5)	; Speichern Sie jedoch d0 und a0 in Kopien
	movem.l	4*4(a5),d0-d1/a0-a1	; Zeiger und Länge tauschen
	exg	d0,a0					; Es wird nur ein Puffer verwendet
	exg	d1,a1					;
	movem.l	d0-d1/a0-a1,4*4(a5)
	move.w	#$820f,$96(a6)
	movem.l	(sp)+,d0-d2/a0-a1/a5-a6
	rts
;--------------------------------------
OldINT:	dc.w	0
OldDMA:	dc.w	0
OldLv4:	dc.l	0
PLSRegs:dc.l	0,0				; Länge,Zeiger des sample - fest
	dc.l	0,0					; Länge,Zeiger des sample - variabel
	dc.l	0,0					; Länge,Zeiger Bank 1 - fest
	dc.l	0,0					; Länge,Zeiger Bank 2 - fest


***************************************
*****  Level 4 Interrupt Handler  *****
***************************************

	cnop	0,8
Lv4IRQ:	
	btst	#10-8,$dff01e		; IRQ AUD3 ?
	beq.s	.exit
	move.w	#$0780,$dff09c
	bsr.w	playlongsample_irq
.Exit:	rte


	SECTION	Sample,DATA_F

	; MammaGamma by Alan Parsons Project (©1981)
Sample:
	;incbin	"/Sources/Mammagamma.17897"		; Datei fehlt
	incbin	"/Sources/carrasco.21056"
SampleEnd:

	end


Diesmal hat sich nicht viel geändert: jetzt sind die Bänke lang und in
unabhängiger Position, nicht mehr benachbart oder gleich lang.
Die Routine hat keine besonderen Änderungen erfahren: ordnet die beiden
Puffer separat zu und im _IRQ tauscht es auch nur ihre Längen,
zusätzlich zu den Zeigern.

N.B.:	Auch hierfür gelten die Hinweise aus dem vorigen Beispiel.

                                                                                                                                                                                                                                                                                                                                                        befindet, im größten Teil des AllolocMem finden kann (MEMF_ANY).

Die Bedienung der Routine ist äußerst einfach: gegeben ein sample von
unbestimmte Länge in JEDEM RAM-Block (Chip oder Fast) wird einem RAM-Chip
Block (MEMF_CHIP) von 256 kB zugewiesen (allocated) - wenn möglich - oder nicht.
Dieser ist in zwei Puffer mit jeweils 128 kB oder weniger aufgeteilt, in die
kopiert werden soll mit einer CPU-Schleife die Sampledaten von 128 kB - 
oder weniger um von der DMA lesen zu können.
Der Grund für die Verwendung der 2 Puffer ist sehr einfach: Während das
Audio einen abspielt, füllt die CPU eine andere mit den Daten, die
dann gelesen werden.

N.B.:	In der Tat sind einige CPUs wie der 68040 oder 68030 so schnell, das
	sie	in der Lage sind, den gesamten Block von 128 kB - oder weniger -
	in etwas mehr eines Rasters zu kopieren. Selbst wenn Sie nicht
	zwei Puffer über alles verwenden. Wenn der Puffer sehr klein ist, ist es
	ehrlich gesagt unmöglich zu hören, das die DMA dieselben Daten zweimal in
	demselben Puffer abspielt, den er durchläuft, weil die CPU sie bereits
	kopiert hat, als die ersten Worte noch gelesen werden.

	Die Gründe, warum zwei separate Puffer verwendet wurden, ist
	das Folgende: Zunächst einmal für die Eleganz der Codierung: IN THEORY
	werden die beiden Puffer benötigt. Auch auf langsamen CPUs wie dem 16-Bit 68000
	beim Zugriff auf den RAM des Amiga 500 ist die Kopie nicht so augenblicklich.
	Schließlich hätte die Routine einen Fehler: den letzten Block des
	sample wird zweimal gespielt vor dem Looping (zum Training,
	versuche zu verstehen warum und repariere das Rad ...).

	Die Mindestlänge für die Puffer beträgt jeweils 4 Byte. Versuchen
	Sie insgesamt nur 8 Bytes zuzuweisen und ein Sample mit der Frequenz abzuspielen
	Maximaler Messwert (ca. 28000 Hz, Periode = 123): Ja, der 040
	- es ist nicht bekannt wie - er schafft es sogar mit der DMA mitzuhalten
	2 Puffer eines Langwortes !!! Sehen heißt glauben...
	
P.S.:	Auf dem _IRQ finden Sie 2 kommentierte Zeilen: Sie werden verwendet,
	um die Hintergrundfarbe immer dann zu ändern, wenn der Interrupt 
	aufgerufen wird. Die CPU startet mit dem Kopieren der Daten aus dem
	Quell-RAM in die Puffer: 
	Kommentar entfernen um zu sehen, was der Prozessor währenddessen vorhat
	DMA scheint Datenänderungen nicht zu bemerken ...   

;----

;---


;---


;-----
