
; B2-Midi-Abspielroutinen
;      (c) 8/1991 by
;     Jörg Schließer
;    Rotenwaldstr. 20
;   D-7000 Stuttgart 1



; Amiga-Os-Library-Offsets

	; Exec-Library
AddIntServer	=	-168
RemIntServer	=	-174
AllocMem	=	-198
FreeMem		=	-210
FindTask	=	-294
AddPort		=	-354
RemPort		=	-360
CloseLibrary	=	-414
OpenDev		=	-444
CloseDev	=	-450
DoIO		=	-456
SendIO		=	-462
OpenLibrary	=	-552

	; Dos-Library
Open		=	-30
Close		=	-36
Read		=	-42
Lock		=	-84
UnLock		=	-90
Examine		=	-102
CurrentDir	=	-126



; Hardware-Register

dmacon		=	$dff096	; (Audio)DMA
cialed		=	$bfe001	; Low-Pass-Filter on/off
audxadr		=	$DFF0A0	; Basisadresse der Soundregister
audxlch		=	$0	; Offset für Adress der Sampledaten
audxlen		=	$4	; Offset für Länge des Samples
audxper		=	$6	; Offset für Sampleperiod
audxvol		=	$8	; Offset für Volume
aud0vol		=	$DFF0a8	; Volume-Register
aud1vol		=	$DFF0b8 ; Stimme 1 - 4
aud2vol		=	$DFF0c8
aud3vol		=	$DFF0d8



; Offsets innerhalb eines B2-Midi Instrumenten-Structs

Name		=	0
ILänge		=	40
Memory		=	44
BODY		=	48
VHDR		=	52
OneLänge	=	56
RepLänge	=	60
HiCycle		=	64
Rate		=	68
Oktaven		=	72
Kennung		=	76



; Offsets Innerhalb des B2IS-Structs

presets		=	2560



; Offsets Innerhalb eines B2-Midi Songbase-Structs

achannels	=	12
midichannels	=	16
onvels		=	32
offvels		=	44
filterstatus	=	61



; Offsets innerhalb eines B2-Midi Play-Structs

playmem		=	0
playpos		=	4
playnote	=	8
playcount	=	12
playtriocount	=	14
playduocount	=	15
playtriorest	=	16
playduorest	=	18
playfermate	=	20
playbogen	=	21
playoffcount	=	22
playinstrument	=	24
playvolume	=	25
playvolmod	=	26
playfreqmod	=	27
playvolcount	=	28
playfreqcount	=	29
playfrequenz	=	30



; Einsprungadressen zur Übergabe für Linker definieren



	xdef _freeb2score,_loadb2score,_playb2score,_stopb2score
	xdef _initb2score,_freeb2insts



	section b2routines,code



; *********************************************************************

; Routine:		FreeB2Score
; Funktion:		Speicher für Score-File und Insts freigeben
; Übergabe-Parameter:	a0,Pointer auf Scoredata
;			d0,Länge des Scores
; Rückgabe-Parameter:	keine

; Mittels Aufruf der Routine 'FreeB2Score' geben Sie den Speicher für
; ein mittels 'LoadB2Score' geladenes B2-Midi-Score- oder B2-Midi-
; Full-Inst-Score-File und für die zugehörigen Instrumente wieder frei.

_freeb2score:
	movem.l	d1-d7/a1-a6,-(sp)
	move.l	d0,d4		;length
	move.l	a0,a4		;memory
	lsr.l	#1,d0
	move.l	#"B2IS",d1	;Inst-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	nofreescore
	move.l	a0,a5
	moveq	#31,d5		;Speicher für im Inst-Struct
	move.l	4,a6
freeinstsloop:
	move.l	40(a5),d0	;angegebene Instrumente freigeben
	beq	nofreethisinst
	move.l	44(a5),a1
	jsr	FreeMem(a6)
nofreethisinst:
	adda.l	#80,a5
	dbra	d5,freeinstsloop
	move.l	d4,d0
	move.l	a4,a1
	jsr	FreeMem(a6)	;Score-Mem freigeben
nofreescore:
	movem.l	(sp)+,d1-d7/a1-a6
	rts



; *********************************************************************

; Routine:		InitB2Score
; Funktion:		Läd für ein B2-Midi-Score die benötigten
;			Instrumente oder kopiert die Instrumente
;			eines Full-I-Scores ins Chip-Ram
; Übergabe-Parameter:	a0,Pointer auf Scoredata
;			d0,Länge des Scores
;			d1,Directory-Lock des Inst-Verzeichnisses
; Rückgabe-Parameter:	a0,Pointer auf Score-Data oder '0' bei Error
; Rückgabe-Parameter:	d0 = '0' ... O.K.
;			d0 = '1' ... einzelne Instrumente fehlen
;			d0 = '2' ... alle Instrumente fehlen
;			d0 = '3' ... kann dos.library nicht öffnen
;			d0 = '4' ... zu wenig Speicher oder anderer Error
;			d0 = '5' ... Es war kein B2-Scorefile

; Die Routine 'InitB2Score' läd für ein bereits im Speicher stehendes 
; B2-Midi-Score-File die nötigen Instrumente und initialisiert den
; B2I(n)S(t)-Struct innerhalb des Scores.
; Wird die Routine auf ein im Speicher stehendes B2-Midi-Full-Inst-Score-
; File angewandt, werden die im Score stehenden Instrumentendaten ins
; Chip-Ram übertragen.
; Die Routine ist NUR auf Songs anzuwenden, die von einem Programm 
; selbständig geladen werden oder fest in ein Programm eingebunden sind.
; Wenn der Score mittels 'LoadB2Score' geladen wird, werden die Instrumente
; automatisch geladen und/oder initialisiert.

_initb2score:
	movem.l	d2-d7/a1-a6,-(sp)
	move.b	#3,error
	move.l	d0,scorelänge
	move.l	a0,scorestruct	;Parameter Zurücksetzen
	move.l	d1,instlock
	move.l	4,a6
	lea	dosname,a1
	moveq	#0,d0
	jsr	OpenLibrary(a6)	;open dos_lib
	move.l	d0,dosbase
	beq	dropinitb2
	move.b	#4,error
	move.l	#512,d0
	move.l	#$10003,d1
	jsr	AllocMem(a6)	;get infomem (for fileinfos)
	move.l	d0,infomem
	beq	dropinitb2
	move.b	#5,error
	clr.b	flag
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	cmp.l	#"B2SC",8(a0)	;B2-Midi-Score
	beq	itsscorefile
	move.b	#1,flag
	cmp.l	#"B2FI",8(a0)	;B2-Midi-Full-Inst-Score
	bne	dropinitb2
itsscorefile:
	lsr.l	#1,d0
	move.l	#"B2IS",d1	;Inst-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	noscorefile
	move.l	a0,inststruct
	moveq	#31,d2
dropikennfori:			;Inst-Kennungen löschen
	clr.l	76(a0)
	adda.l	#80,a0
	dbra	d2,dropikennfori
	tst.b	flag
	beq	initb2scinsts	;kein Full-Inst Score ?
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	lsr.l	#1,d0
	move.l	#"B2II",d1	;Instrumentendaten suchen
	bsr	getchunk
	cmpa.l	#0,a0		;Pointer auf B2II-Struct
	beq	dropinitb2
	clr.b	error		;möglicherweise kein Fehler mehr
	move.b	#2,flag
	moveq	#31,d7		;Clear IINX-Pointers
	lea	iinxe,a1
clriinxefi:
	clr.l	(a1)+
	dbra	d7,clriinxefi
	move.l	scorestruct,d2	;Anfangsadresse
	add.l	scorelänge,d2	;plus Länge gibt Endadr
	sub.l	a0,d2		;Minus Adr von B2II-Struct
	lsr.l	#1,d2		;ergbit Counter
	subq.l	#1,d2
	lea	iinxe,a1
initiinxadrs:			;Adressen der einzelnen Insts ermitteln
	move.l	(a0),d1
	moveq	#0,d3
	move.b	d1,d3		;mögliche Nr. von IINX
	move.b	#"X",d1
	cmp.l	#"IINX",d1	;IINX (InternInst) gefunden ?
	bne	goinitiinx
	cmp.b	#32,d3
	bge	goinitiinx
	asl.w	#2,d3		;Nummer des Insts ermitteln und
	move.l	a0,a2
	adda.l	#8,a2
	move.l	a2,(a1,d3)	;Pointer sichern
goinitiinx:
	adda.l	#2,a0
	dbra	d2,initiinxadrs
	move.l	4,a6		;Interne Insts ins Chip-Mem übertragen
	moveq	#31,d7
	lea	iinxe,a5
	move.l	inststruct,a4
initiinstsl1:
	move.l	(a5)+,a0
	cmpa.l	#0,a0
	beq	nextinitiinst
	suba.l	#4,a0
	move.l	(a0)+,d0	;Länge
	beq	nextinitiinst
	move.l	a0,a2		;Data-Pointer
	move.l	d0,40(a4)
	move.l	#$10003,d1	;Chip-Mem
	jsr	AllocMem(a6)
	move.l	d0,44(a4)	;Memory
	bne	gotmemforiinit
	clr.l	40(a4)
	clr.l	44(a4)
	move.b	#1,error	;einzelne Instrumente fehlen
	bra	nextinitiinst
gotmemforiinit:
	move.l	44(a4),a3
	move.l	40(a4),d3
	subq.l	#1,d3
initiinstsl2:
	move.b	(a2)+,(a3)+	;Sound-Data in Chip-Ram kopieren
	dbra	d3,initiinstsl2
	move.l	a4,a0
	bsr	getiffinfo	;Info über Sound-Data ermitteln
nextinitiinst:
	adda.l	#80,a4
	dbra	d7,initiinstsl1	
	bra	dropinitb2	;fertig für B2-Midi-Full-Inst-Score

initb2scinsts:			;Instrumente laden bei B2-Midi-Score
	clr.b	error		;möglicherweise kein Error mehr
	move.l	instlock,d1
	beq	noib2instlock1
	move.l	dosbase,a6
	jsr	CurrentDir(a6)	;Inst-Dir current
	move.l	d0,d7
noib2instlock1:
	moveq	#0,d2
	moveq	#0,d3
	moveq	#0,d5
	moveq	#31,d6
	moveq	#0,d4
	move.l	inststruct,a2
initalli2:
	tst.b	(a2)		;Instrument nicht nötig ?
	beq	schoniniti	
	move.l	a2,a0	
	move.l	#$10003,d0	;Mem: chip,clear
	bset	d4,d5		;benötigtes Inst markieren
	addq.b	#1,d2
	bsr	loadfile	;File laden
	move.l	d0,40(a2)	;Länge 
	beq	schoniniti
	bclr	d4,d5		;Ok... Markierung löschen
	move.l	a0,44(a2)	;Zeiger auf Speicher
	move.l	a2,a0
	bsr	getiffinfo	;Info über Sound-Data ermitteln
schoniniti:
	adda.l	#80,a2
	addq.b	#1,d4
	dbra	d6,initalli2
	tst.l	instlock
	beq	noib2instlock2
	move.l	d7,d1		;altes Dir current
	jsr	CurrentDir(a6)
noib2instlock2:
	moveq	#31,d6
aufarbiniti:			;schauen, ob alle Insts da sind
	btst	d6,d5
	beq	ininoneedmeld
	move.b	#1,error	;einzelnes Inst fehlt
	addq.b	#1,d3
ininoneedmeld:
	dbra	d6,aufarbiniti
	cmp.b	d2,d3
	bne	dropinitb2
	move.b	#2,error	;alles Insts fehlen !
dropinitb2:
	move.l	4,a6
	tst.l	dosbase
	beq	noib2dropdos	;dos.lib schließen
	move.l	dosbase,a1
	jsr	CloseLibrary(a6)
	clr.l	dosbase
noib2dropdos:
	tst.l	infomem
	beq	nodropininfomem
	move.l	#512,d0		;infomem freigeben
	move.l	infomem,a1
	jsr	FreeMem(a6)
nodropininfomem:
	moveq	#0,d0
	move.b	error,d0	;und fertig
	movem.l	(sp)+,d2-d7/a1-a6
	rts



; *********************************************************************

; Routine:		FreeB2Insts
; Funktion:		Speicher für Insts freigeben
; Übergabe-Parameter:	a0,Pointer auf Scoredata
;			d0,Länge des Scores
; Rückgabe-Parameter:	keine

; 'FreeB2Insts' gibt die Instrumente für ein im Speicher stehendes
; B2-Midi-Score- oder B2-Midi-Full-Insts-Score-File wieder frei.
; Wenn ein Song mittels 'LoadB2Score' geladen wurde und mittels
; 'FreeB2Score' wieder freigegeben werden soll ist das Freigeben der
; Instrumente mittels 'FreeB2Insts' nicht nötig.

_freeb2insts:
	movem.l	d1-d7/a1-a6,-(sp)
	lsr.l	#1,d0
	move.l	#"B2IS",d1	;Inst-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	nofreeinsts
	move.l	a0,a5
	moveq	#31,d5		;Speicher für im Inst-Struct
	move.l	4,a6
freeb2instsloop:
	move.l	40(a5),d0	;angegebene Instrumente freigeben
	beq	nofreethisb2inst
	move.l	44(a5),a1
	jsr	FreeMem(a6)
	clr.l	40(a5)
	clr.l	44(a5)
nofreethisb2inst:
	adda.l	#80,a5
	dbra	d5,freeb2instsloop
nofreeinsts:
	movem.l	(sp)+,d1-d7/a1-a6
	rts



; *********************************************************************

; Routine:		LoadB2Score
; Funktion:		Läd ein B2-Midi-Scorefile und die
;			benötigten Instrumente
; Übergabe-Parameter:	a0,Pointer auf Filename des Scores
;			d0,Directory-Lock des Scores oder '0'
;			d1,Directory-Lock des Inst-Verzeichnisses
; Rückgabe-Parameter:	a0,Pointer auf Score-Data oder '0' bei Error
;			d0 = '0' ... O.K.
;			d0 = '1' ... einzelne Instrumente fehlen
;			d0 = '2' ... alle Instrumente fehlen
;			d0 = '3' ... kann dos.library nicht öffnen
;			d0 = '4' ... kann Score-File nicht laden
;			d0 = '5' ... zu wenig Speicher oder anderer Error
;			d0 = '6' ... Es war kein B2-Scorefile
;			d1 = '0' ... Error (Definition in d0)
;			d1 <> '0' ... Länge des Scores

; Mittels 'LoadB2Score' kann ein B2-Midi-Score- oder ein B2-Midi-Full-
; Inst-Score geladen werden. Die nötigen Instrumente werden automatisch
; mitgeladen bzw. initialisiert.

_loadb2score:
	movem.l	d2-d7/a1-a6,-(sp)
	move.b	#3,error
	clr.l	scorelänge
	clr.l	scorestruct	;Parameter Zurücksetzen
	move.l	a0,scorename
	move.l	d0,scorelock
	move.l	d1,instlock
	move.l	4,a6
	lea	dosname,a1
	moveq	#0,d0
	jsr	OpenLibrary(a6)	;open dos_lib
	move.l	d0,dosbase
	beq	droploadb2
	move.l	#512,d0
	move.l	#$10003,d1
	jsr	AllocMem(a6)	;get infomem (for fileinfos)
	move.l	d0,infomem
	beq	droploadb2
	move.l	scorelock,d1
	beq	nolb2sclock1
	move.l	dosbase,a6	;Score-Dir current
	jsr	CurrentDir(a6)
	move.l	d0,d7
nolb2sclock1:
	move.b	#4,error
	move.l	scorename,a0	;Filename-Pointer
	move.l	#$10001,d0	;Mem: public,clear
	bsr	loadfile	;versuche File zu laden
	move.l	d0,scorelänge	;Länge
	move.l	a0,scorestruct	;Speicher
	tst.l	scorelock
	beq	nolb2sclock2
	move.l	d7,d1		;altes Dir current
	jsr	CurrentDir(a6)
nolb2sclock2:
	tst.l	scorelänge
	beq	droploadb2
	clr.b	flag
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	cmp.l	#"B2SC",8(a0)	;B2-Midi-Score
	beq	gotscorefile
	move.b	#1,flag
	cmp.l	#"B2FI",8(a0)	;B2-Midi-Full-Inst-Score
	bne	noscorefile
gotscorefile:
	lsr.l	#1,d0
	move.l	#"B2IS",d1	;Inst-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	noscorefile
	move.l	a0,inststruct
	moveq	#31,d2
dropikennforl:			;Inst-Kennungen löschen
	clr.l	76(a0)
	adda.l	#80,a0
	dbra	d2,dropikennforl
	tst.b	flag
	beq	loadb2scinsts	;kein Full-Inst Score ?
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	lsr.l	#1,d0
	move.l	#"B2II",d1	;Instrumentendaten suchen
	bsr	getchunk
	cmpa.l	#0,a0		;Pointer auf B2II-Struct
	beq	noscorefile
	clr.b	error		;möglicherweise kein Fehler mehr
	move.b	#2,flag
	moveq	#31,d7		;Clear IINX-Pointers
	lea	iinxe,a1
clriinxe:
	clr.l	(a1)+
	dbra	d7,clriinxe
	move.l	scorestruct,d2	;Anfangsadresse
	add.l	scorelänge,d2	;plus Länge gibt Endadr
	sub.l	a0,d2		;Minus Adr von B2II-Struct
	lsr.l	#1,d2		;ergbit Counter
	subq.l	#1,d2
	lea	iinxe,a1
getiinxadrs:			;Adressen der einzelnen Insts ermitteln
	move.l	(a0),d1
	moveq	#0,d3
	move.b	d1,d3		;mögliche Nr. von IINX
	move.b	#"X",d1
	cmp.l	#"IINX",d1	;IINX (InternInst) gefunden ?
	bne	gogetiinx
	cmp.b	#32,d3
	bge	gogetiinx
	asl.w	#2,d3		;Nummer des Insts ermitteln und
	move.l	a0,a2
	adda.l	#8,a2
	move.l	a2,(a1,d3)	;Pointer sichern
gogetiinx:
	adda.l	#2,a0
	dbra	d2,getiinxadrs
	move.l	4,a6		;Interne Insts ins Chip-Mem übertragen
	moveq	#31,d7
	lea	iinxe,a5
	move.l	inststruct,a4
getiinstsl1:
	move.l	(a5)+,a0
	cmpa.l	#0,a0
	beq	nextgetiinst
	suba.l	#4,a0
	move.l	(a0)+,d0	;Länge
	beq	nextgetiinst
	move.l	a0,a2		;Data-Pointer
	move.l	d0,40(a4)
	move.l	#$10003,d1	;Chip-Mem
	jsr	AllocMem(a6)
	move.l	d0,44(a4)	;Memory
	bne	gotmemforii
	clr.l	40(a4)
	clr.l	44(a4)
	move.b	#1,error	;einzelne Instrumente fehlen
	bra	nextgetiinst
gotmemforii:
	move.l	44(a4),a3
	move.l	40(a4),d3
	subq.l	#1,d3
getiinstsl2:
	move.b	(a2)+,(a3)+	;Sound-Data in Chip-Ram kopieren
	dbra	d3,getiinstsl2
	move.l	a4,a0
	bsr	getiffinfo	;Info über Sound-Data ermitteln
nextgetiinst:
	adda.l	#80,a4
	dbra	d7,getiinstsl1	
	bra	droploadb2	;fertig für B2-Midi-Full-Inst-Score

loadb2scinsts:			;Instrumente laden bei B2-Midi-Score
	clr.b	error		;möglicherweise kein Error mehr
	move.l	instlock,d1
	beq	nolb2instlock1
	move.l	dosbase,a6
	jsr	CurrentDir(a6)	;Inst-Dir current
	move.l	d0,d7
nolb2instlock1:
	moveq	#0,d2
	moveq	#0,d3
	moveq	#0,d5
	moveq	#31,d6
	moveq	#0,d4
	move.l	inststruct,a2
getalli2:
	tst.b	(a2)		;Instrument nicht nötig ?
	beq	schongoti	
	move.l	a2,a0	
	move.l	#$10003,d0	;Mem: chip,clear
	bset	d4,d5		;benötigtes Inst markieren
	addq.b	#1,d2
	bsr	loadfile	;File laden
	move.l	d0,40(a2)	;Länge 
	beq	schongoti
	bclr	d4,d5		;Ok... Markierung löschen
	move.l	a0,44(a2)	;Zeiger auf Speicher
	move.l	a2,a0
	bsr	getiffinfo	;Info über Sound-Data ermitteln
schongoti:
	adda.l	#80,a2
	addq.b	#1,d4
	dbra	d6,getalli2
	tst.l	instlock
	beq	nolb2instlock2
	move.l	d7,d1		;altes Dir current
	jsr	CurrentDir(a6)
nolb2instlock2:
	moveq	#31,d6
aufarbloadi:			;schauen, ob alle Insts da sind
	btst	d6,d5
	beq	inoneedmeld
	move.b	#1,error	;einzelnes Inst fehlt
	addq.b	#1,d3
inoneedmeld:
	dbra	d6,aufarbloadi
	cmp.b	d2,d3
	bne	droploadb2
	move.b	#2,error	;alles Insts fehlen !
	bra	droploadb2
noscorefile:
	move.l	4,a6
	move.l	scorelänge,d0	;Wenn's kein Score-File war, Speicher
	beq	droploadb2
	move.l	scorestruct,a1	;freigeben und error = '6'
	jsr	FreeMem(a6)
	clr.l	scorelänge
	clr.l	scorestruct
	move.b	#6,error
droploadb2:
	move.l	4,a6
	tst.l	dosbase
	beq	nolb2dropdos	;dos.lib schließen
	move.l	dosbase,a1
	jsr	CloseLibrary(a6)
	clr.l	dosbase
nolb2dropdos:
	tst.l	infomem
	beq	nodropinfomem
	move.l	#512,d0		;infomem freigeben
	move.l	infomem,a1
	jsr	FreeMem(a6)
nodropinfomem:
	moveq	#0,d0
	move.b	error,d0	;und fertig
	move.l	scorelänge,d1
	move.l	scorestruct,a0
	movem.l	(sp)+,d2-d7/a1-a6
	rts

; -----------------------------------------------------------------------

; Subroutine:		LoadFile
; Funktion:		File laden und nötigen Speicher allozieren
; Übergabe-Parameter:	a0,Pointer auf Filenamen
;			d0,Speichertyp (Chip,Fast,Public...)
; Rückgabe-Parameter:	a0,Pointer auf Speicherbereich
;			d0,Länge des Speicherbereichs

loadfile:
	movem.l	d1-d7/a1-a6,-(sp)
	move.l	a0,a5		;Zeiger auf Namen retten
	move.l	d0,d5		;Mem-Type retten
	move.l	dosbase,a6	;Dos-Basisadresse in a6
	move.l	a5,d1		;Zeiger auf Namen in d1
	moveq	#-2,d2		;Lock-Mode = -2 ... Lesen !
	jsr	Lock(a6)	;Filelock ermitteln
	move.l	d0,d7		;Zeiger auf Filelock in d7
	beq	lerror1		;Zeiger = 0 ... Error !
	move.l	d7,d1		;Zeiger auf Filelock in d1
	move.l	infomem,d2	;Zeiger auf Fileinfospeicher
	move.l	d2,a3
	jsr	Examine(a6)	;Fileinfodaten lesen
	tst.l	d0		;d0 = 0 ? ... Error !
	beq	lerror1
	move.l	d7,d1		;Zeiger auf Filelock in d1
	jsr	UnLock(a6)	;Filelock wieder freigeben
	move.l	124(a3),d0	;Länge des Files lesen
	move.l	4,a6		;Exec-Basisadresse in a6
	move.l	d5,d1		;Mem-Type nach d1
	jsr	AllocMem(a6)	;Speicher allocieren
	move.l	d0,a2		;Zeiger auf Speicher retten
	beq	lerror1		;Zeiger = 0 ? ... Error !
	move.l	a5,d1		;Zeiger auf Filenamen in d1
	move.l	#1005,d2	;Open-Mode: Mode_old ('altes File')
	move.l	dosbase,a6	;Dos-Basisadresse in a6
	jsr	Open(a6)	;File öffnen
	move.l	d0,d4		;Filehandle retten
	beq	lerror1		;Filehandle = 0 ? ... Error !
	move.l	d0,d1		;Filehandle in d1
	move.l	a2,d2		;Zeiger auf Speicher in d2
	move.l	124(a3),d3	;Länge des Files in d3
	jsr	Read(a6)	;Fileinhalt lesen
	move.l	d4,d1		;Filehandle in d1
	jsr	Close(a6)	;File schließen
	move.l	124(a3),d0	;Länge des Files in d0
	move.l	a2,a0		;Zeiger auf Speicher in a0
exitloadfile:
	movem.l	(sp)+,d1-d7/a1-a6
	rts			;und Fertig !
lerror1:
	moveq	#0,d0		;d0 = 0 ... Error !
	bra	exitloadfile	;und Fertig !

; -----------------------------------------------------------------------

; Subroutine:		Get(IFF)Chunk
; Funktion:		4Byte-Kennung in Speicherbereich finden
; Übergabe-Parameter:	a0,Pointer auf Speicherbereich
;			d0,Länge des Bereichs in Worten
; Rückgabe-Parameter:	a0,Pointer auf erstes Datenbyte oder '0'

getchunk:
	cmp.l	(a0),d1
	beq	gotchunk
	adda.l	#2,a0
	subq.l	#1,d0
	bne     getchunk
	bra	nochunk
gotchunk:
	adda.l	#8,a0
	rts
nochunk:
	move.l	#0,a0
	rts	

; -----------------------------------------------------------------------

; Subroutine:		GetIFFInfo
; Funktion:		Informationen über IFF-8SVX oder RAW-Sample
;			in interenen B2-Midi-Inststruct einlesen
; Übergabe-Parameter:	a0,Pointer auf (Unter-)Inststruct
; Rückgabe-Parameter:	keine

getiffinfo:
	movem.l	d0-d7/a0-a6,-(sp)
	tst.l	ILÄNGE(a0)
	beq	anotsample
	move.l	MEMORY(a0),a1
	cmp.l	#"8SVX",8(a1)
	bne	arawsample
	move.l	#"8SVX",KENNUNG(a0)	;Typ
	move.l	ILänge(a0),d2
	lsr.l	#1,d2
	move.l	a1,a2
get8iffbody:
	cmp.l	#"BODY",(a2)
	beq	got8iffbody
	adda.l	#2,a2
	subq.l	#1,d2
	bne	get8iffbody
	bra	arawsample
got8iffbody:
	adda.l	#8,a2
	move.l	a2,BODY(a0)		;Body (SampleData)
	move.l	ILÄNGE(a0),d2
	lsr.l	#1,d2
	move.l	a1,a2
get8iffvhdr:
	cmp.l	#"VHDR",(a2)
	beq	got8iffvhdr
	adda.l	#2,a2
	subq.l	#1,d2
	bne	get8iffvhdr
	bra	arawsample
got8iffvhdr:
	move.l	a2,VHDR(a0)		;Vhdr (VoiceHeader)
	move.l	8(a2),ONELÄNGE(a0)	;OneShot-Part Länge
	move.l	12(a2),REPLÄNGE(a0)	;Repeat-Part Länge
	btst	#7,HICYCLE(a0)		;HiCycle erzwungen ?
	bne	keepforcecycle1
	move.l	16(a2),HICYCLE(a0)	;Samples per HiCycle
keepforcecycle1:
	moveq	#0,d0
	move.w	20(a2),d0
	move.l	d0,RATE(a0)		;SampleRate
	moveq	#0,d0
	move.b	22(a2),d0
	move.l	d0,OKTAVEN(a0)		;Zahl der Oktaven
	movem.l	(sp)+,d0-d7/a0-a6
	rts
arawsample:
	move.l	Memory(a0),BODY(a0)	;Body (Sample Data)
	clr.l	VHDR(a0)		;VHDR (Kein VHDR-Chunk)
	move.l	ILÄNGE(a0),ONELÄNGE(a0)	;OneShot-Part Länge
	move.l	ILÄNGE(a0),REPLÄNGE(a0)	;Repeat-Part Länge
	btst	#7,64(a0)		;HiCycle erzwungen ?
	bne	keepforcecycle2
	move.l	#32,HICYCLE(a0)		;Samples per HiCycle
keepforcecycle2:
	move.l	#8363,RATE(a0)		;SampleRate
	move.l	#1,OKTAVEN(a0)		;Oktaven
	move.l	#"RAW ",KENNUNG(a0)	;Typ
	movem.l	(sp)+,d0-d7/a0-a6
	rts
anotsample:
	move.l	a0,a2
	adda.l	#48,a2
	moveq	#31,d2
anotsalo:
	clr.b	(a2)+
	dbra	d2,anotsalo
	move.l	#"NOT ",KENNUNG(a0)
	movem.l	(sp)+,d0-d7/a0-a6
	rts



; *********************************************************************

; Routine:		PlayB2Score
; Funktion:		B2-Midi-Score abspielen
; Übergabe-Parameter:	a0,Pointer auf Score
;			d0,Länge des Scores
; Rückgabe-Parameter:	d0 = '0' ... O.K.
;			d0 = '1' ... Das war kein Score-File
;			d0 = '2' ... Kann serial.device nicht öffnen
;			d0 = '3' ... andere Fehler

; Mittels 'PlayB2Score' starten Sie das Abspiels eines im Speicher
; stehenden und intialisierten Songs. Wenn der Song nicht mittels
; 'LoadB2Score' geladen wurde, sondern extern geladen wird oder fest
; im Speicher steht müssen die Instrumente vor dem Start mittels
; 'InitB2Score' initialisiert werden.

_playb2score:
	movem.l	d1-d7/a1-a6,-(sp)
	bsr	_stopb2score	;sicherheitshalber Abspiel stoppen
	move.b	#1,error
	move.l	a0,scorestruct
	move.l	d0,scorelänge
	lsr.l	#1,d0
	move.l	#"B2IS",d1	;Inst-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	exitplayscore
	move.l	a0,inststruct
	move.l	scorestruct,a0
	move.l	scorelänge,d0
	lsr.l	#1,d0
	move.l	#"B2SB",d1	;Song-Base-Struct suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	exitplayscore
	move.l	a0,songbase
	bclr	#1,cialed	;Filter entsprechend Score an/aus
	tst.b	filterstatus(a0)
	bne	filton
	bset	#1,cialed
filton:
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	lsr.l	#1,d0
	move.l	#"B2MD",d1
	bsr	getchunk	;Modulationen-Data suchen
	move.l	a0,modulmem
	move.l	scorelänge,d0
	move.l	scorestruct,a0
	lsr.l	#1,d0
	move.l	#"B2TR",d1	;Track-Data suchen
	bsr	getchunk
	cmpa.l	#0,a0
	beq	exitplayscore
	move.l	a0,a4
	moveq	#1,d7		;Anfangsadressen der Tracks suchen
	moveq	#11,d6
	lea	track1,a0
	move.l	#"TRKX",d0
ctracksforl1:
	move.b	d7,d0
	move.l	a4,a1
	move.l	scorelänge,d1
	lsr.l	#1,d1
lookitrack:
	cmp.l	(a1),d0
	beq	founditrack
	adda.l	#2,a1
	subq.l	#1,d1
	bne	lookitrack
	bra	nextloadtrack
founditrack:
	adda.l	#4,a1
	move.l	a1,(a0)+	;Memory-Pointer für Track
nextloadtrack:
	addq.b	#1,d7
	dbra	d6,ctracksforl1	
	moveq	#31,d7		;Erstes Instrument suchen
	move.b	#$ff,d6
	move.l	inststruct,a0
getbasl:
	tst.l	40(a0)
	bne	foundbasi
	addq.b	#1,d6
	adda.l	#80,a0
	dbra	d7,getbasl
foundbasi:
	move.b	d6,basisinst
	move.w	#1183,d0
	lea	playstruct1,a0	;Player-Strukturen löschen
clearplaystructs:
	clr.b	(a0)+
	dbra	d0,clearplaystructs
	moveq	#3,d0		;Tracks für die 4 Amiga-Kanäle ermitteln
	lea	track1,a0
	lea	aplaystruct1,a1	
	move.l	songbase,a2	;und Track-Zeiger in Playstrukturen
setaplaytracks:
	moveq	#0,d1		;schreiben
	move.b	achannels(a2),d1
	beq	offaplaytrack
	subq.b	#1,d1
	asl.w	#2,d1		;(mal 4)
	tst.l	(a0,d1)
	beq	offaplaytrack
	move.l	(a0,d1),(a1)	
	move.b	basisinst,playinstrument(a1)
offaplaytrack:
	adda.l	#32,a1
	adda.l	#1,a2
	dbra	d0,setaplaytracks
	clr.b	serialflag
	moveq	#11,d0		;Nachschauen, ob Abspiel über Midi
	lea	track1,a0
	lea	playstruct1,a1	;erwünscht ist und Track-Zeiger in
	move.l	songbase,a2
	add.l	#midichannels,a2
setplaytracks:			;entsprechende Playerstrukturen
	tst.b	(a2)+
	beq	offtrack
	move.l	(a0),(a1)
	beq	offtrack	;schreiben
	move.b	#1,serialflag
offtrack:
	adda.l	#4,a0
	adda.l	#32,a1
	dbra	d0,setplaytracks
;Checken, ob in den Stimmen überhaupt was steht
	moveq	#15,d7
	lea	playstruct1,a5
checknotesinv:
	tst.l	(a5)
	beq	nextnotesinv
	move.l	(a5),a4
checknotesl:
	tst.l	(a4)
	beq	nonoteinv
	cmp.l	#$ffffffff,(a4)
	beq	nonoteinv
	tst.b	(a4)
	beq	checknextn
	cmp.b	#17,(a4)
	bls	nextnotesinv
checknextn:
	adda.l	#4,a4
	bra	checknotesl
nonoteinv:
	clr.l	(a5)		;Falls keine Note vorhanden, Track off
nextnotesinv:
	add.l	#32,a5
	dbra	d7,checknotesinv
	move.b	#2,error
	tst.b	serialflag	;Serial Device wird benötigt ?
	beq	noneedserdev
	move.l	4,a6
	move.l	#4096,d0
	move.l	#$10003,d1
	jsr	AllocMem(a6)	;get infomem (for fileinfos)
	move.l	d0,sendmem
	bne	gotsendmem
	clr.b	serialflag
	bra	noneedserdev
gotsendmem:
	suba.l	a1,a1
	jsr	FindTask(a6)
	lea	serialreply,a1	;MSGPort für Serial.Device
	move.l	d0,16(a1)	;Taskadresse in MSGPort
	jsr	AddPort(a6)
	lea	serialdevice,a0
	lea	serialio,a1
	moveq	#0,d0
	moveq	#0,d1		;Serial Device öffnen
	jsr	OpenDev(a6)
	tst.l	d0
	beq	gotserdev
	clr.b	serialflag
	bra	exitplayscore	;Kann Device nicht öffnen !
gotserdev:
	lea	serialio,a1
	move.l	#serialreply,14(a1)
	move.w	#11,28(a1)		;Command: SetParameter
	move.l	#$11130000,48(a1)	;xOn/xOFF
	move.l	#$200,52(a1)		;In-Buff
	move.l	#$200,56(a1)		;Out-Buff
	move.l	#31250,60(a1)		;BaudRate
	move.b	#8,76(a1)		;8 Bits Read
	move.b	#8,77(a1)		;8 Bits Write
	move.b	#2,78(a1)		;1 StopBit
	move.b	#0,79(a1)		;Parity OFF / gerade
	jsr	DoIO(a6)
noneedserdev:
	clr.b	error
	move.l	4,a6		;Interrupt-Server initialisieren
	lea	structmem,a1	;und damit Abspiel starten
	move.l	a1,d0
	add.l	#32,d0
	move.l	d0,14(a1)
	move.b	#-16,9(a1)		;Priority: -16
	move.b	#2,8(a1)		;NodeTyp: 2,Interrupt
	move.l	#playprog,18(a1)	;Pointer to Code
	moveq	#5,d0			;IntNo. 5, VertB
	jsr	AddIntServer(a6)	;Interrupt
	move.b	#1,serverflag
exitplayscore:
	moveq	#0,d0
	move.b	error,d0
	movem.l	(sp)+,d1-d7/a1-a6
	rts


; *********************************************************************

; Routine:		StopB2Score
; Funktion:		B2-Midi-Score-Abspiel anhalten
; Übergabe-Parameter:	keine
; Rückgabe-Parameter:	keine

; Durch Aufruf der Routine 'StopB2Score' wird das Abspiel eines
; Songs beendet.

_stopb2score:
	movem.l	d0-d7/a0-a6,-(sp)
	move.w	#0,aud0vol
	move.w	#0,aud1vol
	move.w	#0,aud2vol		;Lautsträken auf 0
	move.w	#0,aud3vol
	move.w	#15,dmacon		;und Audio-DMA ausschalten
	move.l	4,a6
	tst.b	serverflag
	beq	noremserver
	lea	structmem,a1
	moveq	#5,d0
	jsr	RemIntServer(a6)	;Interrupt-Routinen aus
	clr.b	serverflag
noremserver:
	tst.b	serialflag
	beq	noserialstop
	moveq	#0,d7
	lea	playstruct1,a5
	move.l	sendmem,a0
	move.w	sendbytes,d0		;NoteOff-Kommandos bei
getalloffs:
	bsr	turnoffnote		;Midi-Output setzen
	adda.l	#32,a5
	addq.b	#1,d7
	cmp.b	#12,d7
	bne	getalloffs
	moveq	#11,d7
	lea	midichannels,a2
	move.l	sendmem,a0
	move.w	sendbytes,d0
getoffchannels:
	move.b	(a2)+,d1
	beq	offofftrack
	subq.b	#1,d1	
	or.b	#%10110000,d1		;Command: Ctrl-Chng
	bsr	putsendbyte
	move.b	#%01111011,d1
	bsr	putsendbyte		;AllNotesOff
	moveq	#0,d1
	bsr	putsendbyte
offofftrack:
	dbra	d7,getoffchannels
	lea	serialio,a1
	move.l	#serialreply,14(a1)
	move.w	#3,28(a1)		;Command: Write
	move.l	sendmem,40(a1)		;Data-Pointer
	moveq	#0,d0
	move.w	sendbytes,d0
	beq	nosendoff
	move.l	d0,36(a1)		;Länge
	jsr	DoIo(a6)
nosendoff:
	lea	serialio,a1
	jsr	CloseDev(a6)
	lea	serialreply,a1
	jsr	RemPort(a6)
noserialstop:
	move.l	4,a6
	tst.l	sendmem
	beq	nodropsendmem
	move.l	#4096,d0		;Sendmem freigeben
	move.l	sendmem,a1
	jsr	FreeMem(a6)
	clr.l	sendmem
nodropsendmem:
	movem.l	(sp)+,d0-d7/a0-a6
	rts


; ******************************************************************

; Ouput-Routinen (in VertB-Interrupt eingehängt)...

playprog:
	movem.l	d0-d7/a0-a6,-(sp)
	moveq	#0,d7
	lea	aplaystruct1,a5
playamigaloop:
	tst.l	(a5)
	beq	nextampvoice
	tst.w	playoffcount(a5)
	bne	nopreamioffturn
	bsr	turnoffsample
nopreamioffturn:
	tst.w	playcount(a5)
	bne	countampvoice
	addq.l	#1,playpos(a5)
	move.l	(a5),a4
	move.l	playpos(a5),d4
	subq.l	#1,d4
	asl.l	#2,d4
	adda.l	d4,a4
	tst.l	(a4)
	beq	endofampvoice
	cmp.l	#$ffffffff,(a4)
	beq	endofampvoice	
	moveq	#0,d0
	move.b	(a4),d0		;Zeichennummer
	and.b	#%00011111,d0
	lea	amigaplays,a0
	asl.l	#2,d0
	move.l	(a0,d0),a1
	cmpa.l	#0,a1
	beq	playamigaloop
	jsr	(a1)		;Play something
	tst.w	playcount(a5)
	beq	playamigaloop
countampvoice:		
	subq.w	#1,playoffcount(a5)
	subq.w	#1,playcount(a5)
	bra	nextampvoice
endofampvoice:
	clr.l	playpos(a5)
	move.l	(a5),a4
	tst.l	(a4)
	bne	playamigaloop
nextampvoice:
	adda.l	#32,a5
	addq.b	#1,d7
	cmp.b	#4,d7
	bne	playamigaloop
	tst.b	serialflag
	beq	nosend
	clr.w	sendbytes
	moveq	#0,d7
	lea	playstruct1,a5
playserialloop:
	tst.l	(a5)
	beq	nextserpvoice
	tst.w	playoffcount(a5)
	bne	nopreoffturn
	bsr	turnoffnote	
nopreoffturn:
	tst.w	playcount(a5)
	bne	countserpvoice
	addq.l	#1,playpos(a5)
	move.l	(a5),a4
	move.l	playpos(a5),d4
	subq.l	#1,d4
	asl.l	#2,d4
	adda.l	d4,a4
	tst.l	(a4)
	beq	endofserpvoice
	cmp.l	#$ffffffff,(a4)
	beq	endofserpvoice	
	moveq	#0,d0
	move.b	(a4),d0		;Zeichennummer
	and.b	#%00011111,d0
	lea	serialplays,a0
	asl.l	#2,d0
	move.l	(a0,d0),a1
	cmpa.l	#0,a1
	beq	playserialloop
	jsr	(a1)		;Play something
	tst.w	playcount(a5)
	beq	playserialloop
countserpvoice:		
	subq.w	#1,playoffcount(a5)
	subq.w	#1,playcount(a5)
	bra	nextserpvoice
endofserpvoice:
	clr.l	playpos(a5)
	move.l	(a5),a4
	tst.l	(a4)
	bne	playserialloop
nextserpvoice:
	adda.l	#32,a5
	addq.b	#1,d7
	cmp.b	#12,d7
	bne	playserialloop
	move.l	4,a6
	lea	serialio,a1
	move.l	#serialreply,14(a1)
	move.w	#3,28(a1)		;Command: Write
	move.l	sendmem,40(a1)		;Data-Pointer
	moveq	#0,d0
	move.w	sendbytes,d0
	beq	nosend
	move.l	d0,36(a1)		;Länge
	jsr	SendIo(a6)
nosend:	
	bsr	dolongsets
	bsr	domodulat
	movem.l	(sp)+,d0-d7/a0-a6
	rts

dolongsets:
	move.l	#512,d7
waitlongs:
	dbra	d7,waitlongs
	lea	aplaystruct1,a5
	moveq	#0,d7
longsetsloop:
	btst	d7,longsets
	beq	nextlongset
	move.l	#audxadr,a2
	move.l	d7,d2
	asl.w	#4,d2
	adda.l	d2,a2
	moveq	#0,d0
	move.b	playinstrument(a5),d0	;Number of Inststruct
	cmp.b	#$ff,d0
	beq	gotlongset
	move.l	inststruct,a0
	mulu	#80,d0
	adda.l	d0,a0			;Inststrut
	tst.l	ilänge(a0)
	beq	gotlongset
	tst.l	replänge(a0)
	beq	quietlong
	cmp.l	#2,oktaven(a0)
	bls	longsetok1
	lea	oktavs,a1
	cmp.b	#1,(a1,d7)
	beq	longsetok1
	cmp.b	#2,(a1,d7)
	beq	longsetok2
	cmp.b	#3,(a1,d7)
	bne	longsetok1
longsetok3:
	move.l	replänge(a0),d0
	asl.l	#1,d0			;vierfache Länge für Okt3
	move.w	d0,audxlen(a2)
	move.l	onelänge(a0),d0
	add.l	replänge(a0),d0		;Oktave 2 Überspringen
	asl.l	#1,d0
	add.l	onelänge(a0),d0
	add.l	replänge(a0),d0		;Oktave 1 überspringen
	move.l	onelänge(a0),d1
	asl.l	#2,d1			;Oneshot Okt3 überspringen
	add.l	d1,d0
	move.l	body(a0),a1
	add.l	d0,a1
	move.l	a1,audxlch(a2)
	bra	gotlongset
longsetok2:
	move.l	replänge(a0),d0
	move.w	d0,audxlen(a2)
	move.l	onelänge(a0),d0
	asl.l	#1,d0			;Oktave 1 überspringen und
	add.l	onelänge(a0),d0		;OneShot von Okt2
	add.l	replänge(a0),d0
	move.l	body(a0),a1
	add.l	d0,a1
	move.l	a1,audxlch(a2)
	bra	gotlongset
longsetok1:
	move.l	replänge(a0),d0
	lsr.l	#1,d0
	move.w	d0,audxlen(a2)
	move.l	body(a0),a1
	add.l	onelänge(a0),a1
	move.l	a1,audxlch(a2)
	bra	gotlongset
quietlong:
	move.w	#2,audxlen(a2)
	move.l	#notone,audxlch(a2)
gotlongset:
	bclr	d7,longsets
nextlongset:
	adda.l	#32,a5
	addq.b	#1,d7
	cmp.b	#4,d7
	bne	longsetsloop
	rts

domodulat:
	moveq	#0,d7
	lea	aplaystruct1,a5
modulatloop:
	tst.l	playmem(a5)
	beq	nextmodulat
	moveq	#0,d2
	move.b	playvolmod(a5),d2
	beq	nodovolmod
	move.l	modulmem,a2
	asl.w	#8,d2
	adda.l	d2,a2			;Pointer to Kurve
	moveq	#0,d2
	move.b	playvolcount(a5),d2
	lea	moduladders,a3
	move.b	(a3,d7),d3
	add.b	d3,playvolcount(a5)
	moveq	#0,d0
	move.b	(a2,d2),d0
	moveq	#32,d1
	btst	#7,d0
	beq	plusvolmod
	bclr	#7,d0
	sub.b	d0,d1
	bra	setmodedvol
plusvolmod:
	add.b	d0,d1
setmodedvol:
	move.l	#audxadr,a2
	move.l	d7,d2
	asl.w	#4,d2
	adda.l	d2,a2
	move.w	d1,audxvol(a2)
nodovolmod:
	moveq	#0,d2
	move.b	playfreqmod(a5),d2
	beq	nextmodulat
	move.l	modulmem,a2
	addq.b	#8,d2
	asl.w	#8,d2
	adda.l	d2,a2			;Pointer to Kurve
	moveq	#0,d2
	move.b	playfreqcount(a5),d2
	lea	moduladders,a3
	move.b	(a3,d7),d3
	add.b	d3,playfreqcount(a5)
	moveq	#0,d0
	move.b	(a2,d2),d0
	btst	#7,d0
	beq	plusfreqmod
	bclr	#7,d0
	moveq	#0,d1
	move.w	playfrequenz(a5),d1
	mulu	d0,d1
	divu	#150,d1
	move.w	playfrequenz(a5),d0
	sub.w	d1,d0
	bra	setmodedfreq
plusfreqmod:
	moveq	#0,d1
	move.w	playfrequenz(a5),d1
	mulu	d0,d1
	divu	#150,d1
	move.w	playfrequenz(a5),d0
	add.w	d1,d0
setmodedfreq:
	move.l	#audxadr,a2
	move.l	d7,d2
	asl.w	#4,d2
	adda.l	d2,a2
	move.w	d0,audxper(a2)
nextmodulat:
	adda.l	#32,a5
	addq.b	#1,d7
	cmp.b	#4,d7
	bne	modulatloop
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialfermate:
amigafermate:
	move.b	#1,playfermate(a5)
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
amigafx:
	moveq	#0,d0
	move.b	1(a4),d0
	and.b	#%00011111,d0
	cmp.b	#7,d0
	bls	newvolfxplay
	subq.b	#8,d0
	move.b	d0,playfreqmod(a5)
	clr.b	playfreqcount(a5)
	rts
newvolfxplay:
	move.b	d0,playvolmod(a5)
	clr.b	playvolcount(a5)
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
amigainst:
	move.b	1(a4),d0
	and.b	#%00111111,d0
	cmp.b	#32,d0
	beq	return
	move.b	d0,playinstrument(a5)
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialinst:
	moveq	#0,d0
	move.b	1(a4),d0
	and.b	#%01111111,d0
	cmp.b	#32,d0
	beq	callpreset
	move.b	d0,playinstrument(a5)
	rts
callpreset:
	move.l	sendmem,a0
	move.w	sendbytes,d0
	lea	midichannels,a1
	move.b	(a1,d7),d1		;Number of Midi-Channel	
	beq	nocallpr
	subq.b	#1,d1
	or.b	#%11000000,d1		;Command: ProgChng
	bsr	putsendbyte
	move.b	3(a4),d1		;Preset No.
	bsr	putsendbyte
nocallpr:
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialole:
amigaole:
	btst	#0,1(a4)
	bne	noserialduole
	move.b	#2,playduocount(a5)
	rts
noserialduole:
	btst	#0,1(a4)
	beq	noserialtriole
	move.b	#3,playtriocount(a5)
noserialtriole:
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialbogen:
amigabogen:
	move.b	#1,playbogen(a5)
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialhex:
	move.l	sendmem,a0
	move.w	sendbytes,d0
	move.b	1(a4),d1
	bsr	putsendbyte
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialwdh:
	lea	swdhstruct1,a2
	move.l	d7,d2
	mulu	#42,d2
	adda.l	d2,a2			;Pointer to WDH-Struct
goallwdh:
	move.b	1(a4),d1
	and.b	#%00000011,d1		;Wiederholungszeichen
	tst.b	d1
	beq	beginwdh
	cmp.b	#1,d1
	beq	endwdh
	cmp.b	#2,d1
	beq	jumpwdh
	cmp.b	#3,d1
	beq	endjumpwdh
huargwdh:
	rts

beginwdh:
	cmp.w	#10,(a2)		;maximum:10 WDHS
	beq	huargwdh
	moveq	#0,d2
	move.w	(a2),d2
	asl.b	#1,d2			;pointer to ac-pos
	move.l	playpos(a5),d1
	move.w	d1,2(a2,d2)		;keep pos
	addq.w	#1,(a2)			;Increase Pointer
	rts
endwdh:
endjumpwdh:
	moveq	#0,d2
	move.w	(a2),d2
	beq	huargwdh
	subq.w	#1,d2
	asl.b	#1,d2
	tst.w	22(a2,d2)
	bne	dropthewdh
	move.l	playpos(a5),d1
	move.w	d1,22(a2,d2)
	moveq	#0,d1
	move.w	2(a2,d2),d1
	move.l	d1,playpos(a5)
	rts
dropthewdh:
	clr.w	2(a2,d2)
	clr.w	22(a2,d2)
	tst.w	(a2)
	beq	huargwdh
	subq.w	#1,(a2)
	rts
jumpwdh:
	moveq	#0,d2
	move.w	(a2),d2
	beq	huargwdh
	subq.w	#1,d2
	asl.b	#1,d2
	moveq	#0,d1
	move.w	22(a2,d2),d1
	beq	huargwdh
	move.l	d1,playpos(a5)
	bra	dropthewdh

amigawdh:
	lea	awdhstruct1,a2
	move.l	d7,d2
	mulu	#42,d2
	adda.l	d2,a2			;Pointer to WDH-Struct
	bra	goallwdh

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialnote:
	move.l	sendmem,a0
	move.w	sendbytes,d0
	bsr	serialpause
	tst.b	playbogen(a5)
	beq	noserialbogen
	clr.b	playbogen(a5)
	move.l	playnote(a5),d1
	move.l	(a4),d2
	and.l	#%00000000111111110000000000000000,d1
	and.l	#%00000000111111110000000000000000,d2
	cmp.l	d1,d2
	beq	serialgebogen	
	bsr	turnoffnote
noserialbogen:
	move.l	(a4),playnote(a5)
	moveq	#0,d2
	move.b	playinstrument(a5),d2
	cmp.b	#$ff,d2
	beq	nopreset
	move.l	inststruct,a2
	adda.l	#presets,a2		;Get Preset-No.
	move.b	(a2,d2),d3
	cmp.b	#255,d3			;No Preset Send ???
	beq	nopreset
	lea	midichannels,a1
	move.b	(a1,d7),d1		;Number of Midi-Channel	
	subq.b	#1,d1
	or.b	#%11000000,d1		;Command: ProgChng
	bsr	putsendbyte
	move.b	d3,d1			;Preset No.
	bsr	putsendbyte
nopreset:
	lea	midichannels,a1
	move.b	(a1,d7),d1		;Number of Midi-Channel	
	subq.b	#1,d1
	or.b	#%10010000,d1		;Command: NoteOn
	bsr	putsendbyte
	move.b	1(a4),d1		;Notenhöhe
	bclr	#7,d1			;Clear Staccato
	add.b	#23,d1			;Get MidiNo.
	bsr	putsendbyte	
	move.l	songbase,a1
	add.l	#onvels,a1
	move.b	(a1,d7),d1		;Get ON-Velocity
	beq	velfromvol
	bsr	putsendbyte
	bra	serialgebogen
velfromvol:
	move.w	2(a4),d2
	and.w	#%0000001110000000,d2	;Filter Volume
	lsr.w	#7,d2
	lea	volumemults,a2
	move.b	(a2,d2),d1		;Get Volume-Wert
	asl.b	#1,d1			;Double
	bsr	putsendbyte
serialgebogen:
	move.b	4(a4),d1
	and.b	#%00011111,d1
	cmp.b	#25,d1
	beq	serialbogen
	rts

putsendbyte:
	move.b	d1,(a0,d0)
	addq.w	#1,d0
	addq.w	#1,sendbytes
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
amiganote:
	bsr	amigapause
	move.l	(a4),playnote(a5)
	move.l	#audxadr,a2
	move.l	d7,d2
	asl.w	#4,d2
	adda.l	d2,a2
	moveq	#0,d0
	move.b	playinstrument(a5),d0	;Number of Inststruct
	cmp.b	#$ff,d0
	beq	noamiganoteplay
	move.l	inststruct,a0
	mulu	#80,d0
	adda.l	d0,a0			;Inststrut
	tst.l	ilänge(a0)
	beq	noamiganoteplay
	moveq	#1,d3			;Mark für Mid-Okt, kein mulu
	tst.b	playbogen(a5)
	beq	noamigabogen
	lea	oktavs,a1
	move.b	(a1,d7),d3
	bra	nolchset
noamigabogen:
	cmp.l	#2,oktaven(a0)
	bls	firstoktave
	move.b	1(a4),d1		;Notenhöhe
	bclr	#7,d1			;ClearStaccato
	cmp.b	#24,d1
	bls	thirdoktave		;Tiefste Oktave
	cmp.b	#48,d1
	bls	secondoktave		;Mittlere Oktave
	bra	firstoktave		;Höchste
thirdoktave:
	moveq	#3,d3
	move.l	onelänge(a0),d0
	add.l	replänge(a0),d0
	asl.l	#1,d0			;Vierfache Länge für 3.Okt
	move.w	d0,audxlen(a2)
	move.l	body(a0),d0
	move.l	onelänge(a0),d1		;Ersten beiden Okts überspringen
	add.l	replänge(a0),d1
	asl.l	#1,d1
	add.l	onelänge(a0),d1
	add.l	replänge(a0),d1
	add.l	d1,d0			;Zeiger auf Data für 3.Okt
	move.l	d0,audxlch(a2)
	bra	nolchset
secondoktave:
	moveq	#2,d3
	move.l	onelänge(a0),d0
	add.l	replänge(a0),d0
	move.w	d0,audxlen(a2)
	move.l	body(a0),d0
	add.l	onelänge(a0),d0		;Erste Oktave überspringen
	add.l	replänge(a0),d0		;Zeiger auf Data für 2.Okt
	move.l	d0,audxlch(a2)
	bra	nolchset
firstoktave:
	moveq	#1,d3
	move.l	onelänge(a0),d0
	add.l	replänge(a0),d0
	lsr.l	#1,d0
	move.w	d0,audxlen(a2)		;Länge der Sounddaten
	move.l	body(a0),audxlch(a2)	;Adresse der Sounddaten
nolchset:
	moveq	#0,d1
	move.b	1(a4),d1		;Notenhöhe
	bclr	#7,d1			;Clear Staccato
	asl.w	#1,d1
	lea	frequence,a1
	moveq	#0,d0
	move.w	0(a1,d1),d0		;Frequence der Note
	move.l	hicycle(a0),d1
	bclr	#31,d1
	lea	oktavs,a1
	move.b	d3,(a1,d7)
	cmp.b	#1,d3
	beq	playnormalcycle
	cmp.b	#2,d3
	bne	playhalbecycle
	asl.l	#1,d1
	bra	playnormalcycle	
playhalbecycle:
	asl.l	#2,d1			;Mal Wert für richtige Oktave
playnormalcycle:
	mulu	d1,d0			;Rate (..Cycles*Freq)
	move.l	#3579546,d1
	tst.l	d0
	beq	noamiganoteplay
	divu	d0,d1			;SamplePeriod
	move.w	d1,audxper(a2)
	move.w	d1,playfrequenz(a5)
	move.l	#$8200,d0
	bset	d7,d0
	tst.b	playbogen(a5)
	bne	nodmaset
	move.w	d0,dmacon		;Start DMA
nodmaset:
	move.w	2(a4),d2
	and.w	#%0000001110000000,d2	;Filter Volume
	lsr.w	#7,d2
	lea	volumemults,a1
	moveq	#0,d1
	move.b	(a1,d2),d1		;Get Volume-Wert
	move.b	d1,playvolume(a5)
	move.w	d1,audxvol(a2)
	tst.b	playbogen(a5)
	bne	notegebogen
	bset	d7,longsets
notegebogen:
	clr.b	playbogen(a5)
noamiganoteplay:
	move.b	4(a4),d1
	and.b	#%00011111,d1
	cmp.b	#25,d1
	beq	amigabogen
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
serialpause:
	move.l	sendmem,a0
	move.w	sendbytes,d0
	bsr	turnoffnote
	lea	displaymults,a3
	moveq	#0,d3
	move.b	(a4),d3
	and.b	#%00011111,d3
	moveq	#0,d1
	move.b	(a3,d3),d1		;Länge der Note in 32tel
	moveq	#0,d2
	move.w	2(a4),d2
	and.w	#%0000000001110000,d2	;Filter Speed
	lsr.w	#4,d2
	addq.w	#1,d2			;Min Länge ungleich 0
	mulu	d2,d1			;Länge der Note
	tst.b	playduocount(a5)
	beq	noduoserialplayer
	move.l	d1,d2
	mulu	#3,d2
	divu	#2,d2
	move.w	d2,d1
	lsr.l	#8,d2
	lsr.l	#8,d2
	add.w	d2,playduorest(a5)
	subq.b	#1,playduocount(a5)
	bne	notrioserialplayer
	moveq	#0,d2
	move.w	playduorest(a5),d2
	divu	#2,d2
	add.w	d2,d1
	clr.w	playduorest(a5)
	bra	notrioserialplayer
noduoserialplayer:
	tst.b	playtriocount(a5)
	beq	notrioserialplayer
	move.l	d1,d2
	mulu	#2,d2
	divu	#3,d2
	move.w	d2,d1
	lsr.l	#8,d2
	lsr.l	#8,d2
	add.w	d2,playtriorest(a5)
	subq.b	#1,playtriocount(a5)
	bne	notrioserialplayer
	moveq	#0,d2
	move.w	playtriorest(a5),d2
	divu	#3,d2
	add.w	d2,d1
	clr.w	playtriorest(a5)
notrioserialplayer:
	tst.b	playfermate(a5)
	beq	nofermserial
	asl.w	#1,d1
	clr.b	playfermate(a5)
nofermserial:
	move.w	d1,playcount(a5)
	btst	#7,1(a4)
	beq	nostaccserial
	lsr.w	#1,d1	
nostaccserial:
	move.w	d1,playoffcount(a5)
	rts

; In a4 pointer auf Note, in a5 pointer auf playstruct
amigapause:
	bsr	turnoffsample
	lea	displaymults,a3
	moveq	#0,d3
	move.b	(a4),d3
	and.b	#%00011111,d3
	moveq	#0,d1
	move.b	(a3,d3),d1		;Länge der Note in 32tel
	moveq	#0,d2
	move.w	2(a4),d2
	and.w	#%0000000001110000,d2	;Filter Speed
	lsr.w	#4,d2
	addq.w	#1,d2			;Min Länge ungleich 0
	mulu	d2,d1			;Länge der Note
	tst.b	playduocount(a5)
	beq	noduoamigaplayer
	move.l	d1,d2
	mulu	#3,d2
	divu	#2,d2
	move.w	d2,d1
	lsr.l	#8,d2
	lsr.l	#8,d2
	add.w	d2,playduorest(a5)
	subq.b	#1,playduocount(a5)
	bne	notrioamigaplayer
	moveq	#0,d2
	move.w	playduorest(a5),d2
	divu	#2,d2
	add.w	d2,d1
	clr.w	playduorest(a5)
	bra	notrioamigaplayer
noduoamigaplayer:
	tst.b	playtriocount(a5)
	beq	notrioamigaplayer
	move.l	d1,d2
	mulu	#2,d2
	divu	#3,d2
	move.w	d2,d1
	lsr.l	#8,d2
	lsr.l	#8,d2
	add.w	d2,playtriorest(a5)
	subq.b	#1,playtriocount(a5)
	bne	notrioamigaplayer
	moveq	#0,d2
	move.w	playtriorest(a5),d2
	divu	#3,d2
	add.w	d2,d1
	clr.w	playtriorest(a5)
notrioamigaplayer:
	tst.b	playfermate(a5)
	beq	nofermamiga
	asl.w	#1,d1
	clr.b	playfermate(a5)
nofermamiga:
	move.w	d1,playcount(a5)
	lea	moduladders,a2
	move.l	#256,d2			;Get Adds for Modulation
	divu	d1,d2
	tst.b	d2
	bne	gotmodadd
	addq.b	#1,d2
gotmodadd:
	move.b	d2,(a2,d7)
	btst	#7,1(a4)
	beq	nostaccamiga
	lsr.w	#1,d1	
nostaccamiga:
	subq.w	#1,d1
	move.w	d1,playoffcount(a5)
	rts

;in a5 pointer to playstruct
turnoffnote:
	tst.b	playbogen(a5)
	bne	nonoteofftoset
	tst.l	playnote(a5)
	beq	nonoteofftoset
	move.l	sendmem,a0
	move.w	sendbytes,d0
	lea	midichannels,a1
	move.b	(a1,d7),d1		;Number of Midi-Channel	
	subq.b	#1,d1
	or.b	#%10000000,d1		;Command: NoteOff
	bsr	putsendbyte
	move.l	a5,a3
	add.l	#8,a3
	move.b	1(a3),d1		;Notenhöhe
	bclr	#7,d1			;Clear Staccato
	add.b	#23,d1			;Get MidiNo.
	bsr	putsendbyte	
	move.l	songbase,a1
	add.l	#offvels,a1
	move.b	(a1,d7),d1		;Get ON-Velocity
	beq	getoffvel
	bsr	putsendbyte
	bra	noteoffset
getoffvel:
	move.w	2(a3),d2
	and.w	#%0000001110000000,d2	;Filter Volume
	lsr.w	#7,d2
	addq.w	#1,d2			;Min Wert ungleich 0
	lea	volumemults,a2
	move.b	(a2,d2),d1		;Get Volume-Wert
	asl.b	#1,d1			;Double
	bsr	putsendbyte
noteoffset:
	clr.l	playnote(a5)
nonoteofftoset:
	rts

;in a5 pointer to playstruct
turnoffsample:
	tst.b	playbogen(a5)
	bne	nosampleoff
	tst.l	playnote(a5)
	beq	nosampleoff
	move.l	#audxadr,a0
	move.l	d7,d0
	asl.w	#4,d0
	adda.l	d0,a0
	moveq	#0,d0
	bset	d7,d0
	move.w	d0,dmacon
	move.w	#0,audxvol(a0)
	clr.l	playnote(a5)
	clr.b	playvolcount(a5)
	clr.b	playfreqcount(a5)
nosampleoff:
return:
	rts



; ********************************************************************

; Daten-Bereich (Variablen, Zwischenspeicher, Tabellen usw.)

playstruct1:	ds.b	384	;12 PlayStructs für Midi (12*32 Byte)

aplaystruct1:	ds.b	128	;4 PlayStructs für Amiga (4*32 Byte)

swdhstruct1:	ds.b	504	;12 Wiederholtabs für Midi (12*42 Byte)

awdhstruct1:	ds.b	168	;4 Wiederholtabs für Amiga (4*42 Byte)

serialplays:			;Pointer auf Player-Sub-Routinen
	dc.l	return		;0	;forcetakt
	dc.l	serialnote	;1
	dc.l	serialnote	;2
	dc.l	serialnote	;3
	dc.l	serialnote	;4
	dc.l	serialnote	;5
	dc.l	serialnote	;6
	dc.l	serialnote	;7
	dc.l	serialnote	;8
	dc.l	serialnote	;9
	dc.l	serialnote	;10
	dc.l	serialnote	;11
	dc.l	serialpause	;12
	dc.l	serialpause	;13
	dc.l	serialpause	;14
	dc.l	serialpause	;15
	dc.l	serialpause	;16
	dc.l	serialpause	;17
	dc.l	return		;18	;newtakt
	dc.l	return		;19	;newtonart
	dc.l	return		;20	;newstacc
	dc.l	return		;21	;newhals
	dc.l	return		;22	;newspeed
	dc.l	return		;23	;newvol
	dc.l	serialfermate	;24
	dc.l	serialbogen	;25
	dc.l	serialwdh	;26
	dc.l	serialhex	;27
	dc.l	serialole	;28
	dc.l	return		;29	;balkstatus
	dc.l	serialinst	;30	;newinst
	dc.l	return		;31	;newfx
	dc.l	0

amigaplays:			;Pointer auf Player-Sub-Routinen
	dc.l	return		;0	;forcetakt
	dc.l	amiganote	;1
	dc.l	amiganote	;2
	dc.l	amiganote	;3
	dc.l	amiganote	;4
	dc.l	amiganote	;5
	dc.l	amiganote	;6
	dc.l	amiganote	;7
	dc.l	amiganote	;8
	dc.l	amiganote	;9
	dc.l	amiganote	;10
	dc.l	amiganote	;11
	dc.l	amigapause	;12
	dc.l	amigapause	;13
	dc.l	amigapause	;14
	dc.l	amigapause	;15
	dc.l	amigapause	;16
	dc.l	amigapause	;17
	dc.l	return		;18	;newtakt
	dc.l	return		;19	;newtonart
	dc.l	return		;20	;newstacc
	dc.l	return		;21	;newhals
	dc.l	return		;22	;newspeed
	dc.l	return		;23	;newvol
	dc.l	amigafermate	;24
	dc.l	amigabogen	;25
	dc.l	amigawdh	;26
	dc.l	return		;27	;hexsign
	dc.l	amigaole	;28
	dc.l	return		;29	;balkstatus
	dc.l	amigainst	;30	;newinst
	dc.l	amigafx		;31
	dc.l	0

frequence:			;Frequenzen
	dc.w	0
	dc.w	33,35,37,39,41,44,46,49,52,55,58,62
	dc.w	65,69,73,78,82,87,92,98,104,110,117,123
	dc.w	131,139,147,156,165,175,185,196,208,220,233,247
	dc.w	262,277,294,311,330,349,370,392,415,440,466,494
	dc.w	523,554,587,622,659,698,740,784,831,880,932,988
	dc.w	1047,1109,1175,1245,1319,1397,1480,1568,1661,1760,1865,1976
	dc.w	2093

volumemults:	dc.b	63,63,50,38,26,14,4
		even

displaymults:	dc.b	0,1,2,3,4,6,8,12,16,24,32,48,1,2,4,8,16,32
		even


structmem:	ds.l	32
serialio:	ds.l	25
serialreply:	ds.l	9
track1:		ds.l	12
iinxe:		ds.l	32
sendmem:	dc.l	0
oktavs:		dc.l	0
modulmem:	dc.l	0
songbase:	dc.l	0
inststruct:	dc.l	0
moduladders:	dc.l	0
dosbase:	dc.l	0
infomem:	dc.l	0
scorename:	dc.l	0
scorelock:	dc.l	0
instlock:	dc.l	0
scorestruct:	dc.l	0
scorelänge:	dc.l	0
sendbytes:	dc.w	0
error:		dc.b	0
flag:		dc.b	0
basisinst:	dc.b	0
serverflag:	dc.b	0
longsets:	dc.b	0
playirq:	dc.b	0
serialflag:	dc.b	0
		even

dosname:	dc.b	"dos.library",0
		even
serialdevice:	dc.b	"serial.device",0
		even



	section	b2rdaten,data_c

notone:	dc.l	0

 END

