FastLED 3.10.8
Loading...
Searching...
No Matches
spectral_equalizer.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
13// Define static constexpr arrays
16
20
24
26
28 mConfig = config;
29
30 // Reset stats
31 mStats = Stats();
32
33 // Allocate gain array
34 mGains.clear();
35 mGains.resize(mConfig.numBands, 1.0f);
36
37 // Calculate gains based on curve type
39}
40
42 switch (mConfig.curve) {
45 break;
46
49 break;
50
52 // Use custom gains if provided
53 if (mConfig.customGains.size() == mConfig.numBands) {
54 for (size i = 0; i < mConfig.numBands; ++i) {
55 mGains[i] = mConfig.customGains[i];
56 }
57 } else {
58 FL_WARN("SpectralEqualizer: custom gains size mismatch (" << mConfig.customGains.size() << " != " << mConfig.numBands << "), using flat gains");
60 }
61 break;
62
63 default:
65 break;
66 }
67}
68
70 // All gains = 1.0 (no equalization)
71 for (size i = 0; i < mConfig.numBands; ++i) {
72 mGains[i] = 1.0f;
73 }
74}
75
77 // Use appropriate A-weighting curve based on number of bands
78 const float* curve = nullptr;
79 size curveSize = 0;
80
81 if (mConfig.numBands == 16) {
82 curve = A_WEIGHTING_16BAND;
83 curveSize = 16;
84 } else if (mConfig.numBands == 32) {
85 curve = A_WEIGHTING_32BAND;
86 curveSize = 32;
87 } else {
88 // Unsupported band count - use flat gains
89 FL_WARN("SpectralEqualizer: A-weighting not defined for " << mConfig.numBands << " bands, using flat gains");
91 return;
92 }
93
94 // Copy A-weighting coefficients to gains
95 for (size i = 0; i < mConfig.numBands && i < curveSize; ++i) {
96 mGains[i] = curve[i];
97 }
98}
99
101 if (gains.size() != mConfig.numBands) {
102 FL_WARN("SpectralEqualizer: custom gains size mismatch (" << gains.size() << " != " << mConfig.numBands << ")");
103 return;
104 }
105
106 // Copy custom gains
107 mConfig.customGains.clear();
108 mConfig.customGains.reserve(gains.size());
109 for (size i = 0; i < gains.size(); ++i) {
110 mConfig.customGains.push_back(gains[i]);
111 mGains[i] = gains[i];
112 }
113
114 // Switch to custom curve
116}
117
119 if (inputBins.size() != mConfig.numBands) {
120 FL_WARN("SpectralEqualizer: input size mismatch (" << inputBins.size() << " != " << mConfig.numBands << ")");
121 return;
122 }
123
124 if (outputBins.size() < mConfig.numBands) {
125 FL_WARN("SpectralEqualizer: output buffer too small (" << outputBins.size() << " < " << mConfig.numBands << ")");
126 return;
127 }
128
129 // Track input/output levels for stats
130 float inputPeak = 0.0f;
131 float outputPeak = 0.0f;
132 float inputSum = 0.0f;
133 float outputSum = 0.0f;
134
135 // Apply per-band gains
136 for (size i = 0; i < mConfig.numBands; ++i) {
137 float inputValue = inputBins[i];
138 float gain = mGains[i];
139 float outputValue = inputValue * gain;
140
141 // Apply compression if enabled
142 if (mConfig.enableCompression) {
143 outputValue = applyCompression(outputValue);
144 }
145
146 outputBins[i] = outputValue;
147
148 // Track levels
149 if (inputValue > inputPeak) {
150 inputPeak = inputValue;
151 }
152 if (outputValue > outputPeak) {
153 outputPeak = outputValue;
154 }
155 inputSum += inputValue;
156 outputSum += outputValue;
157 }
158
159 // Calculate makeup gain if enabled
160 float makeupGain = 1.0f;
161 if (mConfig.applyMakeupGain) {
162 makeupGain = calculateMakeupGain(inputBins, outputBins);
163
164 // Apply makeup gain to all output bins
165 for (size i = 0; i < mConfig.numBands; ++i) {
166 outputBins[i] *= makeupGain;
167 }
168
169 // Adjust output stats
170 outputPeak *= makeupGain;
171 outputSum *= makeupGain;
172 }
173
174 // Update mutable stats
175 mStats.applicationsCount++;
176 mStats.lastInputPeak = inputPeak;
177 mStats.lastOutputPeak = outputPeak;
178 mStats.lastMakeupGain = makeupGain;
179 mStats.avgInputLevel = inputSum / static_cast<float>(mConfig.numBands);
180 mStats.avgOutputLevel = outputSum / static_cast<float>(mConfig.numBands);
181}
182
184 // Calculate average levels
185 float inputAvg = 0.0f;
186 float outputAvg = 0.0f;
187
188 for (size i = 0; i < mConfig.numBands; ++i) {
189 inputAvg += inputBins[i];
190 outputAvg += outputBins[i];
191 }
192
193 inputAvg /= static_cast<float>(mConfig.numBands);
194 outputAvg /= static_cast<float>(mConfig.numBands);
195
196 // Avoid division by zero
197 if (outputAvg < 0.001f) {
198 return 1.0f;
199 }
200
201 // Calculate makeup gain to bring output to target level
202 // Target is relative to input average
203 float targetLevel = inputAvg * mConfig.makeupGainTarget;
204 float makeupGain = targetLevel / outputAvg;
205
206 // Clamp to reasonable range (0.1 to 10.0)
207 if (makeupGain < 0.1f) {
208 makeupGain = 0.1f;
209 }
210 if (makeupGain > 10.0f) {
211 makeupGain = 10.0f;
212 }
213
214 return makeupGain;
215}
216
218 // Simple soft-knee compression
219 if (value <= mConfig.compressionThreshold) {
220 // Below threshold - no compression
221 return value;
222 }
223
224 // Above threshold - apply compression ratio
225 float excess = value - mConfig.compressionThreshold;
226 float compressed = excess / mConfig.compressionRatio;
227 return mConfig.compressionThreshold + compressed;
228}
229
233
234} // namespace audio
235} // namespace fl
static constexpr float A_WEIGHTING_16BAND[16]
A-weighting coefficients for 16-band frequency analysis These approximate the A-weighting curve acros...
float applyCompression(float value) const FL_NO_EXCEPT
Apply dynamic range compression per band.
void configure(const SpectralEqualizerConfig &config) FL_NO_EXCEPT
Configure the spectral equalizer This calculates per-band gain multipliers based on the selected curv...
~SpectralEqualizer() FL_NO_EXCEPT
void calculateFlatGains() FL_NO_EXCEPT
Calculate flat gains (all 1.0)
void calculateAWeightingGains() FL_NO_EXCEPT
Calculate A-weighting gains.
void resetStats() FL_NO_EXCEPT
Reset statistics.
void apply(span< const float > inputBins, span< float > outputBins) const FL_NO_EXCEPT
Apply equalization to frequency bins.
float calculateMakeupGain(span< const float > inputBins, span< const float > outputBins) const FL_NO_EXCEPT
Calculate makeup gain to maintain target level.
void calculateGains() FL_NO_EXCEPT
Calculate gains based on current curve.
static constexpr float A_WEIGHTING_32BAND[32]
A-weighting coefficients for 32-band frequency analysis.
void setCustomGains(span< const float > gains) FL_NO_EXCEPT
Set custom per-band gains (switches to Custom curve)
SpectralEqualizerConfig mConfig
vector< float > mGains
Per-band gain multipliers.
Get statistics (for debugging/monitoring)
#define FL_WARN(...)
Definition log.h:437
Configuration for spectral equalizer.
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
Base definition for an LED controller.
Definition crgb.hpp:179