FastLED 3.9.15
Loading...
Searching...
No Matches
fft.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/stl/span.h"
4#include "fl/stl/vector.h"
5#include "fl/math/math.h"
6#include "fl/stl/noexcept.h"
7
8namespace fl {
9namespace audio {
10
11class Sample; // Forward declare in fl::audio (correct namespace)
12
13namespace fft {
14
15class Impl;
16class FloatVectorPool;
17
18// Time-domain window function applied before FFT.
19// AUTO — Selects best window based on Mode (see resolveArgs)
20// NONE — No windowing (rectangular window)
21// HANNING — Classic cosine window, -31 dB sidelobe rejection
22// BLACKMAN_HARRIS — 4-term window, -92 dB sidelobe rejection
29
30// Controls which algorithm produces the log-spaced (CQ) output bins.
31// AUTO — LOG_REBIN for <= 32 bins, CQ_NAIVE or CQ_OCTAVE for > 32
32// LOG_REBIN — Single FFT + geometric bin grouping (~0.15ms on ESP32-S3)
33// CQ_NAIVE — Single FFT + CQ kernels (no input window)
34// CQ_OCTAVE — Octave-wise Constant-Q Transform (~1-5ms on ESP32-S3)
35// CQ_HYBRID — LOG_REBIN for upper freqs + CQ_OCTAVE decimation for bass
36enum class Mode {
41 CQ_HYBRID // If you aren't sure just use this.
42};
43
44class Bins {
45 friend class Context;
46
47 public:
48 Bins(fl::size n) FL_NOEXCEPT;
50
51 Bins(const Bins &) FL_NOEXCEPT = default;
52 Bins &operator=(const Bins &) = default;
53 Bins(Bins &&) FL_NOEXCEPT = default;
54 Bins &operator=(Bins &&) FL_NOEXCEPT = default;
55
56 void clear() FL_NOEXCEPT;
57
58 // Configured band count (stable across clear/populate cycles)
59 fl::size bands() const FL_NOEXCEPT;
60
61 // Read-only span accessors
62 fl::span<const float> raw() const FL_NOEXCEPT;
63
64 // dB magnitudes: 20 * log10(raw[i]).
65 // Lazily computed from raw() on first access; cached until raw changes.
66 fl::span<const float> db() const FL_NOEXCEPT;
67
68 // Bin-width-normalized raw magnitudes: raw[i] * normFactor[i].
69 // Corrects for wider high-frequency bins accumulating more sidelobe energy.
70 // Use this for equalization display; use raw() for feature extraction.
71 // Returns a span into an internal buffer (no per-call allocation).
72 // Lazily recomputed only when raw bins or norm factors change.
73 fl::span<const float> rawNormalized() const FL_NOEXCEPT;
74
75 // Linear-spaced magnitude bins captured directly from raw FFT output.
76 // Same count as CQ bins, evenly spaced from linearFmin() to linearFmax().
77 fl::span<const float> linear() const FL_NOEXCEPT;
78 float linearFmin() const FL_NOEXCEPT;
79 float linearFmax() const FL_NOEXCEPT;
80
81 // CQ parameters (set by Impl after populating bins)
82 float fmin() const FL_NOEXCEPT;
83 float fmax() const FL_NOEXCEPT;
84 int sampleRate() const FL_NOEXCEPT;
85
86 // Log-spaced center frequency for CQ bin i
87 float binToFreq(int i) const FL_NOEXCEPT;
88
89 // Find which CQ bin contains a given frequency (inverse of binToFreq)
90 int freqToBin(float freq) const FL_NOEXCEPT;
91
92 // Frequency boundary between adjacent CQ bins i and i+1 (geometric mean)
93 float binBoundary(int i) const FL_NOEXCEPT;
94
95 private:
97
98 // Mutable accessors for Context (the only writer).
99 // raw_mut() invalidates derived caches (db, normalized).
100 fl::vector<float>& raw_mut() FL_NOEXCEPT;
101 fl::vector<float>& linear_mut() FL_NOEXCEPT;
102
103 void setParams(float fmin, float fmax, int sampleRate) FL_NOEXCEPT;
105
106 // Copy data into the existing buffer to reuse pooled capacity.
107 void setNormFactors(const fl::vector<float>& factors) FL_NOEXCEPT;
108
109 fl::size mBands;
113 mutable fl::vector<float> mBinsDb; // lazily computed from mBinsRaw
114 mutable fl::vector<float> mBinsRawNormalized; // lazily computed from mBinsRaw + mNormFactors
115 mutable bool mDbDirty = true; // invalidated when raw changes
116 mutable bool mNormalizedDirty = true; // invalidated when raw or normFactors change
117 float mFmin = 90.0f;
118 float mFmax = 14080.0f;
119 int mSampleRate = 44100;
120 float mLinearFmin = 0.0f;
121 float mLinearFmax = 0.0f;
122};
123
124struct Args {
125 static int DefaultSamples() FL_NOEXCEPT { return 512; }
126 static int DefaultBands() FL_NOEXCEPT { return 16; }
127 static float DefaultMinFrequency() FL_NOEXCEPT { return 90.0f; }
128 static float DefaultMaxFrequency() FL_NOEXCEPT { return 14080.0f; }
129 static int DefaultSampleRate() FL_NOEXCEPT { return 44100; }
130
138
147
148 // Resolve AUTO values for mode and window in-place.
149 // Mode is resolved first; window depends on the resolved mode.
150 // Takes bins (band count), samples, fmin, fmax as context.
151 static void resolveModeEnums(Mode &mode, Window &window, int bands,
152 int samples, float fmin, float fmax) FL_NOEXCEPT;
153
154 bool operator==(const Args &other) const FL_NOEXCEPT;
155 bool operator!=(const Args &other) const FL_NOEXCEPT { return !(*this == other); }
156};
157
158class FFT {
159 public:
160 FFT() FL_NOEXCEPT = default;
161 ~FFT() FL_NOEXCEPT = default;
162
163 FFT(FFT &&) FL_NOEXCEPT = default;
164 FFT &operator=(FFT &&) FL_NOEXCEPT = default;
165 FFT(const FFT &) FL_NOEXCEPT = default;
166 FFT &operator=(const FFT &) FL_NOEXCEPT = default;
167
168 void run(const span<const i16> &sample, Bins *out,
169 const Args &args = Args()) FL_NOEXCEPT;
170
171 void clear() FL_NOEXCEPT;
172 fl::size size() const FL_NOEXCEPT;
173
174 // FFT kernels are expensive to create, so they are stored in a global
175 // LRU cache shared by all AudioContext instances. This sets the max
176 // number of cached Impl entries (default 10).
177 static void setFFTCacheSize(fl::size size) FL_NOEXCEPT;
178
179 private:
180 struct ImplCache;
181 // Global LRU kernel cache — shared across all FFT / AudioContext instances.
183};
184
185} // namespace fft
186
187} // namespace audio
188}; // namespace fl
float binBoundary(int i) const FL_NOEXCEPT
Definition fft.cpp.hpp:124
fl::vector< float > & raw_mut() FL_NOEXCEPT
Definition fft.cpp.hpp:130
void setParams(float fmin, float fmax, int sampleRate) FL_NOEXCEPT
Definition fft.cpp.hpp:146
fl::vector< float > & linear_mut() FL_NOEXCEPT
Definition fft.cpp.hpp:139
static FloatVectorPool & pool() FL_NOEXCEPT
Definition fft.cpp.hpp:168
fl::vector< float > mBinsRawNormalized
Definition fft.h:114
~Bins() FL_NOEXCEPT
Definition fft.cpp.hpp:175
fl::vector< float > mBinsLinear
Definition fft.h:111
fl::vector< float > mNormFactors
Definition fft.h:112
void setNormFactors(const fl::vector< float > &factors) FL_NOEXCEPT
Definition fft.cpp.hpp:157
float linearFmin() const FL_NOEXCEPT
Definition fft.cpp.hpp:98
fl::span< const float > db() const FL_NOEXCEPT
Definition fft.cpp.hpp:65
fl::span< const float > raw() const FL_NOEXCEPT
Definition fft.cpp.hpp:63
int sampleRate() const FL_NOEXCEPT
Definition fft.cpp.hpp:102
float fmin() const FL_NOEXCEPT
Definition fft.cpp.hpp:100
fl::vector< float > mBinsDb
Definition fft.h:113
int freqToBin(float freq) const FL_NOEXCEPT
Definition fft.cpp.hpp:111
fl::vector< float > mBinsRaw
Definition fft.h:110
fl::size mBands
Definition fft.h:109
fl::size bands() const FL_NOEXCEPT
Definition fft.cpp.hpp:61
float mLinearFmin
Definition fft.h:120
bool mNormalizedDirty
Definition fft.h:116
float mLinearFmax
Definition fft.h:121
float linearFmax() const FL_NOEXCEPT
Definition fft.cpp.hpp:99
friend class Context
Definition fft.h:45
float fmax() const FL_NOEXCEPT
Definition fft.cpp.hpp:101
void clear() FL_NOEXCEPT
Definition fft.cpp.hpp:53
fl::span< const float > rawNormalized() const FL_NOEXCEPT
Definition fft.cpp.hpp:81
Bins(fl::size n) FL_NOEXCEPT
Definition fft.cpp.hpp:172
float binToFreq(int i) const FL_NOEXCEPT
Definition fft.cpp.hpp:104
fl::span< const float > linear() const FL_NOEXCEPT
Definition fft.cpp.hpp:97
void setLinearParams(float linearFmin, float linearFmax) FL_NOEXCEPT
Definition fft.cpp.hpp:152
fl::size size() const FL_NOEXCEPT
Definition fft.cpp.hpp:261
FFT() FL_NOEXCEPT=default
void run(const span< const i16 > &sample, Bins *out, const Args &args=Args()) FL_NOEXCEPT
void clear() FL_NOEXCEPT
Definition fft.cpp.hpp:259
static ImplCache & globalCache() FL_NOEXCEPT
Definition fft.cpp.hpp:243
static void setFFTCacheSize(fl::size size) FL_NOEXCEPT
Definition fft.cpp.hpp:263
CRGB sample(const CRGB *grid, const XYMap &xyMap, float x, float y, SampleMode mode)
Sample a pixel from a 2D CRGB grid at floating-point coordinates.
Definition sample.cpp.hpp:9
FASTLED_FORCE_INLINE bool operator==(const CRGB &lhs, const CRGB &rhs) FL_NOEXCEPT
Check if two CRGB objects have the same color data.
Definition crgb.h:733
Base definition for an LED controller.
Definition crgb.hpp:179
corkscrew_args args
Definition old.h:149
#define FL_NOEXCEPT
bool operator!=(const Args &other) const FL_NOEXCEPT
Definition fft.h:155
static float DefaultMaxFrequency() FL_NOEXCEPT
Definition fft.h:128
static int DefaultSamples() FL_NOEXCEPT
Definition fft.h:125
Args(int samples=DefaultSamples(), int bands=DefaultBands(), float fmin=DefaultMinFrequency(), float fmax=DefaultMaxFrequency(), int sample_rate=DefaultSampleRate(), Mode mode=Mode::AUTO, Window window=Window::AUTO) FL_NOEXCEPT
Definition fft.h:139
static int DefaultSampleRate() FL_NOEXCEPT
Definition fft.h:129
static int DefaultBands() FL_NOEXCEPT
Definition fft.h:126
static float DefaultMinFrequency() FL_NOEXCEPT
Definition fft.h:127