;	MED - by Teijo Kinnunen, 1989, 1990
;	med-player.a	- the player routine
custom	EQU	$dff000
dmacon	EQU	$096
aud0	EQU	$0A0
aud1	EQU	$0B0
aud2	EQU	$0C0
aud3	EQU	$0D0
ac_ptr	EQU	$00
ac_len	EQU	$04
ac_per	EQU	$06
ac_vol	EQU	$08
		xdef	_GetSerial
		xdef	_FreeSerial
		xdef	_AddMIDIData
		xdef	_AudioInit
		xdef	_AudioRem
		xdef	_ChannelOff
		xdef	_SetTempo
		xref	_tamakappale
		xref	_PiirraPylvas
		xref	_soitin
		xref	_aanipaalla
		xref	_zeroptr
		xref	_periodit
		xref	_specialupd
		xref	_counter
		xref	DrawEqualizer

		section	"text",code
		EVEN
		dc.b	' MEDPlayer is here!!!:'
waithwnum:	dc.l	500
newaptr:	dc.l	0,0,0,0
newalen:	dc.w	0,0,0,0
audaddr:	dc.l	custom+aud0,custom+aud1,custom+aud2,custom+aud3

_ChannelOff:	;d0 = channel #
		lea	prevmidinote,a0	;first: is it MIDI??
		move.b	0(a0,d0.w),d1
		beq.s	notcomidi	;not midi note
		clr.b	0(a0,d0.w)
		clr.l	noteondata	; new midi msg
		move.b	d1,noteondata+1
		lea	prevmidichan,a0
		move.b	0(a0,d0.w),noteondata	;prev midi channel
		or.b	#$80,noteondata		;note off
		lea	noteondata,a0
		moveq.l	#3,d0
		bra.w	_AddMIDIData
notcomidi:	cmp.b	#4,d0
		bge.s	notamigatrk
		moveq.l	#1,d1
		lsl.w	d0,d1
		move.w	d1,$dff096
notamigatrk:	rts
_SoitaNuotti:	;d0 = trk #, d1 = note #, d2 = vol, d3 = instr #
		movem.l	a2-a3/d3-d7,-(sp)	;All right, let's start!!
		move.w	d2,-(sp)
		clr.l	d4
		bset	d0,d4	;d4 is mask for this channel
		lea	_soitin,a0		;Is this instrument in mem?
		lsl.w	#2,d3			;d3 = instr.num << 2
		tst.l	0(a0,d3.w)
		bne.s	inmem
		lsr.w	#2,d3
		lea	_tamakappale+1574,a0
		tst.b	0(a0,d3.w)		;is MIDI channel set
		beq.w	retsn2			; NO!!!
		lsl.w	#2,d3
inmem:		lsr.w	#1,d3			;d3 = instr. num << 1
		lea	_aanipaalla,a0		;Is this track on??
		lsl.w	#1,d0			;d0 = track num << 1
		tst.w	0(a0,d0.w)
		beq.w	retsn2			; NO!!!!!!
		lsr.w	#1,d0
		add.b	_tamakappale+1550,d1	;add play transpose
		bgt.s	notenot2low
		add.b	#12,d1	;note was too low, octave up
		bra.s	endpttest
notenot2low:	cmp.b	#63,d1
		ble.s	endpttest
		sub.b	#12,d1	;note was too high, octave down
endpttest:	jsr	DrawEqualizer(pc)
		cmp.b	#4,d0
		bge.s	nodmaoff	;track # >= 4: not an Amiga channel
		move.w	d4,$dff096		;stop this channel (dmacon)
nodmaoff:	lea	prevmidinote,a0
		move.b	0(a0,d0.w),d6		;get prev. midi note
		beq.s	noprevmidi
		clr.b	0(a0,d0.w)
		move.b	d6,noteondata+1
		lea	prevmidichan,a0
		move.b	0(a0,d0.w),noteondata	;prev midi channel
		or.b	#$80,noteondata		;note off
		lea	noteondata,a0
		clr.b	2(a0)		;clear volume
		movem.l	d0-d1,-(sp)
		moveq.l	#3,d0
		bsr.w	_AddMIDIData
		movem.l	(sp)+,d0-d1
noprevmidi:	lea	_tamakappale+1574,a1
		lsr.w	#1,d3
		tst.b	0(a1,d3.w)
		bne.w	handleMIDInote
		cmp.b	#4,d0		;test track # again
		bge.w	retsn2		;no Amiga instruments in tracks > 3
		or.w	d4,dmaonmsk
		subq.b	#1,d1
		lsl.w	#1,d0
		lsl.w	#1,d3
		lea	newalen(pc),a2
		clr.w	0(a2,d0.w)
		move.w	d0,d6
		lsl.w	#1,d6			;d6 = channel num << 2
		move.w	d3,d7
		lsl.w	#1,d7			;d7 = instr. num << 2
		lea	audaddr,a1
		movea.l	0(a1,d6.w),a1	;base of this channel's regs
		lea	newaptr(pc),a3		;a3 = address of newaptr
		lea	_soitin,a2		;get the address of...
		move.l	0(a2,d7.w),d5		;...this instrument
		move.l	d5,a0
		bsr.w	getinsdata
		move.l	d0,ac_ptr(a1)		;put it in ac_ptr
		cmp.w	#2,d3
		bls.s	norepeat
		
		add.l	d2,d0		;d0 = starting address of repeat
		move.l	d0,0(a3,d6.w)	;remember!! (move to newaptr)
		lsr.w	#1,d3		;shift right
		lsr.w	#1,d6
		move.w	d3,16(a3,d6.w)	;remember too (newalen)
		lsr.w	#1,d2		;shift
		beq.s	begin0		;rep. start < 2
		move.w	d2,ac_len(a1)	;move repeat to hardware
		bra.s	retsn1
begin0:		move.w	d3,ac_len(a1)
		bra.s	retsn1
				
norepeat:	move.l	_zeroptr,0(a3,d6.w)	;pointer of zero word
		lea	newalen(pc),a3
		lsr.w	#1,d6
		move.w	#1,0(a3,d6.w)		;length: 1 word
		lsr.l	#1,d1			;shift length right
		move.w	d1,ac_len(a1)		;and put to custom chip

retsn1:		move.w	d5,ac_per(a1)	;getinsdata puts period to d5
		lea	prevper(pc),a0
		move.w	d5,0(a0,d6.w)
		move.w	(sp),ac_vol(a1)		;volume
		lsr.w	#2,d7		;d7 is now instr. number again
drawcol:	move.w	d7,d0		;to d0
		subq.w	#1,d0		;number of column
		clr.l	d1
		move.w	(sp),d1		;volume (height) to d1
		lsr.b	#1,d1		;to range 0 - 32
		and.b	#$fe,d1		;must be even
		beq.s	nodraw		;volume = 1, don't draw
		jsr	_PiirraPylvas(pc)	;draw it
nodraw:		move.b	_tamakappale+1551,d0	;flags
		btst	#1,d0			;jumping ??
		beq.s	retsn2			;no...
		btst	#2,d0			;with instruments
		bne.s	retsn2			;no......
		move.l	_tamakappale+1554,d0	;yes!!!, get instr. mask
		lsr.l	d7,d0			;set this instr. to bit #0
		btst	#0,d0			;and test it
		beq.s	retsn2			;no jump with this instr
		move.b	#1,animcnt		;init animation counter
retsn2:		addq.l	#2,sp	;forget volume
		movem.l	(sp)+,a2-a3/d3-d7
		rts

handleMIDInote:
		add.b	#23,d1		;2 octaves higher and -1
		move.b	d1,noteondata+1	;MIDI msg note #
		lea	prevmidinote(pc),a0
		move.b	d1,0(a0,d0.w)	;save this note number
		move.b	d2,d4		;temporary save the volume
		subq.b	#1,d2		;if 64 => 63
		lsl.b	#1,d2		;volume 0 - 63 => 0 - 127
		bclr	#7,d2		;be sure that bit 7 is clear
		move.b	d2,noteondata+2	;MIDI msg volume
		clr.w	d1
		move.b	0(a1,d3.w),d1	;get midi chan of this instrument
		subq.b	#1,d1		;from 1-16 to 0-15
		lea	prevmidichan(pc),a0
		move.b	d1,0(a0,d0.w)	;save to prev midi channel
		move.b	#$90,noteondata	;MIDI: Note on
		or.b	d1,noteondata	;MIDI msg Note on & channel
		move.b	32(a1,d3.w),d2	;get preset #
		beq.s	nochgpres	;zero = no preset
		lea	prevmchpreset(pc),a0
		move.b	0(a0,d1.w),d0
		cmp.b	d2,d0		;is this previous preset ??
		beq.s	nochgpres	;yes...no need to change
		move.b	#$c0,preschgdata
		or.b	d1,preschgdata
		move.b	d2,0(a0,d1.w) ;save preset to prevmchpreset
		subq.b	#1,d2
		move.b	d2,preschgdata+1
		lea	preschgdata,a0
		moveq.l	#5,d0
		bra.s	preschanged
nochgpres:	moveq.l	#3,d0
		lea	noteondata,a0
preschanged:	bsr.w	_AddMIDIData
		move.w	d3,d7
		bra.w	drawcol

_StartDMA:		;This small routine turns on audio DMA
		move.w	dmaonmsk,d0	;dmaonmsk contains the mask of
		beq.s	retsdma	;the channels that must be turned on
		bset	#15,d0	;DMAF_SETCLR: set these bits in dmacon
		move.l	waithwnum,d1
waithw0:	dbf	d1,waithw0
		move.w	d0,custom+dmacon	;do that!!!
		move.l	waithwnum,d1
waithw1:	dbf	d1,waithw1
		lsr.b	#1,d0	;finally, push new ptrs to audio hw regs
		bcc.s	pushch1
		move.l	newaptr(pc),custom+aud0+ac_ptr
		move.w	newalen(pc),custom+aud0+ac_len
pushch1:	lsr.b	#1,d0
		bcc.s	pushch2
		move.l	newaptr+4(pc),custom+aud1+ac_ptr
		move.w	newalen+2(pc),custom+aud1+ac_len
pushch2:	lsr.b	#1,d0
		bcc.s	pushch3
		move.l	newaptr+8(pc),custom+aud2+ac_ptr
		move.w	newalen+4(pc),custom+aud2+ac_len
pushch3:	lsr.b	#1,d0
		bcc.s	retsdma
		move.l	newaptr+12(pc),custom+aud3+ac_ptr
		move.w	newalen+6(pc),custom+aud3+ac_len
retsdma:	rts

		xref	_mouse1
		xref	_mouse2
		xref	_mouse3
		xref	_mouse4
		xref	_mouse5
frame:	dc.l	0,_mouse2,_mouse3,_mouse4,_mouse5,_mouse5,_mouse4,_mouse3
	dc.l	_mouse2,_mouse1,0
dmaonmsk:	dc.w	0
animcnt:	dc.b	0,0
prevmidinote:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
prevmidichan:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
prevpitchbend:	dc.w	$2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
		dc.w	$2000,$2000,$2000,$2000,$2000,$2000,$2000,$2000
prevmchpreset:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;previous preset
prevper:	dc.w	0,0,0,0
prevnote:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
previnstr:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
prevvol:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
effect:		dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
effectqual:	dc.b	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
nextblock:	dc.b	0
animpause:	dc.b	1
numtracks:	dc.b	0,0
		xref	_soittotila
		xref	_soittolohko
		xref	_lohko
		xref	_soittorivi
		xref	_soittolohkonnum
		xref	_lohkoja
		xref	_naytonpaivitys
		xref	_maintsk
		xref	_nayttomsk
		xref	_tempo
		xref	_sprptr
		xref	_hyppymsk
		xref	_komento
_IntHandler:
		movem.l	d2-d7/a2-a4,-(sp)
		cmp.w	#5,_komento ;Do we have to play note from keyboard
		bne.s	nokbnote	;no...just normal playing
		lea	_komento,a1	;get the address of the structure
		lea	_tamakappale+1284,a2	;and the song
		clr.w	dmaonmsk
		clr.w	d0
		clr.w	d1
		move.b	8(a1),d0	;get all these values from
		move.b	5(a1),d1	;the command structure
		move.w	6(a1),d3
		clr.w	d2
		move.b	0(a2,d3.w),d2
		clr.w	(a1)		;clear the command word
		bsr	_SoitaNuotti	;and play the note finally
		bsr	_StartDMA
		bra.s	notplaying	;exit
nokbnote:	tst.w	_soittotila	;are we playing
		bne.s	playing		;yes, we are
		bclr.b	#0,$bfee01	;no...stop the timer
		move.b	#$05,_counter
		clr.b	animcnt
		move.l	frame+36,_sprptr
		bra.w	sigjump
notplaying:	movem.l	(sp)+,d2-d7/a2-a4	;exit interrupt
		rts
playing:	clr.w	dmaonmsk
		add.b	#1,_counter
		cmp.b	#6,_counter	;if counter = 6: new note and fx
		bne.w	nonewnote	;if counter is not 6: just do fx
		clr.b	_counter		;new note!!!
		clr.l	d7		;number of track
		lea	_lohko,a2	;a2 = address of 1st block's address
		move.w	_soittolohko,d2
		lsl.w	#2,d2		;shift to longword index
		movea.l	0(a2,d2.w),a2	;get the pointer of the block
		move.b	(a2),numtracks+1	;save # of tracks
		addq.l	#4,a2		;skip...
		move.w	numtracks,d3
		mulu	#3,d3
		move.w	_soittorivi,d2
		mulu	d2,d3
		adda.l	d3,a2		;a2 = address of this line
		lea	prevnote(pc),a3
		lea	_tamakappale,a4
trloop0:	clr.w	d5
		move.b	(a2)+,d5	;get the number of this note
		move.b	(a2)+,d6	;and the 4 numbers containing fx
		lsl.w	#8,d6
		move.b	(a2)+,d6
		lea	effectqual(pc),a1
		move.b	d6,0(a1,d7.w)	;save the fx numbers
		clr.b	d4		;d4 is a flag: if set, instr. is
		btst	#7,d5		;in range G-V. If clr, it's 1-F.
		beq.s	nogtov		;In the song, if bit #7 is set in
		bclr	#7,d5		;note number byte, it's G-V
		st.b	d4		;this instrument is in range G-V
nogtov:		move.w	#$f000,d0
		and.w	d6,d0		;d0 now contains only the # of instr
		bne.s	instnum		;instrument number is not 0
		tst.b	d4		;maybe it's G (instr. #0, d4 set)
		beq.s	noinstnum	;no. It's 0!!!
instnum:	lsr.w	#8,d0		;shift it right to get number 0-F
		lsr.b	#4,d0
		tst.b	d4
		beq.s	nogtov2
		add.w	#16,d0		;if G-V, add 16 to the number
nogtov2:	lea	previnstr(pc),a1
		move.b	d0,0(a1,d7.w) ;remember instr. number!
		lea	prevvol(pc),a1
		add.w	#1284,d0	;offset of volumes in song struct
		move.b	0(a4,d0.w),0(a1,d7.w)	;vol of this instr to prevvol
noinstnum:	move.w	d6,d0		;effect again...
		lsr.w	#8,d0
		and.b	#$0f,d0		;now check only the effect part
		lea	effect(pc),a1
		move.b	d0,0(a1,d7.w)	;save the effect number
		beq.s	noeffect	;no effect
		cmp.b	#$0f,d0		;yes effect...is it Tempo???
		bne.s	not0f		;not Tempo
		tst.b	d6		;Tempo !!!
		beq.s	fx0fchgblck	;if effect qualifier (last 2 #'s)..
		cmp.b	#$f0,d6		;..is zero, go to next block
		bhi.s	fx0fspecial	;if it's F1-FF something special
		clr.l	d0		;will happen!!!
		move.b	d6,d0
		bsr	_SetTempo	;change The Tempo
		bra.s	noeffect
fx0fspecial:	cmp.b	#$f2,d6	; | rest - play | SpecialFX#2: no note..yet
		bne.s	isfxfe	;not SpecFX2
		move.b	d5,(a3)	;Yes!!! Save the note number
		clr.w	d5	; clear the number for awhile
		bra.s	noeffect
isfxfe:		cmp.b	#$fe,d6
		bne.s	noeffect
		clr.w	_soittotila
		or.b	#2,_specialupd
		bra.s	noeffect
fx0fchgblck:	st.b	nextblock	;next block????...YES!!!! (F00)
		bra.s	noeffect
not0f:		cmp.b	#$0c,d0		;new volume???
		bne.s	noeffect	;NO!!!!!!!!!!!!!!!!!!!!!!
		move.b	d6,d0
		lsr.b	#4,d0		;Strange code begins now
		mulu	#10,d0
		move.b	d6,d1
		and.b	#$0f,d1
		add.b	d1,d0		;strange code ends now: d0 is vol
		cmp.b	#64,d0
		bls.s	novolov64
		moveq.l	#64,d0
novolov64	lea	prevvol(pc),a1
		move.b	d0,0(a1,d7.w)	;and save it....
noeffect:	tst.b	d5	;Now we'll check if we have to play a note
		beq.s	endtrkloop	;no.
		move.b	d5,(a3)
		move.w	d7,d0
		move.w	d5,d1
		clr.w	d2
		clr.w	d3
		lea	previnstr(pc),a1
		move.b	0(a1,d7.w),d3
		lea	prevvol(pc),a1
		move.b	0(a1,d7.w),d2	;get volume
		bsr	_SoitaNuotti	;play it!!!!!!!!!!!
endtrkloop:	addq.l	#1,a3		;a3 = pointer to prev. note #
		addq.l	#1,d7
		cmp.w	numtracks,d7
		blt.w	trloop0

		add.w	#1,_soittorivi	;very important!!! advance line!!
		cmp.w	#63,_soittorivi	;important too!!! advance block??
		bgt.s	chgblock	;yes!!!
		tst.b	nextblock	;command F00 ??
		beq.s	nochgblock	;no, don't change block
chgblock:	clr.w	_soittorivi	;clear line number
		cmp.w	#2,_soittotila	;play block or play song
		bne.s	nonewseq	;play block only...
		add.w	#1,_soittolohkonnum	;advance sequence number
		move.w	1546(a4),d0	;get the highest seq number
		move.w	_soittolohkonnum,d1	;and current seq number
		cmp.w	d0,d1	;is this the highest seq number
		blt.s	nostartagain	;no
		clr.w	_soittolohkonnum	;yes: play song again
		clr.w	d1			;...forever!!!
nostartagain:	clr.w	d0
		lea	1446(a4),a1	;offset of sequence table
		move.b	0(a1,d1.w),d0	;get number of the block
		move.w	d0,_soittolohko	;and put it to block number var
		move.w	_lohkoja,d1	;get number of blocks
		subq.w	#1,d1		;# of blocks-1 = # of highest block
		cmp.w	d1,d0		;is this block number too big
		blt.s	nonewseq	;no
		move.w	d1,_soittolohko	;yes..then play just the last block
nonewseq:	clr.b	nextblock	;clear this if F00 set it
nochgblock:	tst.w	_naytonpaivitys	;screen updating on??
		beq.s	nonewnote	;no
		movea.l	_maintsk,a1	;ask the main task to update screen
		move.l	_nayttomsk,d0
		jsr	-$144(a6)	;Signal()
nonewnote:
;	*********************** This code produces the effects **
		clr.l	d7	;clear track count
		lea	prevper(pc),a3
		lea	prevvol(pc),a4
trloop1:	clr.w	d5
		lea	effect,a1
		clr.w	d4
		move.b	0(a1,d7.w),d6	;get the fx number
		lea	effectqual,a1
		move.b	0(a1,d7.w),d4	;and the last 2 #'s
		lea	prevmidinote,a0	;first: is it MIDI??
		tst.b	0(a0,d7.w)
		bne.w	midifx
		cmp.b	#1,d6		;effect #1
		bne.s	nofx01
;	**************************************** Effect 01 ******
		cmp.w	#5,_tamakappale+1552
		bne.s	nost1
		tst.b	_counter
		beq	newvals
nost1:		sub.w	d4,(a3)	;slide it up!!!
		cmp.w	#113,(a3)	;too high???
		bge	newvals
		move.w	#113,(a3)	;yes, too high!!!
		bra	newvals
;	*********************************************************
nofx01:		cmp.b	#2,d6
		bne.s	nofx02
;	**************************************** Effect 02 ******
		cmp.w	#5,_tamakappale+1552
		bne.s	nost2
		tst.b	_counter
		beq	newvals
nost2:		add.w	d4,(a3)	;slide it down!!!!!!!!!
		cmp.w	#856,(a3)	;too low??
		ble	newvals
		move.w	#856,(a3)	;too low.
		bra	newvals
;	*********************************************************
nofx02:		tst.b	d6
		bne.s	nofx00
;	**************************************** Effect 00 ******
		tst.b	d4	;both fxqualifiers are 0s: no arpeggio!!
		beq.w	endl
		lea	prevnote,a1
		bsr.w	DoArpeggio
		subq.b	#1,d4		;-1 to make it 0 - 127
		add.b	_tamakappale+1550,d4	;add play transpose
		lsl.b	#1,d4		;shift to make index for UWORD
		lea	_periodit,a1
		move.w	0(a1,d4.w),d5
		bra.w	newvals
;	*********************************************************
nofx00:		cmp.b	#$0d,d6
		bne.s	nofx0d
;	**************************************** Effect 0D ******
		move.b	d4,d1
		move.b	(a4),d0	;move previous vol to d0
		and.b	#$f0,d1
		bne.s	crescendo
		sub.b	d4,d0	;sub from prev. vol
		bpl.s	novolund0
		clr.b	d0	;volumes under zero not accepted!!!
novolund0:	move.b	d0,(a4)	;put new vol back
		bra	newvals
crescendo:	lsr.b	#4,d1
		add.b	d1,d0
		cmp.b	#64,d0
		ble.s	novolover64
		moveq.l	#64,d0
novolover64:	move.b	d0,(a4)
		bra	newvals
;	*********************************************************
nofx0d:		cmp.b	#3,d6
		bne.s	nofx03
;	**************************************** Effect 03 ******
		move.w	(a3),d5	;this is very simple: get the old period
		cmp.b	#3,_counter	;and..
		bge.w	newvals		;if counter < 3
		sub.w	d4,d5	;subtract effect qualifier
		bra.w	newvals
;	*********************************************************
nofx03:		cmp.b	#$0f,d6
		bne.s	nofx0f
;	**************************************** Effect 0F ******
fx0f:		cmp.b	#$ff,d4
		bne.s	no0fff
		move.w	d7,d0
		bsr.w	_ChannelOff
		bra.w	endl
no0fff:		cmp.b	#$f1,d4
		bne.s	no0ff1
		cmp.b	#3,_counter
		bne.s	newvals
		bra.s	playfxnote
no0ff1:		cmp.b	#$f2,d4
		bne.s	no0ff2
		cmp.b	#3,_counter
		bne.s	newvals
		bra.s	playfxnote
no0ff2:		cmp.b	#$f3,d4
		bne.s	endl
		move.b	_counter,d0
		and.b	#2+4,d0		;is 2 or 4
		beq.s	newvals
playfxnote:	move.w	d7,d0		;track # to d0...
		lea	prevnote(pc),a1
		clr.w	d1
		move.b	0(a1,d7.w),d1	;get note # of previous note
		clr.w	d2
		move.b	(a4),d2		;get previous volume
		lea	previnstr(pc),a1
		clr.w	d3
		move.b	0(a1,d7.w),d3
		bsr	_SoitaNuotti
		bra.s	endl
;	*********************************************************
nofx0f:		cmp.b	#$0e,d6
		bne.s	nofx0e
fx0e:		or.b	#1,_specialupd
		tst.b	d4
		bne.s	filteroff
		bclr	#1,$bfe001
		bra.s	endl
filteroff:	bset	#1,$bfe001
		bra.s	endl
nofx0e:		cmp.b	#$0c,d6
		bne.s	endl
newvals:	tst.w	d5	;now: do the effects!!!
		bne.s	nonewper
		move.w	(a3),d5	;no new period specified: get the old
nonewper:	move.w	d7,d4	;channel number to d4
		lsl.w	#2,d4	;and shift it to make it a longword index
		lea	audaddr,a1
		movea.l	0(a1,d4.w),a1
		move.w	d5,ac_per(a1)
		clr.w	d5
		move.b	(a4),d5
		move.w	d5,ac_vol(a1)
endl:		addq.l	#2,a3	;inc pointer to previous period value
		addq.l	#1,a4	;and previous volume
		addq.l	#1,d7	;increment channel number
		cmp.w	numtracks,d7	;all channels done???
		blt.w	trloop1	;not yet!!!

		bsr	_StartDMA	;turn on DMA
		move.b	_tamakappale+1551,d0	;get the flags
		btst	#1,d0		;is Topi's jumping on ???
		beq.w	exitint		;no
		btst	#2,d0		;every 8th note ???
		beq.s	no8th
		move.w	#$0007,d0
		and.w	_soittorivi,d0	;is this 8th note ??
		bne.s	no8th		;no...
		tst.b	animcnt
		bne.s	no8th
		tst.w	_soittotila
		beq.s	no8th
		move.b	#1,animcnt
no8th:		tst.b	animcnt
		beq.s	exitint
		add.b	#1,animpause	;Handles all animation
		cmp.b	#2,animpause
		blt.s	exitint
		cmp.b	#10,animcnt
		bne.s	nojumpend
		clr.b	animcnt
		move.b	#1,animpause
		bra.s	exitint
nojumpend:	clr.w	d0
		move.b	animcnt,d0
		add.b	#1,animcnt
		lsl.w	#2,d0
		lea	frame(pc),a1
		move.l	0(a1,d0.w),_sprptr
		tst.w	_naytonpaivitys
		beq.s	exitint
sigjump:	movea.l	_maintsk,a1	;and asks the main task to...
		move.l	_hyppymsk,d0	;...SetPointer() !!!!!
		jsr	-$144(a6)	;Signal()
		clr.b	animpause
exitint:	movem.l	(sp)+,d2-d7/a2-a4
		rts
_SetTempo:	move.w	d0,_tempo
		cmp.b	#10,d0	;If tempo <= 10, use SoundTracker tempo
		bhi.s	calctempo
		lea	sttempo(pc),a1
		lsl.w	#1,d0
		move.w	0(a1,d0.w),d1
		bra.s	pushtempo
calctempo:	move.l	#470000,d1
		divu	d0,d1
pushtempo:	move.b	d1,$bfe401	;and set the CIA timer
		lsr.w	#8,d1
		move.b	d1,$bfe501
		or.b	#4,_specialupd
		rts	; vv-- These values are the SoundTracker tempos (approx.)
sttempo:	dc.w	$0f00,2417,4833,7250,9666,12083,14500,16916,19332,21436,24163

midifx:		cmp.b	#1,d6
		bne.s	nomidi01fx
		lea	prevmidichan,a1
		lea	prevpitchbend,a0
		clr.w	d1
		move.b	0(a1,d7.w),d1	;get previous midi channel
		lsl.w	#1,d1		;UWORD index
		tst.b	d4		;x100??
		beq.s	resetpbend
		move.w	0(a0,d1.w),d0	;get previous pitch bend
		lsl.w	#3,d4		;multiply bend value by 8
		add.w	d4,d0
		cmp.w	#$3fff,d0
		bls.s	bendpitch
		move.w	#$3fff,d0
bendpitch:	move.w	d0,0(a0,d1.w)	;save current pitch bend
		lsr.b	#1,d1		;back to UBYTE
		or.b	#$e0,d1
		lea	noteondata,a0
		move.b	d1,(a0)		;midi command & channel
		move.b	d0,1(a0)	;lower value
		and.b	#$7f,1(a0)	;clear bit 7
		lsr.w	#7,d0
		and.b	#$7f,d0		;clr bit 7
		move.b	d0,2(a0)	;higher 7 bits
		moveq.l	#3,d0
		bsr.w	_AddMIDIData
		bra.w	endl
nomidi01fx:	cmp.b	#2,d6
		bne.s	nomidi02fx
		lea	prevmidichan,a1
		lea	prevpitchbend,a0
		clr.w	d1
		move.b	0(a1,d7.w),d1
		lsl.w	#1,d1
		tst.b	d4
		beq.s	resetpbend	;x200??
		move.w	0(a0,d1.w),d0
		lsl.w	#3,d4
		sub.w	d4,d0
		bpl.s	bendpitch	;not under 0
		clr.w	d0
		bra.s	bendpitch
nomidi02fx:	cmp.b	#$0f,d6
		beq.w	fx0f
		cmp.b	#$0e,d6
		bne.w	endl
		bra.w	fx0e
resetpbend:	tst.b	_counter
		bne.w	endl
		move.w	#$2000,d0
		bra.s	bendpitch

DoArpeggio:	; beginning note table in a1, note num returned in d4
		move.b	0(a1,d7.w),d1	;d1 = # of previous note played
		move.b	_counter,d0
		tst.b	d0
		beq.s	arpg03
		cmp.b	#3,d0
		bne.s	arpgn03
arpg03:		and.b	#$0f,d4		;counter = 0 or 3: get last number
		add.b	d1,d4		;add it to note number
		rts
arpgn03:	cmp.b	#1,d0
		beq.s	arpg14
		cmp.b	#4,d0
		bne.s	arpgn14
arpg14:		lsr.b	#4,d4	;counter = 1 or 4: get the first number
		add.b	d1,d4	;add to prev. note
		rts
arpgn14:	move.b	d1,d4	;2 or 5: the previous note
		rts

getinsdata:	clr.l	d2
		move.w	4(a0),d0	;Soitin-struct in a0, instr#<<1: d3
		bne.s	iff5or3oct	;note # in d1 (0 - ...)
		move.l	a0,d0
		lea	_periodit,a0
		lsl.b	#1,d1
		move.w	0(a0,d1.w),d5 ;put period to d5
		move.l	d0,a0
		addq.l	#6,d0		;Skip structure
		move.l	(a0),d1		;length
		lea	_tamakappale+1316,a0
		move.w	0(a0,d3.w),d2
		move.w	64(a0,d3.w),d3
		rts
iff5or3oct:	movem.l	a1/d6-d7,-(sp)
		clr.l	d7
		move.w	d1,d7
		divu	#12,d7	;octave #
		move.l	d7,d5
		swap	d5	;note number in this oct (0-11) is in d5
		move.l	(a0),d1
		cmp.b	#2,d0
		bne.s	no3oct
		addq.l	#6,d7
		divu	#7,d1	;get length of the 1st octave
		bra.s	no5oct
no3oct:		divu	#31,d1	;get length of the 1st octave (5 octaves)
no5oct:		move.l	d1,d0		;d0 and d1 = length of the 1st oct
		lea	_tamakappale+1316,a1
		move.w	0(a1,d3.w),d2
		move.w	64(a1,d3.w),d3
		clr.w	d6
		move.b	shiftcnt(pc,d7.w),d6
		lsl.w	d6,d2
		lsl.w	d6,d3
		lsl.w	d6,d1
		move.b	mullencnt(pc,d7.w),d6
		mulu	d6,d0		;offset of this oct from 1st oct
		add.l	a0,d0		;add base address to offset
		addq.l	#6,d0		;skip structure
		lea	_periodit,a1
		add.b	octstart(pc,d7.w),d5
		lsl.b	#1,d5
		move.w	0(a1,d5.w),d5
		movem.l	(sp)+,a1/d6-d7
		rts	;returns period in d5
shiftcnt:	dc.b	4,3,2,1,1,0,2,2,1,1,0,0
mullencnt:	dc.b	15,7,3,1,1,0,3,3,1,1,0,0
octstart:	dc.b	12,12,12,12,24,24,0,12,12,24,24,36

		xref	_ciaaresource
		xref	_maintsk

_AudioInit:	movem.l	a6/d2,-(sp)
		clr.l	d2
		movea.l	4,a6
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ alloc signal bit
		addq.l	#1,d2
		st.l	d0	; -1
		jsr	-$14a(a6)	;AllocSignal()
		tst.b	d0
		bmi.w	initerr
		move.b	d0,sigbitnum
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ prepare IORequest
		lea	allocport(pc),a1
		move.b	d0,15(a1)	;set mp_SigBit
		move.l	_maintsk,16(a1)	;set mp_SigTask
		lea	reqlist(pc),a0
		move.l	a0,(a0)		;NEWLIST begins...
		addq.l	#4,(a0)
		clr.l	4(a0)
		move.l	a0,8(a0)	;NEWLIST ends...
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ open audio.device
		addq.l	#1,d2
		lea	allocreq(pc),a1
		lea	audiodevname(pc),a0
		clr.l	d0
		clr.l	d1
		movea.l	4,a6
		jsr	-$1bc(a6)	;OpenDevice()
		tst.b	d0
		bne.s	initerr
		st.b	audiodevopen
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ open ciaa.resource
		addq.l	#1,d2
		clr.l	d0
		lea	ciaaname(pc),a1
		jsr	-$1f2(a6)	;OpenResource()
		tst.l	d0
		beq.s	initerr
		move.l	d0,_ciaaresource
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ attach interrupt
		addq.l	#1,d2
		move.l	d0,a6
		lea	timerinterrupt(pc),a1
		clr.l	d0	;Bit number 0: Timer A
		jsr	-$6(a6)	;AddICRVector
		tst.l	d0
		bne.s	initerr
		and.b	#%10000000,$bfee01
		move.l	#%10000001,d0
		jsr	-$12(a6)	;AbleICR()
		st.b	timeropen
		clr.w	_soittotila
		clr.l	d0
initret:	movem.l	(sp)+,a6/d2
		rts
initerr:	move.l	d2,d0
		bra.s	initret

_AudioRem:	move.l	a6,-(sp)
		tst.b	timeropen
		beq.s	rem1
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ remove interrupt
		move.l	_ciaaresource,a6
		lea	timerinterrupt(pc),a1
		clr.l	d0	;Bit number 0: Timer A
		jsr	-$c(a6)		;RemICRVector
;There is no CloseResource(). I'm not sure if I should use CloseLibrary()??
rem1:		movea.l	4,a6
		tst.b	audiodevopen
		beq.s	rem2
		move.w	#$000f,$dff096	;stop audio DMA
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ close audio.device
		lea	allocreq(pc),a1
		jsr	-$1c2(a6)	;CloseDevice()
rem2:		clr.l	d0
		move.b	sigbitnum,d0
		bmi.s	rem3
;	+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ free signal bit
		jsr	-$150(a6)	;FreeSignal()
rem3:		move.l	(sp)+,a6
		rts

_GetSerial:	move.l	a6,-(sp)	;Get serial port for MIDI
		move.l	4,a6
		clr.l	d0
		lea	miscresname(pc),a1
		jsr	-$1f2(a6)	;OpenResource()
		move.l	d0,miscresbase
		tst.l	d0
		beq.s	gserror
		move.l	d0,a6
		lea	medname(pc),a1
		clr.l	d0		;serial port
		jsr	-$6(a6)		;AllocMiscResource()
		tst.l	d0
		bne.s	gserror
		st.b	serportalloc
		moveq.l	#0,d0		;TBE
		lea	serinterrupt(pc),a1
		move.l	4,a6
		jsr	-$a2(a6)	;SetIntVector()
		move.l	d0,prevtbe
		moveq.l	#11,d0		;RBF
		lea	rbfinterrupt(pc),a1
		jsr	-$a2(a6)	;SetIntVector()
		move.l	d0,prevrbf
		move.w	#$8001,$dff09a	;TBE on!!
		move.w	#114,$dff032	;set baud rate (SERPER)
		clr.l	d0
retgs:		move.l	(sp)+,a6
		rts
gserror:	st	d0
		bra.s	retgs

_FreeSerial:	move.l	a6,-(sp)
		tst.l	miscresbase
		beq.s	retfs
		tst.b	serportalloc
		beq.s	retfs
		move.w	#$0801,$dff09a	;disable RBF & TBE
		movea.l	prevtbe(pc),a1
		moveq.l	#0,d0
		movea.l	4,a6
		jsr	-$a2(a6)	;SetIntVector()
		movea.l	prevrbf(pc),a1
		moveq.l	#11,d0
		jsr	-$a2(a6)	;SetIntVector()
		movea.l	miscresbase(pc),a6
		clr.l	d0		;serial port
		jsr	-$c(a6)		;FreeMiscResource()
		clr.b	serportalloc
retfs:		move.l	(sp)+,a6
		rts

prevtbe:	dc.l	0
prevrbf:	dc.l	0		
		xref	_recmidi
		xref	_recmidimsk

RBFIntHandler:	move.w	$18(a0),d0	;SERDATR
		move.w	#$0800,$9c(a0)	;clr intreq
		btst	#7,d0		;status??
		beq.s	nostatus
		move.b	d0,(a1)
		move.b	#$1,3(a1)
		rts
nostatus:	clr.w	d1
		move.b	3(a1),d1
		move.b	d0,0(a1,d1.w)
		addq.b	#1,d1
		cmp.b	#3,d1
		bge.s	sigmidirec
		move.b	d1,3(a1)
		rts
sigmidirec:	move.b	#$1,3(a1)
		and.b	#$f0,(a1)
		cmp.b	#$90,(a1)
		bne.s	nosrec
		move.b	1(a1),_recmidi
		movea.l	_maintsk,a1
		move.l	_recmidimsk,d0
		jsr	-$144(a6)	;Signal()
nosrec:		rts
recmidi:	dc.b	0,0,0,0
		
SerIntHandler:	move.w	#1,$9c(a0)	;clear intreq bit
		clr.l	d0
		move.b	bytesinbuff(pc),d0
		beq.s	exsih		;buffer empty
		move.w	#$100,d1	;Stop bit
		move.b	sendbuffer(pc),d1
		move.w	d1,$30(a0)	;SERDAT
		move.w	#$4000,$9a(a0) ;NO ONE may stop us!!!
		addq.b	#1,$126(a6)
		lea	sendbuffer(pc),a5
shiftdataloop:	subq.b	#1,d0		;shift serial buffer 1 byte left
		beq.s	endshiftloop
		move.b	(a1)+,(a5)+	;a1 = is_Data = sendbuffer + 1
		bra.s	shiftdataloop
endshiftloop:	subq.b	#1,bytesinbuff
		subq.b	#1,$126(a6)
		bge.s	exsih
		move.w	#$c000,$9a(a0)
exsih:		rts

_AddMIDIData:	tst.b	serportalloc
		beq.s	retamd
		movem.l	d2/a6,-(sp)
		movea.l	4,a6
		move.w	#$4000,$dff09a	;No interrupts...
		addq.b	#1,$126(a6)
		clr.w	d1
		clr.b	d2
		move.b	bytesinbuff(pc),d1
		seq.b	d2
		add.b	d0,d1
		cmp.b	#127,d1
		bgt.s	overflow	;sorry, can't do anything.
		move.b	d1,bytesinbuff
		sub.b	d0,d1
		lea	sendbuffer(pc,d1.w),a1
adddataloop:	move.b	(a0)+,(a1)+
		subq.b	#1,d0
		bne.s	adddataloop
overflow:	subq.b	#1,$126(a6)
		bge.s	nointena
		move.w	#$c000,$dff09a
nointena:	tst.b	d2
		beq.s	nonewtbe
		move.w	#$8001,$dff09c	;request TBE
nonewtbe:	movem.l	(sp)+,d2/a6
retamd:		rts

sendbuffer:	ds.b	128
miscresbase:	dc.l	0
noteondata:	dc.l	0
audiodevopen:	dc.b	0
timeropen:	dc.b	0
serportalloc:	dc.b	0
bytesinbuff:	dc.b	0
preschgdata:	dc.b	0,0
pbendresdata:	dc.b	$e0,$00,$40 ;for fast pitch bend resetting
sigbitnum:	dc.b	-1
timerinterrupt:	dc.w	0,0,0,0,0
		dc.l	timerintname,0,_IntHandler
serinterrupt:	dc.w	0,0,0,0,0
		dc.l	serintname,sendbuffer+1,SerIntHandler
rbfinterrupt:	dc.w	0,0,0,0,0
		dc.l	rbfintname,recmidi,RBFIntHandler
allocport:	dc.l	0,0	;succ, pred
		dc.b	4,0	;NT_MSGPORT
		dc.l	0	;name
		dc.b	0,0	;flags = PA_SIGNAL
		dc.l	0	;task
reqlist:	dc.l	0,0,0	;list head, tail and tailpred
		dc.b	5,0
allocreq:	dc.l	0,0
		dc.b	5,127	;NT_MESSAGE, maximum priority (127)
		dc.l	0,allocport	;name, replyport
		dc.w	68		;length
		dc.l	0	;io_Device
		dc.l	0	;io_Unit
		dc.w	0	;io_Command
		dc.b	0,0	;io_Flags, io_Error
		dc.w	0	;ioa_AllocKey
		dc.l	sttempo	;ioa_Data
		dc.l	1	;ioa_Length
		dc.w	0,0,0	;ioa_Period, Volume, Cycles
		dc.w	0,0,0,0,0,0,0,0,0,0	;ioa_WriteMsg
ciaaname:	dc.b	'ciaa.resource',0
timerintname:	dc.b	'MEDTimerInterrupt',0
serintname:	dc.b	'MEDSerialInterrupt',0
rbfintname:	dc.b	'MEDSerialRBFInt',0
audiodevname:	dc.b	'audio.device',0
miscresname:	dc.b	'misc.resource',0
medname:	dc.b	'MED',0 ;yeah, our name
		end
