| 235 | } |
| 236 | |
| 237 | void runLogRebin(span<const i16> buffer, Bins *out) { |
| 238 | out->setParams(mFmin, mFmax, mSampleRate); |
| 239 | const int N = mInputSamples; |
| 240 | const int bands = mTotalBands; |
| 241 | const int numRawBins = N / 2 + 1; |
| 242 | |
| 243 | // Use thread-local scratch buffers to avoid stack overflow on |
| 244 | // ESP32 tasks with limited stack (~4-8 KB). |
| 245 | FftScratch &s = scratch(); |
| 246 | s.windowed.resize(N); |
| 247 | s.fftOut.resize(N); |
| 248 | s.re.resize(numRawBins); |
| 249 | s.im.resize(numRawBins); |
| 250 | s.mag.resize(numRawBins); |
| 251 | s.rawBinsI.resize(bands); |
| 252 | |
| 253 | applyWindow(buffer.data(), mWindowBuf.data(), s.windowed.data(), N); |
| 254 | fl_fft_real_forward(mFftrCfg, mInputSamples, s.windowed.data(), s.fftOut.data()); |
| 255 | |
| 256 | // Deinterleave AoS → SoA and batch-compute magnitudes |
| 257 | deinterleave(s.fftOut.data(), s.re.data(), s.im.data(), numRawBins); |
| 258 | batchMag(s.re.data(), s.im.data(), s.mag.data(), numRawBins); |
| 259 | |
| 260 | // Linear bins (same as other paths) |
| 261 | computeLinearBins(s.mag.data(), N, out); |
| 262 | |
| 263 | // Group FFT bins into log-spaced output bins (integer accumulation) |
| 264 | fl::memset(s.rawBinsI.data(), 0, sizeof(u32) * bands); |
| 265 | logRebinRange(s.mag.data(), N, static_cast<float>(mSampleRate), |
| 266 | 0, bands, s.rawBinsI.data(), mLogBinLut); |
| 267 | |
| 268 | // Store raw magnitudes (dB computed lazily by Bins::db()) |
| 269 | fl::vector<float> &rawBins = out->raw_mut(); |
| 270 | rawBins.resize(bands); |
| 271 | for (int i = 0; i < bands; ++i) { |
| 272 | rawBins[i] = static_cast<float>(s.rawBinsI[i]); |
| 273 | } |
| 274 | |
| 275 | // Store bin-width normalization factors so consumers can optionally |
| 276 | // normalize (e.g. for equalization display). Raw output is unchanged. |
| 277 | out->setNormFactors(mLogBinNormFactors); |
| 278 | } |
| 279 | |
| 280 | // ---- Naive single-FFT path (narrow frequency ranges) ---- |
| 281 |
nothing calls this directly
no test coverage detected