a99932b427
silero-vad replaces the energy threshold when -vad-model points at it. Everything after the speech decision is the same state machine: the speech hold, the silence hold, the length cap and the utterance buffer. The model window is 512 samples and the capture frame is 480, so silero.go re-chunks across frames. main.go claimed the two matched, which was true of silero v4. Stage two, the wake word, is not here. It needs a Russian keyword model that does not exist yet.
64 lines
2.8 KiB
Markdown
64 lines
2.8 KiB
Markdown
# silero-vad against the energy threshold in mavwaked
|
|
|
|
*Measured 2026-08-09 on homesrv. V-487, stage one of two.*
|
|
|
|
mavwaked decided an utterance had started by comparing frame energy to an
|
|
adaptive floor. That answers "is this frame loud". A fan, a door and a
|
|
television are all loud, and every utterance mavwaked accepts becomes a turn.
|
|
|
|
silero-vad answers "is this frame speech". It is 2.3MB of ONNX and it replaces
|
|
the comparison and nothing else. The speech hold, the silence hold, the length
|
|
cap and the utterance buffer are the same state machine either way.
|
|
|
|
## What it declines
|
|
|
|
Speech is the four piper fixtures `mavsttd` already scores against, so nothing
|
|
of the owner's voice is committed. Non-speech is white noise at the same RMS as the clip beside it. That is the
|
|
cheapest thing that fools an energy floor.
|
|
|
|
| clip | silero, speech frames on speech | silero on noise | energy on noise |
|
|
|---|---|---|---|
|
|
| ru_fact.wav | 59 | 0 | 68 |
|
|
| ru_query.wav | 69 | 0 | 79 |
|
|
| ru_reminder.wav | 80 | 0 | 89 |
|
|
| en_act.wav | 90 | 0 | 99 |
|
|
|
|
The energy threshold accepts every noise clip as a complete utterance. Silero
|
|
calls not one frame of any of them speech, and still hears all four spoken
|
|
clips. `TestSileroHearsSpeechAndDeclinesNoise` is that table.
|
|
|
|
White noise is a floor, not a proof. It says nothing about a television, which
|
|
is speech, or about a fan, which is narrowband. Those need room recordings and
|
|
this box has none.
|
|
|
|
## What it costs
|
|
|
|
`BenchmarkSileroFrame` on the homesrv laptop (Ryzen 5 5600U), one 30ms frame
|
|
through the model including the re-chunking:
|
|
|
|
509µs per frame
|
|
|
|
That is 1.7% of one core, on the slower of the two machines. The detector runs
|
|
on the workstation beside the microphone, never on the GPU. This number is what
|
|
says it does not need one.
|
|
|
|
## The window is 512 samples, not 480
|
|
|
|
`cmd/mavwaked/main.go` claimed the frame contract matched silero's input
|
|
exactly. That was true of silero v4. Version 5 takes exactly 512 samples at 16kHz, plus 64 samples of context from
|
|
the previous window. So `sileroVAD` buffers across capture frames, and a frame
|
|
completing no window inherits the previous probability. `TestSileroRechunksAcrossFrames` pins it.
|
|
|
|
## Still an energy gate by default
|
|
|
|
`-vad-model` is empty in the code default, so a deployment that does not pass
|
|
it runs exactly what shipped before. Barge-in is untouched and deliberately so. It reads frame energy while she is
|
|
speaking, which is a different question from whether the frame is speech.
|
|
|
|
## Not done here
|
|
|
|
The wake word. This is stage one of the two V-487 asks for. The second needs a
|
|
keyword model that does not exist yet. The pretrained openWakeWord keywords are
|
|
English, and a Russian one has to be trained. Until then anything spoken near
|
|
the microphone still becomes a turn. It is now merely required to be speech.
|