Skip to content

Commit c62967c

Browse files
committed
Equalizer3BandsPerChannel docu
1 parent 8c8f3b2 commit c62967c

File tree

1 file changed

+143
-53
lines changed

1 file changed

+143
-53
lines changed

src/AudioTools/CoreAudio/AudioFilter/Equalizer.h

Lines changed: 143 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,22 @@
1414
namespace audio_tools {
1515

1616
/**
17-
* @brief Configuration for 3 Band Equalizer: Set
18-
* channels,bits_per_sample,sample_rate. Set and update gain_low, gain_medium
19-
* and gain_high to value between 0 and 1.0
17+
* @brief Configuration for 3 Band Equalizer
18+
*
19+
* Configure the basic audio parameters (channels, bits_per_sample, sample_rate)
20+
* and the equalizer settings. The frequency and gain parameters apply to all
21+
* channels identically in the basic Equalizer3Bands class.
22+
*
23+
* Frequency bands:
24+
* - Low band: DC to freq_low Hz
25+
* - Medium band: freq_low to freq_high Hz
26+
* - High band: freq_high to Nyquist frequency
27+
*
28+
* Gain values should typically range from 0.0 to 2.0:
29+
* - 0.0 = complete attenuation (silence)
30+
* - 1.0 = no change (unity gain)
31+
* - 2.0 = 6dB boost
32+
*
2033
* @ingroup equilizer
2134
* @author pschatzmann
2235
*/
@@ -27,33 +40,59 @@ struct ConfigEqualizer3Bands : public AudioInfo {
2740
sample_rate = 44100;
2841
}
2942

30-
// Frequencies
43+
/// Low-pass filter cutoff frequency in Hz. Frequencies below this are considered "low"
3144
int freq_low = 880;
45+
46+
/// High-pass filter cutoff frequency in Hz. Frequencies above this are considered "high"
3247
int freq_high = 5000;
3348

34-
// Gain Controls
49+
/// Gain multiplier for low frequencies (0.0-2.0, where 1.0 = unity gain)
3550
float gain_low = 1.0;
51+
52+
/// Gain multiplier for medium frequencies (0.0-2.0, where 1.0 = unity gain)
3653
float gain_medium = 1.0;
54+
55+
/// Gain multiplier for high frequencies (0.0-2.0, where 1.0 = unity gain)
3756
float gain_high = 1.0;
3857
};
3958

4059
/**
41-
* @brief 3 Band Equalizer inspired from
60+
* @brief 3 Band Equalizer with identical settings for all channels
61+
*
62+
* Digital 3-band equalizer implementation inspired from
4263
* https://www.musicdsp.org/en/latest/Filters/236-3-band-equaliser.html
64+
*
65+
* This equalizer applies the same frequency response and gain settings
66+
* to all audio channels. The audio spectrum is divided into three bands:
67+
* - Low: DC to freq_low Hz (controlled by gain_low)
68+
* - Medium: freq_low to freq_high Hz (controlled by gain_medium)
69+
* - High: freq_high to Nyquist frequency (controlled by gain_high)
70+
*
71+
* Each band uses a 4-pole filter implementation for smooth frequency response.
72+
* If you need different settings per channel, use Equalizer3BandsPerChannel instead.
73+
*
4374
* @ingroup equilizer
4475
* @author pschatzmann
4576
*/
4677
class Equalizer3Bands : public ModifyingStream {
4778
public:
79+
/// Constructor with Print output stream
80+
/// @param out Print stream where processed audio will be written
4881
Equalizer3Bands(Print &out) { setOutput(out); }
4982

83+
/// Constructor with bidirectional Stream
84+
/// @param in Stream for both input and output
5085
Equalizer3Bands(Stream &in) { setStream(in); }
5186

87+
/// Constructor with AudioOutput (includes automatic audio format notifications)
88+
/// @param out AudioOutput where processed audio will be written
5289
Equalizer3Bands(AudioOutput &out) {
5390
setOutput(out);
5491
out.addNotifyAudioChange(*this);
5592
}
5693

94+
/// Constructor with AudioStream (includes automatic audio format notifications)
95+
/// @param stream AudioStream for both input and output
5796
Equalizer3Bands(AudioStream &stream) {
5897
setStream(stream);
5998
stream.addNotifyAudioChange(*this);
@@ -63,19 +102,28 @@ class Equalizer3Bands : public ModifyingStream {
63102
if (state != nullptr) delete[] state;
64103
}
65104

66-
/// Defines/Changes the input & output
105+
/// Defines/Changes the input & output stream
106+
/// @param io Stream to use for both reading and writing audio data
67107
void setStream(Stream &io) override {
68108
p_print = &io;
69109
p_stream = &io;
70110
};
71111

72112
/// Defines/Changes the output target
113+
/// @param out Print stream where processed audio will be written
73114
void setOutput(Print &out) override { p_print = &out; }
74115

116+
/// Access to the current configuration
117+
/// @return Reference to the configuration object
75118
ConfigEqualizer3Bands &config() { return cfg; }
76119

120+
/// Access to the default configuration
121+
/// @return Reference to the default configuration object
77122
ConfigEqualizer3Bands &defaultConfig() { return config(); }
78123

124+
/// Initialize the equalizer with the provided configuration
125+
/// @param config Configuration settings including frequencies and gains
126+
/// @return true if initialization was successful
79127
bool begin(ConfigEqualizer3Bands &config) {
80128
p_cfg = &config;
81129
if (p_cfg->channels > max_state_count) {
@@ -98,21 +146,32 @@ class Equalizer3Bands : public ModifyingStream {
98146
return true;
99147
}
100148

149+
/// Called automatically when audio format changes
150+
/// @param info New audio format information
101151
virtual void setAudioInfo(AudioInfo info) override {
102152
p_cfg->sample_rate = info.sample_rate;
103153
p_cfg->channels = info.channels;
104154
p_cfg->bits_per_sample = info.bits_per_sample;
105155
begin(*p_cfg);
106156
}
107157

158+
/// Process and write audio data through the equalizer
159+
/// @param data Pointer to audio data buffer
160+
/// @param len Length of data in bytes
161+
/// @return Number of bytes written
108162
size_t write(const uint8_t *data, size_t len) override {
109163
filterSamples(data, len);
110164
return p_print->write(data, len);
111165
}
112166

167+
/// Get available space for writing
168+
/// @return Number of bytes available for writing
113169
int availableForWrite() override { return p_print->availableForWrite(); }
114170

115-
/// Provides the data from all streams mixed together
171+
/// Read and process audio data through the equalizer
172+
/// @param data Buffer to store processed audio data
173+
/// @param len Maximum number of bytes to read
174+
/// @return Number of bytes actually read and processed
116175
size_t readBytes(uint8_t *data, size_t len) override {
117176
size_t result = 0;
118177
if (p_stream != nullptr) {
@@ -122,42 +181,46 @@ class Equalizer3Bands : public ModifyingStream {
122181
return result;
123182
}
124183

184+
/// Get available data for reading
185+
/// @return Number of bytes available for reading
125186
int available() override {
126187
return p_stream != nullptr ? p_stream->available() : 0;
127188
}
128189

129190
protected:
130-
ConfigEqualizer3Bands cfg;
131-
ConfigEqualizer3Bands *p_cfg = &cfg;
132-
const float vsa = (1.0 / 4294967295.0); // Very small amount (Denormal Fix)
133-
Print *p_print = nullptr; // support for write
134-
Stream *p_stream = nullptr; // support for write
135-
// AudioOutput *p_out=nullptr; // support for write
136-
// AudioStream *p_in=nullptr; // support for readBytes
137-
int max_state_count = 0;
138-
191+
ConfigEqualizer3Bands cfg; ///< Default configuration instance
192+
ConfigEqualizer3Bands *p_cfg = &cfg; ///< Pointer to active configuration
193+
const float vsa = (1.0 / 4294967295.0); ///< Very small amount for denormal fix
194+
Print *p_print = nullptr; ///< Output stream for write operations
195+
Stream *p_stream = nullptr; ///< Input/output stream for read operations
196+
int max_state_count = 0; ///< Maximum number of allocated channel states
197+
198+
/// Filter state for each channel
139199
struct EQSTATE {
140-
// Filter #1 (Low band)
141-
float lf; // Frequency
142-
float f1p0; // Poles ...
143-
float f1p1;
144-
float f1p2;
145-
float f1p3;
146-
147-
// Filter #2 (High band)
148-
float hf; // Frequency
149-
float f2p0; // Poles ...
150-
float f2p1;
151-
float f2p2;
152-
float f2p3;
153-
154-
// Sample history buffer
155-
float sdm1; // Sample data minus 1
156-
float sdm2; // 2
157-
float sdm3; // 3
200+
// Filter #1 (Low band) - 4-pole low-pass filter
201+
float lf; ///< Low frequency cutoff coefficient
202+
float f1p0; ///< Filter pole 0
203+
float f1p1; ///< Filter pole 1
204+
float f1p2; ///< Filter pole 2
205+
float f1p3; ///< Filter pole 3
206+
207+
// Filter #2 (High band) - 4-pole high-pass filter
208+
float hf; ///< High frequency cutoff coefficient
209+
float f2p0; ///< Filter pole 0
210+
float f2p1; ///< Filter pole 1
211+
float f2p2; ///< Filter pole 2
212+
float f2p3; ///< Filter pole 3
213+
214+
// Sample history buffer for filter calculations
215+
float sdm1; ///< Sample data minus 1 (previous sample)
216+
float sdm2; ///< Sample data minus 2
217+
float sdm3; ///< Sample data minus 3
158218

159219
} *state = nullptr;
160220

221+
/// Apply 3-band equalization to audio samples
222+
/// @param data Pointer to audio data buffer (modified in-place)
223+
/// @param len Length of data buffer in bytes
161224
void filterSamples(const uint8_t *data, size_t len) {
162225
if (state == nullptr){
163226
LOGE("You need to call begin() before using the equalizer");
@@ -198,8 +261,10 @@ class Equalizer3Bands : public ModifyingStream {
198261
}
199262
}
200263

201-
202-
// calculates a single sample using the indicated state
264+
/// Process a single audio sample through the 3-band equalizer
265+
/// @param es Reference to the filter state for this channel
266+
/// @param sample Input sample value (normalized float)
267+
/// @return Processed sample value with equalization applied
203268
float sample(EQSTATE &es, float sample) {
204269
// Locals
205270
float l, m, h; // Low / Mid / High - Sample Values
@@ -324,6 +389,9 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
324389
}
325390

326391
/// Set frequency parameters for a specific channel
392+
/// @param channel Channel index (0-based)
393+
/// @param freq_low_val Low frequency cutoff in Hz
394+
/// @param freq_high_val High frequency cutoff in Hz
327395
void setChannelFrequencies(int channel, int freq_low_val, int freq_high_val) {
328396
ensureChannelArraysAllocated();
329397
if (channel >= 0 && channel < p_cfg->channels && !freq_low.empty()) {
@@ -339,6 +407,10 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
339407
}
340408

341409
/// Set gain parameters for a specific channel
410+
/// @param channel Channel index (0-based)
411+
/// @param gain_low_val Gain multiplier for low frequencies (0.0-2.0)
412+
/// @param gain_medium_val Gain multiplier for medium frequencies (0.0-2.0)
413+
/// @param gain_high_val Gain multiplier for high frequencies (0.0-2.0)
342414
void setChannelGains(int channel, float gain_low_val, float gain_medium_val, float gain_high_val) {
343415
ensureChannelArraysAllocated();
344416
if (channel >= 0 && channel < p_cfg->channels && !gain_low.empty()) {
@@ -349,6 +421,10 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
349421
}
350422

351423
/// Get frequency parameters for a specific channel
424+
/// @param channel Channel index (0-based)
425+
/// @param freq_low_val Reference to store the low frequency cutoff
426+
/// @param freq_high_val Reference to store the high frequency cutoff
427+
/// @return true if successful, false if channel index is invalid
352428
bool getChannelFrequencies(int channel, int &freq_low_val, int &freq_high_val) {
353429
if (channel >= 0 && channel < p_cfg->channels && !freq_low.empty()) {
354430
freq_low_val = freq_low[channel];
@@ -359,6 +435,11 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
359435
}
360436

361437
/// Get gain parameters for a specific channel
438+
/// @param channel Channel index (0-based)
439+
/// @param gain_low_val Reference to store the low frequency gain
440+
/// @param gain_medium_val Reference to store the medium frequency gain
441+
/// @param gain_high_val Reference to store the high frequency gain
442+
/// @return true if successful, false if channel index is invalid
362443
bool getChannelGains(int channel, float &gain_low_val, float &gain_medium_val, float &gain_high_val) {
363444
if (channel >= 0 && channel < p_cfg->channels && !gain_low.empty()) {
364445
gain_low_val = gain_low[channel];
@@ -369,14 +450,23 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
369450
return false;
370451
}
371452

453+
/// Process and write audio data through the per-channel equalizer
454+
/// @param data Pointer to audio data buffer
455+
/// @param len Length of data in bytes
456+
/// @return Number of bytes written
372457
size_t write(const uint8_t *data, size_t len) override {
373458
filterSamples(data, len);
374459
return p_print->write(data, len);
375460
}
376461

462+
/// Get available space for writing
463+
/// @return Number of bytes available for writing
377464
int availableForWrite() override { return p_print->availableForWrite(); }
378465

379-
/// Provides the data from all streams mixed together
466+
/// Read and process audio data through the per-channel equalizer
467+
/// @param data Buffer to store processed audio data
468+
/// @param len Maximum number of bytes to read
469+
/// @return Number of bytes actually read and processed
380470
size_t readBytes(uint8_t *data, size_t len) override {
381471
size_t result = 0;
382472
if (p_stream != nullptr) {
@@ -386,26 +476,26 @@ class Equalizer3BandsPerChannel : public ModifyingStream {
386476
return result;
387477
}
388478

479+
/// Get available data for reading
480+
/// @return Number of bytes available for reading
389481
int available() override {
390482
return p_stream != nullptr ? p_stream->available() : 0;
391483
}
392484

393485
protected:
394-
ConfigEqualizer3Bands cfg;
395-
ConfigEqualizer3Bands *p_cfg = &cfg;
396-
const float vsa = (1.0 / 4294967295.0); // Very small amount (Denormal Fix)
397-
Print *p_print = nullptr; // support for write
398-
Stream *p_stream = nullptr; // support for write
399-
int max_state_count = 0;
400-
401-
// Per-channel frequency settings using Vector
402-
Vector<int> freq_low;
403-
Vector<int> freq_high;
404-
405-
// Per-channel gain controls using Vector
406-
Vector<float> gain_low;
407-
Vector<float> gain_medium;
408-
Vector<float> gain_high;
486+
ConfigEqualizer3Bands cfg; ///< Default configuration instance
487+
ConfigEqualizer3Bands *p_cfg = &cfg; ///< Pointer to active configuration
488+
const float vsa = (1.0 / 4294967295.0); ///< Very small amount for denormal fix
489+
Print *p_print = nullptr; ///< Output stream for write operations
490+
Stream *p_stream = nullptr; ///< Input/output stream for read operations
491+
int max_state_count = 0; ///< Maximum number of allocated channel states
492+
493+
// Per-channel frequency and gain settings using Vector containers
494+
Vector<int> freq_low; ///< Low frequency cutoffs per channel (Hz)
495+
Vector<int> freq_high; ///< High frequency cutoffs per channel (Hz)
496+
Vector<float> gain_low; ///< Low frequency gains per channel
497+
Vector<float> gain_medium; ///< Medium frequency gains per channel
498+
Vector<float> gain_high; ///< High frequency gains per channel
409499

410500
struct EQSTATE {
411501
// Filter #1 (Low band)

0 commit comments

Comments
 (0)