[comp.dsp] My pitch shifter for 56000

todd@ivucsb.sba.ca.us (Todd Day) (09/25/89)

Here is that crappy pitch shifter I was talking about.  It's
simply a circular buffer that has another pointer walking
through it at a different rate.

This was not written by me originally, but I converted it
for use in a stereo sampling system.

Explanation at end.

;**********************************************************
;
; 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

You do not need the include files... they are for setting up MY
particular system (you can get them off my archive server, though;
send the following lines to dsp@ivucsb.sba.ca.us

send README
send HOWTO

to get them).

You can get rid of a large part of the code in the center.  I am
simply monitoring the serial port for keys hit so I can change
the pitch shifting on the fly.  It also prints out over the serial
port the alpha value currently being used.

Note that the code for the left channel does not do the update.
You can nuke it if you want to do mono.

The alpha value determines the frequency multiplication.  If you
set it to 1.25, you increase the pitch by 25%, and if you set it
to 0.75, you decrease the pitch by 25%.

Note: this method has serious clicking problems, especially at low
values of alpha.  You can make it better by changing the buffer
length.

-- 

Todd Day  |  todd@ivucsb.sba.ca.us  |  ivucsb!todd@anise.acc.com
"It takes a smart man to know when he's stupid." - Barney Rubble

cyamamot@castor.usc.edu (Cliff Yamamoto) (09/25/89)

In article <1989Sep25.074206.972@ivucsb.sba.ca.us> todd@ivucsb.sba.ca.us (Todd Day) writes:
>This was not written by me originally, but I converted it
>for use in a stereo sampling system.
>	      ^^^^^^^^^^^^^^^^^^^^^^
>[code deleted]...
>
>You can get rid of a large part of the code in the center.  I am
>simply monitoring the serial port for keys hit so I can change
		   ^^^^^^^^^^^^^^^
>the pitch shifting on the fly.  It also prints out over the serial
>port the alpha value currently being used.

Todd,

Did you assemble this "system" yourself?  I'd like to get into DSP, but is
it really necessary that I spend >$1K to have such a system?  I have an AT
compatible and I really don't need to have a stand-alone system (like yours
with a serial port).  Does anyone out there have a 56001 system running on
an AT platform that they built/bought for under $1K?  Does adding a second
pair of ADC/DAC's for stereo increase the cost/complexity a lot?

Since I don't have any 56000 data sheets can you tell me what's the
difference between the 56000 and the 56001?

Thanks for any info!

Cliff

mhorne@ka7axd.WV.TEK.COM (Michael T. Horne) (09/26/89)

> compatible and I really don't need to have a stand-alone system (like yours
> with a serial port).  Does anyone out there have a 56001 system running on
> an AT platform that they built/bought for under $1K?

If you're looking for a board for the PC to experiment with (assuming you
don't want to build one yourself), you can pick up the PC-56 from Ariel.
I believe it costs $595 w/o the TI codec option (add $100 for this option).
Actually, I suspect you can buy the codec for very little money from a
distributor and save yourself the extremely overpriced option that Ariel
provides. If you're looking for `CD quality' audio, I suggest you stay
away from
the codec entirely (it is exactly that; a codec, narrow bandpass and all...).
The PC-56 has a wide socket on the board for external peripherals providing
access to the 56K's data/address bus.  I'd suggest wiring up a separate board
for acquisition, preferably external to the PC box with a separate
supply, since
the PC is loaded with RF and noisy supply lines.

If you don't want to spend that much, and you feel you can handle a wire-wrap
gun and soldering iron, I'd suggest wire-wrapping a system on a board that
drops into the PC.  I've done exactly that for a project I'm working on, and
its fairly straightforward.  If you don't expect to have/need any external
RAM (at least for a while), you can really save a lot of time and effort.  You
should be able to put together a system with 16Kx24 RAM for < $200 bucks,
perhaps < $100 in a `stripped down' version.

> Does adding a second
> pair of ADC/DAC's for stereo increase the cost/complexity a lot?

Complexity, no.  Cost, probably, depending on the quality of the ADC/DACs that
you use.  You should be able to configure two complete, good quality, 12-bit
channels (both directions) for < $50 extra.  Prices rise quickly for more bits.
I'd suggest looking at Moto's new S/D ADC (the 56ADC16) which will provide you
with clean, 16-bit input at 100KHz (and it interfaces nicely to the 56K).  If
you are planning on keeping the acquisition circuit internally within the PC,
using more than 12 bits may be moot unless you take great care in layout and
cleaning up the supply lines.

Mike

dean@image.soe.clarkson.edu (Dean Swan) (09/26/89)

> Did you assemble this "system" yourself?  I'd like to get into DSP, but is
> it really necessary that I spend >$1K to have such a system?  I have an AT
> compatible and I really don't need to have a stand-alone system (like yours
> with a serial port).  Does anyone out there have a 56001 system running on
> an AT platform that they built/bought for under $1K?  Does adding a second
> pair of ADC/DAC's for stereo increase the cost/complexity a lot?

Well, there are two companies that I can think of to get you going on this.

First, Turtle Beach Softworks has announced a 56k card for the AT.  I don't
know the price off hand, but it's a place to start.

Second, a company called Spectral Synthesis makes a system based on TI's
32C020.  Each of their cards has two DSP's on board, and you can connect
up to seven cards in a system.  They can get you going for about $2000, but
when I last saw their software, about eight months ago, they were not ready
to ship just yet.  Their software is called AudioCAD, and basically it lets
you connect fundamental blocks (mixers, amplifiers, etc.) graphically under
windows, then it compiles the code and assigns it to the bank of DSP's.
Their big goal is real time processing, so the have a neat set of resource
allocation routines, and process scheduling system to best use however many
DSP's you have in your system.  A full blown system is about $10k.  Oh, and
you can write your own primatives too.

-Dean Swan
dean@sun.soe.clarkson.edu

dean@image.soe.clarkson.edu (Dean Swan) (09/26/89)

Todd,
  Have you considered using a sample rate conversion filter to do your
pitch shifting?  To increase the pitch you'd also have to low-pass filter
the original to prevent nyquist aliasing, and use the sample rate converter
to generate a lower sample rate. Then just output the new samples at the 
same rate.
  To decrease pitch, you can skip the low-pass and use the conversion filter
to generate a higher sample rate, then just play it back at the same old
speed.
  This method would tend to sound Mickey Mouse-y or Darth Vader-like if you
do any extreme pitch shifting, and it's also subject to time compression and
expansion problems proportional to the amount of pitch shifting, but it would
give the "smoothest" (I hesitate to say "best" because the time compression
could be unaccecptable) sounding results.

Here's another possibility, which may or may not work:

      Assume that your input is of the form:
        Y=Sin( F*A )

      Then  F = ArcSin(Y)/A
      Next do F=F+pitch shift amount
      and reconstruct with Y=Sin(F*A).

I've been doing a lot of work with FM synthesis, and this idea just ocurred
to me because of that.  If it works, let me know, and apropriately credit
your sources (i.e. Me).  This is not compute intensive at all and it isn't
subject to time compression or expansion either.

By the way A represents the phase angle.  In your case you would use T, the
time value and pick some scaling factor so that the trig functions (or more
likely, table look-ups and interpolations) will make sense.

Good Luck, and let me know what the results are.  I'll try to do some math
on this and see if it's really workable, if I have some spare time.

-Dean Swan
dean@sun.soe.clarkson.edu

d88-jwa@nada.kth.se (Jon W{tte) (09/27/89)

In article <1989Sep25.172140.27543@sun.soe.clarkson.edu> dean@image.soe.clarkson.edu (Dean Swan) writes:
>      Assume that your input is of the form:
>        Y=Sin( F*A )

>      Then  F = ArcSin(Y)/A
>      Next do F=F+pitch shift amount
                 ^^^
		That should be a * ! a * ! a * !

>      and reconstruct with Y=Sin(F*A).

How many times will I have to read this ? Pitch shift isn't about
"adding 100 Hz", it's about scaling a spectra. Are you people
conspiring against me just to drive me mad ? (note the crosspost)

The problem is; input is

sum i from 1 to n   sin ( Fi * t + Pi )

for some unknown (often large) n, unknown F and unknown P...
You could not possibly solve that equation fast enough.

Someone mentioned a 1024-point FFT with a sliding window.
That just might be the solution ? But the 5600{0,1} does
a 1024-point FFT in 3.3 ms which is 100 times too slow for
any kind of HiFi quality. (ONE channel only !)

h+@nada.kth.se
-- 
Another good night not to sleep in a eucalyptus tree.

jensen@bessel.eedsp.gatech.edu (P. Allen Jensen) (09/30/89)

There is a group here in town (Atlanta, Ga, USA) called
Atlanta Signal Processors, Inc. (ASPI) that has a board called
a banshee that is based on the TMS320C20 (They also have some
stuff for the C30 and C10)

If anyone is interested, I can lookup their address and post it....


P. Allen Jensen
Georgia Tech, School of Electrical Engineering, Atlanta, GA  30332
USENET: ...!{allegra,hplabs,ihnp4,ulysses}!gatech!eedsp!jensen
INTERNET: jensen@eedsp.gatech.edu