Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!anise.acc.com!ivucsb!todd From: todd@ivucsb.sba.ca.us (Todd Day) Newsgroups: comp.dsp Subject: My pitch shifter for 56000 Message-ID: <1989Sep25.074206.972@ivucsb.sba.ca.us> Date: 25 Sep 89 07:42:06 GMT Reply-To: todd@ivucsb.sba.ca.us (Todd Day) Organization: Disillusioned Graduate Hackers, Santa Barbara, CA Lines: 219 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