From 61983d4b8da4c54ae3b8dcd37c7f9435161a7d1a Mon Sep 17 00:00:00 2001 From: Fisto Date: Tue, 22 Sep 2026 20:00:13 +0200 Subject: [PATCH] Revert the VOX preset to the NetTTS approximation --- CURRENT.md | 7 ++++ microslopsam/README.md | 8 ++-- microslopsam/docs/NOTES.md | 12 ++---- microslopsam/docs/TTS-DESIGN.md | 59 ++++++------------------------ microslopsam/setup/test-wrapper.sh | 8 ++-- microslopsam/setup/veskslop-tts.sh | 16 ++++---- 6 files changed, 36 insertions(+), 74 deletions(-) diff --git a/CURRENT.md b/CURRENT.md index c701565..1507f3a 100644 --- a/CURRENT.md +++ b/CURRENT.md @@ -40,6 +40,13 @@ mobile draft at 390px. - [x] C11 preview caching: Discord-hosted image/GIF previews (WebP 320px, hash-addressed, 5 MiB cap, one attempt) run after every walk in both modes. Live run `...-20260916090722`: `previewed: 2`; thumbs served over `/api/media///thumb` (200). + - [x] C84 Revert the VOX preset to the NetTTS approximation. The tuned values matched the + reference metrics but sounded far off the game voice, so SAM commit `c6b5fb7` restores pitch 3, + rate 17, prominences 22, head size 52, lowering 40, volume 70 and reverts the tests, metadata + and docs; `tools/vox_compare.py` stays for future experiments. Merged on Veskslop and + `poc/.env`'s `VESKSLOP_TTS_VOICES` regenerated (back to `pitch:3:rate:17:…`). The stored + profile stayed cleared, so the auto path now renders the reverted tuning — verified + byte-identical to an explicit old-profile render. Wrapper tests pass. - [x] C83 Merge the SAM updates. `~/Projects/Sam/MicroslopSam` moved ahead (VOX preset tuned against the game word assets, `tools/vox_compare.py`, docs, wrapper/test sync). The updates matched our tree except the local `microslopsam.env` paths, so the merge is: the retuned VOX diff --git a/microslopsam/README.md b/microslopsam/README.md index 3389bc1..4affa83 100644 --- a/microslopsam/README.md +++ b/microslopsam/README.md @@ -93,11 +93,9 @@ A short low-level leading hum (80 ms, 75 Hz, -48 dBFS) primes Discord's audio pi so the first word is not gated; tune with `VESKSLOP_TTS_HUM_MS` (0 = off), `VESKSLOP_TTS_HUM_HZ`, and `VESKSLOP_TTS_HUM_DB`. -**Half-Life presets** (Keith Bell): `VESKSLOP_TTS_PRESET=vox` applies the Valve VOX -profile (pitch 0, rate 15, head size 34, lowering 50) and enables VOX prosody; -`VESKSLOP_TTS_PRESET=hev` is a starting point for the HEV suit voice. The `vox` and `hev` -voice IDs select these directly. The VOX values were -tuned against the game's word assets with `tools/vox_compare.py`; details in +**Half-Life presets** (Keith Bell): `VESKSLOP_TTS_PRESET=vox` applies the approximated +Valve VOX profile and enables VOX prosody; `VESKSLOP_TTS_PRESET=hev` is a starting point +for the HEV suit voice. The `vox` and `hev` voice IDs select these directly. Values are in `docs/TTS-DESIGN.md`. `VESKSLOP_TTS_CRUNCH` (`hl90`, `hl90hq`, `telephone`, `adpcm`, `crush`) adds 1990s lossy diff --git a/microslopsam/docs/NOTES.md b/microslopsam/docs/NOTES.md index a7be815..5946ca1 100644 --- a/microslopsam/docs/NOTES.md +++ b/microslopsam/docs/NOTES.md @@ -129,14 +129,10 @@ without them. - VOX mode is Flextalk-only. The wrapper enables it with `VESKSLOP_TTS_VOX=1` (`VESKSLOP_TTS_VOX_CLEAN=1` drops the stutter wrapper); word mode (`VESKSLOP_TTS_WORDS=1`) wins and skips VOX prosody. -- Half-Life presets (`VESKSLOP_TTS_PRESET=vox|hev`) target Keith Bell only. VOX starts - from NetTTS `nettts_flextalk_vox_profile.reg` (pitch 3, rate 17, head 52, lowering 40) - and is tuned against the game's word assets from `suchipi/half-life-vox-console`: - shipped values are pitch 0, rate 15, prominences 22, head size 34, lowering 50, - volume 70. Measured on 38 words vs the game assets: F0 82.3 vs 82.3 Hz, duration - 22.99 vs 23.36 s, >2 kHz share 0.0172 vs 0.0186 (old approximation: 87.5 Hz / - 22.28 s / 0.0137). `tools/vox_compare.py` reproduces the comparison. `hev` - (pitch 15, rate 24) remains an unverified starting point - HL1 credits the suit +- Half-Life presets (`VESKSLOP_TTS_PRESET=vox|hev`) target Keith Bell only. VOX values + come from NetTTS `nettts_flextalk_vox_profile.reg`: pitch 3, rate 17, prominences 22, + head size 52, volume 70 (factory: 27/33/17/46/100); `vox` also implies VOX prosody. + `hev` (pitch 15, rate 24) is an unverified starting point - HL1 credits the suit sounds to Kelly Bailey with no published settings. - Flextalk rate/pitch are applied as **vendor tags** (`\!R` = duration factor, `\!%` = pitch multiplier), never `-s`/`-p`, because ITTSAttributes override the diff --git a/microslopsam/docs/TTS-DESIGN.md b/microslopsam/docs/TTS-DESIGN.md index 292ad62..780efc3 100644 --- a/microslopsam/docs/TTS-DESIGN.md +++ b/microslopsam/docs/TTS-DESIGN.md @@ -402,20 +402,16 @@ Kerry Watson at factory values. The wrapper implements it as a preset: VESKSLOP_TTS_PRESET=vox # implies VOX prosody unless VESKSLOP_TTS_VOX is set VESKSLOP_TTS_PRESET=hev # HEV suit starting point (see note below) -| Profile value | Factory (Keith) | VOX preset (tuned) | HEV preset (approx.) | +| Profile value | Factory (Keith) | VOX preset | HEV preset (approx.) | | --- | --- | --- | --- | -| Pitch | 27 | 0 | 15 | -| Speaking Rate | 33 | 15 | 24 | +| Pitch | 27 | 3 | 15 | +| Speaking Rate | 33 | 17 | 24 | | Prominences | 17 | 22 | 22 | -| Head Size | 46 | 34 | 52 | -| Lowering | 40 | 50 | 40 | +| Head Size | 46 | 52 | 52 | +| Lowering | 40 | 40 | 40 | | Volume | 100 | 70 | 70 | | Expression | 59 | 59 | 59 | -The VOX column starts from NetTTS's approximation (pitch 3, rate 17, head 52, lowering -40) and is refined against the actual game word assets; see -"Tuning against the actual game assets" below. - - Presets apply only to `keith-bell`; every other voice keeps its defaults. - Precedence: preset < `VESKSLOP_TTS_PROFILE` < `VESKSLOP_TTS_EXPRESSION`. - Equivalent explicit override: @@ -473,49 +469,16 @@ Verified matrix (same line, Keith Bell): | Run | Duration | F0 median | | --- | --- | --- | | factory, no adjustments | 3.35 s | 123 Hz | -| VOX preset, no adjustments | 6.06 s | 82 Hz | -| VOX preset + `speed=1.0 pitch=0` | 6.06 s, byte-identical | 82 Hz | -| VOX preset + `speed=1.3` | 4.02 s | - | -| VOX preset + `pitch=+3` | 6.06 s | 96 Hz | +| VOX preset, no adjustments | 5.83 s | 87 Hz | +| VOX preset + `speed=1.0 pitch=0` | 5.83 s, byte-identical | 87 Hz | +| VOX preset + `speed=1.3` | 4.02 s | 84 Hz | +| VOX preset + `pitch=+3` | 5.83 s | 88 Hz | +| HEV preset, no adjustments | 3.79 s | - | Registry inspection after a preset run: 26 values in the Keith speaker key in both -hives, `Pitch=0x0`, `Speaking Rate=0xf`, `Head Size=0x22`, `Lowering=0x32`, -`Gender=0x2`, `Line Mode=0x1`, +hives, `Pitch=0x3`, `Speaking Rate=0x11`, `Gender=0x2`, `Line Mode=0x1`, `Default Speaker={11260610-C84A-11CE-AEC4-0000C0E9CB87}`. -#### Tuning against the actual game assets (2026-09-22) - -Reference: the word WAVs from `suchipi/half-life-vox-console` -(`public/vox/*.wav`, Valve assets - used locally for analysis only, never committed). -38 words at 11025 Hz 16-bit, the engine's native rate. `tools/vox_compare.py` -reproduces the comparison; it reports the cepstrum F0 median, total audible duration, -energy-weighted spectral centroid and the >2 kHz energy share per word set. - -| Metric (38 words) | Game assets | NetTTS approximation | Shipped VOX preset | -| --- | --- | --- | --- | -| F0 median | 82.3 Hz | 87.5 Hz | 82.3 Hz | -| Duration | 23.36 s | 22.28 s | 22.99 s | -| Spectral centroid | 515 Hz | 479 Hz | 453 Hz | -| >2 kHz energy share | 0.0186 | 0.0137 | 0.0172 | - -Findings: - -- Registry `Pitch 0` is the engine minimum and matches the game's F0; the NetTTS - approximation (3) was about 5 Hz high. -- `Speaking Rate 15` matches the word durations within about 1.6%; NetTTS's 17 was - about 4.6% fast on this corpus. -- The game voice is brighter than the approximation. Smaller `Head Size` raises - brightness (34 is the engine's effective minimum here; 30 gives identical output) and - `Lowering 50` adds a little more, together closing most of the >2 kHz gap - (0.0137 -> 0.0172 against 0.0186). -- The residual centroid difference is mostly the reference's mid/high-band noise floor - (game assets), not voice timbre. -- HEV stays a starting point: no published settings and no word-level reference exists. - -Re-run recipe: write the profile to both hives, synthesize the reference word list with -`build/sapi4host-winlib.exe -v "Keith Bell" -t -o /.wav`, then -`tools/vox_compare.py `. - ### Inline rate/pitch controls (engine-side) The wrapper consumes NetTTS-style, line-leading controls, so Veskslop and the WebUI do diff --git a/microslopsam/setup/test-wrapper.sh b/microslopsam/setup/test-wrapper.sh index 0144efd..a218309 100755 --- a/microslopsam/setup/test-wrapper.sh +++ b/microslopsam/setup/test-wrapper.sh @@ -94,8 +94,8 @@ check "vox preset implies VOX parser" "1" "$(grep -c 'wH1' "$STUB_LOG")" # The preset writes the full audible profile to both hives. VESKSLOP_TTS_VOICE=keith-bell VESKSLOP_TTS_PRESET=vox run_wrapper check "preset writes both hives" "2" "$(grep -c 'Speakers\\{11260610' "$STUB_REG")" -check "preset pitch (both hives)" "2" "$(grep -c '"Pitch"=dword:00000000' "$STUB_REG")" -check "preset rate (both hives)" "2" "$(grep -c '"Speaking Rate"=dword:0000000f' "$STUB_REG")" +check "preset pitch (both hives)" "2" "$(grep -c '"Pitch"=dword:00000003' "$STUB_REG")" +check "preset rate (both hives)" "2" "$(grep -c '"Speaking Rate"=dword:00000011' "$STUB_REG")" check "preset gender and line mode" "4" "$(grep -cE '"Gender"=dword:00000002|"Line Mode"=dword:00000001' "$STUB_REG")" check "preset default speaker" "2" "$(grep -c '"Default Speaker"' "$STUB_REG")" @@ -111,7 +111,7 @@ check "word mode with preset synthesizes every word" "3" "$(grep -c '^ARGV:' "$S check "word mode skips the VOX parser" "0" "$(grep -c 'wH1' "$STUB_LOG")" check "word mode tags every word" "3" \ "$(sed -n 's/.*\[-t\] \[\(.*\)\] \[-o\].*/\1/p' "$STUB_LOG" | grep -c '^\\!R0.80 ')" -check "word mode keeps the preset profile" "2" "$(grep -c '"Pitch"=dword:00000000' "$STUB_REG")" +check "word mode keeps the preset profile" "2" "$(grep -c '"Pitch"=dword:00000003' "$STUB_REG")" check "word mode emits no attributes" "0" "$(attr_count)" # The vox preset implies VOX when the variable is unset, but word mode still wins. @@ -139,7 +139,7 @@ check "stream has a gap per word break" "2" \ # The Half-Life voices carry their profile preset. VESKSLOP_TTS_VOICE=vox VESKSLOP_TTS_VOX=1 run_wrapper -check "vox voice writes the VOX profile (both hives)" "2" "$(grep -c '"Pitch"=dword:00000000' "$STUB_REG")" +check "vox voice writes the VOX profile (both hives)" "2" "$(grep -c '"Pitch"=dword:00000003' "$STUB_REG")" check "vox voice runs VOX prosody" "1" "$(grep -c 'wH1' "$STUB_LOG")" VESKSLOP_TTS_VOICE=hev run_wrapper check "hev voice writes the HEV profile (both hives)" "2" "$(grep -c '"Pitch"=dword:0000000f' "$STUB_REG")" diff --git a/microslopsam/setup/veskslop-tts.sh b/microslopsam/setup/veskslop-tts.sh index ee6737a..359b885 100755 --- a/microslopsam/setup/veskslop-tts.sh +++ b/microslopsam/setup/veskslop-tts.sh @@ -46,7 +46,7 @@ ROOT=$MICROSLOP_ROOT # The Keith Bell defaults follow the active preset so the UI's "default" snap points # match the values the preset actually writes. -VOX_DEFAULTS="pitch:0:rate:15:prominences:22:head_size:34:lowering:50:expression:59" +VOX_DEFAULTS="pitch:3:rate:17:prominences:22:head_size:52:lowering:40:expression:59" HEV_DEFAULTS="pitch:15:rate:24:prominences:22:head_size:52:lowering:40:expression:59" case "${VESKSLOP_TTS_PRESET:-}" in vox) KB_DEFAULTS="$VOX_DEFAULTS" ;; @@ -243,17 +243,15 @@ if [ -n "$SPEAKER_GUID" ]; then P_LOWER=40 P_EXPR="" - # Half-Life presets for Keith Bell (the game's announcement voice). "vox" - # starts from the approximated Valve VOX profile published by NetTTS - # (scripts/winetricks/nettts_flextalk_vox_profile.reg), then refines pitch, - # rate, head size and lowering against the actual game word assets - # (see docs/TTS-DESIGN.md). "hev" is a starting point for the HEV suit - # voice, which has no published profile. + # Half-Life presets for Keith Bell (the game's announcement voice). + # "vox" is the approximated Valve VOX profile published by NetTTS + # (scripts/winetricks/nettts_flextalk_vox_profile.reg); "hev" is a starting + # point for the HEV suit voice, which has no published profile. case "$PRESET" in vox) if [ "$ENGVOICE" = "Keith Bell" ]; then - P_PITCH=0; P_RATE=15; P_VOLUME=70 - P_PROM=22; P_HEAD=34; P_LOWER=50 + P_PITCH=3; P_RATE=17; P_VOLUME=70 + P_PROM=22; P_HEAD=52; P_LOWER=40 fi ;; hev)