FastLED 3.9.15
Loading...
Searching...
No Matches

◆ initOctaveWise()

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

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

574 {
575
576
577 // Use floor so the top octave covers the remaining frequency range
578 // rather than creating a tiny sliver octave with 1 bin.
579 int numOctaves = static_cast<int>(floorf(log2f(fmax / fmin)));
580 if (numOctaves < 1)
581 numOctaves = 1;
582
583 // Log-spaced center frequencies for all bins
584 float logRatio = logf(fmax / fmin);
585 FASTLED_STACK_ARRAY(float, centerFreqs, bands);
586 for (int i = 0; i < bands; i++) {
587 centerFreqs[i] =
588 fmin *
589 expf(logRatio * static_cast<float>(i) /
590 static_cast<float>(bands - 1));
591 }
592
593 // Assign each bin to an octave: oct j spans [fmin*2^j, fmin*2^(j+1))
594 FASTLED_STACK_ARRAY(int, binOctave, bands);
595 for (int i = 0; i < bands; i++) {
596 int oct =
597 static_cast<int>(floorf(log2f(centerFreqs[i] / fmin)));
598 if (oct < 0)
599 oct = 0;
600 if (oct >= numOctaves)
601 oct = numOctaves - 1;
602 binOctave[i] = oct;
603 }
604
605 // Build per-octave CQ kernel sets
606 mOctaves.resize(numOctaves);
608 for (int oct = 0; oct < numOctaves; oct++) {
609 int first = -1, last = -1;
610 for (int i = 0; i < bands; i++) {
611 if (binOctave[i] == oct) {
612 if (first < 0)
613 first = i;
614 last = i;
615 }
616 }
617
618 OctaveInfo &oi = mOctaves[oct];
619 fl::memset(&oi.cfg, 0, sizeof(oi.cfg));
620 oi.kernels = nullptr;
621 if (first < 0) {
622 oi.firstBin = 0;
623 oi.numBins = 0;
624 continue;
625 }
626
627 oi.firstBin = first;
628 oi.numBins = last - first + 1;
629 if (oi.numBins > mMaxBinsPerOctave) {
630 mMaxBinsPerOctave = oi.numBins;
631 }
632
633 // Decimation: top octave (numOctaves-1) uses original sample rate.
634 // Each lower octave halves the effective sample rate.
635 int decimExp = numOctaves - 1 - oct;
636 float effectiveFs =
637 static_cast<float>(sr) /
638 static_cast<float>(1 << decimExp);
639
640 oi.cfg.samples = samples;
641 oi.cfg.bands = oi.numBins;
642 oi.cfg.fmin = centerFreqs[first];
643 oi.cfg.fmax = (oi.numBins > 1) ? centerFreqs[last]
644 : centerFreqs[first] * 2.0f;
645 oi.cfg.fs = effectiveFs;
646 oi.cfg.min_val = FL_FFT_MIN_VAL;
647
648 oi.kernels = generate_kernels(oi.cfg);
649 }
650
651 // Pre-allocate reusable buffers
652 mWorkBuf.resize(samples);
653 mFftOut.resize(samples);
654
656 // Note: CQ kernels already apply Hamming windowing in frequency domain.
657 // Adding time-domain Hanning would double-window and over-attenuate.
658 }
#define FASTLED_STACK_ARRAY(TYPE, NAME, SIZE)
Stack-allocated array with automatic zero-initialization.
Definition alloca.h:32
fl::vector< kiss_fft_scalar > mWorkBuf
fl::vector< u8 > mLinearBinLut
void buildLinearBinLut(fl::vector< u8 > &lut, int fftN)
fl::vector< OctaveInfo > mOctaves
fl::vector< kiss_fft_cpx > mFftOut
struct sparse_arr * generate_kernels(struct cq_kernel_cfg cfg) FL_NOEXCEPT
#define FL_FFT_MIN_VAL
float expf(float value) FL_NOEXCEPT
Definition math.h:398
float floorf(float value) FL_NOEXCEPT
Definition math.h:304
void * memset(void *s, int c, size_t n) FL_NOEXCEPT
const oct_t oct
Definition ios.cpp.hpp:8
float log2f(float value) FL_NOEXCEPT
Definition math.h:430
float logf(float value) FL_NOEXCEPT
Definition math.h:418

References cq_kernel_cfg::bands, buildLinearBinLut(), fl::audio::fft::Context::OctaveInfo::cfg, fl::expf(), FASTLED_STACK_ARRAY, fl::audio::fft::Context::OctaveInfo::firstBin, FL_FFT_MIN_VAL, fl::floorf(), cq_kernel_cfg::fmax, cq_kernel_cfg::fmin, cq_kernel_cfg::fs, generate_kernels(), fl::audio::fft::Context::OctaveInfo::kernels, fl::log2f(), fl::logf(), fl::memset(), mFftOut, cq_kernel_cfg::min_val, mLinearBinLut, mMaxBinsPerOctave, mOctaves, mWorkBuf, fl::audio::fft::Context::OctaveInfo::numBins, fl::oct, and cq_kernel_cfg::samples.

Referenced by Context().

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