FastLED 3.10.8
Loading...
Searching...
No Matches
frequency_bin_mapper.cpp.hpp
Go to the documentation of this file.
1
3
5#include "fl/math/math.h"
6#include "fl/math/math.h"
8#include "fl/stl/noexcept.h"
9
10namespace fl {
11namespace audio {
12
16
20
22
24 mConfig = config;
25
26 // Reset stats
27 mStats = Stats();
28
29 // Calculate frequency boundaries for output bins
31
32 // Calculate fft::FFT bin to frequency bin mappings
34}
35
37 const size numBins = static_cast<size>(mConfig.mode);
38
39 // Allocate space for bin boundaries (numBins + 1 edges)
40 mBinFrequencies.clear();
41 mBinFrequencies.reserve(numBins + 1);
42
43 if (mConfig.useLogSpacing) {
45 } else {
47 }
48}
49
51 const size numBins = static_cast<size>(mConfig.mode);
52 const float logMin = fl::logf(mConfig.minFrequency);
53 const float logMax = fl::logf(mConfig.maxFrequency);
54 const float logStep = (logMax - logMin) / static_cast<float>(numBins);
55
56 // Calculate logarithmically-spaced bin edges
57 for (size i = 0; i <= numBins; ++i) {
58 float logFreq = logMin + static_cast<float>(i) * logStep;
59 float freq = fl::expf(logFreq);
60 mBinFrequencies.push_back(freq);
61 }
62}
63
65 const size numBins = static_cast<size>(mConfig.mode);
66 const float step = (mConfig.maxFrequency - mConfig.minFrequency) / static_cast<float>(numBins);
67
68 // Calculate linearly-spaced bin edges
69 for (size i = 0; i <= numBins; ++i) {
70 float freq = mConfig.minFrequency + static_cast<float>(i) * step;
71 mBinFrequencies.push_back(freq);
72 }
73}
74
76 const size numBins = static_cast<size>(mConfig.mode);
77
78 mBinMappings.clear();
79 mBinMappings.reserve(numBins);
80
81 // For each output frequency bin, determine which fft::FFT bins contribute
82 for (size i = 0; i < numBins; ++i) {
83 float minFreq = mBinFrequencies[i];
84 float maxFreq = mBinFrequencies[i + 1];
85
86 // Convert frequencies to fft::FFT bin indices
87 float startBinFloat = frequencyToFFTBin(minFreq);
88 float endBinFloat = frequencyToFFTBin(maxFreq);
89
90 // Round to integer fft::FFT bin indices
91 u32 startBin = static_cast<u32>(startBinFloat);
92 u32 endBin = static_cast<u32>(fl::ceilf(endBinFloat));
93
94 // Clamp to valid fft::FFT bin range
95 if (startBin >= mConfig.fftBinCount) {
96 startBin = mConfig.fftBinCount - 1;
97 }
98 if (endBin > mConfig.fftBinCount) {
99 endBin = mConfig.fftBinCount;
100 }
101
102 // Ensure at least one fft::FFT bin per output bin
103 if (endBin <= startBin) {
104 endBin = startBin + 1;
105 }
106
107 BinMapping mapping;
108 mapping.startBin = startBin;
109 mapping.endBin = endBin;
110 mBinMappings.push_back(mapping);
111 }
112}
113
115 // fft::FFT bin index = (frequency / sampleRate) * fftSize
116 // fftSize = fftBinCount * 2 (fft::FFT produces fftSize/2 bins)
117 const float fftSize = static_cast<float>(mConfig.fftBinCount) * 2.0f;
118 return (frequency / static_cast<float>(mConfig.sampleRate)) * fftSize;
119}
120
122 const size numBins = static_cast<size>(mConfig.mode);
123
124 // Validate output buffer size
125 if (outputBins.size() < numBins) {
126 FL_WARN("FrequencyBinMapper: output buffer too small (" << outputBins.size() << " < " << numBins << ")");
127 return;
128 }
129
130 // Track maximum magnitude for stats
131 float maxMag = 0.0f;
132 u32 fftBinsUsed = 0;
133
134 // Map fft::FFT bins to frequency bins by averaging
135 for (size i = 0; i < numBins; ++i) {
136 const BinMapping& mapping = mBinMappings[i];
137
138 float sum = 0.0f;
139 u32 count = 0;
140
141 // Average fft::FFT bins in this range
142 for (u32 j = mapping.startBin; j < mapping.endBin && j < fftBins.size(); ++j) {
143 sum += fftBins[j];
144 ++count;
145 ++fftBinsUsed;
146
147 if (fftBins[j] > maxMag) {
148 maxMag = fftBins[j];
149 }
150 }
151
152 // Calculate average
153 if (count > 0) {
154 outputBins[i] = sum / static_cast<float>(count);
155 } else {
156 outputBins[i] = 0.0f;
157 }
158 }
159
160 // Update stats (mutable in const method for statistics)
161 const_cast<FrequencyBinMapper*>(this)->mStats.binMappingCount++;
162 const_cast<FrequencyBinMapper*>(this)->mStats.lastFFTBinsUsed = fftBinsUsed;
163 const_cast<FrequencyBinMapper*>(this)->mStats.maxMagnitude = maxMag;
164}
165
167 if (frequencyBins.size() < BASS_BIN_END) {
168 return 0.0f;
169 }
170
171 // Average bins 0-1 (bass range)
172 float sum = 0.0f;
173 for (size i = BASS_BIN_START; i < BASS_BIN_END; ++i) {
174 sum += frequencyBins[i];
175 }
176 return sum / static_cast<float>(BASS_BIN_END - BASS_BIN_START);
177}
178
180 if (frequencyBins.size() < MID_BIN_END) {
181 return 0.0f;
182 }
183
184 // Average bins 6-7 (mid range)
185 float sum = 0.0f;
186 for (size i = MID_BIN_START; i < MID_BIN_END; ++i) {
187 sum += frequencyBins[i];
188 }
189 return sum / static_cast<float>(MID_BIN_END - MID_BIN_START);
190}
191
193 if (frequencyBins.size() < TREBLE_BIN_END) {
194 return 0.0f;
195 }
196
197 // Average bins 14-15 (treble range)
198 float sum = 0.0f;
199 for (size i = TREBLE_BIN_START; i < TREBLE_BIN_END; ++i) {
200 sum += frequencyBins[i];
201 }
202 return sum / static_cast<float>(TREBLE_BIN_END - TREBLE_BIN_START);
203}
204
206 FrequencyRange range = {0.0f, 0.0f};
207
208 if (binIndex >= mBinFrequencies.size() - 1) {
209 return range;
210 }
211
212 range.minFreq = mBinFrequencies[binIndex];
213 range.maxFreq = mBinFrequencies[binIndex + 1];
214 return range;
215}
216
217} // namespace audio
218} // namespace fl
FrequencyRange getBinFrequencyRange(size binIndex) const FL_NO_EXCEPT
void configure(const FrequencyBinMapperConfig &config) FL_NO_EXCEPT
Configure the frequency bin mapper This calculates bin boundaries and FFT-to-frequency bin mappings.
static constexpr size TREBLE_BIN_START
float getBassEnergy(span< const float > frequencyBins) const FL_NO_EXCEPT
Get bass energy (average of bins 0-1 in 16-bin mode)
void calculateLogFrequencies() FL_NO_EXCEPT
Calculate logarithmically-spaced frequency boundaries.
float frequencyToFFTBin(float frequency) const FL_NO_EXCEPT
Convert frequency (Hz) to FFT bin index.
static constexpr size BASS_BIN_START
Bass/mid/treble bin indices (for 16-bin mode) These are pre-calculated based on the bin count.
vector< float > mBinFrequencies
Pre-calculated frequency boundaries for each output bin Size: numBins + 1 (includes both lower and up...
void calculateLinearFrequencies() FL_NO_EXCEPT
Calculate linearly-spaced frequency boundaries.
float getTrebleEnergy(span< const float > frequencyBins) const FL_NO_EXCEPT
Get treble energy (average of bins 14-15 in 16-bin mode)
FrequencyBinMapperConfig mConfig
float getMidEnergy(span< const float > frequencyBins) const FL_NO_EXCEPT
Get mid energy (average of bins 6-7 in 16-bin mode)
void calculateBinBoundaries() FL_NO_EXCEPT
Calculate frequency bin boundaries (linear or logarithmic spacing)
void calculateBinMappings() FL_NO_EXCEPT
Calculate FFT bin to frequency bin mappings Pre-calculates which FFT bins contribute to each frequenc...
void mapBins(span< const float > fftBins, span< float > outputBins) const FL_NO_EXCEPT
Map FFT bins to frequency channels.
~FrequencyBinMapper() FL_NO_EXCEPT
Get frequency boundaries for a specific output bin.
Mapping from output bins to FFT bin ranges Each entry contains (startBin, endBin) for averaging.
Get statistics (for debugging/monitoring)
#define FL_WARN(...)
Definition log.h:437
Configuration for frequency bin mapping.
float logf(float value) FL_NO_EXCEPT
Definition math.h:426
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NO_EXCEPT
float ceilf(float value) FL_NO_EXCEPT
Definition math.h:318
float expf(float value) FL_NO_EXCEPT
Definition math.h:406
Base definition for an LED controller.
Definition crgb.hpp:179