******************************************************************************
*
* VOC Datatype, based on the sourcecode found in OS3.1 Native Developer Kit
*
* Written by Christian Buchner
*
******************************************************************************
* fastconvert.asm

		SECTION Code


; scaling of an ULONG given two ULONGS (68020 really needed)
; ==========================================================

		; d0=source length
		; d1=source frequency
		; d2=destination frequency
		; ->d0=destination length

		XDEF _ScaleLength

_ScaleLength	move.l	d3,-(sp)
		mulu.l	d2,d3:d0
		divu.l	d1,d3:d0
		move.l	(sp)+,d3
		rts


; 8 bit unsigned MONO -> 8 bit signed MONO conversion/stretching
; ==============================================================

		; a0=source
		; a1=destination
		; d0=destination length
		; d1=source frequency
		; d2=destination frequency

		XDEF _ConvertMono8

_ConvertMono8	cmp.l	d1,d2
		beq.s	quickloopm8

		; source and destination frequency differ
		; use a scaling conversion loop

		movem.l	d3/d4/d5,-(sp)	; save registers

		move.l	d1,d4		; calc skip value in d4
		moveq	#0,d1		; d4=d1/d2
		divu.l	d2,d1:d4	; d1=MOD(d1/d2) -> d1<d2

		move.l	d2,d5		; init counter

		bra.s	loopentrym8	; enter loop
outerloopm8	swap	d0

innerloopm8	move.b	(a0),d3		; get UBYTE
		eor.b	#$80,d3		; fix sign bit
		move.b	d3,(a1)+	; put BYTE

		add.l	d4,a0		; add skip to source ptr

		sub.l	d1,d5		; decrease counter
		bgt.s	loopentrym8	; skip if no underflow
		addq.w	#1,a0		; add 1 to source ptr
		add.l	d2,d5		; reset counter

loopentrym8	dbra	d0,innerloopm8	; loop length
		swap	d0
		dbra	d0,outerloopm8

		movem.l	(sp)+,d3/d4/d5	; restore registers
		rts

		; source and destination frequency are equal
		; use an optimized loop consisting of two parts

quickloopm8	movem.l	d3/d4,-(sp)	; save registers

		move.l	#$80808080,d4	; keep EOR value in d4 (faster!)

		move.l	d0,-(sp)	; save length
		lsr.l	#2,d0		; divide length by 4
		bra.s	quickentrym8	; enter loop
quickouterm8	swap	d0

quickinnerm8	move.l	(a0)+,d3	; get ULONG
		eor.l	d4,d3		; fix sign bits
		move.l	d3,(a1)+	; put ULONG

quickentrym8	dbra	d0,quickinnerm8	; loop length/4
		swap	d0
		dbra	d0,quickouterm8

		move.l	(sp)+,d0	; get length
		and.l	#$3,d0		; calc length MOD 4
		bra.s	restentrym8	; enter loop

restloopm8	move.b	(a0)+,d3	; get UBYTE
		eor.b	d4,d3		; fix sign bits
		move.b	d3,(a1)+	; put BYTE

restentrym8	dbra	d0,restloopm8	; loop length MOD 4

		movem.l	(sp)+,d3/d4	; restore registers
		rts


; 8 bit unsigned STEREO -> 8 bit signed MONO conversion/stretching
; ================================================================

		; a0=source
		; a1=destination
		; d0=destination length
		; d1=source frequency
		; d2=destination frequency

		XDEF _ConvertStereo8

_ConvertStereo8	cmp.l	d1,d2
		beq.s	quickloops8

		; source and destination frequency differ
		; use a scaling conversion loop

		movem.l	d3/d4/d5/d6,-(sp)	; save registers

		move.l	d1,d4		; calc skip value in d4
		moveq	#0,d1		; d4=d1/d2
		divu.l	d2,d1:d4	; d1=MOD(d1/d2) -> d1<d2

		lsl.l	#1,d4		; multiply skip by 2 (stereo)

		move.l	d2,d5		; init counter

		bra.s	loopentrys8	; enter loop
outerloops8	swap	d0

innerloops8	move.b	(a0),d3		; get UBYTE
		lsr.b	#1,d3		; halve value
		move.b	1(a0),d6	; get UBYTE
		lsr.b	#1,d6		; halve value
		add.b	d6,d3		; add values
		eor.b	#$80,d3		; fix sign bit
		move.b	d3,(a1)+	; put BYTE

		add.l	d4,a0		; add skip to source ptr

		sub.l	d1,d5		; decrease counter
		bgt.s	loopentrys8	; skip if no underflow
		addq.w	#2,a0		; add 2 to source ptr (stereo)
		add.l	d2,d5		; reset counter

loopentrys8	dbra	d0,innerloops8	; loop length
		swap	d0
		dbra	d0,outerloops8

		movem.l	(sp)+,d3/d4/d5/d6	; restore registers
		rts

		; source and destination frequency are equal
		; use a quicker loop without scaling

quickloops8	movem.l	d3/d4/d6,-(sp)	; save registers

		bra.s	quickentrys8	; enter loop
quickouters8	swap	d0

quickinners8	move.b	(a0)+,d3	; get UBYTE
		lsr.b	#1,d3		; halve value
		move.b	(a0)+,d6	; get UBYTE
		lsr.b	#1,d6		; halve value
		add.b	d6,d3		; add values
		eor.b	#$80,d3		; fix sign bit
		move.b	d3,(a1)+	; put BYTE

quickentrys8	dbra	d0,quickinners8	; loop length
		swap	d0
		dbra	d0,quickouters8

		movem.l	(sp)+,d3/d4/d6	; restore registers
		rts


		END
