;PS3M Replay version 0.942/020+ / 30.10.1994
;Copyright (c) Jarno Paananen a.k.a. Guru / S2 1994-95

;Some portions based on STMIK 0.9ß by Sami Tammilehto / PSI of Future Crew

;ASM-ONE 1.20 or newer is required unless disable020 is set to 1, when
;at least 1.09 (haven't tried older) is sufficient.


*****************************************************************************
** Contraption by K-P / HpD / iNS (14.12.1995)
** What's left: killermode, 000/020+ mixingroutines, all 5 playmodes, and
** the S3M replayer.
*****************************************************************************

MONO = 1
STEREO = 2
SURROUND = 3
REAL = 4
STEREO14 = 5

mtS3M = 1

ENABLED = 0
DISABLED = 1

* Mixauspuskurin koko

BUFFER = 4*1024					; MUST BE 2^N
						; MIN 4K

disable020 = 0


	incdir	include:

	include	exec/execbase.i
	include	exec/exec_lib.i
	include	exec/memory.i
	include	graphics/graphics_lib.i
	
	include	Guru.i
	include	ps3m.i



pushm	macro
	ifc	"\1","all"
	movem.l	d0-a6,-(sp)
	else
	movem.l	\1,-(sp)
	endc
	endm

popm	macro
	ifc	"\1","all"
	movem.l	(sp)+,d0-a6
	else
	movem.l	(sp)+,\1
	endc
	endm

push	macro
	move.l	\1,-(sp)
	endm

pop	macro
	move.l	(sp)+,\1
	endm

lob	macro
	jsr	_LVO\1(a6)
	endm

iword	macro
	ror	#8,\1
	endm

ilword	macro
	ror	#8,\1
	swap	\1
	ror	#8,\1
	endm

tlword	macro
	move.b	\1,\2
	ror.l	#8,\2
	move.b	\1,\2
	ror.l	#8,\2
	move.b	\1,\2
	ror.l	#8,\2
	move.b	\1,\2
	ror.l	#8,\2
	endm

tword	macro
	move.b	\1,\2
	ror	#8,\2
	move.b	\1,\2
	ror	#8,\2
	endm



s3init	
	move.l	4.w,a6
	lea	gfxname,a1
	lob	OldOpenLibrary
	move.l	d0,gfxbase
	

	clr	PS3M_eject
	clr	PS3M_position
	clr	PS3M_wait
	clr	PS3M_play
	clr	PS3M_initialized


	move.l	#28000,mixingrate	* Mixingrate (0-n)
	move.l	#2,vboost		* Volumeboost (0-8)
	move.l	#module,s3m		* module address
	move	#SURROUND,pmode		* playmode
;	move	#STEREO14,pmode		* playmode


	bsr.w	init

	move	#$40,PS3M_master	* master volume


	lea	data,a5
	basereg	data,a5

*** Alloc mem


	move.l	#BUFFER,d0
	move.l	d0,buffSize(a5)
	subq.l	#1,d0
	move.l	d0,buffSizeMask(a5)
	lsl.l	#8,d0
	move.b	#$ff,d0
	move.l	d0,buffSizeMaskFF

	move.l	4.w,a6

	move.l	#1024*4*2,d0
	move.l	#MEMF_PUBLIC!MEMF_CLEAR,d1
	lob	AllocMem
	move.l	d0,tbuf(a5)
	beq.w	.memerr
	add.l	#1024*4,d0
	move.l	d0,tbuf2(a5)	

	move.l	buffSize(a5),d0
	move.l	#MEMF_CHIP!MEMF_CLEAR,d1
	lob	AllocMem
	move.l	d0,buff1(a5)
	beq.w	.memerr

	move.l	buffSize(a5),d0
	move.l	#MEMF_CHIP!MEMF_CLEAR,d1
	lob	AllocMem
	move.l	d0,buff2(a5)
	beq.w	.memerr

	move.l	#66*256,d7			; Volume tab size

	cmp	#REAL,pmode(a5)
	beq.b	.varaa
	cmp	#STEREO14,pmode(a5)
	bne.b	.ala2

.varaa	move.l	buffSize(a5),d0
	move.l	#MEMF_CHIP!MEMF_CLEAR,d1
	lob	AllocMem
	move.l	d0,buff3(a5)
	beq.b	.memerr

	move.l	buffSize(a5),d0
	move.l	#MEMF_CHIP!MEMF_CLEAR,d1
	lob	AllocMem
	move.l	d0,buff4(a5)
	beq.b	.memerr

.ala2	cmp	#STEREO14,pmode(a5)
	beq.b	.bit14

	moveq	#0,d0
	move	maxchan(a5),d1
	move.l	#256,d2
	subq	#1,d1
.l	add.l	d2,d0
	add.l	#256,d2
	dbf	d1,.l

	move.l	d0,dtabsize(a5)
	moveq	#MEMF_PUBLIC,d1
	lob	AllocMem
	move.l	d0,dtab(a5)
	beq.b	.memerr	
	bra.b	.alavaraa

.bit14	move.l	#66*256*2,d7			; Volume tab size

	move.l	#64*1024,d0
	moveq	#MEMF_PUBLIC,d1
	lob	AllocMem
	move.l	d0,buff14(a5)
	bne.b	.alavaraa

.memerr	bsr.w	s3end

	moveq	#-1,d0			* ERROR: no mem!
	rts

.alavaraa
	move.l	d7,d0
	moveq	#MEMF_PUBLIC,d1
	lob	AllocMem
	move.l	d0,vtab(a5)
	beq.b	.memerr

	add.l	#255,d0
	and.l	#~$ff,d0
	move.l	d0,vtabaddr(a5)

	clr	PS3M_cont(a5)
	clr	PS3M_eject(a5)
	clr	PS3M_position(a5)
	st 	PS3M_play(a5)

	bsr.w	s3mPlay
	bsr.b	s3end
	moveq	#0,d0			* All ok
	rts

 	endb	a5




** Stop playing

s3stop	pushm	all
	lea	data,a5
	st	PS3M_paused-data(a5)
	bsr.w	PS3M_pause
	st	jjo
	popm	all
	rts

jjo	dc	0


** continue after stop

s3cont	tst	jjo
	bne.b	.jm
	rts
.jm	pushm	all
	lea	data,a5
	clr	PS3M_paused-data(a5)
	bsr.w	PS3M_pause
	clr	jjo
	popm	all
	rts

** End music

s3end
	lea	data,a5
	basereg	data,a5

	bsr.b	s3cont

	st	PS3M_eject(a5)
	st	PS3M_wait(a5)

	move.l	4.w,a6
	move.l	tbuf(a5),d0
	beq.b	.eumg
	move.l	d0,a1
	move.l	#1024*4*2,d0
	lob	FreeMem
	clr.l	tbuf(a5)
	clr.l	tbuf2(a5)

.eumg	move.l	buff1(a5),d0
	beq.b	.eimem
	move.l	d0,a1
	move.l	buffSize(a5),d0
	lob	FreeMem
	clr.l	buff1(a5)

.eimem	move.l	buff2(a5),d0
	beq.b	.eimem1
	move.l	d0,a1
	move.l	buffSize(a5),d0
	lob	FreeMem
	clr.l	buff2(a5)

.eimem1	move.l	buff3(a5),d0
	beq.b	.eimem2
	move.l	d0,a1
	move.l	buffSize(a5),d0
	lob	FreeMem
	clr.l	buff3(a5)

.eimem2	move.l	buff4(a5),d0
	beq.b	.eimem3
	move.l	d0,a1
	move.l	buffSize(a5),d0
	lob	FreeMem
	clr.l	buff4(a5)

.eimem3	move.l	buff14(a5),d0
	beq.b	.eimem4
	move.l	d0,a1
	move.l	#64*1024,d0
	lob	FreeMem
	clr.l	buff14(a5)

.eimem4	move.l	vtab(a5),d0
	beq.b	.eimem5
	move.l	d0,a1
	move.l	#66*256,d0
	cmp	#STEREO14,pmode(a5)
	bne.b	.cd
	add.l	d0,d0
.cd	lob	FreeMem
	clr.l	vtab(a5)

.eimem5	move.l	dtab(a5),d0
	beq.b	.eimem6
	move.l	d0,a1
	move.l	dtabsize(a5),d0
	lob	FreeMem
	clr.l	dtab(a5)

.eimem6	rts

	endb	a5



** Forward one pattern

eteen	pushm	all
	move	positioneita,d1
	subq	#2,d1
	bmi.b	.bb
	move	PS3M_position,d0
	addq	#1,d0
	cmp	d1,d0
	blo.b	.a
	clr	d0
.a	bsr.w	setPosition
.bb	popm	all
	rts

** Backward one pattern

taakse	pushm	all
	move	PS3M_position,d0
	subq	#1,d0
	bpl.b	.b
	clr	d0
.b	bsr.w	setPosition
	popm	all
	rts




*********************************
*	   PS3M 0.9A ®		*
*	  Version 0.950		*
*   © 1994-95 Jarno Paananen	*
*      All rights reserved	*
*********************************

;; LEV4 - IRQ HANDLER

lev4	clr.l	playpos
	move	#$80,$dff09c
	nop
	rte

* Lev3 

lev3	move.l	d0,-(sp)
	move	#$20,$dff09c
	move.l	mrate50,d0
	add.l	d0,playpos
	move.l	buffSizeMaskFF(pc),d0
	and.l	d0,playpos
	move.l	(sp)+,d0
	nop
	rte


buffSizeMaskFF
	dc.l	(BUFFER-1)<<8!$ff


	basereg	data,a5
play	;movem.l	d0-a6,-(sp)
	lea	data,a5

	move.l	playpos(a5),d2
	lsr.l	#8,d2
	move.l	bufpos(a5),d0
	cmp.l	d2,d0
	ble.b	.norm
	sub.l	buffSize(a5),d0
.norm	move.l	mrate50(a5),d1
	lsr.l	#7,d1
	add.l	d0,d1

	sub.l	d1,d2
	bmi.b	.ei

	moveq	#1,d0
	and.l	d2,d0
	add	d0,d2

	cmp.l	#16,d2
	blt.b	.ei

	move	d2,todobytes(a5)

.mix	move	bytes2music(a5),d0
	cmp	todobytes(a5),d0
	bgt.b	.mixaa

	sub	d0,todobytes(a5)
	sub	d0,bytes2music(a5)
	move	d0,bytes2do(a5)
	beq.b	.q
	
	bsr.w	domix

.q	tst	PS3M_paused
	bne.b	.o

	tst	PS3M_play
	beq.b	.o

;	cmp	#mtS3M,mtype(a5)
;	bne.b	.xm
	bsr.w	s3m_music
	lea	data,a5
;	bra.b	.o

.o	move	bytesperframe(a5),d0
	add	d0,bytes2music(a5)
	bra.b	.mix

.mixaa	move	todobytes(a5),d0
	sub	d0,bytes2music(a5)
	move	d0,bytes2do(a5)
	beq.b	.q2

	bsr.w	domix

.q2	lea	data,a5
.ei	moveq	#0,d7
	rts


init	lea	data,a5
	clr	mtype(a5)

;	move.l	s3m(a5),a0
;	cmp.l	#`SCRM`,44(a0)
;	beq	.s3m

.s3m	move	#mtS3M,mtype(a5)


.init	
	cmp	#2,maxchan(a5)
	bhs.b	.opk
	move	#2,maxchan(a5)
.opk	
	tst	mtype(a5)
	beq.b	.error

	cmp	#mtS3M,mtype(a5)
	beq.w	s3m_init

.error	moveq	#1,d0
	rts


FinalInit
	lea	data,a5
	clr.l	bufpos(a5)
	clr.l	playpos(a5)

	clr	cn(a5)
;	clr.b	mt_counter

	lea	buff1,a0
	moveq	#3,d6
.clloop
	move.l	(a0)+,d0
	beq.b	.skip
	move.l	d0,a1

	move.l	buffSize(a5),d7
	lsr.l	#2,d7
	subq.l	#1,d7
.cl	clr.l	(a1)+
	dbf	d7,.cl
.skip	dbf	d6,.clloop

	tst	PS3M_cont(a5)
	bne.w	.q

.huu	lea	cha0(a5),a0
	move	#mChanBlock_SIZE*16-1,d7
.cl2	clr	(a0)+
	dbf	d7,.cl2

	lea	c0(a5),a0
	move	#s3mChanBlock_SIZE*8-1,d7
.cl3	clr.l	(a0)+
	dbf	d7,.cl3

	move	tempo(a5),d0
	bne.b	.qw
	moveq	#125,d0
.qw	move.l	mrate(a5),d1
	move.l	d1,d2
	lsl.l	#2,d1
	add.l	d2,d1
	add	d0,d0
	divu	d0,d1

	addq	#1,d1
	and	#~1,d1

	move	d1,bytesperframe(a5)
	clr	bytes2do(a5)

	bset	#1,$bfe001

	bsr.w	makedivtabs
	bsr.w	Makevoltable

	ifeq	disable020
	
	move.l	4.w,a6
	btst	#1,297(a6)
	beq.b	.no020

; Processor is 020+!

	st	opt020(a5)
	
	cmp	#STEREO14,pmode(a5)
	beq.b	.s14_020

	move.l	#mix_020,mixad1(a5)
	move.l	#mix2_020,mixad2(a5)
	bra.b	.e

.s14_020
	move.l	#mix16_020,mixad1(a5)
	move.l	#mix162_020,mixad2(a5)
	bra.b	.e

	endc

; Processor is 000/010

.no020	clr	opt020(a5)

	cmp	#STEREO14,pmode(a5)
	beq.b	.s14_000

	move.l	#mix,mixad1(a5)
	move.l	#mix2,mixad2(a5)
	bra.b	.e

.s14_000
	move.l	#mix16,mixad1(a5)
	move.l	#mix162,mixad2(a5)


.e	cmp	#STEREO14,pmode(a5)
	bne.b	.nop

	move.l	#copybuf14,cbufad(a5)

	bsr.w	do14tab
	bra.b	.q

.nop	cmp	#REAL,pmode(a5)
	beq.b	.surr

	move.l	#copybuf,cbufad(a5)
	bra.b	.q

.surr	move.l	#copysurround,cbufad(a5)

.q	moveq	#0,d0
	rts




; D0 = New position

setPosition
	lea	data,a5
	move	d0,PS3M_position(a5)

; S3M
.s3m	subq	#1,d0
	move	d0,pos(a5)
	move.l	s3m(a5),a0
	move.b	initialspeed(a0),d0
	bne.b	.ok
	moveq	#6,d0
.ok	move	d0,spd(a5)
	clr	cn
	bra.w	burk

; XM
.xm	move	d0,pos(a5)
	st	pbflag(a5)
	clr	rows(a5)
	rts

PS3M_pause
	lea	data,a5
	tst	PS3M_paused(a5)
	beq.b	.restore

.save	lea	cha0,a0
	lea	saveArray(pc),a1
	moveq	#31,d0
.l	move.b	mOnOff(a0),(a1)+
	st	mOnOff(a0)
	lea	mChanBlock_SIZE(a0),a0
	dbf	d0,.l
	rts

.restore
	lea	cha0,a0
	lea	saveArray(pc),a1
	moveq	#31,d0
.l2	move.b	(a1)+,mOnOff(a0)
	lea	mChanBlock_SIZE(a0),a0
	dbf	d0,.l2
	rts

saveArray
	dcb.b	32




;;***** Mixing routines *********


domix	lea	cha0(a5),a4
	lea	pantab(a5),a0
	moveq	#31,d7
	move.l	mixad1(a5),a1
.loo	tst.b	(a0)+
	beq.b	.n
	bmi.b	.n

	move.l	tbuf(a5),a2
	Push	a0/a1/d7
	jsr	(a1)				; Mix
	Pull	a0/a1/d7
	move	#1,chans(a5)
	lea	mChanBlock_SIZE(a4),a4
	subq	#1,d7
	bra.b	.loo2

.n	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.loo
	bra.b	.ddq


.loo2	cmp	#1,maxchan(a5)
	beq.b	.ddq

	move.l	mixad2(a5),a1
.loka	tst.b	(a0)+
	beq.b	.n2
	bmi.b	.n2

	move.l	tbuf(a5),a2
	Push	a0/a1/d7
	jsr	(a1)
	Pull	a0/a1/d7

.n2	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.loka

.ddq	move.l	tbuf(a5),a0
	move.l	buff1(a5),a1
	move.l	buff3(a5),a4
	move.l	cbufad(a5),a2
	jsr	(a2)


right	lea	cha0(a5),a4
	lea	pantab(a5),a0
	move.l	mixad1(a5),a1
	moveq	#31,d7
.loo	tst.b	(a0)+
	bpl.b	.n

	move.l	tbuf2(a5),a2
	Push	a0/a1/d7
	jsr	(a1)
	Pull	a0/a1/d7
	move	#1,chans(a5)
	lea	mChanBlock_SIZE(a4),a4
	subq	#1,d7
	bra.b	.loo2

.n	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.loo
	bra.b	.ddq


.loo2	cmp	#1,maxchan(a5)
	beq.b	.ddq
	move.l	mixad2(a5),a1
.loka	tst.b	(a0)+
	bpl.b	.n2

	move.l	tbuf2(a5),a2
	Push	a0/a1/d7
	jsr	(a1)
	Pull	a0/a1/d7

.n2	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.loka

.ddq	move.l	tbuf2(a5),a0
	move.l	buff2(a5),a1
	move.l	buff4(a5),a4
	move.l	cbufad(a5),a2
	jsr	(a2)

	moveq	#0,d0
	move	bytes2do(a5),d0
	add.l	d0,bufpos(a5)
	move.l	buffSizeMask(a5),d0
	and.l	d0,bufpos(a5)
	clr	bytes2do(a5)
	rts


copybuf	move.l	bufpos(a5),d0
	move.l	d0,d1
	moveq	#0,d2
	move	bytes2do(a5),d2
	add.l	d2,d1
	cmp.l	buffSizeMask(a5),d1
	ble.b	.dd

	move.l	a1,a3

	move.l	buffSize(a5),d7
	sub.l	d0,d7
	lsr.l	#1,d7
	subq	#1,d7
	add.l	d0,a1
	lea	divtabs(a5),a2
	move	chans(a5),d0
	lsl	#2,d0
	move.l	-4(a2,d0),a2

.ldd	move	(a0)+,d2
	move.b	(a2,d2),(a1)+
	move	(a0)+,d2
	move.b	(a2,d2),(a1)+
	dbf	d7,.ldd

	move.l	a3,a1
	move.l	d1,d7
	sub.l	buffSize(a5),d7
	lsr.l	#1,d7
	subq	#1,d7
	bmi.b	.ddq
.ldd2	move	(a0)+,d2
	move.b	(a2,d2),(a1)+
	move	(a0)+,d2
	move.b	(a2,d2),(a1)+
	dbf	d7,.ldd2
.ddq	rts

.dd	add.l	d0,a1
	lea	divtabs(a5),a2
	move	chans(a5),d0
	lsl	#2,d0
	move.l	-4(a2,d0),a2
	move	bytes2do(a5),d7
	lsr	#1,d7
	subq	#1,d7
.ldd3	move	(a0)+,d1
	move.b	(a2,d1),(a1)+
	move	(a0)+,d1
	move.b	(a2,d1),(a1)+
	dbf	d7,.ldd3
	rts

copysurround
	move.l	bufpos(a5),d0
	move.l	d0,d1

	moveq	#0,d2
	move	bytes2do(a5),d2
	add.l	d2,d1

	cmp.l	buffSizeMask(a5),d1
	ble.b	.dd

	movem.l	a1/a4,-(sp)

	move.l	buffSize(a5),d7
	sub.l	d0,d7
	lsr.l	#1,d7
	subq	#1,d7
	add.l	d0,a1
	add.l	d0,a4
	lea	divtabs(a5),a2
	move	chans(a5),d0
	lsl	#2,d0
	move.l	-4(a2,d0),a2

.ldd	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+

	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+
	dbf	d7,.ldd

	movem.l	(sp)+,a1/a4

	move.l	d1,d7
	sub.l	buffSize(a5),d7
	lsr.l	#1,d7
	subq	#1,d7
	bmi.b	.ddq
.ldd2	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+

	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+
	dbf	d7,.ldd2
.ddq	rts

.dd	add.l	d0,a1
	add.l	d0,a4
	lea	divtabs(a5),a2
	move	chans(a5),d0
	lsl	#2,d0
	move.l	-4(a2,d0),a2
	move	bytes2do(a5),d7
	lsr	#1,d7
	subq	#1,d7
.ldd3	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+

	move	(a0)+,d2
	move.b	(a2,d2),d2
	move.b	d2,(a1)+
	not	d2
	move.b	d2,(a4)+
	dbf	d7,.ldd3
	rts


copybuf14
	move.l	bufpos(a5),d0
	move.l	d0,d1
	moveq	#0,d2
	move	bytes2do(a5),d2
	add.l	d2,d1
	cmp.l	buffSizeMask(a5),d1
	ble.b	.dd

	movem.l	a1/a4,-(sp)

	move.l	buffSize(a5),d7
	sub.l	d0,d7
	subq	#1,d7
	add.l	d0,a1
	add.l	d0,a4
	moveq	#0,d2
	move.l	buff14(a5),a2
	moveq	#-2,d0
.ldd	move	(a0)+,d2
	and.l	d0,d2
	move.b	(a2,d2.l),(a1)+
	move.b	1(a2,d2.l),(a4)+
	dbf	d7,.ldd

.huu	movem.l	(sp)+,a1/a4
	move.l	d1,d7
	sub.l	buffSize(a5),d7
	subq	#1,d7
	bmi.b	.ddq

.ldd2	move	(a0)+,d2
	and.l	d0,d2
	move.b	(a2,d2.l),(a1)+
	move.b	1(a2,d2.l),(a4)+
	dbf	d7,.ldd2
.ddq	rts


.dd	add.l	d0,a1
	add.l	d0,a4
	move	bytes2do(a5),d7
	subq	#1,d7
	move.l	buff14(a5),a2
	moveq	#0,d2
	moveq	#-2,d0
.ldd3	move	(a0)+,d2
	and.l	d0,d2
	move.b	(a2,d2.l),(a1)+
	move.b	1(a2,d2.l),(a4)+
	dbf	d7,.ldd3
	rts


; 000/010 Mixing routines

; Mixing routine for the first channel (moves data)


mix	moveq	#0,d7
	move	bytes2do(a5),d7
	subq	#1,d7
	
	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty			;sound off

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4

	move.l	vtabaddr(a5),d2
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	lsl.l	#8,d0
	add.l	d0,d2				; Position in volume table

	move.l	(a4),a0				;mStart
	move.l	mFPos(a4),d0

	moveq	#0,d3
	moveq	#0,d5

	move.l	mLength(a4),d6
	bne.b	.2

	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.qw

.2	cmp.l	#$ffff,d6
	bls.b	.leii
	move	#$ffff,d6

.leii	cmp	#32,d7
	blt.b	.lep
	move.l	d4,d1
	swap	d1
	lsl.l	#5,d1
	swap	d1
	add.l	d0,d1
	cmp	d6,d1
	bhs.b	.lep
	pea	.leii(pc)
	bra.w	.mix32

.lep	move.b	(a0,d0),d2
	move.l	d2,a1
	add.l	d4,d0
	move.b	(a1),d3
	addx	d5,d0
	move	d3,(a2)+

	cmp	d6,d0
	bhs.b	.ddwq
	dbf	d7,.lep
	bra.b	.qw

.ddwq	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	dbf	d7,.ty
	bra.b	.qw

.q	move.l	mLStart(a4),a0
	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)

	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0				;reset integer part
	dbf	d7,.leii

.qw	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)				;mStart
	move.l	d0,mFPos(a4)

	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)				; mStart
.u	rts

.ty	addq	#1,d7
	beq.b	.u

	move.l	#$800080,d0
	lsr	d7
	bcc.b	.sk
	move	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	move.l	d0,(a2)+
	dbf	d7,.lk
	rts

.mix32	rept	16
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	add.l	d4,d0
	addx	d5,d0
	swap	d3
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	move.l	d3,(a2)+
	add.l	d4,d0
	addx	d5,d0
	endr

	sub	#32,d7
	rts



.vol0	move.l	clock(a5),d4
	divu	mPeriod(a4),d4		;period
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4
	swap	d4

	move.l	(a4),a0			;mStart
	move.l	mFPos(a4),d0

	addq	#1,d7

	movem.l	d0/d1,-(sp)
	move.l	d7,d1
	move.l	d4,d0
	bsr.w	mulu_32
	move.l	d0,d4
	movem.l	(sp)+,d0/d1

	subq	#1,d7

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.w	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.w	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.w	.ty



; Mixing routine for rest of the channels (adds data)

mix2	moveq	#0,d7
	move	bytes2do(a5),d7

	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty			;noloop

	tst	mVolume(a4)
	beq.w	.vol0

.dw	subq	#1,d7

	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4

	move.l	vtabaddr(a5),d2
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	lsl.l	#8,d0
	add.l	d0,d2

	move.l	(a4),a0			;mStart
	move.l	mFPos(a4),d0

	moveq	#0,d3
	moveq	#0,d5

	move.l	mLength(a4),d6
	bne.b	.2

	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.qw

.2	cmp.l	#$ffff,d6
	bls.b	.leii
	move	#$ffff,d6

.leii	cmp	#32,d7
	blt.b	.lep
	move.l	d4,d1
	swap	d1
	lsl.l	#5,d1
	swap	d1
	add.l	d0,d1
	cmp	d6,d1
	bhs.b	.lep
	pea	.leii(pc)
	bra.w	.mix32

.lep	move.b	(a0,d0),d2
	move.l	d2,a1
	add.l	d4,d0
	move.b	(a1),d3
	addx	d5,d0
	add	d3,(a2)+

	cmp	d6,d0
	bhs.b	.ddwq
	dbf	d7,.lep
	bra.b	.qw

.ddwq	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	dbf	d7,.tyy
	bra.b	.qw

.q	move.l	mLStart(a4),a0
	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	dbf	d7,.leii

.qw	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)

	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)

.u	addq	#1,chans(a5)
.ty	rts

.tyy	addq	#1,d7
	beq.b	.u

	move.l	#$800080,d0
	lsr	d7
	bcc.b	.sk
	add	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	add.l	d0,(a2)+
	dbf	d7,.lk
	bra.b	.u

.mix32	rept	16
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	add.l	d4,d0
	addx	d5,d0
	swap	d3
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	add.l	d3,(a2)+
	add.l	d4,d0
	addx	d5,d0
	endr
	sub	#32,d7
	rts


.vol0	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4
	swap	d4

	move.l	(a4),a0			;pos (addr)
	move.l	mFPos(a4),d0

	addq	#1,d7
	movem.l	d0/d1,-(sp)
	move.l	d7,d1
	move.l	d4,d0
	bsr.w	mulu_32
	move.l	d0,d4
	movem.l	(sp)+,d0/d1

	subq	#1,d7
	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.w	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.w	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.w	.ty


; 16-bit mixing routine for first channel (moves data)

mix16	moveq	#0,d7
	move	bytes2do(a5),d7
	subq	#1,d7

	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4

	move.l	vtabaddr(a5),a3
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	add	d0,d0
	lsl.l	#8,d0
	add.l	d0,a3				; Position in volume table

	move.l	(a4),a0				;mStart
	move.l	mFPos(a4),d0

	moveq	#0,d3
	moveq	#0,d5

	move.l	mLength(a4),d6
	bne.b	.2

	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.qw

.2	cmp.l	#$ffff,d6
	bls.b	.leii
	move	#$ffff,d6

.leii	cmp	#32,d7
	blt.b	.lep
	move.l	d4,d1
	swap	d1
	lsl.l	#5,d1
	swap	d1
	add.l	d0,d1
	cmp	d6,d1
	bhs.b	.lep
	pea	.leii(pc)
	bra.w	.mix32

.lep	moveq	#0,d2
	move.b	(a0,d0),d2
	add	d2,d2
	add.l	d4,d0
	move	(a3,d2),(a2)+
	addx	d5,d0

	cmp	d6,d0
	bhs.b	.ddwq
	dbf	d7,.lep
	bra.b	.qw

.ddwq	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	dbf	d7,.ty
	bra.b	.qw

.q	move.l	mLStart(a4),a0
	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)

	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0				;reset integer part
	dbf	d7,.leii

.qw	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)				;mStart
	move.l	d0,mFPos(a4)

	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)				; mStart
.u	rts

.ty	addq	#1,d7
	beq.b	.u

	moveq	#0,d0
	lsr	d7
	bcc.b	.sk
	move	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	move.l	d0,(a2)+
	dbf	d7,.lk
	rts

.mix32	rept	32

	moveq	#0,d2
	move.b	(a0,d0),d2
	add	d2,d2
	add.l	d4,d0
	move	(a3,d2),(a2)+
	addx	d5,d0

	endr

	sub	#32,d7
	rts


.vol0	move.l	clock(a5),d4
	divu	mPeriod(a4),d4		;period
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4
	swap	d4

	move.l	(a4),a0			;mStart
	move.l	mFPos(a4),d0

	addq	#1,d7

	movem.l	d0/d1,-(sp)
	move.l	d7,d1
	move.l	d4,d0
	bsr.w	mulu_32
	move.l	d0,d4
	movem.l	(sp)+,d0/d1

	subq	#1,d7

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.w	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.w	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.w	.ty



; Mixing routine for rest of the channels (adds data)

mix162	moveq	#0,d7
	move	bytes2do(a5),d7

	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	subq	#1,d7

	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4

	move.l	vtabaddr(a5),a3
	move	mVolume(a4),d0		;volu
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	add	d0,d0
	lsl.l	#8,d0
	add.l	d0,a3

	move.l	(a4),a0			;mStart
	move.l	mFPos(a4),d0

	moveq	#0,d3
	moveq	#0,d5

	move.l	mLength(a4),d6
	bne.b	.2

	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.qw

.2	cmp.l	#$ffff,d6
	bls.b	.leii
	move	#$ffff,d6

.leii	cmp	#32,d7
	blt.b	.lep
	move.l	d4,d1
	swap	d1
	lsl.l	#5,d1
	swap	d1
	add.l	d0,d1
	cmp	d6,d1
	bhs.b	.lep
	pea	.leii(pc)
	bra.w	.mix32

.lep	moveq	#0,d2
	move.b	(a0,d0),d2
	add	d2,d2
	add.l	d4,d0
	move	(a3,d2),d3
	addx	d5,d0
	add	d3,(a2)+

	cmp	d6,d0
	bhs.b	.ddwq
	dbf	d7,.lep
	bra.b	.qw

.ddwq	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	dbf	d7,.tyy
	bra.b	.qw

.q	move.l	mLStart(a4),a0
	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	dbf	d7,.leii

.qw	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)

	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)

.u
.ty
.tyy
	rts


.mix32	rept	32
	moveq	#0,d2
	move.b	(a0,d0),d2
	add	d2,d2
	move	(a3,d2),d3
	add	d3,(a2)+
	add.l	d4,d0
	addx	d5,d0
	endr
	sub	#32,d7
	rts

.vol0	move.l	clock(a5),d4
	divu	mPeriod(a4),d4
	swap	d4
	clr	d4
	lsr.l	#2,d4

	move.l	mrate(a5),d0
	divu	d0,d4
	swap	d4
	clr	d4
	rol.l	#4,d4
	swap	d4

	move.l	(a4),a0			;pos (addr)
	move.l	mFPos(a4),d0

	addq	#1,d7
	movem.l	d0/d1,-(sp)
	move.l	d7,d1
	move.l	d4,d0
	bsr.w	mulu_32
	move.l	d0,d4
	movem.l	(sp)+,d0/d1

	subq	#1,d7
	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.w	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.w	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.w	.ty




	ifeq	disable020

; 020+ Optimized versions!

; Mixing routine for the first channel (moves data)


mix_020	moveq	#0,d7
	move	bytes2do(a5),d7
	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4
	swap	d4

	move.l	vtabaddr(a5),d2
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	lsl.l	#8,d0
	add.l	d0,d2			; Position in volume table

	move.l	(a4),a0			;pos (addr)
	move.l	mFPos(a4),d0		;fpos

	move.l	mLength(a4),d6		;len
	beq.w	.resloop

	cmp.l	#$ffff,d6
	bls.b	.restart
	move	#$ffff,d6
.restart
	swap	d6
	swap	d0
	sub.l	d0,d6
	swap	d0
	move.l	d4,d5
	swap	d5

	divul.l	d5,d5:d6		; bytes left to loop end
	tst.l	d5
	beq.b	.e
	addq.l	#1,d6
.e
	moveq	#0,d3
	moveq	#0,d5
.mixloop
	moveq	#8,d1
	cmp	d1,d7
	bhs.b	.ok
	move	d7,d1
.ok	cmp.l	d1,d6
	bhs.b	.ok2
	move.l	d6,d1
.ok2	sub	d1,d7
	sub.l	d1,d6

	jmp	.jtab1(pc,d1*2)

.a set 0
.jtab1
	rept	8
	bra.b	.mend-.a
.a set .a+14				; (mend - dmix) / 8
	endr

.dmix	rept	8
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	add.l	d4,d0
	move	d3,(a2)+
	addx	d5,d0
	endr
.mend	tst	d7
	beq.b	.done
	tst.l	d6
	bne.w	.mixloop

.resloop
	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.ty

.q	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	move.l	mLStart(a4),a0
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	bra.w	.restart

.done	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)
.u	rts

.ty	move.l	#$800080,d0
	lsr	d7
	bcc.b	.sk
	move	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	move.l	d0,(a2)+
	dbf	d7,.lk
	rts


.vol0	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	mulu.l	d7,d4

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.b	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.b	.ty


; Mixing routine for rest of the channels (adds data)

mix2_020
	moveq	#0,d7
	move	bytes2do(a5),d7
	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	swap	d4

	move.l	vtabaddr(a5),d2
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	lsl.l	#8,d0
	add.l	d0,d2			; Position in volume table

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	move.l	mLength(a4),d6
	beq.w	.resloop

	cmp.l	#$ffff,d6
	bls.b	.restart
	move	#$ffff,d6
.restart
	swap	d6
	swap	d0
	sub.l	d0,d6
	swap	d0

	move.l	d4,d5
	swap	d5

	divul.l	d5,d5:d6		; bytes left to loop end
	tst.l	d5
	beq.b	.e
	addq.l	#1,d6
.e	moveq	#0,d3
	moveq	#0,d5
.mixloop
	moveq	#8,d1
	cmp	d1,d7
	bhi.b	.ok
	move	d7,d1
.ok	cmp.l	d1,d6
	bhi.b	.ok2
	move	d6,d1
.ok2	sub	d1,d7
	sub.l	d1,d6
	jmp	.jtab1(pc,d1*2)

.a set 0
.jtab1	rept	8
	bra.b	.mend-.a
.a set .a+14				; (mend - dmix) / 8
	endr

.dmix	rept	8
	move.b	(a0,d0),d2
	move.l	d2,a1
	move.b	(a1),d3
	add	d3,(a2)+
	add.l	d4,d0
	addx	d5,d0
	endr
.mend	tst	d7
	beq.b	.done
	tst.l	d6
	bne.w	.mixloop

.resloop
	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.tyy

.q	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	move.l	mLStart(a4),a0
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	bra.w	.restart

.done	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)

.u	addq	#1,chans
.ty	rts

.tyy	move.l	#$800080,d0
	lsr	d7
	bcc.b	.sk
	add	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	add.l	d0,(a2)+
	dbf	d7,.lk
	bra.b	.u


.vol0	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	mulu.l	d7,d4

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.b	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.b	.ty



; Mixing routine for the first channel (moves data)


mix16_020
	moveq	#0,d7
	move	bytes2do(a5),d7
	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4
	swap	d4

	move.l	vtabaddr(a5),a3
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	add	d0,d0
	lsl.l	#8,d0
	add.l	d0,a3			; Position in volume table

	move.l	(a4),a0			;pos (addr)
	move.l	mFPos(a4),d0		;fpos

	move.l	mLength(a4),d6		;len
	beq.w	.resloop

	cmp.l	#$ffff,d6
	bls.b	.restart
	move	#$ffff,d6
.restart
	swap	d6
	swap	d0
	sub.l	d0,d6
	swap	d0
	move.l	d4,d5
	swap	d5

	divul.l	d5,d5:d6		; bytes left to loop end
	tst.l	d5
	beq.b	.e
	addq.l	#1,d6
.e
	moveq	#0,d5
	moveq	#0,d2
.mixloop
	moveq	#8,d1
	cmp	d1,d7
	bhs.b	.ok
	move	d7,d1
.ok	cmp.l	d1,d6
	bhs.b	.ok2
	move.l	d6,d1
.ok2	sub	d1,d7
	sub.l	d1,d6

	jmp	.jtab1(pc,d1*2)

.a set 0
.jtab1
	rept	8
	bra.b	.mend-.a
.a set .a+12				; (mend - dmix) / 8
	endr

.dmix	rept	8
	move.b	(a0,d0),d2
	add.l	d4,d0
	move	(a3,d2*2),(a2)+
	addx	d5,d0
	endr

.mend	tst	d7
	beq.b	.done
	tst.l	d6
	bne.w	.mixloop

.resloop
	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.ty

.q	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	move.l	mLStart(a4),a0
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	bra.w	.restart

.done	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)
.u	rts

.ty	addq	#1,d7
	beq.b	.u

	moveq	#0,d0
	lsr	d7
	bcc.b	.sk
	move	d0,(a2)+
.sk	subq	#1,d7
	bmi.b	.u
.lk	move.l	d0,(a2)+
	dbf	d7,.lk
	rts

.vol0	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	mulu.l	d7,d4

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.b	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.b	.ty


; Mixing routine for rest of the channels (adds data)

mix162_020
	moveq	#0,d7
	move	bytes2do(a5),d7
	tst	mPeriod(a4)
	beq.w	.ty
	tst.b	mOnOff(a4)
	bne.w	.ty

	tst	mVolume(a4)
	beq.w	.vol0

.dw	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	swap	d4

	move.l	vtabaddr(a5),a3
	move	mVolume(a4),d0
	mulu	PS3M_master(a5),d0
	lsr	#6,d0
	add	d0,d0
	lsl.l	#8,d0
	add.l	d0,a3			; Position in volume table

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	move.l	mLength(a4),d6
	beq.w	.resloop

	cmp.l	#$ffff,d6
	bls.b	.restart
	move	#$ffff,d6
.restart
	swap	d6
	swap	d0
	sub.l	d0,d6
	swap	d0

	move.l	d4,d5
	swap	d5

	divul.l	d5,d5:d6		; bytes left to loop end
	tst.l	d5
	beq.b	.e
	addq.l	#1,d6
.e	moveq	#0,d2
	moveq	#0,d5
.mixloop
	moveq	#8,d1
	cmp	d1,d7
	bhi.b	.ok
	move	d7,d1
.ok	cmp.l	d1,d6
	bhi.b	.ok2
	move	d6,d1
.ok2	sub	d1,d7
	sub.l	d1,d6
	jmp	.jtab1(pc,d1*2)

.a set 0
.jtab1
	rept	8
	bra.b	.mend-.a
.a set .a+14				; (mend - dmix) / 8
	endr

.dmix	rept	8
	move.b	(a0,d0),d2
	add.l	d4,d0
	move	(a3,d2*2),d3
	addx	d5,d0
	add	d3,(a2)+
	endr

.mend	tst	d7
	beq.b	.done
	tst.l	d6
	bne.w	.mixloop

.resloop
	tst.b	mLoop(a4)
	bne.b	.q
	st	mOnOff(a4)
	bra.b	.tyy

.q	moveq	#0,d1
	move	d0,d1
	sub.l	mLength(a4),d1
	move.l	mLStart(a4),a0
	add.l	d1,a0
	move.l	mLLength(a4),d6
	sub.l	d1,d6
	move.l	d6,mLength(a4)
	cmp.l	#$ffff,d6
	bls.b	.j
	move	#$ffff,d6
.j	clr	d0			;reset integer part
	bra.w	.restart

.done	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.u

	tst.b	mLoop(a4)
	bne.b	.q2
	st	mOnOff(a4)
	bra.b	.u

.q2	move.l	mLLength(a4),d6
	sub.l	(a4),a0
	add.l	mLStart(a4),a0
	sub.l	d6,a0
	add.l	d6,mLength(a4)
	move.l	a0,(a4)
.u
.ty
.tyy	rts


.vol0	move.l	clock(a5),d4
	moveq	#0,d0
	move	mPeriod(a4),d0

	divu.l	d0,d4

	lsl.l	#8,d4
	lsl.l	#6,d4

	move.l	mrate(a5),d0
	lsr.l	#4,d0

	divu.l	d0,d4

	move.l	(a4),a0
	move.l	mFPos(a4),d0

	mulu.l	d7,d4

	swap	d0
	add.l	d4,d0			; Position after "mixing"
	swap	d0
	
	moveq	#0,d1
	move	d0,d1
	add.l	d1,a0
	clr	d0
	move.l	a0,(a4)
	move.l	d0,mFPos(a4)
	sub.l	d1,mLength(a4)
	bpl.b	.ty			; OK, Done!

; We're about to mix past the end of the sample

	tst.b	mLoop(a4)
	bne.b	.q3
	st	mOnOff(a4)
	bra.b	.ty

.q3	move.l	mLLength(a4),d6
.loop	sub.l	d6,a0
	add.l	d6,mLength(a4)
	bmi.b	.loop
	beq.b	.loop

	move.l	a0,(a4)
	bra.b	.ty

	endc


* mulu_32 --- d0 = d0*d1
mulu_32	movem.l	d2/d3,-(sp)
	move.l	d0,d2
	move.l	d1,d3
	swap	d2
	swap	d3
	mulu	d1,d2
	mulu	d0,d3
	mulu	d1,d0
	add	d3,d2
	swap	d2
	clr	d2
	add.l	d2,d0
	movem.l	(sp)+,d2/d3
	rts	

* divu_32 --- d0 = d0/d1, d1=jakojäännös
divu_32	move.l	d3,-(a7)
	swap	d1
	tst	d1
	bne.b	lb_5f8c
	swap	d1
	move.l	d1,d3
	swap	d0
	move	d0,d3
	beq.b	lb_5f7c
	divu	d1,d3
	move	d3,d0
lb_5f7c	swap	d0
	move	d0,d3
	divu	d1,d3
	move	d3,d0
	swap	d3
	move	d3,d1
	move.l	(a7)+,d3
	rts	

lb_5f8c	swap	d1
	move	d2,-(a7)
	moveq	#16-1,d3
	move	d3,d2
	move.l	d1,d3
	move.l	d0,d1
	clr	d1
	swap	d1
	swap	d0
	clr	d0
lb_5fa0	add.l	d0,d0
	addx.l	d1,d1
	cmp.l	d1,d3
	bhi.b	lb_5fac
	sub.l	d3,d1
	addq	#1,d0
lb_5fac	dbf	d2,lb_5fa0
	move	(a7)+,d2
	move.l	(a7)+,d3
	rts	


;;******** Init routines ***********


detectchannels
	lea	ch(pc),a0
	moveq	#7,d0
.l2	clr.l	(a0)+
	dbf	d0,.l2

	move.l	patts(a5),a1
	lea	ch(pc),a2
	move.l	s3m(a5),a0
	move	pats(a5),d7
	subq	#1,d7
.pattloop
	moveq	#0,d0
	move	(a1)+,d0
	beq.b	.qt
	iword	d0
	lsl.l	#4,d0
	lea	(a0,d0.l),a3
	addq.l	#2,a3
	moveq	#63,d6
.rowloop
	move.b	(a3)+,d0
	beq.b	.newrow

	moveq	#31,d1
	and	d0,d1

	moveq	#32,d2
	and	d0,d2
	beq.b	.nnot

	tst.b	(a3)
	bmi.b	.skip
	beq.b	.skip

	tst.b	1(a3)
	bmi.b	.skip
	beq.b	.skip

	st	(a2,d1)

.skip	addq.l	#2,a3

.nnot	moveq	#64,d2
	and	d0,d2
	beq.b	.nvol

	addq.l	#1,a3

.nvol	and	#128,d0
	beq.b	.rowloop

	move.b	(a3),d0
	cmp.b	#1,d0
	blo.b	.skip2

	cmp.b	#`Z`-`@`,d0
	bhi.b	.skip2

	st	(a2,d1)

.skip2	addq.l	#2,a3
	bra.b	.rowloop

.newrow
	dbf	d6,.rowloop
.qt
	dbf	d7,.pattloop	

	moveq	#1,d0
	moveq	#1,d1
	moveq	#31,d7
	moveq	#0,d5
	moveq	#0,d6
	lea	$40(a0),a1
	lea	pantab(a5),a0
.l	clr.b	(a0)
	tst.b	(a2)+
	beq.b	.d

	move.b	(a1),d2
	bmi.b	.d
	cmp.b	#8,d2
	blo.b	.vas
	move.b	#-1,(a0)
	move	d1,d0
	addq	#1,d5
	bra.b	.d
.vas	move.b	#1,(a0)
	move	d1,d0
	addq	#1,d6
.d	addq.l	#1,a1
	addq.l	#1,a0
	addq	#1,d1
	dbf	d7,.l

	cmp	d5,d6
	bls.b	.k	
	move	d6,d5
.k	move	d5,maxchan(a5)
	
	move	d0,numchans(a5)
ret	rts

ch	ds.b	32


makedivtabs
	cmp	#STEREO14,pmode(a5)
	beq.b	ret

	lea	divtabs(a5),a1
	move.l	dtab(a5),a0

	move	#255,d6
	moveq	#0,d5
	move	maxchan(a5),d5
	move.l	d5,d3
	move.l	d5,d2

	subq	#1,d5
	move	d5,d4
	lsl.l	#7,d5

	lsl.l	#7,d2

	sub.l	vboost(a5),d3
	cmp	#1,d3
	bge.b	.laa
	moveq	#1,d3

.laa	moveq	#0,d0
	move	d6,d7
	move.l	a0,(a1)+
.l	move.l	d0,d1
	add.l	d5,d1
	sub.l	d2,d1
	divs	d3,d1
	cmp	#$7f,d1
	ble.b	.d
	move	#$7f,d1
.d	cmp	#$ff80,d1
	bge.b	.d2
	move	#$80,d1
.d2	move.b	d1,(a0)+
	addq.l	#1,d0
	dbf	d7,.l

	add	#256,d6
	sub.l	#$80,d5
	dbf	d4,.laa
	rts


Makevoltable
	move.l	vtabaddr(a5),a0

	cmp	#STEREO14,pmode(a5)
	beq.b	bit16

	moveq	#0,d3		;volume
	cmp	#1,fformat(a5)
	beq.b	signed

.lop	moveq	#0,d4		;data
.lap	move	d4,d5
	sub	#$80,d5
	mulu	d3,d5
	asr.l	#6,d5
	add	#$80,d5
	move.b	d5,(a0)+
	addq	#1,d4
	cmp	#256,d4
	bne.b	.lap
	addq	#1,d3
	cmp	#65,d3
	bne.b	.lop
	rts

signed
.lop	moveq	#0,d4		;data
.lap	move.b	d4,d5
	ext	d5
	mulu	d3,d5
	asr.l	#6,d5
	add	#$80,d5
	move.b	d5,(a0)+
	addq	#1,d4
	cmp	#256,d4
	bne.b	.lap
	addq	#1,d3
	cmp	#65,d3
	bne.b	.lop
	rts


bit16	move	maxchan(a5),d3
	moveq	#0,d7		; "index"

	cmp	#1,fformat(a5)
	beq.b	signed2

.lop	move	d7,d6
	tst.b	d7
	bmi.b	.above

	and	#127,d6
	move	#128,d5
	sub	d6,d5
	lsl	#8,d5
	move	d7,d6
	lsr	#8,d6
	mulu	d6,d5
	divu	#63,d5
	swap	d5
	clr	d5
	swap	d5
	divu	d3,d5
	neg	d5
	move	d5,(a0)+
	addq	#1,d7
	cmp	#256*65,d7
	bne.b	.lop
	rts

.above	and	#127,d6
	lsl	#8,d6

	move	d7,d5
	lsr	#8,d5
	mulu	d6,d5
	divu	#63,d5
	swap	d5
	clr	d5
	swap	d5
	divu	d3,d5
	move	d5,(a0)+
	addq	#1,d7
	cmp	#256*65,d7
	bne.b	.lop
	rts

signed2
.lop	move	d7,d6
	tst.b	d7
	bpl.b	.above

	and	#127,d6
	move	#128,d5
	sub	d6,d5
	lsl	#8,d5
	move	d7,d6
	lsr	#8,d6
	mulu	d6,d5
	divu	#63,d5
	swap	d5
	clr	d5
	swap	d5
	divu	d3,d5
	neg	d5
	move	d5,(a0)+
	addq	#1,d7
	cmp	#256*65,d7
	bne.b	.lop
	rts

.above	and	#127,d6
	lsl	#8,d6

	move	d7,d5
	lsr	#8,d5
	mulu	d6,d5
	divu	#63,d5
	swap	d5
	clr	d5
	swap	d5
	divu	d3,d5
	move	d5,(a0)+
	addq	#1,d7
	cmp	#256*65,d7
	bne.b	.lop
	rts


do14tab	move.l	buff14(a5),a0
	moveq	#0,d7
.loo	move	d7,d2
	bpl.b	.plus

	neg	d2
	move	d2,d3
	lsr	#8,d2
	neg.b	d2

	lsr.b	#2,d3
	neg	d3

	move.b	d2,(a0)+
	move.b	d3,(a0)+
	addq.l	#2,d7
	cmp.l	#$10000,d7
	bne.b	.loo
	rts

.plus	move	d2,d3
	lsr	#8,d2
	lsr.b	#2,d3
	move.b	d2,(a0)+
	move.b	d3,(a0)+
	addq.l	#2,d7
	cmp.l	#$10000,d7
	bne.b	.loo
	rts





;;********** S3M Play Routine **********


s3m_init
	move.l	s3m(a5),a0
	move.l	a0,mname(a5)
	move	ordernum(a0),d0
	iword	d0
	move	d0,slen(a5)
	move	d0,positioneita(a5)

	move	patnum(a0),d0
	iword	d0
	move	d0,pats(a5)

	move	insnum(a0),d0
	iword	d0
	move	d0,inss(a5)

	move	ffv(a0),d0
	iword	d0
	move	d0,fformat(a5)

	move	flags(a0),d0
	iword	d0
	move	d0,sflags(a5)

	cmp	#$1301,fformat(a5)
	bhi.b	.ok

	bset	#6,sflags+1(a5)

.ok	lea	$60(a0),a1
	moveq	#0,d0
	move	slen(a5),d0
	moveq	#1,d1
	and	d0,d1
	add	d1,d0
	lea	(a1,d0.l),a2
	move.l	a2,samples(a5)

	move	inss(a5),d0
	add	d0,d0
	lea	(a2,d0.l),a3
	move.l	a3,patts(a5)

	moveq	#0,d0
	move.b	(a1),d0
	add	d0,d0
	sub.l	a1,a1
	move	(a3,d0),d0
	beq.b	.q
	iword	d0
	asl.l	#4,d0
	lea	2(a0,d0.l),a1
.q	move.l	a1,ppos(a5)

	moveq	#0,d0
	move.b	initialspeed(a0),d0
	bne.b	.ok2
	moveq	#6,d0
.ok2	move	d0,spd(a5)

	move.b	initialtempo(a0),d0
	cmp	#32,d0
	bhi.b	.qw
	moveq	#125,d0
.qw	move	d0,tempo(a5)

	move	inss(a5),d0
	subq	#1,d0
	move.l	samples(a5),a2
.instloop
	moveq	#0,d1
	move	(a2)+,d1
	iword	d1
	lsl.l	#4,d1
	lea	(a0,d1.l),a1
	btst	#0,insflags(a1)
	beq.b	.eloo
	move.l	insloopend(a1),d1
	ilword	d1
	cmp.l	#2,d1
	bls.b	.eloo
	move.l	insloopend(a1),inslength(a1)
.eloo	dbf	d0,.instloop

	clr	pos(a5)
	clr	rows(a5)
	clr	cn(a5)
	clr	pbrkflag(a5)
	clr	pbrkrow(a5)
	clr	loopcnt(a5)
	clr	loopflag(a5)
	clr	looprow(a5)

	bsr.w	detectchannels

	move.l	#14317056/4,clock(a5)		; Clock constant
	move	#64,globalVol(a5)
	moveq	#0,d0
	rts


s3m_music
	lea	data,a5
	move.l	s3m(a5),a0

	addq	#1,cn
	move	cn(a5),d0
	cmp	spd(a5),d0
	beq.b	uusrow

ccmds	lea	c0(a5),a2
	lea	cha0(a5),a4
	move	numchans(a5),d7
	subq	#1,d7
.loo	btst	#7,5(a2)
	beq.b	.edi

	lea	cct(pc),a1
	moveq	#0,d0
	move.b	cmd(a2),d0
	cmp	#`Z`-`@`,d0
	bhi.b	.edi
	add	d0,d0
	move	(a1,d0),d0
	jsr	(a1,d0)

.edi	lea	s3mChanBlock_SIZE(a2),a2
	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.loo
	rts

uusrow	clr	cn

	lea	c0(a5),a2
	move	numchans(a5),d7
	subq	#1,d7
.cl	clr.b	flgs(a2)
	lea	s3mChanBlock_SIZE(a2),a2
	dbf	d7,.cl

	move.l	ppos(a5),d0
	beq.b	process
	move.l	d0,a1

	lea	c0(a5),a4		;chanblocks
.loo	move.b	(a1)+,d0
	beq.b	.end

	moveq	#$1f,d5
	and	d0,d5			;chan
	mulu	#s3mChanBlock_SIZE,d5
	lea	(a4,d5),a2

	and	#~31,d0
	move.b	d0,flgs(a2)
	
	moveq	#32,d2
	and	d0,d2
	beq.b	.nnot

	move.b	(a1)+,(a2)
	move.b	(a1)+,inst(a2)

.nnot	moveq	#64,d2
	and	d0,d2
	beq.b	.nvol

	move.b	(a1)+,vol(a2)

.nvol	and	#128,d0
	beq.b	.loo

	move.b	(a1)+,d0
	bmi.b	.d
	move.b	d0,cmd(a2)
.d	move.b	(a1)+,info(a2)
	bra.b	.loo

.end	move.l	a1,ppos

process	lea	c0(a5),a2
	lea	cha0(a5),a4
	move	numchans(a5),d7
	move.l	samples(a5),a5
	subq	#1,d7
	endb	a5

.lloo	tst.b	5(a2)
	beq.w	.evol

	moveq	#32,d0
	and.b	flgs(a2),d0
	beq.w	.f

	move.b	inst(a2),d0
	beq.w	.esmp
	bmi.w	.esmp

	cmp	inss,d0
	bgt.w	.mute

	btst	#7,flgs(a2)
	beq.b	.eii
	cmp.b	#`S`-`@`,cmd(a2)
	bne.b	.eii
	move.b	info(a2),d1
	and	#$f0,d1
	cmp	#$d0,d1
	beq.w	.evol

.eii	add	d0,d0
	move	-2(a5,d0),d0
	iword	d0
	lsl	#4,d0
	lea	(a0,d0),a1

	moveq	#0,d0
	move	insmemseg(a1),d0
	iword	d0
	lsl.l	#4,d0
	move.l	a0,d4
	add.l	d0,d4

	move.l	insloopbeg(a1),d1
	ilword	d1
	move.l	insloopend(a1),d2
	ilword	d2
	sub.l	d1,d2
	add.l	d4,d1

	move.l	d1,mLStart(a4)
	move.l	d2,mLLength(a4)
	move.b	insvol(a1),volume+1(a2)
	cmp	#64,volume(a2)
	blo.b	.e
	move	#63,volume(a2)
.e	move.l	a1,sample(a2)

	btst	#0,insflags(a1)
	beq.b	.eloo
	cmp.l	#2,d2
	shi	mLoop(a4)
	bra.b	.esmp


.mute	st	mOnOff(a4)
	bra.w	.f

.eloo	clr.b	mLoop(a4)
.esmp	moveq	#0,d0
	move.b	(a2),d0
	beq.w	.f
	cmp.b	#254,d0
	beq.b	.mute
	cmp.b	#255,d0
	beq.w	.f

	move.b	d0,note(a2)
	move	d0,d1
	lsr	#4,d1

	and	#$f,d0
	add	d0,d0

	move.l	sample(a2),a1
	move.l	$20(a1),d2
	ilword	d2

	lea	Periods(pc),a1
	move	(a1,d0),d0
	mulu	#8363,d0
	lsl.l	#4,d0
	lsr.l	d1,d0	

	divu	d2,d0


	btst	#7,flgs(a2)
	beq.b	.ei

	cmp.b	#`Q`-`@`,cmd(a2)	;retrig
	beq.b	.eiik

.ei	clr.b	retrigcn(a2)

.eiik	clr.b	vibpos(a2)


	btst	#7,flgs(a2)
	beq.b	.eitopo

	cmp.b	#`G`-`@`,cmd(a2)	;TOPO
	beq.b	.eddo

	cmp.b	#`L`-`@`,cmd(a2)	;TOPO+VSLD
	bne.b	.eitopo

.eddo	move	d0,toperiod(a2)
	bra.b	.f

.eitopo	move	d0,mPeriod(a4)
	move	d0,period(a2)
	clr.l	mFPos(a4)

	move.l	sample(a2),d0
	beq.b	.f
	move.l	d0,a1

	moveq	#0,d0
	move	insmemseg(a1),d0
	iword	d0
	lsl.l	#4,d0
	move.l	a0,d4
	add.l	d0,d4

	move.l	inslength(a1),d0
	ilword	d0

	move.l	d4,(a4)
	move.l	d0,mLength(a4)
	clr.b	mOnOff(a4)

.f	moveq	#64,d0
	and.b	flgs(a2),d0
	beq.b	.evol
	move.b	vol(a2),volume+1(a2)
	cmp	#64,volume(a2)
	blo.b	.evol
	move	#63,volume(a2)

.evol	btst	#7,flgs(a2)
	beq.b	.eivib

	cmp.b	#`H`-`@`,cmd(a2)
	beq.b	.vib

.eivib	bsr.w	checklimits
.vib

	btst	#7,flgs(a2)
	beq.b	.eitre

	cmp.b	#`R`-`@`,cmd(a2)
	beq.b	.tre
	cmp.b	#`I`-`@`,cmd(a2)
	beq.b	.tre

.eitre	move	volume(a2),d0
	mulu	globalVol,d0
	lsr	#6,d0
	move	d0,mVolume(a4)

.tre	btst	#7,flgs(a2)
	beq.b	.edd

	move.b	info(a2),d0
	beq.b	.dd
	move.b	d0,lastcmd(a2)
.dd	lea	ct(pc),a1
	moveq	#0,d0
	move.b	cmd(a2),d0
	cmp	#`Z`-`@`,d0
	bhi.b	.edd

	add	d0,d0
	move	(a1,d0),d0
	jsr	(a1,d0)

.edd	lea	s3mChanBlock_SIZE(a2),a2
	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.lloo

	basereg	data,a5
	lea	data,a5

	tst	pbrkflag(a5)
	bne.b	.newpos

	addq	#1,rows(a5)

	move	rows(a5),d0
	cmp	#64,d0
	blo.w	dee

.newpos
	clr	pbrkflag(a5)
	move	pbrkrow(a5),rows(a5)
	clr	pbrkrow(a5)

burk	addq	#1,pos(a5)
	move	slen(a5),d0
	cmp	pos(a5),d0
	bgt.b	.notend

	clr	pos(a5)
	st	PS3M_break(a5)

	move.b	initialspeed(a0),d0
	bne.b	.ok
	moveq	#6,d0
.ok	move	d0,spd(a5)

.notend	move	pos(a5),d0

	sub.l	a1,a1

	moveq	#0,d1
	move.b	$60(a0,d0),d1
	cmp.b	#$fe,d1
	beq.b	burk
	cmp.b	#$ff,d1
	beq.b	burk
	cmp	pats(a5),d1
	bhs.b	.newp

	add	d1,d1
	move.l	patts(a5),a3
	moveq	#0,d0
	move	(a3,d1),d0
	beq.b	.newp
	iword	d0
	lsl.l	#4,d0
	lea	2(a0,d0.l),a1

	move	rows(a5),d0
	beq.b	.newp
	subq	#1,d0
	moveq	#0,d1
.loop	move.b	(a1)+,d1
	beq.b	.next

	moveq	#32,d2
	and	d1,d2
	beq.b	.nnot
	addq	#2,a1
.nnot
	moveq	#64,d2
	and	d1,d2
	beq.b	.nvol
	addq	#1,a1
.nvol
	and	#128,d1
	beq.b	.loop
	addq	#2,a1

	bra.b	.loop
.next
	dbf	d0,.loop
.newp
	move.l	a1,ppos(a5)

	move	pos(a5),d0
	move	d0,PS3M_position(a5)
	st	PS3M_poscha(a5)
dee
;	bra	xm_dee




xm_dee	lea	c0(a5),a2
	lea	cha0(a5),a4
	move	numchans(a5),d7
	subq	#1,d7

.luu	tst	volume(a2)
	bne.b	.noaging

	cmp.b	#8,age(a2)
	bhs.b	.stop
	addq.b	#1,age(a2)
	bra.b	.nextt
.stop	st	mOnOff(a4)
	bra.b	.nextt
.noaging
	clr.b	age(a2)

.nextt	lea	s3mChanBlock_SIZE(a2),a2
	lea	mChanBlock_SIZE(a4),a4
	dbf	d7,.luu
xm_exit	rts


	endb	a5


ct	dc	rt-ct
	dc	changespeed-ct
	dc	posjmp-ct
	dc	patbrk-ct
	dc	vslide-ct
	dc	portadwn-ct
	dc	portaup-ct
	dc	rt-ct
	dc	rt-ct
	dc	tremor-ct
	dc	arpeggio-ct
	dc	rt-ct
	dc	rt-ct
	dc	rt-ct
	dc	rt-ct
	dc	soffset-ct
	dc	rt-ct
	dc	retrig-ct
	dc	rt-ct
	dc	specials-ct
	dc	stempo-ct
	dc	rt-ct
	dc	setmaster-ct
	dc	rt-ct
	dc	rt-ct
	dc	rt-ct
	dc	rt-ct



cct	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	vslide-cct
	dc	portadwn-cct
	dc	portaup-cct
	dc	noteporta-cct
	dc	vibrato-cct
	dc	tremor-cct
	dc	arpeggio-cct
	dc	vvslide-cct
	dc	pvslide-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	retrig-cct
	dc	tremolo-cct
	dc	specials-cct
	dc	rt-cct
	dc	finevib-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct
	dc	rt-cct

tremor
tremolo
rt	rts









changespeed
	move.b	info(a2),d0
	bne.b	.e
	st	PS3M_break
	st	PS3M_poscha
	rts
.e	move.b	info(a2),spd+1
	rts

posjmp	clr	pbrkrow
	st	pbrkflag

	moveq	#0,d0
	move.b	pos,d0
	addq	#1,d0

	cmp	slen,d0
	bne.b	.notlast
	st	PS3M_break
.notlast
	moveq	#0,d0
	move.b	info(a2),d0
	cmp	pos,d0
	bhi.b	.e
	st	PS3M_break
	moveq	#0,d0
.e	subq	#1,d0
	move	d0,pos
	st	PS3M_poscha
	rts

patbrk	moveq	#0,d0
	move.b	info(a2),d0
	moveq	#$f,d2
	and	d0,d2
	lsr	#4,d0
	add.b	.dtab(pc,d0),d2
	cmp.b	#63,d2		; valid line number given?
	ble.s	.ok	
	moveq	#0,d2		; else zero it
.ok	move	d2,pbrkrow
	st	pbrkflag
	st	PS3M_poscha
	rts

.dtab:	dc.b	0,10,20,30	; Don't think this little table is a waste!
	dc.b 	40,50,60,70	; The routine is shorter using this table
	dc.b	80,90,100,110	; and faster too :-)
	dc.b 	120,130,140,150	; 16 bytes vs. 8 instructions (wordlength)

vslide	moveq	#0,d0
	move.b	lastcmd(a2),d0
	moveq	#$f,d1
	and	d0,d1
	move	d0,d2
	lsr	#4,d2

	cmp.b	#$f,d1
	beq.b	.addfine

	cmp.b	#$f,d2
	beq.b	.subfine

	btst	#6,sflags+1
	bne.b	.ok

	tst	cn
	beq.b	.dd	

.ok	tst	d1
	beq.b	.add
	and	#$f,d0
	bra.b	.sub

.subfine
	tst	cn
	bne.b	.dd
	and	#$f,d0
.sub	sub	d0,volume(a2)
	bpl.b	.dd
	clr	volume(a2)
.dd	move	volume(a2),d0
	mulu	globalVol,d0
	lsr	#6,d0
	move	d0,mVolume(a4)
	rts

.addfine
	tst	d2
	beq.b	.sub
	tst	cn
	bne.b	.dd
.add	lsr	#4,d0

.add2	add	d0,volume(a2)
	cmp	#64,volume(a2)
	blo.b	.dd
	move	#63,volume(a2)
	bra.b	.dd


portadwn
	moveq	#0,d0
	move.b	lastcmd(a2),d0

	tst	cn
	beq.b	.fined
	cmp.b	#$e0,d0
	bhs.b	.dd
	lsl	#2,d0

.ddd	add	d0,period(a2)
	bra.b	checklimits
.dd	rts

.fined	cmp.b	#$e0,d0
	bls.b	.dd
	cmp.b	#$f0,d0
	bls.b	.extr
	and	#$f,d0
	lsl	#2,d0
	bra.b	.ddd

.extr	and	#$f,d0
	bra.b	.ddd

portaup
	moveq	#0,d0
	move.b	lastcmd(a2),d0

	tst	cn
	beq.b	.fined
	cmp.b	#$e0,d0
	bhs.b	.dd
	lsl	#2,d0

.ddd	sub	d0,period(a2)
	bra.b	checklimits

.dd	rts

.fined	cmp.b	#$e0,d0
	bls.b	.dd
	cmp.b	#$f0,d0
	bls.b	.extr
	and	#$f,d0
	lsl	#2,d0
	bra.b	.ddd

.extr	and	#$f,d0
	bra.b	.ddd


checklimits
	move	period(a2),d0
	btst	#4,sflags+1
	beq.b	.sii
	
	cmp	#856*4,d0
	bls.b	.dd
	move	#856*4,d0
.dd	cmp	#113*4,d0
	bhs.b	.dd2
	move	#113*4,d0
.dd2	move	d0,period(a2)
	move	d0,mPeriod(a4)
	rts

.sii	cmp	#$7fff,d0
	bls.b	.dd3
	move	#$7fff,d0
.dd3	cmp	#64,d0
	bhs.b	.dd4
	move	#64,d0
.dd4	move	d0,mPeriod(a4)
	rts


noteporta
	move.b	info(a2),d0
	beq.b	notchange
	move.b	d0,notepspd(a2)
notchange
	move	toperiod(a2),d0
	beq.b	.1
	moveq	#0,d1
	move.b	notepspd(a2),d1
	lsl	#2,d1

	cmp	period(a2),d0
	blt.b	.topoup

	add	d1,period(a2)
	cmp	period(a2),d0
	bgt.b	.1
	move	d0,period(a2)
	clr	toperiod(a2)
.1	move	period(a2),mPeriod(a4)
	rts

.topoup	sub	d1,period(a2)
	cmp	period(a2),d0
	blt.b	.dd
	move	d0,period(a2)
	clr	toperiod(a2)
.dd	move	period(a2),mPeriod(a4)
	rts


vibrato	move.b	cmd(a2),d0
	bne.b	.e
	move.b	vibcmd(a2),d0
	bra.b	.skip2

.e	move	d0,d1
	and	#$f0,d1
	bne.b	.skip2

	move.b	vibcmd(a2),d1
	and	#$f0,d1
	or	d1,d0

.skip2
	move.b	d0,vibcmd(a2)

vibrato2
	moveq	#$1f,d0
	and.b	vibpos(a2),d0
	moveq	#0,d2
	lea	mt_vibratotable(pc),a3
	move.b	(a3,d0),d2
	moveq	#$f,d0
	and.b	vibcmd(a2),d0
	mulu	d0,d2

	moveq	#4,d0
	btst	#0,sflags+1
	bne.b	.sii
	moveq	#5,d0
.sii	lsr	d0,d2
	move	period(a2),d0
	btst	#5,vibpos(a2)
	bne.b	.neg
	add	d2,d0
	bra.b	.vib3
.neg
	sub	d2,d0
.vib3
	move	d0,mPeriod(a4)
	move.b	vibcmd(a2),d0
	lsr.b	#4,d0
	add.b	d0,vibpos(a2)
	rts


finevib	move.b	cmd(a2),d0
	bne.b	.e
	move.b	vibcmd(a2),d0
	bra.b	.skip2

.e	move	d0,d1
	and	#$f0,d1
	bne.b	.skip2

	move.b	vibcmd(a2),d1
	and	#$f0,d1
	or	d1,d0

.skip2
	move.b	d0,vibcmd(a2)
	moveq	#$1f,d0
	and.b	vibpos(a2),d0
	moveq	#0,d2
	lea	mt_vibratotable(pc),a3
	move.b	(a3,d0),d2
	moveq	#$f,d0
	and.b	vibcmd(a2),d0
	mulu	d0,d2

	lsr	#7,d2
	move	period(a2),d0
	btst	#5,vibpos(a2)
	bne.b	.neg
	add	d2,d0
	bra.b	.vib3
.neg	sub	d2,d0
.vib3	move	d0,mPeriod(a4)
	move.b	vibcmd(a2),d0
	lsr.b	#4,d0
	add.b	d0,vibpos(a2)
	rts


arpeggio
	moveq	#0,d0
	move.b	note(a2),d0
	beq.b	.qq

	moveq	#$70,d1
	and	d0,d1
	and	#$f,d0

	moveq	#0,d2
	move	cn,d2
	divu	#3,d2
	swap	d2
	tst	d2
	beq.b	.norm
	subq	#1,d2
	beq.b	.1

	moveq	#$f,d2
	and.b	lastcmd(a2),d2
	add	d2,d0
.f	cmp	#12,d0
	blt.b	.norm
	sub	#12,d0
	add	#$10,d1
	bra.b	.f

.1	move.b	lastcmd(a2),d2
	lsr.b	#4,d2
	add.b	d2,d0
.f2	cmp	#12,d0
	blt.b	.norm
	sub	#12,d0
	add	#$10,d1
	bra.b	.f2

.norm	add	d0,d0
	lsr	#4,d1

	move.l	sample(a2),a1

	move.l	$20(a1),d2
	ilword	d2

	lea	Periods(pc),a1
	move	(a1,d0),d0
	mulu	#8363,d0
	lsl.l	#4,d0
	lsr.l	d1,d0
	divu	d2,d0
	move	d0,mPeriod(a4)
.qq	rts


pvslide	bsr.w	notchange
	bra.w	vslide

vvslide	bsr.w	vibrato2
	bra.w	vslide

soffset	moveq	#32,d0
	and.b	flgs(a2),d0
	beq.b	.f
	move.b	(a2),d0
	beq.b	.f
	cmp.b	#255,d0
	beq.b	.f

	move.l	sample(a2),d0
	beq.b	.f
	move.l	d0,a1

	moveq	#0,d0
	move	insmemseg(a1),d0
	iword	d0
	lsl.l	#4,d0
	move.l	a0,d4
	add.l	d0,d4

	move.l	inslength(a1),d0
	ilword	d0

	moveq	#0,d2
	move.b	lastcmd(a2),d2
	lsl.l	#8,d2
	add.l	d2,d4
	sub.l	d2,d0
	bpl.b	.ok
	move.l	mLStart(a4),d4
	move.l	mLLength(a4),d0
.ok	move.l	d4,(a4)
	move.l	d0,mLength(a4)
.f	rts


retrig	move.b	retrigcn(a2),d0
	subq.b	#1,d0
	cmp.b	#0,d0
	ble.b	.retrig

	move.b	d0,retrigcn(a2)
	rts

.retrig	move.l	sample(a2),d0
	beq.w	.f
	move.l	d0,a1
	moveq	#0,d1
	move	insmemseg(a1),d1
	iword	d1
	lsl.l	#4,d1
	move.l	a0,d4
	add.l	d1,d4

	move.l	inslength(a1),d1
	ilword	d1

	move.l	d4,(a4)
	move.l	d1,mLength(a4)
	clr.b	mOnOff(a4)
	clr.l	mFPos(a4)

	move.b	lastcmd(a2),d0
	moveq	#$f,d1
	and.b	d0,d1
	move.b	d1,retrigcn(a2)

	and	#$f0,d0
	lsr	#4,d0
	lea	ftab2(pc),a3
	moveq	#0,d2
	move.b	(a3,d0),d2
	beq.b	.ddq

	mulu	volume(a2),d2
	lsr	#4,d2
	move	d2,volume(a2)
	bra.b	.ddw

.ddq	lea	ftab1(pc),a3
	move.b	(a3,d0),d2
	ext	d2
	add	d2,volume(a2)

.ddw	tst	volume(a2)
	bpl.b	.ei0
	clr	volume(a2)
.ei0	cmp	#64,volume(a2)
	blo.b	.ei64
	move	#63,volume(a2)
.ei64	move	volume(a2),d0
	mulu	globalVol,d0
	lsr	#6,d0
	move	d0,mVolume(a4)
.f	rts

specials
ncut_delay
	move.b	info(a2),d0
	and	#$f0,d0
	cmp	#$b0,d0
	beq.b	.ploop
	cmp	#$d0,d0
	beq.b	.delay
	cmp	#$c0,d0
	bne.b	.dd

	move.b	info(a2),d0
	and	#$f,d0
	cmp	cn,d0
	bne.b	.dd
	clr	volume(a2)
	clr	mVolume(a4)
.dd	rts

.ploop	tst	cn
	bne.b	.dd

	moveq	#$f,d0
	and.b	info(a2),d0
	beq.b	.setlp			; 0 means "set loop mark" in current line

	tst	loopflag
	beq.b	.jcnt

	subq	#1,loopcnt		; count down
	bne.b	.jloop			; jump again if still not zero
	clr	loopflag
	rts

.jcnt	move	d0,loopcnt		; accept new loop value
	st	loopflag
.jloop	move	looprow,pbrkrow		; put line number to jump to
	subq	#1,pos
	st	pbrkflag
	rts
.setlp	move	rows,looprow
	rts

.delay	move.b	info(a2),d0
	and	#$f,d0
	cmp	cn,d0
	bne.b	.dd
	
	moveq	#32,d0
	and.b	flgs(a2),d0
	beq.w	.f

	move.b	inst(a2),d0
	beq.w	.esmp
	bmi.w	.esmp

	cmp	inss,d0
	bgt.w	.dd

	move.l	samples,a5
	add	d0,d0
	move	-2(a5,d0),d0
	iword	d0
	asl	#4,d0
	lea	(a0,d0),a1

	moveq	#0,d0
	move	insmemseg(a1),d0
	iword	d0
	asl.l	#4,d0
	move.l	a0,d4
	add.l	d0,d4

	move.l	insloopbeg(a1),d1
	ilword	d1
	move.l	insloopend(a1),d2
	ilword	d2
	sub.l	d1,d2
	add.l	d4,d1

	move.l	inslength(a1),d0
	ilword	d0

	move.l	d4,(a4)
	move.l	d0,mLength(a4)
	move.l	d1,mLStart(a4)
	move.l	d2,mLLength(a4)
	move.b	insvol(a1),volume+1(a2)
	cmp	#64,volume(a2)
	blo.b	.e
	move	#63,volume(a2)
.e	clr.b	mOnOff(a4)

	move.l	a1,sample(a2)

	btst	#0,insflags(a1)
	bne.b	.loo
	clr.b	mLoop(a4)
	bra.b	.esmp
.loo	cmp.l	#2,d2
	shi	mLoop(a4)

.esmp	moveq	#0,d0
	move.b	(a2),d0
	beq.b	.f
	bmi.b	.f

	moveq	#$70,d1
	and	d0,d1
	lsr	#4,d1

	and	#$f,d0
	add	d0,d0

	move.l	sample(a2),a1

	move.l	$20(a1),d2
	ilword	d2

	lea	Periods(pc),a1
	move	(a1,d0),d0
	mulu	#8363,d0
	lsl.l	#4,d0
	lsr.l	d1,d0
	divu	d2,d0

	move	d0,mPeriod(a4)
	move	d0,period(a2)
	clr.l	mFPos(a4)
	clr.b	vibpos(a2)

.f	moveq	#64,d0
	and.b	flgs(a2),d0
	beq.b	.evol
	move.b	vol(a2),volume+1(a2)
	cmp	#64,volume(a2)
	blo.b	.evol
	move	#63,volume(a2)
.evol	move	volume(a2),d0
	mulu	globalVol,d0
	lsr	#6,d0
	move	d0,mVolume(a4)
	rts


stempo	moveq	#0,d0
	move.b	info(a2),d0
	cmp	#32,d0
	bls.b	.e
	move.l	mrate,d1
	move.l	d1,d2
	lsl.l	#2,d1
	add.l	d2,d1
	add	d0,d0
	divu	d0,d1

	addq	#1,d1
	and	#~1,d1
	move	d1,bytesperframe
.e	rts

setmaster
	moveq	#0,d0
	move.b	info(a2),d0
	cmp	#64,d0
	bls.b	.d
	moveq	#64,d0
.d	move	d0,globalVol
	rts

Periods
 dc	1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,907

ftab1	dc.b	0,-1,-2,-4,-8,-16,0,0
	dc.b	0,1,2,4,8,16,0,0

ftab2	dc.b	0,0,0,0,0,0,10,8
	dc.b	0,0,0,0,0,0,24,32



mt_vibratotable	
	dc.b   0, 24, 49, 74, 97,120,141,161
	dc.b 180,197,212,224,235,244,250,253
	dc.b 255,253,250,244,235,224,212,197
	dc.b 180,161,141,120, 97, 74, 49, 24









******************************************************************************
******************************************************************************
******************************************************************************
* Soittolooppi


	basereg	data,a5


s3mPlay	movem.l	d0-a6,-(sp)
	lea	data,a5
	move	$dff002,-(sp)		;Old DMAs

	move.l	gfxbase(pc),a6
	move.l	34(a6),-(sp)		;Old view
	move.l	a6,-(sp)
	sub.l	a1,a1
	CALL	LoadView
	CALL	WaitTOF
	CALL	WaitTOF

	lob	WaitBlit

	lea	$dff000,a6
	move	$1c(a6),d1
.irqs	move	$1e(a6),d0		;Wait for all IRQs to finish...
	and	d1,d0			;before killing the system...
	bne.b	.irqs			;Over safety you might think, but...

	move	#$7ff,$96(a6)		;Disable DMAs
	move	#$8200,$96(a6)		;Enable master DMA
	move	$1c(a6),-(sp)		;Old IRQs
	move	#$7fff,$9a(a6)		;Disable IRQs

	move.l	4.w,a6
	move.b	PowerSupplyFrequency(a6),d0
	cmp.b	#60,d0
	beq.b	.NTSC
	move.l	#3546895,audiorate(a5)
	bra.b	.qw
.NTSC
	move.l	#3579545,audiorate(a5)
.qw
	move.l	audiorate(a5),d0
	move.l	mixingrate(a5),d1
	divu	d1,d0
	move.l	audiorate(a5),d1
	divu	d0,d1
	swap	d1
	clr	d1
	swap	d1
	move.l	d1,mrate(a5)

	move.l	audiorate(a5),d0
	divu	d1,d0

	swap	d0
	clr	d0
	swap	d0
	move.l	d0,mixingperiod(a5)

	lsl.l	#8,d1				; 8-bit fraction
	move.l	d1,d0
	move.l	4.w,a6
	moveq	#0,d1
	move.b	VBlankFrequency(a6),d1
	bsr.w	divu_32
	move.l	d0,mrate50(a5)			;In fact vblank frequency

	movem.l	buff1(a5),a0-a3
	move.l	mixingperiod(a5),d0

	lea	$dff000,a6
	move.l	buffSize(a5),d1
	lsr.l	#1,d1
	move	d1,$a4(a6)
	move	d1,$b4(a6)
	move	d1,$c4(a6)
	move	d1,$d4(a6)
	move	d0,$a6(a6)
	move	d0,$b6(a6)
	move	d0,$c6(a6)
	move	d0,$d6(a6)

	moveq	#64,d1

	move	pmode(a5),d0	
	subq	#1,d0
	bne.b	.nosurround

	moveq	#32,d2

	move.l	a0,$a0(a6)
	move.l	a1,$b0(a6)
	move.l	a0,$c0(a6)
	move.l	a1,$d0(a6)
	move	d1,$a8(a6)
	move	d1,$b8(a6)
	move	d2,$c8(a6)
	move	d2,$d8(a6)
	bra.w	.ohiis

.nosurround
	subq	#1,d0
	bne.b	.nostereo

	move.l	a0,$a0(a6)
	move.l	a1,$b0(a6)
	move.l	a1,$c0(a6)
	move.l	a0,$d0(a6)
	move	d1,$a8(a6)
	move	d1,$b8(a6)
	move	d1,$c8(a6)
	move	d1,$d8(a6)
	bra.b	.ohiis

.nostereo
	subq	#1,d0
	bne.b	.nomono

	move.l	a0,$a0(a6)
	move.l	a1,$b0(a6)
	move.l	a0,$c0(a6)
	move.l	a1,$d0(a6)
	move	d1,$a8(a6)
	move	d1,$b8(a6)
	move	d1,$c8(a6)
	move	d1,$d8(a6)
	bra.b	.ohiis

.nomono

; REAL SURROUND!

	subq	#1,d0
	bne.b	.bit14

	move.l	a0,$a0(a6)
	move.l	a1,$b0(a6)
	move.l	a2,$c0(a6)
	move.l	a3,$d0(a6)
	move	d1,$a8(a6)
	move	d1,$b8(a6)
	move	d1,$c8(a6)
	move	d1,$d8(a6)
	bra.b	.ohiis


; 14-BIT STEREO

.bit14	moveq	#1,d2

	move.l	a0,$a0(a6)
	move.l	a1,$b0(a6)
	move.l	a3,$c0(a6)
	move.l	a2,$d0(a6)
	move	d1,$a8(a6)
	move	d1,$b8(a6)
	move	d2,$c8(a6)
	move	d2,$d8(a6)

.ohiis	move.l	4.w,a6
	moveq	#0,d0
	btst	d0,AttnFlags+1(a6)
	beq.b	.no68010

	Push	a5
	lea	liko(pc),a5
	CALL	Supervisor
	Pull	a5
.no68010
	move.l	d0,vbrr(a5)

	Push	a5
	jsr	FinalInit
	Pull	a5

	lea	$dff000,a6
	move.l	vbrr(a5),a0
	move.l	$70(a0),olev4(a5)
	move.l	#lev4,$70(a0)
	move.l	$6c(a0),olev3(a5)
	move.l	#lev3,$6c(a0)
	move	#$800f,$96(a6)

	move	#$80+$20,$9c(a6)
	move	#$c080+$20,$9a(a6)

sync

.q	btst	#0,5(a6)		* VBlank
	beq.b	.q
.qq	btst	#0,5(a6)
	bne.b	.qq

	move	#4,$180(a6)		* Rastermeter
	bsr	play			* Play!
	move	#$5a,$180(a6)

** You don't have to call play within regular intervals. The routine just 
** swallows cpu as it needs fit, but probably some 50Hz is the best.

	btst	#6,$bfe001
	bne.b	sync


exitz	move	#$f00,$180(a6)
	move	#$7fff,$9a(a6)		;Restore system status
	move	#$7ff,$96(a6)
	move	#$7fff,$9c(a6)		;Clear possible IRQ-requests (4 safety)

	move.l	vbrr(a5),a0
	move.l	olev4(a5),$70(a0)	;Restore IRQ-vectors
	move.l	olev3(a5),$6c(a0)

.q	btst	#6,$bfe001
	beq.b	.q

	move	(sp)+,d7		;Old IRQs

	move.l	(sp)+,a6		;Old gfxbase
	move.l	(sp)+,a1		;Old view

	lea	$dff000,a0
	move	#$ff0,$180(a0)		;!!! debug color

	or	#$8000,d7
	and	#~$780,d7		;And off Audio IRQs (for safety again)
	move	d7,$9a(a0)		;Old IRQs

	move	(sp)+,d7		;Old DMAs
	or	#$8000,d7
	and	#~$f,d7			;And off Audio DMAs (convenience...)
	move	d7,$96(a0)

	clr	$a8(a0)			;Volumes down...
	clr	$b8(a0)
	clr	$c8(a0)
	clr	$d8(a0)

	move	#$ff,$180(a0)		;!!! debug color2

	CALL	LoadView		;Old view
	move.l	38(a6),d3		;Old Copper1
	move.l	d3,$dff080		;Set old Copper
	move	d3,$dff088		;Trigger

	movem.l	(sp)+,d0-a6
	moveq	#0,d0			;No error code
	move	#$f0,$dff000		;Safe! (Hopefully...)
	rts

liko	ifeq	disable020
	MOVEC	VBR,d0
	endc
	rte


*******

;*** Datas ***

data

vbrr		dc.l	0
olev4		dc.l	0
olev3		dc.l	0
vtabaddr	dc.l	0
playpos		dc.l	0
bufpos		dc.l	0
buffSize	dc.l	BUFFER
buffSizeMask	dc.l	BUFFER-1

bytesperframe	dc	0
bytes2do	dc	0
todobytes	dc	0
bytes2music	dc	0

mixad1		dc.l	0
mixad2		dc.l	0
cbufad		dc.l	0
opt020		dc	0

mixingrate	dc.l	16000
mixingperiod	dc.l	0
vboost		dc.l	0
pmode		dc	SURROUND

PS3M_play	dc	0
PS3M_break	dc	0
PS3M_poscha	dc	0
PS3M_position	dc	0
PS3M_master	dc	64
PS3M_eject	dc	0
PS3M_wait	dc	0
PS3M_cont	dc	0
PS3M_paused	dc	0
PS3M_initialized dc	0
PS3M_reinit	dc	0

audiorate	dc.l	0
mrate		dc.l	0
mrate50		dc.l	0

slen		dc	0
pats		dc	0
inss		dc	0

samples		dc.l	0
patts		dc.l	0

fformat		dc	0
sflags		dc	0

rows		dc	63
pbrkrow		dc	0
pbrkflag	dc	0
loopcnt		dc	0
loopflag	dc	0
looprow		dc	0
spd		dc	6
tempo		dc	125

cn		dc	0
pbflag		dc	0
pdelaycnt	dc.b	0
ploopcnt	dc.b	0

chans		dc	0
numchans	dc	0
maxchan		dc	0
mtype		dc	0			
clock		dc.l	0			; 14317056/4 for S3Ms
globalVol	dc	0

pos		dc	0
plen		dc	0
ppos		dc.l	0

divtabs		ds.l	16

c0		ds.b	s3mChanBlock_SIZE*32

cha0		ds.b	mChanBlock_SIZE*32

pantab		ds.b	32			;channel panning infos


s3m		dc.l	0
s3mlen		dc.l	0

tbuf		dc.l	0
tbuf2		dc.l	0
buff1		dc.l	0
buff2		dc.l	0
buff3		dc.l	0
buff4		dc.l	0
buff14		dc.l	0
vtab		dc.l	0
dtab		dc.l	0
dtabsize	dc.l	0

mname		dc.l	0

gfxbase		dc.l	0

thi		dc.b	0
tlo		dc.b	0
timer		dc.l	0
ciares		dc.l	0
craddr		dc.l	0,0,0
positioneita	dc	1
gfxname		dc.b	"graphics.library",0
		even



	section	blahb,data_f

module	incbin	"music:done/s3m.the crossing"
