Reputation: 1466
I'm still very new to signal processing, and I wanted to create a sort of example VST plugin using FFTW (since the FFT and IFFT I found on Rosetta Code seemed to be working too slowly) that does nothing but (uselessly) apply a FFT to each input sample, then apply an IFFT to the result of this. The goal was to get the original sound back, but the output seems (for lack of knowledge of a better term to describe the quality of the sound) "garbled." Here is the code for the processReplacing
function:
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);
}
}
My expectation was that I would get the signal from in1
and in2
(left and right input in the expected use) input back almost identically on out4
and out5
(rear left and rear right output in the expected use). Have I made a mistake in the code, or is my expectation of FFTW's behavior incorrect?
Upvotes: 0
Views: 221
Reputation: 1466
The problem was evidently caused by, in addition to the copy-and-paste error, the fact that FFTW computes an unnormalized transform. From "What FFTW really computes,"
FFTW computes an unnormalized transform, in that there is no coefficient in front of the summation in the DFT. In other words, applying the forward and then the backward transform will multiply the input by n.
The solution to this problem was to divide the signals by initialFrames
in order to normalize:
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++;
}
Upvotes: 2
Reputation: 213190
Probably not your only problem, but you have a copy-paste error here:
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++;
}
Upvotes: 1
Reputation: 3324
From the FFTW reference:
FFTW_MEASURE tells FFTW to find an optimized plan by actually computing several FFTs and measuring their execution time. Depending on your machine, this can take some time (often a few seconds).
This suggest that you probably should run this routine in advance and then use the plans it produced, and not recreate them with every cycle. Of course, this would require the fixed size of a frame, but you would've faced this problem sooner or later anyway.
Upvotes: 1