FastLED 3.10.8
Loading...
Searching...
No Matches

◆ runHybrid()

void fl::audio::fft::Context::runHybrid ( span< const i16 > buffer,
Bins * out )
inlineprivate

Definition at line 962 of file fft_impl.cpp.hpp.

962 {
963 const int N = mInputSamples;
964 const int numRawBins = N / 2 + 1;
965
966 out->setParams(mFmin, mFmax, mSampleRate);
967
968 // Use thread-local scratch buffers
969 FftScratch &s = scratch();
970 s.re.resize(numRawBins);
971 s.im.resize(numRawBins);
972 s.mag.resize(numRawBins);
973 s.windowed.resize(N);
974 s.rawBinsI.resize(mTotalBands);
975
976 // Phase 1: Windowed 512pt FFT → LOG_REBIN for upper bins
977 applyWindow(buffer.data(), mWindowBuf.data(), s.windowed.data(), N);
978
979 fl_fft_real_forward(mFftrCfg, mInputSamples, s.windowed.data(), mFftOut.data());
980
981 deinterleave(mFftOut.data(), s.re.data(), s.im.data(), numRawBins);
982 batchMag(s.re.data(), s.im.data(), s.mag.data(), numRawBins);
983
984 computeLinearBins(s.mag.data(), N, out);
985
986 // Integer accumulation for log-rebin
987 fl::memset(s.rawBinsI.data(), 0, sizeof(u32) * mTotalBands);
988
989 // Upper tier: LOG_REBIN for bins [mHybridMidSplitBin, mTotalBands)
990 logRebinRange(s.mag.data(), N,
991 static_cast<float>(mSampleRate),
992 mHybridMidSplitBin, mTotalBands, s.rawBinsI.data(),
993 mLogBinLut);
994
995 // Decimate signal: 512 → 256 → 128 (2 steps for mid tier)
996 int workLen = N;
997 for (int i = 0; i < N; i++) {
998 mWorkBuf[i] =
999 (i < static_cast<int>(buffer.size())) ? buffer[i] : 0;
1000 }
1001 decimateBy2(mWorkBuf.data(), workLen);
1002 workLen /= 2;
1003 decimateBy2(mWorkBuf.data(), workLen);
1004 workLen /= 2;
1005
1006 // Phase 2: Zero-padded 256pt FFT (128 windowed + 128 zeros) → LOG_REBIN for mid bins
1008 int midFftN = mHybridMidN * 2;
1009 int midRawBins = midFftN / 2 + 1;
1010 s.windowed.resize(midFftN);
1011 applyWindow(mWorkBuf.data(), mHybridMidWindow.data(),
1012 s.windowed.data(), mHybridMidN);
1013 for (int i = mHybridMidN; i < midFftN; ++i) {
1014 s.windowed[i] = 0;
1015 }
1017 s.windowed.data(),
1018 mHybridMidFftOut.data());
1019 deinterleave(mHybridMidFftOut.data(), s.re.data(), s.im.data(), midRawBins);
1020 batchMag(s.re.data(), s.im.data(), s.mag.data(), midRawBins);
1021
1022 logRebinRange(s.mag.data(), midFftN,
1024 mHybridSplitBin, mHybridMidSplitBin, s.rawBinsI.data(),
1026 }
1027
1028 // Decimate 1 more step: 128 → 64 (reuse unwindowed workBuf)
1029 decimateBy2(mWorkBuf.data(), workLen);
1030 workLen /= 2;
1031
1032 // Phase 3: Windowed 64pt FFT → LOG_REBIN for bass bins
1033 if (mHybridSplitBin > 0 && mHybridSmallFft) {
1034 int bassRawBins = mHybridSmallN / 2 + 1;
1035 s.windowed.resize(mHybridSmallN);
1036 applyWindow(mWorkBuf.data(), mHybridBassWindow.data(),
1037 s.windowed.data(), mHybridSmallN);
1039 s.windowed.data(),
1040 mHybridSmallFftOut.data());
1041 deinterleave(mHybridSmallFftOut.data(), s.re.data(), s.im.data(), bassRawBins);
1042 batchMag(s.re.data(), s.im.data(), s.mag.data(), bassRawBins);
1043 logRebinRange(s.mag.data(), mHybridSmallN,
1045 0, mHybridSplitBin, s.rawBinsI.data(),
1047 }
1048
1049 // Store raw magnitudes (dB computed lazily by Bins::db())
1050 fl::vector<float> &rawBins = out->raw_mut();
1051 rawBins.resize(mTotalBands);
1052 for (int i = 0; i < mTotalBands; ++i) {
1053 rawBins[i] = static_cast<float>(s.rawBinsI[i]);
1054 }
1055
1056 // Use pre-computed merged norm factors (no per-frame allocation)
1057 out->setNormFactors(mHybridMergedNorm);
1058 }
fl::vector< alpha16 > mHybridBassWindow
static void batchMag(const kiss_fft_scalar *re, const kiss_fft_scalar *im, u16 *mag, int n) FL_NO_EXCEPT
void computeLinearBins(const u16 *mag, int, Bins *out) FL_NO_EXCEPT
void logRebinRange(const u16 *mag, int fftN, float fs, int binStart, int binEnd, u32 *rawBinsI, const fl::vector< u8 > &lut) FL_NO_EXCEPT
fl::vector< kiss_fft_scalar > mWorkBuf
fl::vector< alpha16 > mWindowBuf
fl::vector< alpha16 > mHybridMidWindow
fl::vector< kiss_fft_cpx > mHybridMidFftOut
fl::vector< u8 > mLogBinLutMid
fl::vector< kiss_fft_cpx > mHybridSmallFftOut
static FftScratch & scratch() FL_NO_EXCEPT
static void deinterleave(const kiss_fft_cpx *cpx, kiss_fft_scalar *re, kiss_fft_scalar *im, int n) FL_NO_EXCEPT
fl::vector< u8 > mLogBinLutBass
static void applyWindow(const kiss_fft_scalar *samples, const alpha16 *win, kiss_fft_scalar *out, int N) FL_NO_EXCEPT
fl::vector< u8 > mLogBinLut
fl::vector< kiss_fft_cpx > mFftOut
static void decimateBy2(kiss_fft_scalar *buf, int len) FL_NO_EXCEPT
fl::vector< float > mHybridMergedNorm
void resize(fl::size n) FL_NO_EXCEPT
Definition vector.h:593
void fl_fft_real_forward(kiss_fftr_cfg cfg, int N, const kiss_fft_scalar *in, kiss_fft_cpx *out) FL_NO_EXCEPT
Forward real-to-complex FFT.
FASTLED_FORCE_INLINE void * memset(void *s, int c, size_t n) FL_NO_EXCEPT
Definition cstring.h:148

References applyWindow(), batchMag(), computeLinearBins(), fl::vector< T >::data(), decimateBy2(), deinterleave(), fl::audio::fft::fl_fft_real_forward(), fl::FL_NO_EXCEPT, fl::audio::fft::Context::FftScratch::im, logRebinRange(), fl::audio::fft::Context::FftScratch::mag, fl::memset(), mFftOut, mFftrCfg, mFmax, mFmin, mHybridBassWindow, mHybridMergedNorm, mHybridMidFft, mHybridMidFftOut, mHybridMidFs, mHybridMidN, mHybridMidSplitBin, mHybridMidWindow, mHybridSmallFft, mHybridSmallFftOut, mHybridSmallFs, mHybridSmallN, mHybridSplitBin, mInputSamples, mLogBinLut, mLogBinLutBass, mLogBinLutMid, mSampleRate, mTotalBands, mWindowBuf, mWorkBuf, fl::audio::fft::Context::FftScratch::rawBinsI, fl::audio::fft::Context::FftScratch::re, fl::vector< T >::resize(), scratch(), and fl::audio::fft::Context::FftScratch::windowed.

Referenced by run().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: