;**********************************************************
;
; Frequency Scaler
; This program implements a frequency scaler.  It will attempt
; to take the input and provide and output which has its
; frequency scaled by the factor alpha.  It does this by
; reading the input in sections and outputting the samples
; at a rate of alpha times the input rate.  If alpha is < 1,
; the output frequencies are slowed, and some of the signal
; is lost.  If alpha > 1, the output frequencies are sped up,
; and some of the signal is repeated.
;
; Daniel Howell
; 3 Jun 1988
; ECE 148
;
; Modified to run in stereo by Todd Day
;
;**********************************************************
	page	79,66,1,1

	include	'defs.inc'
	include	'ioequ.inc'
	include	'intequ.inc'

buffer	equ	$0000			; beginning of buffer
L	equ	2048			; buffer length (multiple of 2!)
savea0	equ	buffer+L		; place to save a register
savea1	equ	savea0+1
savea2	equ	savea1+1
pointer	equ	savea2+1		; pointer to buffer

; ****************************************
; SSI receive data vector
; do long interrupt (save stack and ccr)
	org	p:i_ssird
	jsr	dofreq

; ****************************************
; begin program
;
	org	p:pgmram

; setup SSI and others
	include	'setup.asm'

	move	#buffer,r6		; r6 points to input of buffer
	move	#L-1,m6			; mod L addressing

	move	#>1.0/2048,x0		; alpha (scaling factor)

	move	#buffer,r4		; r4 points to output of buffer
	move	#L-1,m4			; mod L addressing
	clr  	a	#0,n4		; initialize pointer
	move	a,l:pointer

	move	#L-1,y0			; mask for mod L update of pointer

; start interrupts
	movep	#$b200,x:m_crb
	andi	#$00,mr

; ****************************************
; monitor the keyboard for changes in alpha
; uses b
	include	'monitor.asm'

; compare key hit to 'i', get incr, get ready for 'd'
	move	#'i',x1
	move	#>(1.0/16)/2048,y1
	cmp	x1,b		#'d',x1
	jne	d

; increment alpha by 1/16
	move	x0,b
	add	y1,b
	move	b,x0

; print b in decimal
pdec	do	#12,pdec1	;get ones place
	asl	b
pdec1	jsr	pnum		;print number in b2 as ASCII
	move	#'.',a		;print decimal place
	jsr	pwait
	tfr	b,a		;get tenths place
	do	#4,pdec2	; * 5
	add	a,b
pdec2	asl	b		; * 2
	jsr	pnum
	tfr	b,a		;get hundredths place
	do	#4,pdec3	; * 5
	add	a,b
pdec3	asl	b		; * 2
	jsr	pnum
	tfr	b,a		;get thousandths place
	do	#4,pdec4	; * 5
	add	a,b
pdec4	asl	b		; * 2
	jsr	pnum
crlf	move	#13,a		;CR
	jsr	pwait
	move	#10,a		;LF
	jsr	pwait
	jmp	getch

; print number in b2 to serial port as ASCII
pnum	move	b2,a
	move	#>'0',x1
	add	x1,a	#0,b2
	do	#16,pwait
	lsl	a
pwait	jclr	#m_tdre,x:m_ssr,pwait
	movep	a,x:m_srxh
	rts

; compare key hit to 'd'
d	cmp	x1,b
	jne	crlf

; decrement alpha by 1/16
	move	x0,b
	sub	y1,b
	move	b,x0
	jmp	pdec

; ****************************************
; do frequency shifting

; which channel input?
; when SCO is low, we get left channel data
dofreq	jclr	#m_if0,x:m_sr,left

; ****************************************
; right channel
;
right	move	a2,x:savea2		; save a register
	move	a1,x:savea1
	move	a0,x:savea0

	movep	x:m_rx,a		; get an input sample
	move		a,y:(r6)+	; store input sample (update pointer)

	move		y:(r4+n4),a	; get output sample
	movep	a,x:m_tx		; output a sample
;
; pointer update - get ready for left channel (it is first in data stream)
;
	move	l:pointer,a		; grab pointer
	add	x0,a			; add alpha to pointer
	rep	#12			; shift so a1 contains integer part
	asr	a
	and	y0,a			; modulo L
	move	a1,n4			; update pointer
	rep	#12			; shift back
	asl	a
	move	a,l:pointer		; save pointer
	nop

resta	move	x:savea2,a2		; restore a register
	move	x:savea1,a1
	move	x:savea0,a0
	rti

; ****************************************
; left channel
;
left	move	a2,x:savea2		; save a register
	move	a1,x:savea1
	move	a0,x:savea0

	movep	x:m_rx,a		; get an input sample
	move	a,x:(r6)		; store input sample

	move	x:(r4+n4),a		; get output sample
	movep	a,x:m_tx		; output a sample

	jmp	resta			; restore a register


	end	pgmram
