Voice performance and deployment
Accessor now exposes repeatable local STT and TTS benchmarks. Results are file and software timings, not promises for a particular room, microphone, network or CPU. The development machine reports an Intel i7-1260P; the intended 2012 dual-core i7 must be measured separately. Limiting modern hardware to two threads does not emulate the older CPU, memory bandwidth, instructions or thermal limits. An SSD helps loading models, not their steady-state computation.
Changes
- Piper is now the default spoken voice on new profiles: a pinned local
neural engine with a persistent worker, one WAV per completed chunk, no key
and no network. System, Kokoro, and Cartesia remain selectable.
acc tts benchmark --provider pipermeasures it on your machine. - End-of-speech silence is configurable from 300–2000 ms, default 600 ms, previously 1000 ms. This removes 400 ms of intentional waiting for continuous speech; set it back to 1000–1200 ms if thoughtful pauses split sentences. The playback capture hold follows the selected cutoff instead of a fixed 1200 ms.
- Local inference defaults to two CPU threads, spinning off. Thread count (1–8) and spinning are configurable and require restart. Spinning can shave latency while wasting idle CPU/battery; benchmark before enabling it.
- Cartesia TTS plays incoming raw PCM from its HTTP streaming endpoint by default.
It no longer has to receive a whole sentence’s audio before starting playback.
The queue is bounded, has a 120 ms prebuffer, pauses without dropping samples
during user capture, and feeds actual speaker samples to echo cancellation.
Network starvation produces silence and rebuffering; incomplete audio errors
are surfaced without automatically repeating already-spoken output. Set
tts.streaming falsefor the previous completed-WAV, prefetched-sentence path. Streaming sentence requests are currently sequential, so longer replies can have gaps between chunks; the buffered option retains next-sentence prefetch. - Cancellation owns and stops in-flight synthesis/prefetch jobs. Spoken-audio caching stays in memory and is invalidated by locking.
The full model still decodes wake speech locally. Cartesia after-wake streaming
overlaps upload with capture, but the current STT path also runs local recognition
for controls and fallback. It does not eliminate local compute. Relevance
filtering and the selected agent add further latency. /analytics separates the
measured stages; /audio reports wake decoder timing and capture diagnostics.
Repeat on the Dell
Generate a non-private speech sample once, or copy the synthetic WAV used here:
acc tts test "Twenty nine. What is on my calendar tomorrow morning?" --provider cartesia --output sample.wav
acc stt benchmark sample.wav --runs 7 --engine canary
python scripts/benchmark_voice.py sample.wav --assets PATH_TO_ACCESSOR_ASSETS --output results/voice.json --runs 7
acc tts benchmark --provider piper --runs 4
acc tts benchmark --provider system --runs 4
acc tts benchmark --provider kokoro --runs 4
acc tts benchmark --provider cartesia --runs 4
acc tts benchmark --provider cartesia --runs 3 --playback
Only the Cartesia commands use the service/key and incur provider usage. The file
benchmarks don’t open the microphone or contact an agent. --playback explicitly
plays test audio; its playback-start flag is software timing, not a microphone
measurement of audible onset. The STT comparison script isolates its settings,
leaves the user’s configuration unchanged, and compares one/two/four threads plus
spinning using clean, quiet, 10 dB synthetic noise and delayed-echo variants. Run
benchmarks serially with other heavy work stopped. Reports include load, first
decode, seven warm runs, median, nearest-rank P95, RTF, and exact recognized text.
An RTF below 1 means computation faster than clip duration; it says nothing by
itself about wake false positives or far-field accuracy.
The checked-in synthetic WAV can be used without a Cartesia account. Raw results and fixture metadata are in benchmarks/2026-09-21. The default Piper voice was measured separately on a 2012 dual-core i7-3520M (warm median 418.9 ms, RTF 0.14 for a 2.9-second reply); see benchmarks/2026-09-27. That is a machine of the intended class but not the exact Dell, so re-run there before relying on it.
Suggested starting setups
| Setup | Local recognition | After-wake STT | TTS | Tradeoff |
|---|---|---|---|---|
| Default local (new profiles) | Canary warm, 2 threads, no spin | Local | Piper | No key, no network; fast local synthesis on any supported desktop CPU |
| Responsive cloud-assisted | Canary warm, 2 threads, no spin | Cartesia streaming | Cartesia streaming | Lowest cloud result wait; awake speech uploads before relevance is known |
| Conservative cloud upload | Canary warm, 2 threads, no spin | Cartesia finished clip | Cartesia streaming | Local word check before upload, additional transcription round trip |
| Entirely local voice | Canary warm, 1–2 threads | Local | System | Smallest footprint; OS voice quality varies |
| Local neural voice | Canary | Local | Kokoro warm | Better neural voice; competing CPU load, particularly on the old Dell |
For the Dell, start with Piper (neutral, fast) or System TTS and Canary kept warm; use Cartesia streaming when network latency is acceptable and a key is available. Kokoro’s cold start and CPU demand can dominate response time. The current Whisper adapter spawns whisper-cli and reloads the model per utterance; a tiny model does not automatically mean a faster always-on experience. Lazy STT frees RAM when asleep but introduces wake-time loading. Parakeet’s larger model needs measurements before choosing it for a dual-core machine. None of these settings requires an OpenAI API key; agent login remains the harness’s own responsibility.
acc config set tts.provider piper
acc config set tts.piper-voice en_GB-alan-medium
acc config set stt.endpoint-ms 600
acc config set stt.threads 2
acc config set stt.spin false
acc config set stt.lazy false
acc config set tts.streaming true
Dedicated wake spotting
The research script scripts/benchmark_keywords.py tests the official sherpa-onnx
3M Chinese/English keyword model with “twenty nine,” two chunk sizes and one/two
threads. It is an experiment, not wired into production. The model accepts new
keywords through a pronunciation list, avoiding a newly trained classifier for
every numeric code. Official documentation lists a 4.4 MiB quantized encoder and
160/320 ms model chunk latency. Model and customization documentation.
On Linux, install the isolated experiment and its checksum-pinned model, then try the live microphone detector:
python3 scripts/setup_wakeword.py
python3 scripts/test_wakeword.py
Use --seconds 30 for a bounded microphone run, --device NAME to select a
PipeWire input, or --wav tests/fixtures/voice-benchmark.wav for a repeatable
file check. A successful detection prints DETECTED twenty_nine. Exit status 2
means the test completed without a detection. This tool does not change saved
settings or replace Accessor’s production Canary wake path.
To test the production local STT path across a real room, run:
python3 scripts/test_room_wake.py
The guided test records three trials at 1, 3 and 5 metres in quiet and ordinary
background noise, transcribes every clip locally in one model process, prints
wake recall, and deletes the WAV files afterward. The JSON report retains the
recognized text. Use --keep-audio DIR only when you deliberately want to keep
the room recordings. If PipeWire exposes an RNNoise or other noise-suppressed
virtual source, compare it with the physical/default source in the same run:
python3 scripts/test_room_wake.py --device RAW_NODE --denoised-device FILTERED_NODE
The built-in stt.denoise=highpass experiment removes sub-speech rumble on the
recognizer thread. Compare the same recorded wake clip with
acc stt wake room.wav --noise-gate off --denoise off and
acc stt wake room.wav --noise-gate off --denoise highpass. This filters wake
probes after capture; it does not alter VAD timing or Cartesia’s live streaming
upload. Keep it off if quiet or distant wake words become less reliable.
List candidate source names with acc devices or wpctl status. This is a
positive recall test of full-clip recognition, not the rolling wake-window
timing or an estimate of false activations per hour.
openWakeWord is another credible candidate: it supports ONNX on Windows and custom wake models, but “twenty nine” needs a trained and validated model. Review model licensing separately from its Apache-licensed code before distribution. Project documentation.
Neither candidate makes “29” an identity or password. A short common number can occur on TV or in ordinary conversation. Offer “hey twenty-nine” as a more distinct activation option and test similar numbers, accents and recordings of the assistant itself. The current password lock remains independent of wake technology.
Product work worth prioritizing next
- Microphone calibration and a room acceptance suite. Test 1/3/5 metres, facing/sideways/away, fan/TV/music, different voices, and TTS/alarm playback. Measure wake recall, false accepts per hour, interruptions, password success and median/P95 response. Synthetic noise tests cannot substitute for this. Consider a microphone near the user or a tested microphone array only after comparing the built-in mic; gain alone also amplifies noise.
- A separately validated small wake engine. Keep full STT asleep until a confirmed keyword; preserve local password/quick-command recognition. Require an hours-long negative corpus, near-number confusions, and room tests before making it default. Avoid advertising noisy-room reliability from one WAV.
- Visible privacy state and recovery. Make locked/local-listening/cloud-active states obvious; retain hardware mic-off as the reliable capture switch. Add microphone unplug/reconnect recovery and a guided setup/level check.
- Sensitive-action policy. Voice passwords are replayable. A separate typed confirmation for sending/deleting mail, purchases and account changes is more useful than pretending wake codes identify household members.
- Packaging and soak tests. Signed installer/update rollback, suspend/resume, network-loss recovery, overnight CPU/RAM/power and bounded logging checks. Keep one user profile for now; accounts, permissions, voice identity and shared speakers need a deliberate design before mapping “29” and “30” to people.
Cartesia protocol references: streaming TTS bytes, manual streaming STT.