arduino-audio-tools
All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Macros Modules Pages
FrequencyDetector.h
1#pragma once
2
3#include "AudioTools/CoreAudio/AudioBasic/Collections/Vector.h"
4#include "AudioTools/CoreAudio/AudioStreams.h"
5
6namespace audio_tools {
7
23 public:
29 buffer_size = bufferSize;
30 };
31
38 p_out = &out;
39 buffer_size = bufferSize;
40 };
41
48 p_out = ∈
49 p_in = ∈
50 buffer_size = bufferSize;
51 }
52
58 bool begin(AudioInfo info) {
59 setAudioInfo(info);
60 return begin();
61 }
62
67 bool begin() {
69 freq.resize(info.channels);
70 return AudioStream::begin();
71 }
72
76 int available() override {
77 if (p_in) return p_in->available();
78 return 0;
79 }
80
84 int availableForWrite() override {
85 if (p_out) return p_out->availableForWrite();
86 return DEFAULT_BUFFER_SIZE;
87 }
88
95 size_t readBytes(uint8_t* data, size_t len) override {
96 size_t result = p_in->readBytes(data, len);
97 for (int i = 0; i < len; i++) {
98 buffer.write(data[i]);
99 if (buffer.isFull()) {
100 // Process buffer when full, based on sample format
101 switch (info.bits_per_sample) {
102 case 16:
103 detect<int16_t>((int16_t*)buffer.data(),
104 buffer.available() / sizeof(int16_t));
105 break;
106 case 24:
107 detect<int24_t>((int24_t*)buffer.data(),
108 buffer.available() / sizeof(int24_t));
109 break;
110 case 32:
111 detect<int32_t>((int32_t*)buffer.data(),
112 buffer.available() / sizeof(int32_t));
113 break;
114 }
115 buffer.reset();
116 }
117 }
118 return result;
119 }
120
127 virtual size_t write(const uint8_t* data, size_t len) override {
128 for (int i = 0; i < len; i++) {
129 buffer.write(data[i]);
130 if (buffer.isFull()) {
131 // Process buffer when full, based on sample format
132 switch (info.bits_per_sample) {
133 case 16:
134 detect<int16_t>((int16_t*)buffer.data(),
135 buffer.available() / sizeof(int16_t));
136 break;
137 case 24:
138 detect<int24_t>((int24_t*)buffer.data(),
139 buffer.available() / sizeof(int24_t));
140 break;
141 case 32:
142 detect<int32_t>((int32_t*)buffer.data(),
143 buffer.available() / sizeof(int32_t));
144 break;
145 }
146 buffer.reset();
147 }
148 }
149
150 size_t result = len;
151 if (p_out != nullptr) result = p_out->write(data, len);
152 return result;
153 }
154
160 float frequency(int channel) {
161 if (channel >= info.channels) {
162 LOGE("Invalid channel: %d", channel);
163 return 0;
164 }
165 return freq[channel];
166 }
167
172 AudioInfo result;
173 return result;
174 }
175
180 void setFrequencyCallback(void (*callback)(int channel, float freq)) {
181 freq_callback = callback;
182 }
183
184 protected:
186 Print* p_out = nullptr;
187 Stream* p_in = nullptr;
188 void (*freq_callback)(int channel, float freq);
189 int buffer_size = 0;
191
198 template <class T>
199 void detect(T* samples, size_t len) {
200 freq.resize(info.channels);
201 for (int ch = 0; ch < info.channels; ch++) {
202 freq[ch] = detectFrequencyForChannel(ch, samples, len);
203 if (freq_callback) freq_callback(ch, freq[ch]);
204 }
205 }
206
215 template <class T>
216 float detectFrequencyForChannel(int ch, T* samples, size_t len) {
217 LOGD("detectFrequencyForChannel: %d / len: %u", ch, (unsigned int)len);
218 // Prepare variables for autocorrelation
219 int sample_rate = info.sample_rate;
220 int channels = info.channels;
221 int buffer_size = len / info.channels;
222
223 // Autocorrelation lag range: 1000 Hz max, 50 Hz min
224 size_t min_lag = sample_rate / 1000;
225 size_t max_lag = sample_rate / 50;
226 if (max_lag >= buffer_size) max_lag = buffer_size - 1;
227
228 LOGD("lag min/max: %u / %u", (unsigned)min_lag, (unsigned)max_lag);
229
230 float max_corr = 0.0f;
231 size_t best_lag = 0;
232 for (size_t lag = min_lag; lag < max_lag; ++lag) {
233 float sum = 0.0f;
234 for (size_t i = 0; i < buffer_size - lag; ++i) {
235 sum += samples[i * channels] * samples[(i + lag) * channels];
236 }
237 if (sum > max_corr) {
238 max_corr = sum;
239 best_lag = lag;
240 }
241 }
242
243 LOGD("best_lag: %u / max_corr: %f", (unsigned)best_lag, max_corr);
244
245 if (best_lag == 0) return 0.0f;
246 return (float)sample_rate / best_lag;
247 }
248};
249
263 public:
268
274
280 p_out = &in;
281 p_in = &in;
282 };
283
289 bool begin(AudioInfo info) {
290 setAudioInfo(info);
291 return AudioStream::begin();
292 }
293
297 int available() override {
298 if (p_in) return p_in->available();
299 return 0;
300 }
301
305 int availableForWrite() override {
306 if (p_out) return p_out->availableForWrite();
307 return DEFAULT_BUFFER_SIZE;
308 }
309
316 size_t readBytes(uint8_t* data, size_t len) override {
317 size_t result = p_in->readBytes(data, len);
318 switch (info.bits_per_sample) {
319 case 16:
320 detect<int16_t>((int16_t*)data, len / sizeof(int16_t));
321 break;
322 case 24:
323 detect<int24_t>((int24_t*)data, len / sizeof(int24_t));
324 break;
325 case 32:
326 detect<int32_t>((int32_t*)data, len / sizeof(int32_t));
327 break;
328 }
329 return result;
330 }
331
338 virtual size_t write(const uint8_t* data, size_t len) override {
339 switch (info.bits_per_sample) {
340 case 16:
341 detect<int16_t>((int16_t*)data, len / sizeof(int16_t));
342 break;
343 case 24:
344 detect<int24_t>((int24_t*)data, len / sizeof(int24_t));
345 break;
346 case 32:
347 detect<int32_t>((int32_t*)data, len / sizeof(int32_t));
348 break;
349 }
350
351 size_t result = len;
352 if (p_out != nullptr) result = p_out->write(data, len);
353 return result;
354 }
355
361 float frequency(int channel) {
362 if (channel >= info.channels) {
363 LOGE("Invalid channel: %d", channel);
364 return 0;
365 }
366 return states[channel].freq;
367 }
368
373 void setFrequencyCallback(void (*callback)(int channel, float freq)) {
374 freq_callback = callback;
375 }
376
377 protected:
382 int count = 0;
383 bool active = false;
384 float freq = 0.0f;
385 };
387 Print* p_out = nullptr;
388 Stream* p_in = nullptr;
389 int count = 0;
390 bool active = false;
391 void (*freq_callback)(int channel, float freq);
392
399 template <class T>
400 void detect(T* samples, size_t len) {
401 states.resize(info.channels);
402 for (int ch = 0; ch < info.channels; ch++) {
403 detectChannel(ch, samples, len);
404 }
405 }
406
414 template <class T>
415 void detectChannel(int channel, T* samples, size_t len) {
416 ChannelState& state = states[channel];
417 for (int i = channel; i < (int)(len - info.channels); i += info.channels) {
418 if (state.active) state.count++;
419 // Detect upward zero crossing (negative to positive)
420 if (samples[i] <= 0 && samples[i + info.channels] > 0) {
421 if (state.count > 0) {
422 state.freq = (1.0f * info.sample_rate) / state.count;
423 if (freq_callback) freq_callback(channel, state.freq);
424 }
425 state.count = 0;
426 state.active = true;
427 }
428 }
429 }
430};
431
432} // namespace audio_tools
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:122
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:130
Detects frequency using autocorrelation on audio samples.
Definition FrequencyDetector.h:22
virtual size_t write(const uint8_t *data, size_t len) override
Writes bytes to the output stream and processes them for frequency detection.
Definition FrequencyDetector.h:127
void detect(T *samples, size_t len)
Detects frequency for all channels using autocorrelation.
Definition FrequencyDetector.h:199
FrequencyDetectorAutoCorrelation(int bufferSize)
Construct with buffer size.
Definition FrequencyDetector.h:28
Stream * p_in
Input stream pointer.
Definition FrequencyDetector.h:187
void setFrequencyCallback(void(*callback)(int channel, float freq))
Sets a callback function to be called when a new frequency is detected.
Definition FrequencyDetector.h:180
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream and processes them for frequency detection.
Definition FrequencyDetector.h:95
bool begin()
Initialize internal buffers based on audio info.
Definition FrequencyDetector.h:67
int available() override
Returns the number of bytes available for reading.
Definition FrequencyDetector.h:76
FrequencyDetectorAutoCorrelation(int bufferSize, Stream &in)
Construct with buffer size and input stream.
Definition FrequencyDetector.h:47
FrequencyDetectorAutoCorrelation(int bufferSize, Print &out)
Construct with buffer size and output stream.
Definition FrequencyDetector.h:37
AudioInfo defaultConfig()
Returns a default AudioInfo configuration.
Definition FrequencyDetector.h:171
int availableForWrite() override
Returns the number of bytes available for writing.
Definition FrequencyDetector.h:84
Vector< float > freq
Stores detected frequency for each channel.
Definition FrequencyDetector.h:185
Print * p_out
Output stream pointer.
Definition FrequencyDetector.h:186
SingleBuffer< uint8_t > buffer
Buffer for incoming audio data.
Definition FrequencyDetector.h:190
void(* freq_callback)(int channel, float freq)
Frequency callback function.
Definition FrequencyDetector.h:188
float detectFrequencyForChannel(int ch, T *samples, size_t len)
Performs autocorrelation to estimate frequency for a single channel.
Definition FrequencyDetector.h:216
float frequency(int channel)
Returns the last detected frequency for the given channel.
Definition FrequencyDetector.h:160
bool begin(AudioInfo info)
Initialize with audio configuration.
Definition FrequencyDetector.h:58
int buffer_size
Buffer size in samples.
Definition FrequencyDetector.h:189
Detects frequency using upward zero crossings in audio samples.
Definition FrequencyDetector.h:262
Vector< ChannelState > states
State for each channel.
Definition FrequencyDetector.h:386
virtual size_t write(const uint8_t *data, size_t len) override
Writes bytes to the output stream and processes them for frequency detection.
Definition FrequencyDetector.h:338
bool active
Counting active flag (unused, kept for compatibility)
Definition FrequencyDetector.h:390
void detect(T *samples, size_t len)
Detects frequency for all channels using zero crossing method.
Definition FrequencyDetector.h:400
Stream * p_in
Input stream pointer.
Definition FrequencyDetector.h:388
void setFrequencyCallback(void(*callback)(int channel, float freq))
Sets a callback function to be called when a new frequency is detected.
Definition FrequencyDetector.h:373
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream and processes them for frequency detection.
Definition FrequencyDetector.h:316
int available() override
Returns the number of bytes available for reading.
Definition FrequencyDetector.h:297
FrequencyDetectorZeroCrossing(Stream &in)
Construct with input stream.
Definition FrequencyDetector.h:279
int availableForWrite() override
Returns the number of bytes available for writing.
Definition FrequencyDetector.h:305
Print * p_out
Output stream pointer.
Definition FrequencyDetector.h:387
FrequencyDetectorZeroCrossing(Print &out)
Construct with output stream.
Definition FrequencyDetector.h:273
void(* freq_callback)(int channel, float freq)
Frequency callback function.
Definition FrequencyDetector.h:391
void detectChannel(int channel, T *samples, size_t len)
Detects frequency for a single channel by counting upward zero crossings.
Definition FrequencyDetector.h:415
FrequencyDetectorZeroCrossing()=default
Default constructor.
int count
Sample count (unused, kept for compatibility)
Definition FrequencyDetector.h:389
float frequency(int channel)
Returns the last detected frequency for the given channel.
Definition FrequencyDetector.h:361
bool begin(AudioInfo info)
Initialize with audio configuration.
Definition FrequencyDetector.h:289
Definition NoArduino.h:62
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:172
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:202
int available() override
provides the number of entries that are available to read
Definition Buffers.h:229
bool isFull() override
checks if the buffer is full
Definition Buffers.h:236
bool resize(int size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:292
T * data()
Provides address of actual data.
Definition Buffers.h:271
void reset() override
clears the buffer
Definition Buffers.h:273
Definition NoArduino.h:142
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition Int24_4bytes_t.h:16
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition AudioCodecsBase.h:10
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:53
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:55
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:57
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:59
Holds state for each channel during zero crossing detection.
Definition FrequencyDetector.h:381
bool active
True if counting is active.
Definition FrequencyDetector.h:383
float freq
Last detected frequency.
Definition FrequencyDetector.h:384
int count
Sample count since last zero crossing.
Definition FrequencyDetector.h:382