feat(audio): choose a male or female local voice per language
The installer now fetches one male and one female Piper voice per language (Swedish NST/Lisa, English Ryan/Lessac), with genders confirmed by measuring each voice's pitch rather than guessed from the name. Settings -> Audio gets a voice selector per language with its own Test button that always plays the Piper voice. Male is preselected for both. The integration test now runs its server with an empty home directory, so voices installed on the developer's own machine can't leak into it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
11
ROADMAP.md
11
ROADMAP.md
@@ -156,6 +156,17 @@ Deferred 2026-09-09 at the user's request - requires a paid third-party neural T
|
||||
|
||||
Verified 2026-09-27: `tests/tts.test.js` (voice discovery/picking, project-installed Piper preferred over PATH, one generation at a time, caching, in-flight dedupe, speed -> length scale, clear errors, pre-generate counts) and `tests/piper_speech.test.js` (fallback on 503, on a 2.5 s timeout, successful playback with volume/onEnd, busy refusal, interrupt cancels without the cancelled line falling back and talking over the new one). An integration test runs a real server against a fake Piper binary: WAV served, second request cached, 400/503 on bad input/missing language, 401 once the admin PIN is on. `tests/browser_tts_settings.js`: panel shows sv/en status, the engine choice persists across a reload. A real end-to-end run with the actual installer output (downloaded Piper + both voices) in a real browser: "Test the voice" played Piper audio 0.4 s after the click with no browser-voice fallback, and pre-generation produced 60 lines with 0 failures. The Windows zip's layout (`piper/piper.exe`) was checked against what the server looks for, but the installer hasn't been run on an actual Windows machine yet.
|
||||
|
||||
### Follow-up 2026-09-27: male or female voice per language
|
||||
|
||||
Asked by the user right after confirming Piper works on both Linux and Windows: how to switch between a male and a female voice. Until then only one voice per language was installed and picked automatically.
|
||||
|
||||
- [x] Checked genders instead of assuming them from the voice names: generated the same sentence with each candidate and measured the median pitch (male ~85-155 Hz, female ~165-255 Hz). Swedish `nst` 81 Hz (male), `lisa` 184 Hz and `alma` 187 Hz (female); English `ryan` 152 Hz (male), `lessac` 208 Hz (female).
|
||||
- [x] The installer's voice catalog (`server/tts_install.js`) now has one male and one female voice per language, each with a gender and a label. Defaults chosen by the user: male on both (NST, Ryan).
|
||||
- [x] `pickVoice` uses the voice chosen in Settings if it's installed and speaks that language, otherwise the catalog default, then any medium voice. The choice travels as `voice` in `POST /api/tts/speech`; the cache is already keyed per voice, so switching never replays the other voice's lines.
|
||||
- [x] Settings -> Audio -> Voice engine: a voice selector per language ("NST (male)", "Lisa (female)", ...) with its own Test button that always plays the Piper voice, never the browser fallback, so picking and hearing a voice can't be confused. New settings `ttsVoiceSv` / `ttsVoiceEn`, added to all three settings allowlists (anything not listed there is silently dropped on load). Pre-generation uses the chosen voices.
|
||||
|
||||
Verified 2026-09-27: unit tests cover catalog gender labels, the chosen voice winning, a chosen voice from the wrong language or no longer installed falling back, and the same text in another voice being a separate cached line. The integration test now checks that the chosen voice reaches the Piper process through the real server - and while updating it, found the test depended on the developer's own machine (it picked up voices from `~/.local/share/piper-voices`), fixed by giving the test server its own empty home directory. A real browser run switched the Swedish voice from automatic to Lisa and measured the audio actually played: 80 Hz -> 182 Hz, and the choice was saved on the server.
|
||||
|
||||
## 6. Permissions and mobile Race Control
|
||||
|
||||
Deferred 2026-09-09 at the user's request - the largest remaining item, on par with or bigger than the full optimistic-locking rework already deferred under section 2. Today there is no login or authorization at all: anyone reaching the server on the network has full admin access. Building this needs an identity system that doesn't exist yet (no user accounts, no sessions), server-side authorization on every mutating endpoint (not just hiding UI controls), and a genuinely new "compact mobile Race Control" surface (start/stop, track call, flags, next heat) - plus a real decision on how login should work in practice on a shared trackside laptop (PIN codes per role? named accounts? offline/LAN-only requirement?) before any of it can be designed, let alone built. Revisit as its own dedicated design conversation.
|
||||
|
||||
Reference in New Issue
Block a user