I want to perform pitch shifting with the method described in NEW PHASE-VOCODER TECHNIQUES FOR PITCH-SHIFTING, HARMONIZING AND OTHER EXOTIC EFFECTS. Basically, it involves:
Locate the spectral peaks and their indices in spectrums.
Determine the region of influence (ROI) for each detected peak.
Perform peak shifting according to the amount of frequency shift. Specifically, peaks and their ROI are shifted by an amount of frequency.
Update the phase to maintain the phase coherence, as in phase vocoder for time-scaling.
I am stuck in step 3. The paper describes that with a fractional number of frequency bin shifting (rather than integer number of frequency bin), one should use interpolation since the frequency bins are discrete:
If the amount of frequency shift is a fractional number of frequency bins, then frequency-domain interpolation is required, since the sinusoidal peak is only known at discrete frequencies.
My problem is that how do I perform peak shifting through, say, linear interpolation? And, assume a shifted spectrum is obtained, as interpolation insert values between the original discrete bins, how is it finally istf to the pitch-shifted output? I appreciate for any help.
EDIT:
I've realized my question can be simply be phrased as "fractional shifting of spectrum components". The following code is an example to achieve fractional shifting with a random signal using linear interpolation:
import numpy as np
import matplotlib.pyplot as plt
np.random.seed(5)
y = np.random.random(20)
alpha = 3.2 # shifting factor
# Pad the signal with zero
# to avoid spill-out caused by
# large shifting factor
nPad = np.ceil(alpha*len(y))
yPad = np.concatenate(
(y, np.zeros(int(nPad))))
x = np.arange(len(yPad))
xInt = x[0:len(y)]*alpha # the 'xp' in function interp
yInt = y # the 'fp' in function interp
# Now define 'x' in function interp
start = np.ceil(xInt[0])
end = np.ceil(xInt[-1])
if float(xInt[-1]).is_integer():
xQue = np.arange(start, end+1, 1).astype(int)
else:
xQue = np.arange(start, end, 1).astype(int)
yNew = np.interp(xQue, xInt, yInt) # linear interpolation
shifted = np.zeros(len(yPad))
shifted[xQue] = yNew
plt.plot(yPad, 'b')
plt.plot(shifted, 'r')
plt.show()
The above example uses a randomly generated signal to illustrate fractional shifting of a spectrum.
However, in the real case, a spectrum shouldn't be padded with zero in the first case as I do in the code. So, how to deal with the "spill" with spectrum component if the shifting factor is too large?