// Streaming int8 phoneme engine - portable C (PC test build + ESP32-S3). // Consumes one 40 ms feature frame at a time (40 log-mel values at the // model's 20 ms output rate this is stride-2, so the caller feeds TWO // 10 ms-hop mel frames per step); emits one logits vector per step. // // Design contract = phoneme_engine/quantize.py fake_quant_forward(): // - weights int8 per-output-channel, BN folded // - int8 x int8 -> int32 accumulate, float requant (combined scale), // residual added in float, ReLU, snap to int8 grid of the next layer // - strictly causal: each layer keeps a ring buffer of its int8 input // history, so per-step cost is one new column per layer #pragma once #include #ifdef __cplusplus extern "C" { #endif #define PWW_MELS 40 typedef struct pww_engine pww_engine_t; // Allocates all layer state (ring buffers) on the heap. Returns NULL on // allocation failure. pww_engine_t *pww_engine_create(void); void pww_engine_destroy(pww_engine_t *e); void pww_engine_reset(pww_engine_t *e); // Feed TWO consecutive 10 ms-hop mel frames (each PWW_MELS floats, already // EMA-normalized like features.py). Writes PWW_NUM_CLASSES float logits // (log-prob differences are what the decoder consumes; absolute offset is // meaningless). Returns 0 on success. int pww_engine_step(pww_engine_t *e, const float *mel0, const float *mel1, float *logits_out); #ifdef __cplusplus } #endif