I'm trying to use KissFFT natively in a java app, but the forward/inverse of an input signal isn't returning as it should: the signal amplitude is almost non-existent. If I remove the scaling factor (dividing by 2N), the result is harmonic noise. Can anyone spot the bug?
Here is the forward call (copied from GDX, so should be ok!):
JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_spectrum(JNIEnv* env, jclass clazz, jlong handle, jshortArray obj_samples, jfloatArray obj_spectrum) {
short* samples = (short*)env->GetPrimitiveArrayCritical(obj_samples, 0);
float* spectrum = (float*)env->GetPrimitiveArrayCritical(obj_spectrum, 0);
KissFFT* fft = (KissFFT*)handle;
kiss_fftr( fft->forwardConfig, (kiss_fft_scalar*)samples, fft->spectrum );
int len = fft->numSamples / 2 + 1;
for( int i = 0; i < len; i++ )
{
float re = scale(fft->spectrum[i].r) * fft->numSamples;
float im = scale(fft->spectrum[i].i) * fft->numSamples;
if( i > 0 )
spectrum[i] = sqrtf(re*re + im*im);
else
spectrum[i] = sqrtf(re*re + im*im);
}
env->ReleasePrimitiveArrayCritical(obj_samples, samples, 0);
env->ReleasePrimitiveArrayCritical(obj_spectrum, spectrum, 0);
}
And here is the inverse (written by me, probably has an error ;) ):
JNIEXPORT void JNICALL Java_com_badlogic_gdx_audio_analysis_KissFFT_inverse(JNIEnv* env, jclass clazz, jlong handle, jshortArray obj_samples) {
short* shortSamples = (short*)env->GetPrimitiveArrayCritical(obj_samples, 0);
//@line:108
KissFFT* fft = (KissFFT*)handle;
kiss_fft_cpx out[fft->numSamples];
kiss_fftri( fft->inverseConfig, fft->spectrum, (kiss_fft_scalar*)out );
for (int i=0; i < fft->numSamples; i++) {
shortSamples[i] = (out[i].r) / (fft->numSamples*2);
}
env->ReleasePrimitiveArrayCritical(obj_samples, shortSamples, 0);
}
Per protectedmember's request, here is a more complete example (on the native side, anyway). I ended up modifying the libgdx code slightly (using v.0.9.4). I also compiled with floating-point rather than fixed, as the latter introduced quantization noise when inversing. This code should work for either (because kiss_fft_scalar adapts to short or float depending on the compiler flag), but have not re-tested with fixed, since I found it's not useful for a fft->ifft series.
I am curious to know if you are successful, do let me know!
(Please note that this code, following libgdx, is under Apache 2.0 license!)
See my answer to a similar question.
or from the kissfft README file:
Whoops! Found the problem. I should have been doing the inverse transform right into the short array: