Pitchshifting with FFT
Yesterday, I outlined a process for time-stretching a signal by interpolating between FFT frames in Reaktor. Today, I’ll explain how to pitch-shift using the FFT frequency detector I posted recently, and demonstrate how we can add it to the time-stretcher. The algorithm I’ll be using was outlined in this paper by Stephan Bernsee, a true titan of the DSP world.
The first step we must accomplish is calculating the true frequency of each FFT bin. This is not too hard, and I’ve already outlined how to do it in my post on the FFT frequency detector. After this process is complete, we are left with three pieces of information – the FFT bin number, the amplitude of the sine wave, and the true frequency of the sine wave. Now that we know the pitch, we are ready to shift it.
The true frequencies and the bin number should be multiplied by the variable pitch shift value. The amplitudes do not change – we are changing the pitch after all. Both the amplitudes and the new frequencies can then be stored in an array using the new FFT bin we calculated. Once we have done this for an entire FFT frame, we can read the values we’ve stored out. We have to wait for a whole frame due to the lack of iteration in core and the nature of the ezFFT modules. This means that implementing this algorithm in Reaktor will impose an extra 512 samples of latency. Here’s what all of this looks like:
The copy-erase modules do exactly that – The copy the Buf array into the Out array, and then erase all the data in the Buf array. What comes out of these arrays is the amplitudes and true frequencies, shifted in position. Now we can just undo the frequency detection math we did earlier and plug it all into iFFT and we’re done! Undoing the math:
Now we have the phase difference and the amplitude values, we simply add the phase difference to the phase from 512 samples ago (remember we’re latent by a whole FFT cycle at this point). Now we convert from polar form back to Cartesian coordinates, (the pol2Vec macro that comes as part of the ezFFT package) and run send it to an iFFT.
Here’s a sample of the sound. I play around with some octave jumps and then start time-stretching as well as pitch-shifting to demonstrate the two together.
Turn off On button
Load a file
Press Read button
Wait a second
Then press On, and play with the knobs
Let me know if you do anything cool with it!