694 {
696 const int numOctaves =
static_cast<int>(
mOctaves.size());
697 const int numRawBins = N / 2 + 1;
698
700
701
702 int workLen = N;
703 for (int i = 0; i < N; i++) {
705 (i < static_cast<int>(buffer.size())) ? buffer[i] : 0;
706 }
707
708
710
711
713 s.re.resize(numRawBins);
714 s.im.resize(numRawBins);
715 s.mag.resize(numRawBins);
717 batchMag(s.re.data(), s.im.data(), s.mag.data(), numRawBins);
718
720
721
722 fl::vector<float> &rawBins = out->raw_mut();
725 rawBins[i] = 0.0f;
726 }
727
728
730
731
732
733
734 for (
int oct = numOctaves - 1;
oct >= 0;
oct--) {
736 if (oi.numBins <= 0 || !oi.kernels)
737 continue;
738
739 if (
oct != numOctaves - 1) {
741 workLen = workLen / 2;
742
743 for (int i = workLen; i < N; i++)
746 }
747
748 fl::memset(cq, 0,
sizeof(kiss_fft_cpx) * oi.numBins);
750
751 for (int i = 0; i < oi.numBins; i++) {
752 int binIdx = oi.firstBin + i;
753 i32 real = cq[i].r;
754 i32 imag = cq[i].i;
755#ifdef FIXED_POINT
756 rawBins[binIdx] =
static_cast<float>(
fastMag(real, imag));
757#else
758 float r2 = float(real * real);
759 float i2 = float(imag * imag);
760 rawBins[binIdx] =
sqrt(r2 + i2);
761#endif
762 }
763 }
764
765
766
767
768
769 s.windowed.resize(N);
770 s.fftOut.resize(N);
774 deinterleave(s.fftOut.data(), s.re.data(), s.im.data(), numRawBins);
775 batchMag(s.re.data(), s.im.data(), s.mag.data(), numRawBins);
779
780
781
782 static constexpr float kCoverageGain = 0.02f;
786#ifdef FIXED_POINT
787
788 s.cqSnapshot[i] = static_cast<u32>(rawBins[i]);
789#else
790 s.cqSnapshot[i] = rawBins[i];
791#endif
792 }
793 int head = 0;
794 int tail = 0;
795 int next = 0;
798 while (tail > head &&
799 s.cqSnapshot[s.coverageMaxQueue[tail - 1]] <=
800 s.cqSnapshot[next]) {
801 --tail;
802 }
803 s.coverageMaxQueue[tail++] = static_cast<u16>(next++);
804 }
805 while (head < tail &&
807 ++head;
808 }
809#ifdef FIXED_POINT
810
811
813 s.rawBinsI[i], s.cqSnapshot[i],
814 s.cqSnapshot[s.coverageMaxQueue[head]])) {
815 rawBins[i] = static_cast<float>(s.rawBinsI[i]) * kCoverageGain;
816 }
817#else
818 const float localCq = s.cqSnapshot[s.coverageMaxQueue[head]];
819 static constexpr float kDetectedCqMagnitude = 20.0f;
820 float coverage = static_cast<float>(s.rawBinsI[i]) * kCoverageGain;
821 if (localCq < kDetectedCqMagnitude && coverage > rawBins[i]) {
822 rawBins[i] = coverage;
823 }
824#endif
825 }
826 }
#define FASTLED_STACK_ARRAY(TYPE, NAME, SIZE)
Stack-allocated array with automatic zero-initialization.
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< u16 > mCoverageLast
static u16 fastMag(i32 re, i32 im) FL_NO_EXCEPT
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< u16 > mCoverageFirst
fl::vector< OctaveInfo > mOctaves
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
void resize(fl::size n) FL_NO_EXCEPT
void apply_kernels(kiss_fft_cpx fft[], kiss_fft_cpx cq[], struct sparse_arr kernels[], struct cq_kernel_cfg cfg)
bool coverageFloorApplies(u32 fftMag, u32 cqMag, u32 localCqMax) FL_NO_EXCEPT
CQ_OCTAVE coverage supplement decision (FastLED#4301/#4540), integer form used in FIXED16: the full-r...
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
constexpr enable_if< is_fixed_point< T >::value, T >::type sqrt(T x) FL_NO_EXCEPT