arduino-audio-tools
Loading...
Searching...
No Matches
WakeWordDetector.h
Go to the documentation of this file.
1#pragma once
2
3#include <algorithm>
4#include <cmath>
5
10
11namespace audio_tools {
12
13/*
14 * @brief Frame holding the top N dominant frequencies (in Hz) of an FFT window.
15 *
16 * Used as a compact representation of the dominant frequency content in a frame
17 * of audio.
18 */
19template <size_t N>
21 uint16_t top_freqs[N];
22};
23
88template <typename T = int16_t, size_t N = 3>
90 public:
91 struct Template {
96 const char* name;
98 0.0f;
99 };
100
101 using WakeWordCallback = void (*)(const char* name);
102
104 : p_fft(&fft) {
105 _frame_pos = 0;
106 }
107
109 _recent_frames.clear();
110 _is_recording = true;
111 }
112
117
118 bool isRecording() const { return _is_recording; }
119
120 // Note: takes a non-const reference because AudioTools' Vector::size() is
121 // not const-qualified.
123 float threshold_percent, const char* name) {
124 Template t;
125 t.frames = frames;
126 t.threshold_percent = threshold_percent;
127 t.name = name;
128 t.last_match_percent = 0.0f;
129 _templates.push_back(t);
130 if (frames.size() > _max_template_len) _max_template_len = frames.size();
131 }
132
134
135 size_t write(const uint8_t* buf, size_t size) override {
136 // Reasserted on every write (instead of only in the constructor) because
137 // AudioFFTBase::begin(AudioFFTConfig) replaces the whole config object
138 // (cfg = info), which would silently wipe out ref/callback if they had
139 // only been set once, before the user's fft.begin(cfg) call.
140 auto& fft_cfg = p_fft->config();
141 if (fft_cfg.ref != this || fft_cfg.callback != fftResult) {
142 fft_cfg.ref = this;
143 fft_cfg.callback = fftResult;
144 }
145 return p_fft->write(buf, size);
146 }
147
148 static void fftResult(AudioFFTBase& fft) {
149 // This static method must access instance data via fft.config().ref
150 auto* self = static_cast<WakeWordDetector<T,N>*>(fft.config().ref);
151 if (!self) return;
152 FrequencyFrame<N> frame;
153 AudioFFTResult result[N];
154 fft.resultArray(result);
155 for (size_t j = 0; j < N; j++) {
156 frame.top_freqs[j] = result[j].frequency;
157 }
158 self->_recent_frames.push_back(frame);
159
160 if (self->_is_recording) {
161 return;
162 }
163
164 if (self->_recent_frames.size() > self->_max_template_len)
165 self->_recent_frames.erase(self->_recent_frames.begin());
166 for (size_t i = 0; i < self->_templates.size(); ++i) {
167 Template& tmpl = self->_templates[i];
168 if (self->_recent_frames.size() >= tmpl.frames.size()) {
169 float percent = self->matchTemplate(tmpl);
170 if (percent >= tmpl.threshold_percent) {
171 if (self->_callback) self->_callback(tmpl.name);
172 }
173 }
174 }
175 }
176
177 protected:
181 AudioFFTBase* p_fft = nullptr;
182 bool _is_recording = false;
183 size_t _frame_pos;
184 size_t _max_template_len = 0;
186
187 float matchTemplate(Template& tmpl) {
188 size_t matches = 0;
189 size_t offset = _recent_frames.size() - tmpl.frames.size();
190 for (size_t i = 0; i < tmpl.frames.size(); ++i) {
191 size_t frame_matches = 0;
192 for (size_t j = 0; j < N; ++j) {
193 if (tmpl.frames[i].top_freqs[j] ==
194 _recent_frames[offset + i].top_freqs[j])
195 frame_matches++;
196 }
197 if (frame_matches >= (N >= 2 ? N - 1 : 1)) // at least N-1 out of N match
198 matches++;
199 }
200 float percent = (tmpl.frames.size() > 0)
201 ? (100.0f * matches / tmpl.frames.size())
202 : 0.0f;
203 tmpl.last_match_percent = percent;
204 return percent;
205 }
206};
207
208} // namespace audio_tools
Executes FFT using audio data privded by write() and/or an inverse FFT where the samples are made ava...
Definition AudioFFT.h:200
AudioFFTConfig & config()
Provides the actual configuration.
Definition AudioFFT.h:648
size_t write(const uint8_t *data, size_t len) override
Provide the audio data as FFT input.
Definition AudioFFT.h:303
void resultArray(AudioFFTResult(&result)[N])
Determines the N biggest result values.
Definition AudioFFT.h:388
Abstract Audio Ouptut class.
Definition AudioOutput.h:25
Vector implementation which provides the most important methods as defined by std::vector....
Definition Vector.h:21
Template-based wake word detector for microcontrollers using dominant frequency patterns.
Definition WakeWordDetector.h:89
static void fftResult(AudioFFTBase &fft)
Definition WakeWordDetector.h:148
void(*)(const char *name) WakeWordCallback
Definition WakeWordDetector.h:101
Vector< FrequencyFrame< N > > stopRecording()
Definition WakeWordDetector.h:113
bool isRecording() const
Definition WakeWordDetector.h:118
bool _is_recording
True if currently recording a template.
Definition WakeWordDetector.h:182
size_t _max_template_len
Length of the longest template.
Definition WakeWordDetector.h:184
size_t _frame_pos
Current position in frame buffer.
Definition WakeWordDetector.h:183
AudioFFTBase * p_fft
Definition WakeWordDetector.h:181
Vector< Template > _templates
List of wake word templates.
Definition WakeWordDetector.h:178
float matchTemplate(Template &tmpl)
Definition WakeWordDetector.h:187
void setWakeWordCallback(WakeWordCallback cb)
Definition WakeWordDetector.h:133
void startRecording()
Definition WakeWordDetector.h:108
Vector< FrequencyFrame< N > > _recent_frames
Recent frames for comparison.
Definition WakeWordDetector.h:179
WakeWordCallback _callback
Definition WakeWordDetector.h:185
WakeWordDetector(AudioFFTBase &fft)
Definition WakeWordDetector.h:103
Vector< T > _buffer
Buffer for incoming PCM samples.
Definition WakeWordDetector.h:180
void addTemplate(Vector< FrequencyFrame< N > > &frames, float threshold_percent, const char *name)
Definition WakeWordDetector.h:122
size_t write(const uint8_t *buf, size_t size) override
Definition WakeWordDetector.h:135
Generic Implementation of sound input and output for desktop environments using portaudio.
Definition LMSEchoCancellationStream.h:6
void * ref
caller
Definition AudioFFT.h:66
Result of the FFT.
Definition AudioFFT.h:23
float frequency
Definition AudioFFT.h:26
Definition WakeWordDetector.h:20
uint16_t top_freqs[N]
Top N dominant frequencies of the frame, in Hz.
Definition WakeWordDetector.h:21
Definition WakeWordDetector.h:91
const char * name
Name/label of the wake word.
Definition WakeWordDetector.h:96
Vector< FrequencyFrame< N > > frames
Sequence of frequency frames for the wake word.
Definition WakeWordDetector.h:93
float last_match_percent
Last computed match percent for this template.
Definition WakeWordDetector.h:97
float threshold_percent
Definition WakeWordDetector.h:94