Я работаю на частотном переключателе с использованием примитивного алгоритма FFT, поставляемого Rosetta Code. Я понимаю, что для сдвига частоты сигнала образцов, один применяет БПФ к исходному звуку, умножает частоту каждой результирующей синусоидальной частоты на частотный сдвиг (определяемый пользователем), а затем снова объединяет синусоидальные волны. Когда я запускаю свой алгоритм, выход имеет крайне низкое качество, как будто в алгоритме не было достаточного количества синусоидальных волн, чтобы вначале правильно воспроизвести сигнал. Алгоритм реализован в классе в файле заголовка и называется (правильно) в другом месте.Частотный преобразователь с использованием FFT
#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));
}
}
}
};
Я предполагаю, что часть проблемы заключается в том, что я только в том числе sampleRate/inFramesToProcess
частоты для синусоиды, чтобы покрыть. Посылал бы большие аудиофайлы (таким образом, больше *inBlock
s и inFramesToProcess
s) сделать звук менее зернистым? Как бы это сделать без, просто изменяя значения или длины аргументов?
Что вы подразумеваете под «нет выхода»? – 1201ProgramAlarm
@ 1201ProgramAlarm Когда я тестирую вывод '* inBlock', нет уровня (уровень звука равен 0 или какая-то другая ошибка). По сути, в алгоритме есть некоторая ошибка, которую я не могу обнаружить и исправить. –
Действительно ли 'convertToReal' правильный путь? Тривиально, если 'inFramesToProcess' равен 1,' data' будет иметь комплексное число, в котором нет мнимой части. 'fft' ничего не сделает с этим, поэтому, когда он будет преобразован обратно, вы попытаетесь взять sqrt отрицательного числа. Нет. 'Fft' ничего не сделает с последним элементом' x', если 'x.size()' нечетно. – 1201ProgramAlarm