Phoneme wake word engine: student+teacher models, INT8 export, C engine, enrollment tooling
f6aec75 verified | // Keyword-filler Viterbi spotter over streaming logits - C port of | |
| // phoneme_engine/decoder.py (KeywordSpotter). Same states, gates and | |
| // scoring; consumes raw logits (only within-frame differences matter). | |
| extern "C" { | |
| typedef struct { | |
| int n_phones; | |
| int n_states; | |
| uint8_t labels[PWW_DEC_MAX_STATES]; // class id per state | |
| uint8_t n_allowed[PWW_DEC_MAX_STATES]; | |
| uint8_t allowed[PWW_DEC_MAX_STATES][PWW_DEC_MAX_ALLOWED]; | |
| int8_t preds[PWW_DEC_MAX_STATES][2]; // predecessor ids, -1 unused | |
| uint8_t entry[PWW_DEC_MAX_STATES]; | |
| int min_dur, max_dur; | |
| float threshold; | |
| float strong_margin; // 1.5 | |
| float strong_ratio; // 0.5 | |
| int refractory; // frames | |
| // runtime state | |
| float rel[PWW_DEC_MAX_STATES]; | |
| int32_t start[PWW_DEC_MAX_STATES]; | |
| int32_t pframes[PWW_DEC_MAX_STATES]; | |
| int32_t strong[PWW_DEC_MAX_STATES]; | |
| int cooldown; | |
| int32_t t; | |
| float best_seen; // best gate-passing score since last clear (diag) | |
| } pww_spotter_t; | |
| // phone_ids: sequence of class ids (1..39, from PWW_PHONES order +1). | |
| // Returns 0 on success, -1 if too long/short. | |
| int pww_spotter_init(pww_spotter_t *sp, const uint8_t *phone_ids, | |
| int n_phones, float threshold); | |
| void pww_spotter_reset(pww_spotter_t *sp); | |
| // One frame of logits (PWW_NUM_CLASSES floats). Returns 1 and fills | |
| // score/dur when the keyword fires, else 0. | |
| int pww_spotter_step(pww_spotter_t *sp, const float *logits, | |
| float *score_out, int *dur_out); | |
| } | |