Я все еще очень новичок в обработке сигналов, и я хотел создать своего рода пример VST-плагина с использованием FFTW (так как FFT и IFFT я нашел на Розетта Код казалось, работает слишком медленно), который ничего не делает, но (бесполезно) применяет БПФ к каждой входной выборке, а затем применяет IFFT к результату этого. Цель состояла в том, чтобы вернуть исходный звук, но результат кажется (из-за отсутствия знания лучшего термина для описания качества звука) искаженным. Вот код для processReplacing
функция:
void VST_Testing::VST_Testing::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) {
resume();
time = 0;
float *in1 = inputs[0];
float *in2 = inputs[1];
float *out1 = outputs[0]; //L
float *out2 = outputs[1]; //R
float *out3 = outputs[2]; //C
float *out4 = outputs[3]; //RL
float *out5 = outputs[4]; //RR
VstInt32 initialFrames = sampleFrames;
fftw_complex* left = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
fftw_complex* right = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
int i = 0;
while (--sampleFrames >= 0)
{
left[i][0] = *in1++;
left[i][1] = 0;
right[i][0] = *in2++;
left[i][1] = 0;
i++;
}
sampleFrames = initialFrames;
fftw_complex* l_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
fftw_complex* r_out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*sampleFrames);
fftw_plan p_l = fftw_plan_dft_1d(sampleFrames, left, l_out, FFTW_FORWARD, FFTW_MEASURE);
fftw_plan p_r = fftw_plan_dft_1d(sampleFrames, right, r_out, FFTW_FORWARD, FFTW_MEASURE);
fftw_execute(p_l);
fftw_execute(p_r);
fftw_destroy_plan(p_l);
fftw_destroy_plan(p_r);
p_l = fftw_plan_dft_1d(sampleFrames, l_out, left, FFTW_BACKWARD, FFTW_MEASURE);
p_r = fftw_plan_dft_1d(sampleFrames, r_out, right, FFTW_BACKWARD, FFTW_MEASURE);
fftw_execute(p_l);
fftw_execute(p_r);
i = 0;
while (--sampleFrames >= 0)
{
(*out3++) = 0.5*left[i][0] + 0.5*right[i][0];
(*out4++) = left[i][0];
(*out5++) = right[i][0];
i++;
}
fftw_destroy_plan(p_l);
fftw_destroy_plan(p_r);
fftw_free(left);
fftw_free(right);
fftw_free(l_out);
fftw_free(r_out);
}
}
Я ожидал, что я получу сигнал от in1
а также in2
(левый и правый вход в ожидаемом использовании) вход почти одинаково включен out4
а также out5
(задний левый и задний правый выход в ожидаемом использовании). Я сделал ошибку в коде, или мои ожидания от поведения FFTW неверны?
Эта проблема, очевидно, была вызвана, помимо ошибки копирования и вставки, тем фактом, что FFTW вычисляет ненормализованное преобразование. От «Что на самом деле вычисляет FFTW,»
FFTW вычисляет ненормализованное преобразование, в котором отсутствует коэффициент перед суммированием в DFT. Другими словами, применение прямого и обратного преобразования умножит входной сигнал на n.
Решением этой проблемы было разделение сигналов на initialFrames
для нормализации:
while (--sampleFrames >= 0)
{
(*out3++) = 0.5*(left[i][0]/initialFrames) + 0.5*(right[i][0]/initialFrames);
(*out4++) = left[i][0]/initialFrames;
(*out5++) = right[i][0]/initialFrames;
i++;
}
Из ссылки FFTW:
FFTW_MEASURE говорит FFTW найти оптимизированный план, фактически вычисляя несколько FFT и измеряя время их выполнения. В зависимости от вашей машины это может занять некоторое время (часто несколько секунд).
Это говорит о том, что вам, вероятно, следует выполнить эту процедуру заранее, а затем использовать планы, которые она разработала, и не создавать их заново с каждым циклом. Конечно, для этого потребуется фиксированный размер кадра, но вы все равно столкнулись бы с этой проблемой рано или поздно.
Вероятно, не единственная проблема, но у вас есть ошибка копирования-вставки здесь:
while (--sampleFrames >= 0)
{
left[i][0] = *in1++;
left[i][1] = 0;
right[i][0] = *in2++;
left[i][1] = 0; // <<< should be right[i][1] = 0;
i++;
}