FastLED 3.9.15
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 742 of file fft_impl.cpp.hpp.

742 {
743 float logRatio = logf(fmax / fmin);
744
745 // Log-spaced center frequencies for all bins
746 FASTLED_STACK_ARRAY(float, centerFreqs, bands);
747 for (int i = 0; i < bands; i++) {
748 centerFreqs[i] =
749 fmin * expf(logRatio * static_cast<float>(i) /
750 static_cast<float>(bands - 1));
751 }
752
753 // 3-tier split at octave boundaries:
754 // bass/mid at fmin*4 (~698 Hz, 2 octaves above fmin)
755 // mid/upper at fmin*8 (~1397 Hz, 3 octaves above fmin)
756 float bassMidFreq = fmin * 4.0f;
757 float midUpperFreq = fmin * 8.0f;
758
759 // Clamp splits to valid range
760 if (midUpperFreq >= fmax) midUpperFreq = fmax * 0.5f;
761 if (bassMidFreq >= midUpperFreq) bassMidFreq = midUpperFreq * 0.5f;
762
763 // Find split bin indices
764 mHybridSplitBin = 0;
765 for (int i = 0; i < bands; i++) {
766 if (centerFreqs[i] < bassMidFreq)
767 mHybridSplitBin = i + 1;
768 }
770 for (int i = mHybridSplitBin; i < bands; i++) {
771 if (centerFreqs[i] < midUpperFreq)
772 mHybridMidSplitBin = i + 1;
773 }
774
775 // Ensure each tier has at least 1 bin
776 if (mHybridSplitBin < 1) mHybridSplitBin = 1;
779 if (mHybridMidSplitBin >= bands)
780 mHybridMidSplitBin = bands - 1;
781
782 // LOG_REBIN bin edges (shared by all three tiers)
783 mLogBinEdges.resize(bands + 1);
784 if (bands <= 1) {
785 mLogBinEdges[0] = fmin;
786 mLogBinEdges[1] = fmax;
787 } else {
788 float denom = 2.0f * static_cast<float>(bands - 1);
789 mLogBinEdges[0] = fmin * expf(-logRatio / denom);
790 for (int i = 1; i < bands; i++) {
791 mLogBinEdges[i] =
792 fmin * expf(logRatio *
793 (2.0f * static_cast<float>(i) - 1.0f) / denom);
794 }
795 mLogBinEdges[bands] = fmax * expf(logRatio / denom);
796 }
797
798 // Clamp top bin edge to Nyquist
799 float nyquist = static_cast<float>(sr) / 2.0f;
800 if (mLogBinEdges[bands] > nyquist) {
801 mLogBinEdges[bands] = nyquist;
802 }
803
805
806 // Window for the full-rate 512pt FFT (upper tier)
807 initWindow();
808
809 // Mid-tier: 2 decimation steps → samples/4 at sr/4
810 // Zero-pad 2x: 128 real samples → 256pt FFT → 43 Hz bins
811 mHybridMidN = samples / 4;
812 mHybridMidFs = static_cast<float>(sr) / 4.0f;
813 mHybridMidFft = kiss_fftr_alloc(mHybridMidN * 2, 0, nullptr, nullptr);
814 mHybridMidFftOut.resize(mHybridMidN * 2);
816
817 // Bass-tier: 3 decimation steps → samples/8 at sr/8
818 mHybridSmallN = samples / 8;
819 mHybridSmallFs = static_cast<float>(sr) / 8.0f;
821 kiss_fftr_alloc(mHybridSmallN, 0, nullptr, nullptr);
824
825 // Work buffer for decimation (reused across phases)
826 mWorkBuf.resize(samples);
827 mFftOut.resize(samples);
828
829 // Pre-computed bin mapping LUTs for each tier
830 buildLogBinLut(mLogBinLut, samples,
831 static_cast<float>(sr),
832 mHybridMidSplitBin, bands);
838 0, mHybridSplitBin);
840
841 // Pre-compute normalization factors for each hybrid tier
843 samples, static_cast<float>(sr),
844 mHybridMidSplitBin, bands);
850 0, mHybridSplitBin);
851
852 // Pre-compute merged norm factors (avoids per-frame allocation)
853 mHybridMergedNorm.resize(bands);
854 for (int i = 0; i < bands; ++i) {
855 if (i >= mHybridMidSplitBin && i < static_cast<int>(mHybridNormUpper.size())) {
857 } else if (i >= mHybridSplitBin && i < static_cast<int>(mHybridNormMid.size())) {
859 } else if (i < static_cast<int>(mHybridNormBass.size())) {
861 } else {
862 mHybridMergedNorm[i] = 1.0f;
863 }
864 }
865 }
#define FASTLED_STACK_ARRAY(TYPE, NAME, SIZE)
Stack-allocated array with automatic zero-initialization.
Definition alloca.h:32
void computeLogRebinNormFactors(fl::vector< float > &normFactors, const fl::vector< u8 > &lut, int fftN, float fs, int binStart, int binEnd)
fl::vector< alpha16 > mHybridBassWindow
void buildLogBinLut(fl::vector< u8 > &lut, int fftN, float fs, int binStart, int binEnd)
fl::vector< kiss_fft_scalar > mWorkBuf
fl::vector< u8 > mLinearBinLut
fl::vector< alpha16 > mHybridMidWindow
fl::vector< kiss_fft_cpx > mHybridMidFftOut
fl::vector< float > mLogBinEdges
fl::vector< u8 > mLogBinLutMid
fl::vector< kiss_fft_cpx > mHybridSmallFftOut
void buildLinearBinLut(fl::vector< u8 > &lut, int fftN)
fl::vector< float > mHybridNormUpper
fl::vector< u8 > mLogBinLutBass
fl::vector< u8 > mLogBinLut
fl::vector< kiss_fft_cpx > mFftOut
fl::vector< float > mHybridNormBass
fl::vector< float > mHybridMergedNorm
fl::vector< float > mHybridNormMid
static void computeWindow(fl::vector< alpha16 > &win, int N, Window type)
kiss_fftr_cfg kiss_fftr_alloc(int nfft, int inverse_fft, void *mem, size_t *lenmem) FL_NOEXCEPT
float expf(float value) FL_NOEXCEPT
Definition math.h:398
float logf(float value) FL_NOEXCEPT
Definition math.h:418

References buildLinearBinLut(), buildLogBinLut(), computeBinEdgesQ16(), computeLogRebinNormFactors(), computeWindow(), fl::expf(), FASTLED_STACK_ARRAY, 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: