54 for (size i = 0; i <
mConfig.numBands; ++i) {
58 FL_WARN(
"SpectralEqualizer: custom gains size mismatch ("
60 <<
"), using flat gains");
73 for (size i = 0; i <
mConfig.numBands; ++i) {
80 const float* curve =
nullptr;
86 }
else if (
mConfig.numBands == 32) {
91 FL_WARN(
"SpectralEqualizer: A-weighting not defined for " <<
mConfig.numBands
92 <<
" bands, using flat gains");
98 for (size i = 0; i <
mConfig.numBands && i < curveSize; ++i) {
105 FL_WARN(
"SpectralEqualizer: custom gains size mismatch ("
106 << gains.
size() <<
" != " <<
mConfig.numBands <<
")");
113 for (size i = 0; i < gains.
size(); ++i) {
114 mConfig.customGains.push_back(gains[i]);
124 FL_WARN(
"SpectralEqualizer: input size mismatch ("
125 << inputBins.
size() <<
" != " <<
mConfig.numBands <<
")");
130 FL_WARN(
"SpectralEqualizer: output buffer too small ("
131 << outputBins.
size() <<
" < " <<
mConfig.numBands <<
")");
136 float inputPeak = 0.0f;
137 float outputPeak = 0.0f;
138 float inputSum = 0.0f;
139 float outputSum = 0.0f;
142 for (size i = 0; i <
mConfig.numBands; ++i) {
143 float inputValue = inputBins[i];
145 float outputValue = inputValue * gain;
148 if (
mConfig.enableCompression) {
152 outputBins[i] = outputValue;
155 if (inputValue > inputPeak) {
156 inputPeak = inputValue;
158 if (outputValue > outputPeak) {
159 outputPeak = outputValue;
161 inputSum += inputValue;
162 outputSum += outputValue;
166 float makeupGain = 1.0f;
171 for (size i = 0; i <
mConfig.numBands; ++i) {
172 outputBins[i] *= makeupGain;
176 outputPeak *= makeupGain;
177 outputSum *= makeupGain;
181 mStats.applicationsCount++;
182 mStats.lastInputPeak = inputPeak;
183 mStats.lastOutputPeak = outputPeak;
184 mStats.lastMakeupGain = makeupGain;
185 mStats.avgInputLevel = inputSum /
static_cast<float>(
mConfig.numBands);
186 mStats.avgOutputLevel = outputSum /
static_cast<float>(
mConfig.numBands);
191 float inputAvg = 0.0f;
192 float outputAvg = 0.0f;
194 for (size i = 0; i <
mConfig.numBands; ++i) {
195 inputAvg += inputBins[i];
196 outputAvg += outputBins[i];
199 inputAvg /=
static_cast<float>(
mConfig.numBands);
200 outputAvg /=
static_cast<float>(
mConfig.numBands);
203 if (outputAvg < 0.001f) {
209 float targetLevel = inputAvg *
mConfig.makeupGainTarget;
210 float makeupGain = targetLevel / outputAvg;
213 if (makeupGain < 0.1f) {
216 if (makeupGain > 10.0f) {
232 float compressed = excess /
mConfig.compressionRatio;
233 return mConfig.compressionThreshold + compressed;
static constexpr float A_WEIGHTING_16BAND[16]
A-weighting coefficients for 16-band frequency analysis These approximate the A-weighting curve acros...
SpectralEqualizer() FL_NOEXCEPT
void calculateGains()
Calculate gains based on current curve.
void setCustomGains(span< const float > gains)
Set custom per-band gains (switches to Custom curve)
void configure(const SpectralEqualizerConfig &config)
Configure the spectral equalizer This calculates per-band gain multipliers based on the selected curv...
~SpectralEqualizer() FL_NOEXCEPT
void resetStats()
Reset statistics.
float calculateMakeupGain(span< const float > inputBins, span< const float > outputBins) const
Calculate makeup gain to maintain target level.
void calculateFlatGains()
Calculate flat gains (all 1.0)
void calculateAWeightingGains()
Calculate A-weighting gains.
void apply(span< const float > inputBins, span< float > outputBins) const
Apply equalization to frequency bins.
float applyCompression(float value) const
Apply dynamic range compression per band.
static constexpr float A_WEIGHTING_32BAND[32]
A-weighting coefficients for 32-band frequency analysis.
SpectralEqualizerConfig mConfig
vector< float > mGains
Per-band gain multipliers.
Get statistics (for debugging/monitoring)
constexpr fl::size size() const FL_NOEXCEPT
Configuration for spectral equalizer.
constexpr int type_rank< T >::value
Base definition for an LED controller.