Hi I m implementing pitch shifter. I have done some tests on sinus wave and when i set my ratio = 2 so i want to change pitch one octave up i got some artifacts:
So i as you see on the picture above i was able to chagne pitch correctly but i got some unwanted freqs in signal.
When I set a ratio = 1 :
the pitch was unchanged, as wanted and also i didnt get any artifacts.
I assume that the problem is with FFT size and hop size, because when i was changing those values the results was different some got more artifacts, some less.
Is there a rule how to set a FFT size and hop size to get the best results without artifacts? Or maybe there can be a mistake in my implementation?
With this vaules it worked the best:
my buffer size =441;
fftSize = 64;
hopSize = fftSize/8;
Also i noticed that when i change the ratio the sum of artifacts is changing…
This is my code in procces block:
my_fft.perform(preFFTBuffer.data(), fftBuffer.data(), false);
for (int i = 0; i < fftSize / 2+1; i++)
{
// magnitude and phase calculation
double magnitude = getMagnitude(fftBuffer[i]);
double phase = getPhase(fftBuffer[i]); // in radians
/// calcualte phase diff between the last phase from previous hop and new one
float phaseDiff = phase - previousInputPhases[i];
// get Central Freq of bin
float binCentreFrequency = getFreq(i);
/// amount of phase increment we'd expect
phaseDiff = wrapPhase(phaseDiff - binCentreFrequency * hopSize);
//deviation in (fractional) number of bins from the centre frequency
float binDevation = phaseDiff * (float)fftSize / (float)hopSize / (2.0 * M_PI);
// add the original bin number to get the fractional bin where this partial belongs
analysisFreqs[i] = (float)i + binDevation;
/// save magnitude for later
analysisMagnitude[i] = magnitude;
// saving phase for later
previousInputPhases[i] = phase;
}
// Zero out the synthesis bins, ready for new data
//// std::fill(synthFreqs.begin(),synthFreqs.end(),0.f);
/// std::fill(synthMagnitude.begin(), synthMagnitude.end(), 0.f);
for (int i = 0; i <= fftSize / 2; i++)
{
synthMagnitude[i] = synthFreqs[i] = 0;
}
for (int i = 0; i <= fftSize / 2; i++)
{
// finding the nearest bin to the shifted frequency
int newBin = floorf(i * ratio + 0.5);
if (newBin <= fftSize / 2)
{
synthMagnitude[newBin] += analysisMagnitude[i];
synthFreqs[newBin] = analysisFreqs[i] * ratio;
}
}
for (int i = 0; i <= fftSize / 2; i++)
{
double amplitude = synthMagnitude[i];
float binDeviation = synthFreqs[i] - i;
float phaseDiff = binDeviation * 2.0 * M_PI * (float)hopSize / (float)fftSize;
float binCentrFreq = 2.0 * M_PI * (float)i / (float)fftSize;
phaseDiff += binCentrFreq * hopSize;
float outPhase = wrapPhase(previousOutputPhases[i] + phaseDiff);
/// converting phase and magnitude to complex numbers
fftBuffer[i] = amplitude * cosf(outPhase) + (amplitude * sinf(outPhase) * 1i);
if (i > 0 && i < fftSize / 2)
{
fftBuffer[fftSize - i] = amplitude * cosf(outPhase) + (-(amplitude * sinf(outPhase) * 1i));
}
previousOutputPhases[i] = outPhase;
}
my_fft.perform(fftBuffer.data(), outputFFTBuffer.data(), true);