| 293 | } |
| 294 | |
| 295 | void runNaive(span<const i16> buffer, Bins *out) { |
| 296 | out->setParams(mFmin, mFmax, mSampleRate); |
| 297 | const int fftSize = mInputSamples; |
| 298 | const int numRawBins = fftSize / 2 + 1; |
| 299 | |
| 300 | FftScratch &s = scratch(); |
| 301 | s.fftOut.resize(fftSize); |
| 302 | s.re.resize(numRawBins); |
| 303 | s.im.resize(numRawBins); |
| 304 | s.mag.resize(numRawBins); |
| 305 | |
| 306 | fl_fft_real_forward(mFftrCfg, mInputSamples, buffer.data(), s.fftOut.data()); |
| 307 | |
| 308 | // Deinterleave AoS → SoA and batch-compute magnitudes |
| 309 | deinterleave(s.fftOut.data(), s.re.data(), s.im.data(), numRawBins); |
| 310 | batchMag(s.re.data(), s.im.data(), s.mag.data(), numRawBins); |
| 311 | |
| 312 | computeLinearBins(s.mag.data(), fftSize, out); |
| 313 | |
| 314 | FASTLED_STACK_ARRAY(kiss_fft_cpx, cq, mCqCfg.bands); |
| 315 | apply_kernels(s.fftOut.data(), cq, mKernels, mCqCfg); |
| 316 | |
| 317 | const int bands = mCqCfg.bands; |
| 318 | fl::vector<float> &rawBins = out->raw_mut(); |
| 319 | rawBins.resize(bands); |
| 320 | for (int i = 0; i < bands; ++i) { |
| 321 | i32 real = cq[i].r; |
| 322 | i32 imag = cq[i].i; |
| 323 | #ifdef FIXED_POINT |
| 324 | rawBins[i] = static_cast<float>(fastMag(real, imag)); |
| 325 | #else |
| 326 | float r2 = float(real * real); |
| 327 | float i2 = float(imag * imag); |
| 328 | rawBins[i] = sqrt(r2 + i2); |
| 329 | #endif |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | // Fast integer magnitude: max(|re|,|im|) + 0.40625*min(|re|,|im|) |
| 334 | // Max error ~3.5% vs exact sqrt(re²+im²). No float, no division. |
nothing calls this directly
no test coverage detected