FastLED 3.10.9
Loading...
Searching...
No Matches

◆ initHybrid()

void fl::audio::fft::Context::initHybrid ( int samples,
int bands,
float fmin,
float fmax,
int sr )
inlineprivate

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

836 {
837 float logRatio = logf(fmax / fmin);
838
839 // Log-spaced center frequencies for all bins
840 FASTLED_STACK_ARRAY(float, centerFreqs, bands);
841 for (int i = 0; i < bands; i++) {
842 centerFreqs[i] =
843 fmin * expf(logRatio * static_cast<float>(i) /
844 static_cast<float>(bands - 1));
845 }
846
847 // 3-tier split at octave boundaries:
848 // bass/mid at fmin*4 (~698 Hz, 2 octaves above fmin)
849 // mid/upper at fmin*8 (~1397 Hz, 3 octaves above fmin)
850 float bassMidFreq = fmin * 4.0f;
851 float midUpperFreq = fmin * 8.0f;
852
853 // Clamp splits to valid range
854 if (midUpperFreq >= fmax) midUpperFreq = fmax * 0.5f;
855 if (bassMidFreq >= midUpperFreq) bassMidFreq = midUpperFreq * 0.5f;
856
857 // Find split bin indices
858 mHybridSplitBin = 0;
859 for (int i = 0; i < bands; i++) {
860 if (centerFreqs[i] < bassMidFreq)
861 mHybridSplitBin = i + 1;
862 }
864 for (int i = mHybridSplitBin; i < bands; i++) {
865 if (centerFreqs[i] < midUpperFreq)
866 mHybridMidSplitBin = i + 1;
867 }
868
869 // Ensure each tier has at least 1 bin
870 if (mHybridSplitBin < 1) mHybridSplitBin = 1;
873 if (mHybridMidSplitBin >= bands)
874 mHybridMidSplitBin = bands - 1;
875
876 // LOG_REBIN bin edges (shared by all three tiers)
877 mLogBinEdges.resize(bands + 1);
878 if (bands <= 1) {
879 mLogBinEdges[0] = fmin;
880 mLogBinEdges[1] = fmax;
881 } else {
882 float denom = 2.0f * static_cast<float>(bands - 1);
883 mLogBinEdges[0] = fmin * expf(-logRatio / denom);
884 for (int i = 1; i < bands; i++) {
885 mLogBinEdges[i] =
886 fmin * expf(logRatio *
887 (2.0f * static_cast<float>(i) - 1.0f) / denom);
888 }
889 mLogBinEdges[bands] = fmax * expf(logRatio / denom);
890 }
891
892 // Clamp top bin edge to Nyquist
893 float nyquist = static_cast<float>(sr) / 2.0f;
894 if (mLogBinEdges[bands] > nyquist) {
895 mLogBinEdges[bands] = nyquist;
896 }
897
899
900 // Window for the full-rate 512pt FFT (upper tier)
901 initWindow();
902
903 // Mid-tier: 2 decimation steps → samples/4 at sr/4
904 // Zero-pad 2x: 128 real samples → 256pt FFT → 43 Hz bins
905 mHybridMidN = samples / 4;
906 mHybridMidFs = static_cast<float>(sr) / 4.0f;
907 mHybridMidFft = kiss_fftr_alloc(mHybridMidN * 2, 0, nullptr, nullptr);
908 mHybridMidFftOut.resize(mHybridMidN * 2);
910
911 // Bass-tier: 3 decimation steps → samples/8 at sr/8
912 mHybridSmallN = samples / 8;
913 mHybridSmallFs = static_cast<float>(sr) / 8.0f;
915 kiss_fftr_alloc(mHybridSmallN, 0, nullptr, nullptr);
918
919 // Work buffer for decimation (reused across phases)
920 mWorkBuf.resize(samples);
921 mFftOut.resize(samples);
922
923 // Pre-computed bin mapping LUTs for each tier
924 buildLogBinLut(mLogBinLut, samples,
925 static_cast<float>(sr),
926 mHybridMidSplitBin, bands);
932 0, mHybridSplitBin);
934
935 // Pre-compute normalization factors for each hybrid tier
937 samples, static_cast<float>(sr),
938 mHybridMidSplitBin, bands);
944 0, mHybridSplitBin);
945
946 // Pre-compute merged norm factors (avoids per-frame allocation)
947 mHybridMergedNorm.resize(bands);
948 for (int i = 0; i < bands; ++i) {
949 if (i >= mHybridMidSplitBin && i < static_cast<int>(mHybridNormUpper.size())) {
951 } else if (i >= mHybridSplitBin && i < static_cast<int>(mHybridNormMid.size())) {
953 } else if (i < static_cast<int>(mHybridNormBass.size())) {
955 } else {
956 mHybridMergedNorm[i] = 1.0f;
957 }
958 }
959 }
#define FASTLED_STACK_ARRAY(TYPE, NAME, SIZE)
Stack-allocated array with automatic zero-initialization.
Definition alloca.h:32
fl::vector< alpha16 > mHybridBassWindow
fl::vector< kiss_fft_scalar > mWorkBuf
void buildLinearBinLut(fl::vector< u8 > &lut, int fftN) FL_NO_EXCEPT
void buildLogBinLut(fl::vector< u8 > &lut, int fftN, float fs, int binStart, int binEnd) FL_NO_EXCEPT
fl::vector< u8 > mLinearBinLut
void initWindow() FL_NO_EXCEPT
fl::vector< alpha16 > mHybridMidWindow
fl::vector< kiss_fft_cpx > mHybridMidFftOut
fl::vector< float > mLogBinEdges
fl::vector< u8 > mLogBinLutMid
fl::vector< kiss_fft_cpx > mHybridSmallFftOut
fl::vector< float > mHybridNormUpper
fl::vector< u8 > mLogBinLutBass
fl::vector< u8 > mLogBinLut
fl::vector< kiss_fft_cpx > mFftOut
static void computeWindow(fl::vector< alpha16 > &win, int N, Window type) FL_NO_EXCEPT
void computeBinEdgesQ16() FL_NO_EXCEPT
fl::vector< float > mHybridNormBass
fl::vector< float > mHybridMergedNorm
void computeLogRebinNormFactors(fl::vector< float > &normFactors, const fl::vector< u8 > &lut, int fftN, float fs, int binStart, int binEnd) FL_NO_EXCEPT
fl::vector< float > mHybridNormMid
kiss_fftr_cfg kiss_fftr_alloc(int nfft, int inverse_fft, void *mem, size_t *lenmem)
float logf(float value) FL_NO_EXCEPT
Definition math.h:426
float expf(float value) FL_NO_EXCEPT
Definition math.h:406

References buildLinearBinLut(), buildLogBinLut(), computeBinEdgesQ16(), computeLogRebinNormFactors(), computeWindow(), fl::expf(), FASTLED_STACK_ARRAY, fl::FL_NO_EXCEPT, initWindow(), kiss_fftr_alloc(), fl::logf(), mFftOut, mHybridBassWindow, mHybridMergedNorm, mHybridMidFft, mHybridMidFftOut, mHybridMidFs, mHybridMidN, mHybridMidSplitBin, mHybridMidWindow, mHybridNormBass, mHybridNormMid, mHybridNormUpper, mHybridSmallFft, mHybridSmallFftOut, mHybridSmallFs, mHybridSmallN, mHybridSplitBin, mLinearBinLut, mLogBinEdges, mLogBinLut, mLogBinLutBass, mLogBinLutMid, mWindow, and mWorkBuf.

Referenced by Context().

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