BelaPlatform / Bela

Bela: core code, IDE and lots of fun!
Other
490 stars 139 forks source link

fft.fda() might return NaN #727

Open wjslager opened 6 months ago

wjslager commented 6 months ago

Calling fft.fda() returns NaN when both the real and imaginary value of that bin equal 0.0f, which might occur if a bin is somehow completely silent. It doesn't seem to happen that often and checking with std::isnan always returns false when compiling -ffast-math.

I fixed it by checking the real and imaginary part beforehand.

if (_fft.fdr(b) <= 0.0f && _fft.fdi(b) <= 0.0f)
    amp = 0.0f;
else
    amp = _fft.fda(b);
giuliomoro commented 3 months ago

That check should probably be added in fda() itself (or - even better - in sqrtf_neon(), as this looks like a failure in the library). As for the cause, math_neon implements sqrtf_neon() starting off with:

"vmov.f32       d1, d0                  \n\t"   //d1 = d0
"vrsqrte.f32    d0, d0                  \n\t"   //d0 = ~ 1.0 / sqrt(d0)

I assume the second instruction may cause something similar to a division by 0 and the consequent NaN. FWIW, there's also a void sqrtfv_neon(float *x, int n, float *y) function which takes array inputs and outputs and is probably more than three times faster at doing sqrt than individual calls to sqrtf_neon(), so one may find it useful to use that instead if you need to compute the absolute value across all values of the FFT.

giuliomoro commented 3 months ago

@wjslager can you try the dev branch to verify it's fixed?