54 for (size i = 0; i <
mConfig.numBands; ++i) {
58 FL_WARN(
"SpectralEqualizer: custom gains size mismatch (%s != %s), using flat gains",
mConfig.customGains.size(),
mConfig.numBands);
71 for (size i = 0; i <
mConfig.numBands; ++i) {
78 const float* curve =
nullptr;
84 }
else if (
mConfig.numBands == 32) {
89 FL_WARN(
"SpectralEqualizer: A-weighting not defined for %s bands, using flat gains",
mConfig.numBands);
95 for (size i = 0; i <
mConfig.numBands && i < curveSize; ++i) {
102 FL_WARN(
"SpectralEqualizer: custom gains size mismatch (%s != %s)", gains.
size(),
mConfig.numBands);
109 for (size i = 0; i < gains.
size(); ++i) {
110 mConfig.customGains.push_back(gains[i]);
120 FL_WARN(
"SpectralEqualizer: input size mismatch (%s != %s)", inputBins.
size(),
mConfig.numBands);
125 FL_WARN(
"SpectralEqualizer: output buffer too small (%s < %s)", outputBins.
size(),
mConfig.numBands);
130 float inputPeak = 0.0f;
131 float outputPeak = 0.0f;
132 float inputSum = 0.0f;
133 float outputSum = 0.0f;
136 for (size i = 0; i <
mConfig.numBands; ++i) {
137 float inputValue = inputBins[i];
139 float outputValue = inputValue * gain;
142 if (
mConfig.enableCompression) {
146 outputBins[i] = outputValue;
149 if (inputValue > inputPeak) {
150 inputPeak = inputValue;
152 if (outputValue > outputPeak) {
153 outputPeak = outputValue;
155 inputSum += inputValue;
156 outputSum += outputValue;
160 float makeupGain = 1.0f;
165 for (size i = 0; i <
mConfig.numBands; ++i) {
166 outputBins[i] *= makeupGain;
170 outputPeak *= makeupGain;
171 outputSum *= makeupGain;
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);
185 float inputAvg = 0.0f;
186 float outputAvg = 0.0f;
188 for (size i = 0; i <
mConfig.numBands; ++i) {
189 inputAvg += inputBins[i];
190 outputAvg += outputBins[i];
193 inputAvg /=
static_cast<float>(
mConfig.numBands);
194 outputAvg /=
static_cast<float>(
mConfig.numBands);
197 if (outputAvg < 0.001f) {
203 float targetLevel = inputAvg *
mConfig.makeupGainTarget;
204 float makeupGain = targetLevel / outputAvg;
207 if (makeupGain < 0.1f) {
210 if (makeupGain > 10.0f) {
226 float compressed = excess /
mConfig.compressionRatio;
227 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_NO_EXCEPT
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...
void resetStats()
Reset statistics.
SpectralEqualizer() FL_NO_EXCEPT
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_NO_EXCEPT
Configuration for spectral equalizer.
constexpr int type_rank< T >::value
InputGamut g FL_NO_EXCEPT
Base definition for an LED controller.