Skip to content

RustTts is frozen pre-floravox: ABI mismatch on shipped DLL + floravox catch-up #15

Description

@willwade

Summary

The RustTts integration layer is frozen at 2026-08-21 (e80eca2) — the moment floravox landed in rust-tts-wrapper (first commit 2026-08-20). Everything since (floravox engine, lexicon routing, measured boundaries, floravox-core 0.8.x fixes) is absent. There is also a latent ABI mismatch shipping today.

Reference state: VoiceGarden-SPD consumes rust-tts-wrapper v0.5.2 (floravox-core 0.8.4, moving to 0.8.5) directly from the tagged git dep with floravox-lexicons.

Critical

1. ABI mismatch on tts_set_on_boundary

  • VoiceGarden.UI.csproj:23 pins RustTtsWrapper.Bindings 0.3.20
  • Our loader/thunk (updated in e80eca2) target the post-consolidation (rust-tts-wrapper#31) 7-arg callback: (word, charOffset, charLen, startS, endS, estimated, ud)
  • The 0.3.20 DLL exports the same symbol with the old 4-arg signature: (word, startS, endS, ud)
  • GetProcAddress succeeds (symbol name unchanged), so RustTtsLoader cannot detect it. The Rust side invokes the thunk with 4 args; charOffset / charLen / estimated are read from never-set registers → garbage offsets or crashes in the boundary lambda (TTSEngine.cpp:998)

Fix: bump NuGet to 0.5.0+ (consolidated signature verified) and add an ABI canary — e.g. resolve tts_set_on_mark (exists only ≥ 0.5.x) and refuse to load the DLL without it.

2. CI ships a nondeterministic DLL

  • .github/workflows/msbuild.yml:228 grabs Get-ChildItem ~/.nuget/packages/rustttswrapper.bindings -Recurse -Filter rust_tts_wrapper.dll | Select -First 1 — whichever cached version sorts first, decoupled from the csproj pin
    Fix: pin the exact runtimes/win-{x64,x86}/native path from the referenced package version.

3. The NuGet package has no floravox

  • rust-tts-wrapper publish.yml builds the Windows DLL with sapi,cloud,sherpaonnx only — no floravox, no floravox-lexicons. Even after a pin bump, SAPI cannot create a floravox engine.
  • Also NuGet stops at 0.5.0 while the wrapper is at v0.5.2 — releases aren't published consistently.

Fix (wrapper side, tracked separately): add floravox-lexicons to the Windows NuGet build matrix, tag, publish.

Floravox catch-up (SPD parity)

Gap SPD has SAPI needs
Local engine floravox engine via rust-tts-wrapper v0.5.2 Route piper-family voices to engine id floravox (needs wrapper NuGet fix above)
Word boundaries Measured (floravox duration tensor) Currently estimated-only via sherpaonnx path; TTSEngine.cpp:998 receives but ignores the estimated flag — use it to gate wpm/silence compensation
Bookmarks marks → SPD events tts_set_on_mark not resolved in RustTtsLoader.cpp — map it to SPEI_TTSBOOKMARK
Model install hardening sidecar generate_sidecar() re-run, phoneme_id_map casefold, language_code sidecar (floravox 0.8.5) Port equivalent logic to the UI model installer for local voices
Version hygiene pinned tag + bump discipline Pin NuGet to wrapper releases, note the mapping in release notes

Code nits

  • RustTtsEngine.cpp:57-63 — hardcoded debug dump to C:\Users\WillWade\AppData\Local\Temp\vg_ssml_debug.txt on every SpeakSsml. Leftover debug; remove.
  • TTSEngine.cpp:1037m_rustTtsUseSsml = false always, making the SpeakSsml path (lines 336/366) dead code — despite the integration plan calling the C++ BuildSSML() "superior" and c322489 adding PUA-sentinel SSML normalization. Decide: pass SSML for engines that support it (floravox, Azure), or delete the dead path.
  • TTSEngine.cpp:1001 — boundaries with charOffset < 0 are dropped entirely; consider emitting audio-time-only events instead of losing them.

Suggested order

  1. Remove debug file writes; fix CI DLL selection (trivial)
  2. Bump NuGet 0.3.20 → 0.5.0+ and add the ABI canary in RustTtsLoader
  3. Wrapper: Windows NuGet build with floravox-lexicons, tag, publish (blocks 4)
  4. Route local voices through the floravox engine (measured boundaries + marks)
  5. Port SPD installer hardening for local model sidecars

No architecture change required — the C-API-over-NuGet approach is correct for C++ (same reasoning as AVSynth's dylib). This is version rot plus a never-wired floravox path.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions