arduino-audio-tools
Loading...
Searching...
No Matches
FrequencyDetectorAutoCorrelation.h
Go to the documentation of this file.
1#pragma once
2
5
6namespace audio_tools {
7
23 public:
29
35 buffer_size = bufferSize;
36 };
37
44 p_out = &out;
45 buffer_size = bufferSize;
46 };
47
54 p_out = ∈
55 p_in = ∈
56 buffer_size = bufferSize;
57 }
58
66 return begin();
67 }
68
74 void setBufferSize(int bufferSize) { buffer_size = bufferSize; }
75
80 bool begin() {
81 if (buffer_size <= 0) {
82 // must be large enough to contain at least one period of the lowest
83 // frequency we try to detect (50Hz, see detectFrequencyForChannel)
84 buffer_size = info.sample_rate / 50 + 16;
85 }
89 return AudioStream::begin();
90 }
91
95 int available() override {
96 if (p_in) return p_in->available();
97 return 0;
98 }
99
103 int availableForWrite() override {
104 if (p_out) return p_out->availableForWrite();
105 return DEFAULT_BUFFER_SIZE;
106 }
107
114 size_t readBytes(uint8_t* data, size_t len) override {
115 size_t result = p_in->readBytes(data, len);
116 for (int i = 0; i < len; i++) {
117 buffer.write(data[i]);
118 if (buffer.isFull()) {
119 // Process buffer when full, based on sample format
120 switch (info.bits_per_sample) {
121 case 16:
122 detect<int16_t>((int16_t*)buffer.data(),
123 buffer.available() / sizeof(int16_t));
124 break;
125 case 24:
126 detect<int24_t>((int24_t*)buffer.data(),
127 buffer.available() / sizeof(int24_t));
128 break;
129 case 32:
130 detect<int32_t>((int32_t*)buffer.data(),
131 buffer.available() / sizeof(int32_t));
132 break;
133 }
134 buffer.reset();
135 }
136 }
137 return result;
138 }
139
146 virtual size_t write(const uint8_t* data, size_t len) override {
147 for (int i = 0; i < len; i++) {
148 buffer.write(data[i]);
149 if (buffer.isFull()) {
150 // Process buffer when full, based on sample format
151 switch (info.bits_per_sample) {
152 case 16:
153 detect<int16_t>((int16_t*)buffer.data(),
154 buffer.available() / sizeof(int16_t));
155 break;
156 case 24:
157 detect<int24_t>((int24_t*)buffer.data(),
158 buffer.available() / sizeof(int24_t));
159 break;
160 case 32:
161 detect<int32_t>((int32_t*)buffer.data(),
162 buffer.available() / sizeof(int32_t));
163 break;
164 }
165 buffer.reset();
166 }
167 }
168
169 size_t result = len;
170 if (p_out != nullptr) result = p_out->write(data, len);
171 return result;
172 }
173
179 float frequency(int channel) {
180 if (channel >= info.channels) {
181 LOGE("Invalid channel: %d", channel);
182 return 0;
183 }
184 return freq[channel];
185 }
186
197 float confidence(int channel) {
198 if (channel >= info.channels) {
199 LOGE("Invalid channel: %d", channel);
200 return 0;
201 }
202 return conf[channel];
203 }
204
211 bool isTonal(int channel, float threshold = 0.3f) {
212 return confidence(channel) >= threshold;
213 }
214
219 AudioInfo result;
220 return result;
221 }
222
227 void setFrequencyCallback(void (*callback)(int channel, float freq)) {
228 freq_callback = callback;
229 }
230
231 protected:
234 Print* p_out = nullptr;
235 Stream* p_in = nullptr;
236 void (*freq_callback)(int channel, float freq);
237 int buffer_size = 0;
239
246 template <class T>
247 void detect(T* samples, size_t len) {
250 for (int ch = 0; ch < info.channels; ch++) {
251 float channel_confidence = 0.0f;
252 freq[ch] = detectFrequencyForChannel(ch, samples, len, channel_confidence);
253 conf[ch] = channel_confidence;
254 if (freq_callback) freq_callback(ch, freq[ch]);
255 }
256 }
257
270 template <class T>
271 float detectFrequencyForChannel(int ch, T* samples, size_t len,
272 float& confidenceOut) {
273 LOGD("detectFrequencyForChannel: %d / len: %u", ch, (unsigned int)len);
274 confidenceOut = 0.0f;
275 // Prepare variables for autocorrelation
276 int sample_rate = info.sample_rate;
277 int channels = info.channels;
278 int buffer_size = len / info.channels;
279
280 // Autocorrelation lag range: 1000 Hz max, 50 Hz min
281 size_t min_lag = sample_rate / 1000;
282 size_t max_lag = sample_rate / 50;
283 if (max_lag >= buffer_size) max_lag = buffer_size - 1;
284
285 LOGD("lag min/max: %u / %u", (unsigned)min_lag, (unsigned)max_lag);
286
287 // Energy at lag 0 - used to normalize the correlation peak into a
288 // loudness-independent confidence score
289 double energy = 0.0;
290 for (int i = 0; i < buffer_size; ++i) {
291 double s = (double)samples[i * channels];
292 energy += s * s;
293 }
294
295 double max_corr = 0.0;
296 size_t best_lag = 0;
297 for (size_t lag = min_lag; lag < max_lag; ++lag) {
298 double sum = 0.0;
299 for (size_t i = 0; i < buffer_size - lag; ++i) {
300 sum += (double)samples[i * channels] * (double)samples[(i + lag) * channels];
301 }
302 if (sum > max_corr) {
303 max_corr = sum;
304 best_lag = lag;
305 }
306 }
307
308 LOGD("best_lag: %u / max_corr: %f", (unsigned)best_lag, max_corr);
309
310 if (energy > 0.0) {
311 confidenceOut = (float)(max_corr / energy);
312 if (confidenceOut > 1.0f) confidenceOut = 1.0f;
313 if (confidenceOut < 0.0f) confidenceOut = 0.0f;
314 }
315
316 if (best_lag == 0) return 0.0f;
317 return (float)sample_rate / best_lag;
318 }
319};
320
321} // namespace audio_tools
#define LOGD(...)
Definition AudioLoggerIDF.h:27
#define LOGE(...)
Definition AudioLoggerIDF.h:30
#define DEFAULT_BUFFER_SIZE
Definition avr.h:20
Definition Arduino.h:56
virtual int availableForWrite()
Definition Arduino.h:128
virtual size_t write(const uint8_t *data, size_t len)
Definition Arduino.h:120
Definition Arduino.h:136
virtual size_t readBytes(uint8_t *data, size_t len)
Definition Arduino.h:140
virtual int available()
Definition Arduino.h:139
Base class for all Audio Streams. It support the boolean operator to test if the object is ready with...
Definition BaseStream.h:120
AudioInfo info
Definition BaseStream.h:171
virtual void setAudioInfo(AudioInfo newInfo) override
Defines the input AudioInfo.
Definition BaseStream.h:128
virtual bool begin()
Definition BaseStream.h:40
Detects frequency using autocorrelation on audio samples.
Definition FrequencyDetectorAutoCorrelation.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 FrequencyDetectorAutoCorrelation.h:146
void detect(T *samples, size_t len)
Detects frequency for all channels using autocorrelation.
Definition FrequencyDetectorAutoCorrelation.h:247
FrequencyDetectorAutoCorrelation(int bufferSize)
Construct with buffer size.
Definition FrequencyDetectorAutoCorrelation.h:34
Stream * p_in
Input stream pointer.
Definition FrequencyDetectorAutoCorrelation.h:235
float confidence(int channel)
Returns a tonality/periodicity confidence for the given channel, in the range 0.0 (no periodic struct...
Definition FrequencyDetectorAutoCorrelation.h:197
void setFrequencyCallback(void(*callback)(int channel, float freq))
Sets a callback function to be called when a new frequency is detected.
Definition FrequencyDetectorAutoCorrelation.h:227
size_t readBytes(uint8_t *data, size_t len) override
Reads bytes from the input stream and processes them for frequency detection.
Definition FrequencyDetectorAutoCorrelation.h:114
Vector< float > conf
Stores tonality confidence (0-1) for each channel.
Definition FrequencyDetectorAutoCorrelation.h:233
bool begin()
Initialize internal buffers based on audio info.
Definition FrequencyDetectorAutoCorrelation.h:80
int available() override
Returns the number of bytes available for reading.
Definition FrequencyDetectorAutoCorrelation.h:95
FrequencyDetectorAutoCorrelation(int bufferSize, Stream &in)
Construct with buffer size and input stream.
Definition FrequencyDetectorAutoCorrelation.h:53
void setBufferSize(int bufferSize)
Sets the analysis buffer size explicitly (in samples). If not called, begin() derives a size that cov...
Definition FrequencyDetectorAutoCorrelation.h:74
FrequencyDetectorAutoCorrelation(int bufferSize, Print &out)
Construct with buffer size and output stream.
Definition FrequencyDetectorAutoCorrelation.h:43
AudioInfo defaultConfig()
Returns a default AudioInfo configuration.
Definition FrequencyDetectorAutoCorrelation.h:218
int availableForWrite() override
Returns the number of bytes available for writing.
Definition FrequencyDetectorAutoCorrelation.h:103
bool isTonal(int channel, float threshold=0.3f)
Convenience check: is the given channel currently tonal (periodic) rather than noise-like,...
Definition FrequencyDetectorAutoCorrelation.h:211
Vector< float > freq
Stores detected frequency for each channel.
Definition FrequencyDetectorAutoCorrelation.h:232
Print * p_out
Output stream pointer.
Definition FrequencyDetectorAutoCorrelation.h:234
FrequencyDetectorAutoCorrelation()=default
Default constructor. The buffer size is auto-derived from the AudioInfo passed to begin() unless setB...
SingleBuffer< uint8_t > buffer
Buffer for incoming audio data.
Definition FrequencyDetectorAutoCorrelation.h:238
void(* freq_callback)(int channel, float freq)
Frequency callback function.
Definition FrequencyDetectorAutoCorrelation.h:236
float detectFrequencyForChannel(int ch, T *samples, size_t len, float &confidenceOut)
Performs autocorrelation to estimate frequency for a single channel.
Definition FrequencyDetectorAutoCorrelation.h:271
float frequency(int channel)
Returns the last detected frequency for the given channel.
Definition FrequencyDetectorAutoCorrelation.h:179
bool begin(AudioInfo info)
Initialize with audio configuration.
Definition FrequencyDetectorAutoCorrelation.h:64
int buffer_size
Buffer size in samples.
Definition FrequencyDetectorAutoCorrelation.h:237
A simple Buffer implementation which just uses a (dynamically sized) array.
Definition Buffers.h:194
bool write(T sample) override
write add an entry to the buffer
Definition Buffers.h:228
int available() override
provides the number of entries that are available to read
Definition Buffers.h:255
bool isFull() override
checks if the buffer is full
Definition Buffers.h:262
T * data()
Provides address of actual data.
Definition Buffers.h:306
bool resize(size_t size)
Resizes the buffer if supported: returns false if not supported.
Definition Buffers.h:327
void reset() override
clears the buffer
Definition Buffers.h:308
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
bool resize(size_t newSize, T value)
Definition Vector.h:266
24bit integer which is used for I2S sound processing. The values are represented as int32_t,...
Definition int24_4bytes_t.h:22
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
Basic Audio information which drives e.g. I2S.
Definition AudioTypes.h:56
sample_rate_t sample_rate
Sample Rate: e.g 44100.
Definition AudioTypes.h:58
uint16_t channels
Number of channels: 2=stereo, 1=mono.
Definition AudioTypes.h:60
uint8_t bits_per_sample
Number of bits per sample (int16_t = 16 bits)
Definition AudioTypes.h:62