@@ -77,7 +77,7 @@ class GoertzelDetector {
77
77
this ->config = config;
78
78
this ->sample_count = 0 ;
79
79
80
- if (config.target_frequency == 0 .0f ){
80
+ if (config.target_frequency == 0 .0f ) {
81
81
return false ;
82
82
}
83
83
@@ -110,9 +110,9 @@ class GoertzelDetector {
110
110
config.sample_rate );
111
111
float imag =
112
112
s2 * sin (2 .0f * M_PI * config.target_frequency / config.sample_rate );
113
- magnitude_squared = real * real + imag * imag;
113
+ magnitude_squared = ( real * real) + ( imag * imag) ;
114
114
magnitude = sqrt (magnitude_squared);
115
-
115
+
116
116
// Reset for next block
117
117
reset ();
118
118
return true ;
@@ -146,15 +146,14 @@ class GoertzelDetector {
146
146
* @return True if magnitude is above configured threshold
147
147
*/
148
148
bool isDetected () const { return isDetected (config.threshold ); }
149
-
149
+
150
150
/* *
151
151
* @brief Reset the detector state
152
152
*/
153
153
void reset () {
154
154
s1 = 0 .0f ;
155
155
s2 = 0 .0f ;
156
156
sample_count = 0 ;
157
- magnitude = 0 .0f ;
158
157
magnitude_squared = 0 .0f ;
159
158
}
160
159
@@ -173,14 +172,14 @@ class GoertzelDetector {
173
172
*/
174
173
const GoertzelConfig& getConfig () const { return config; }
175
174
176
- void setReference (void * ref){ this ->reference = ref; }
175
+ void setReference (void * ref) { this ->reference = ref; }
177
176
178
- void * getReference (){ return reference; }
177
+ void * getReference () { return reference; }
179
178
180
179
protected:
181
180
GoertzelConfig config;
182
181
float coeff = 0 .0f ;
183
- void * reference = nullptr ;
182
+ void * reference = nullptr ;
184
183
185
184
// State variables
186
185
float s1 = 0 .0f ;
@@ -193,10 +192,13 @@ class GoertzelDetector {
193
192
};
194
193
195
194
/* *
196
- * @brief AudioStream-based multi-frequency Goertzel detector for real-time audio analysis.
195
+ * @brief AudioStream-based multi-frequency Goertzel detector for real-time
196
+ * audio analysis.
197
197
*
198
- * GoertzelStream enables efficient detection of one or more target frequencies in a continuous audio stream.
199
- * It acts as a transparent filter: audio data flows through unchanged, while the class analyzes the signal for specified tones.
198
+ * GoertzelStream enables efficient detection of one or more target frequencies
199
+ * in a continuous audio stream. It acts as a transparent filter: audio data
200
+ * flows through unchanged, while the class analyzes the signal for specified
201
+ * tones.
200
202
*
201
203
* Key Features:
202
204
* - Detects multiple frequencies simultaneously (DTMF, tone detection, etc.)
@@ -208,10 +210,12 @@ class GoertzelDetector {
208
210
* - Configurable detection parameters (block size, threshold, volume, etc.)
209
211
*
210
212
* Usage:
211
- * 1. Configure the stream with GoertzelConfig or AudioInfo (sample rate, channels, etc.)
213
+ * 1. Configure the stream with GoertzelConfig or AudioInfo (sample rate,
214
+ * channels, etc.)
212
215
* 2. Add one or more target frequencies using addFrequency()
213
216
* 3. Optionally set a detection callback with setFrequencyDetectionCallback()
214
- * 4. Use write() or readBytes() to process audio data; detection runs automatically
217
+ * 4. Use write() or readBytes() to process audio data; detection runs
218
+ * automatically
215
219
*
216
220
* Supported sample formats:
217
221
* - 8-bit: unsigned (0-255), internally converted to signed (-128 to 127)
@@ -226,7 +230,12 @@ class GoertzelDetector {
226
230
*/
227
231
class GoertzelStream : public AudioStream {
228
232
public:
233
+ // Default Constructor with no output or input
229
234
GoertzelStream () = default ;
235
+ GoertzelStream (Print& out) { setOutput (out); }
236
+ GoertzelStream (AudioOutput& out) { setOutput (out); }
237
+ GoertzelStream (Stream& io) { setStream (io); };
238
+ GoertzelStream (AudioStream& io) { setStream (io); };
230
239
231
240
/* *
232
241
* @brief Set audio format and initialize detector array
@@ -245,6 +254,20 @@ class GoertzelStream : public AudioStream {
245
254
begin ();
246
255
}
247
256
257
+ /* *
258
+ * @brief Returns a default GoertzelConfig instance with standard parameters
259
+ *
260
+ * This utility method provides a convenient way to obtain a default
261
+ * configuration for the Goertzel algorithm. The returned config can be
262
+ * customized before use.
263
+ *
264
+ * @return GoertzelConfig with default values
265
+ */
266
+ GoertzelConfig defaultConfig () {
267
+ GoertzelConfig result;
268
+ return result;
269
+ }
270
+
248
271
/* *
249
272
* @brief Initialize with GoertzelConfig
250
273
*
@@ -284,11 +307,12 @@ class GoertzelStream : public AudioStream {
284
307
GoertzelConfig cfg = default_config;
285
308
cfg.target_frequency = freq;
286
309
GoertzelDetector detector;
287
- if (i++ < references.size ()){
310
+ if (i < references.size ()) {
288
311
detector.setReference (references[i]);
289
312
}
290
313
detector.begin (cfg);
291
314
detectors.push_back (detector);
315
+ i++;
292
316
}
293
317
sample_no = 0 ;
294
318
return true ;
@@ -308,9 +332,21 @@ class GoertzelStream : public AudioStream {
308
332
p_print = ∈
309
333
}
310
334
335
+ // / Defines/Changes the input & output
336
+ void setStream (AudioStream& io) {
337
+ setStream ((Stream&)io);
338
+ addNotifyAudioChange (io);
339
+ }
340
+
311
341
// / Defines/Changes the output target
312
342
void setOutput (Print& out) { p_print = &out; }
313
343
344
+ // / Defines/Changes the output target
345
+ void setOutput (AudioOutput& out) {
346
+ setOutput ((Print&)out);
347
+ addNotifyAudioChange (out);
348
+ }
349
+
314
350
/* *
315
351
* @brief Set detection callback function for channel-aware frequency
316
352
* detection
@@ -322,8 +358,9 @@ class GoertzelStream : public AudioStream {
322
358
* @param callback Function to call when frequency is detected, includes
323
359
* channel info
324
360
*/
325
- void setFrequencyDetectionCallback (void (*callback)(
326
- int channel, float frequency, float magnitude, void * ref)) {
361
+ void setFrequencyDetectionCallback (void (*callback)(float frequency,
362
+ float magnitude,
363
+ void * ref)) {
327
364
frequency_detection_callback = callback;
328
365
}
329
366
@@ -340,8 +377,6 @@ class GoertzelStream : public AudioStream {
340
377
* @return Number of bytes written to output stream
341
378
*/
342
379
size_t write (const uint8_t * data, size_t len) override {
343
- if (p_print == nullptr ) return 0 ;
344
-
345
380
// Process samples for detection
346
381
processSamples (data, len);
347
382
@@ -408,40 +443,43 @@ class GoertzelStream : public AudioStream {
408
443
GoertzelDetector& getDetector (int no) { return detectors[no]; }
409
444
410
445
/* *
411
- * @brief Add a frequency to the detection list
446
+ * @brief Add a frequency to the detection list
412
447
*
413
448
* @param freq Frequency in Hz to add to the detection list
414
449
*/
415
450
void addFrequency (float freq) { frequencies.push_back (freq); }
416
451
417
452
/* *
418
- * @brief Add a frequency to the detection list with a custom reference pointer
453
+ * @brief Add a frequency to the detection list with a custom reference
454
+ * pointer
419
455
*
420
- * This method allows you to associate a user-defined reference (context pointer)
421
- * with a specific frequency. The reference will be passed to the detection callback
422
- * when this frequency is detected, enabling per-frequency context handling.
456
+ * This method allows you to associate a user-defined reference (context
457
+ * pointer) with a specific frequency. The reference will be passed to the
458
+ * detection callback when this frequency is detected, enabling per-frequency
459
+ * context handling.
423
460
*
424
461
* @param freq Frequency in Hz to add to the detection list
425
462
* @param ref Pointer to user-defined context object for this frequency
426
463
*/
427
- void addFrequency (float freq, void * ref) {
428
- frequencies.push_back (freq);
464
+ void addFrequency (float freq, void * ref) {
465
+ frequencies.push_back (freq);
429
466
references.push_back (ref);
430
467
}
431
468
432
469
protected:
433
470
// Core detection components
434
- Vector<GoertzelDetector> detectors; // /< One detector per frequency in frequencies
471
+ Vector<GoertzelDetector>
472
+ detectors; // /< One detector per frequency in frequencies
435
473
Vector<float > frequencies; // /< List of frequencies to detect
436
- Vector<void *> references; // /< List of frequencies to detect
474
+ Vector<void *> references; // /< List of frequencies to detect
437
475
GoertzelConfig default_config; // /< Current algorithm configuration
438
476
// Stream I/O components
439
477
Stream* p_stream = nullptr ; // /< Input stream for reading audio data
440
478
Print* p_print = nullptr ; // /< Output stream for writing audio data
441
479
442
480
// Callback system
443
- void (*frequency_detection_callback)(int channel , float frequency ,
444
- float magnitude, void * ref) =
481
+ void (*frequency_detection_callback)(float frequency , float magnitude ,
482
+ void * ref) =
445
483
nullptr ; // /< User callback for detection events
446
484
void * ref = this ; // /< User-defined reference for callback context
447
485
@@ -452,13 +490,15 @@ class GoertzelStream : public AudioStream {
452
490
*/
453
491
void checkDetection (GoertzelDetector& detector) {
454
492
float magnitude = detector.getMagnitude ();
493
+ if (magnitude > 0 .0f )
494
+ LOGD (" frequency: %f / magnitude: %f / threshold: %f" , detector.getTargetFrequency (), magnitude, default_config.threshold );
495
+
455
496
if (magnitude > default_config.threshold ) {
456
497
float frequency = detector.getTargetFrequency ();
457
- void * reference = detector.getReference ();
458
- if (reference== nullptr ) reference = ref;
498
+ void * reference = detector.getReference ();
499
+ if (reference == nullptr ) reference = ref;
459
500
if (frequency_detection_callback != nullptr ) {
460
- frequency_detection_callback (default_config.channel , frequency,
461
- magnitude, reference);
501
+ frequency_detection_callback (frequency, magnitude, reference);
462
502
}
463
503
}
464
504
}
@@ -487,8 +527,9 @@ class GoertzelStream : public AudioStream {
487
527
if (sample_no % channels == default_config.channel ) {
488
528
float normalized = clip (NumberConverter::toFloatT<T>(samples[i]) *
489
529
default_config.volume );
530
+ LOGD (" sample: %f" , normalized);
490
531
// process all frequencies
491
- for (auto & detector : detectors) {
532
+ for (auto & detector : detectors) {
492
533
if (detector.processSample (normalized)) {
493
534
checkDetection (detector);
494
535
}
0 commit comments