Cabbage Logo
Back to Cabbage Site

PD Pitchshifter Port

Hey friends, I have tried to port Miller Pucket’s pitchshifter here to csound:

opcode StanyDelay, a, akk

ain, kx1, kx2  xin    
kcout init 0   

kPortTime linseg   0, 0.2, 0.0
kinT    portk  kx1  , kPortTime
aDel delayr 4
aT deltapi a(kinT)
delayw ain+(aT * kx2)

        xout aT        ; write output


opcode MPitch, a, akkkkk
ain, kt, kwin,kdel, kmix, kz xin
kwm max kwin, .001
kdm max kdel, .0015
ares atone ain, 300
kval = ((exp(kt*.05776)-1)*-1)/kwm

aphas phasor kval

apw = aphas +.5
apa = cos((aphas-.5)*.5)

aw wrap apw, 0, 1
awa  = cos((aw-.5)*.5)
kPortTime linseg   0, 0.2, 0
ksig = k(aphas*kwm+kdm)
ksigb = k(aw*kwm+kdm)
kinT    portk  ksig, kPortTime
kinTb    portk  ksigb, kPortTime
awm StanyDelay ares,kinT,kz
ada StanyDelay ares,kinTb,kz

ai = apa*awm
aj = awa*ada
apshift = (ai+aj)
amix ntrpol ain, apshift, kmix

xout amix


I am having difficulty with the delay lines and despite interpolating the incoming values, there seems to be a bad click on the delay line when the phasor wraps, maybe im assuming similarities of some of the names of the pd and csound library but any help would be appreciated. I did look at this as well (might be a bad rabbit hole) but im wondering if pd’s phasor c code handles multiplying by zero on the audio thread and maybe i need to account for this:

You’ll need to apply envelopes to the delayed signal. Maybe you already are? I’ve not had my morning coffee yet, so I’m a little slow still!

FWIW, here is a pitch-shifter that also employs a single delay lines, with out of phase read/write pointers. I have probably over-simplified this but it does the trick. I don’t bother with this approach in Csound any more, as the PVS opcodes offers so much more control.

giEnv ftgen 1, 0, 1024, 7, 0, 512, 1, 512, 0; gain envelop

   aSnd diskin2 "Guitar2.wav", 1, 0, 1    ;read source a normal speed
   iDelay = .1
   kRate = 1.5
   kReadFreq = (1-kRate)/iDelay
   aReadPointer1 phasor kReadFreq
   aReadPointer2 phasor kReadFreq, 0.5
   aSig1 vdelay aSnd, aReadPointer1 * iDelay * 1000, 2000
   aSig2 vdelay aSnd, aReadPointer2 * iDelay * 1000, 2000
   aXFade1 tab aReadPointer1, 1, 1
   aXFade2 tab aReadPointer2, 1, 1
   aMix = aSig1 * (aXFade1)+aSig2 * (aXFade2)
   outs aMix, aMix                          ;output

schedule("REALTIME_PITCH_SHIFT", 0, 10)
1 Like

thanks rory! is ftable at the top supposed to be used for something in the code?

It’s being read by the tab opcodes to apply the crossfading envelopes.

1 Like