I've been working on a frequency shifter using a primitive FFT algorithm supplied by Rosetta Code. I understand that to frequency shift a signal of samples, one applies an FFT to the original audio, multiplies the frequency of each resulting sine-wave by the frequency-shift factor (user defined), and then adds the sine-waves back together. When I run my algorithm, the output is of extremely low quality, as though there were not enough sine waves collected within the algorithm to have reproduced the signal close to correctly in the first place. The algorithm is implemented in a class in a header file and called (correctly) elsewhere.
#include <complex>
#include <valarray>
typedef std::complex<double> Complex;
typedef std::valarray<Complex> CArray;
class FrequencyShifter {
float sampleRate;
public:
FrequencyShifter() {
}
void setSampleRate(float inSampleRate) {
sampleRate = inSampleRate;
}
double abs(double in0) {
if (in0>=0) return in0;
else return -in0;
}
void fft(CArray& x)
{
const size_t N = x.size();
if (N <= 1) return;
// divide
CArray even = x[std::slice(0, N/2, 2)];
CArray odd = x[std::slice(1, N/2, 2)];
// conquer
fft(even);
fft(odd);
// combine
for (size_t k = 0; k < N/2; ++k)
{
Complex t = std::polar(1.0, -2 * PI * k / N) * odd[k];
x[k ] = even[k] + t;
x[k+N/2] = even[k] - t;
}
}
double convertToReal(double im, double re) {
return sqrt(abs(im*im - re*re));
}
void processBlock(float *inBlock, const int inFramesToProcess, float scale) {
//inFramesToProcess is the amount of samples in inBlock
Complex *copy = new Complex[inFramesToProcess];
for (int frame = 0; frame<inFramesToProcess; frame++) {
copy[frame] = Complex((double)inBlock[frame], 0.0);
}
CArray data(copy, inFramesToProcess);
fft(data);
const float freqoffsets = sampleRate/inFramesToProcess;
for (float x = 0; x<data.size()/2; x++) {
for (float frame = 0; frame<inFramesToProcess; frame++) {
inBlock[(int)frame] = (float)(convertToReal(data[(int)x].imag(), data[(int)x].real())*sin(freqoffsets*x*frame*scale));
}
}
}
};
I'm assuming that part of the problem is that I'm only including sampleRate/inFramesToProcess frequencies for the sine waves to cover. Would sending larger audio files (thus larger *inBlocks and inFramesToProcesss) make the audio less grainy? How would I accomplish this without just changing the values or lengths of the arguments?



*inBlockthere is no level (audio level is 0 or some other error was encountered). Essentially, there is some mistake in the algorithm which I am unable to detect and fix. - Linus RastegarconvertToRealthe correct way round? Trivially, ifinFramesToProcessis 1,datawill have a complex number with no imaginary part in it.fftwon't do anything to it, so when this gets converted back you'll try to take the sqrt of a negative number. Nontrivially,fftwon't do anything to the last element ofxifx.size()is odd. - 1201ProgramAlarm