Skip to content

BigLinux TTS 4.1.0: reliable History, Kokoro sound fix, release cleanup - #61

Merged
ruscher merged 16 commits into
biglinux:mainfrom
ruscher:main
Oct 9, 2026
Merged

ruscher merged 16 commits into
biglinux:mainfrom
ruscher:main

Conversation

@ruscher

@ruscher ruscher commented Oct 9, 2026

Copy link
Copy Markdown
Member

Brings the fork's main to upstream: three merged fork PRs (ruscher/tts-biglinux #9, #10, #11).

4.1.0 release (#9)

  • One version everywhere: app, Cargo.toml/Cargo.lock, PKGBUILD (epoch=1, pkgver=4.1.0) and README. A test keeps them in sync.
  • Author list: Rafael Ruscher, Bruno Gonçalves, Tales A. Mendonça, with emails.
  • Audit and cleanup:
    • backends reviewed;
    • Rust engine checks;
    • performance, UX and security fixes;
    • i18n in 30 languages;
    • CI and translation validation;
    • README and screenshots.
  • PKGBUILD builds from this repository with official-repo dependencies only. TTS_BIGLINUX_SOURCE can build another repository or branch.

Reliable History (#10)

  • Recording
    • Every engine (RHVoice, espeak-ng, Piper, Kokoro) records each reading with the audio that was actually played. Each entry has a status: completed, stopped or error.
    • Readings started from the shortcut, the tray, the media keys, "Read again" and the queue are all recorded.
  • Settings and menu
    • Saving the History is on by default for new users. Existing settings are respected.
    • History is always in the main menu.
  • Recovery
    • Interrupted recordings and orphaned files are recovered at startup, without data loss.
    • A damaged index is set aside and rebuilt.
    • Deleted entries go to the Trash, with Undo.
  • Redesigned view: search, filters, sorting, multi-select, an empty state, auto-refresh and paging.
  • Fixes queue mode not advancing when there is no tray icon.

Kokoro sound (#11)

  • koko stream mixes its log lines into the audio on stdout, so Kokoro was silent.
  • Kokoro is back on koko pipe -o FILE: koko plays the audio itself and writes it to FILE, which is the History recording. Sound start is detected from its Streaming audio stderr line.
  • A stopped reading keeps only the time actually heard. Pauses are not counted.
  • pkgrel=2.

Verification

  • 265 tests pass (headless GTK under broadway), and ruff is clean. The tests never touch the user's real History, settings or Trash.
  • Built with makepkg (check() passed) and installed as 1:4.1.0-2 on BigLinux. Kokoro was checked with the real koko: sound, a completed History entry, and valid float audio.

ruscher added 16 commits October 8, 2026 18:29
- clippy -D warnings passes: the FFI module carries one documented
  allow(unsafe_code); the 100-line NFD match became a lookup table (with a
  unit test); the unused sample_rate() is gone.
- espeak synthesis takes the sample buffer instead of cloning it, so the
  largest synthesis no longer stays allocated: 24 MB resident after a
  41k-character text (was 133 MB).
- Version 4.1.0 and the authors in Cargo.toml.
…, text rules per voice

Reading
- History records every reading that was heard, for every engine (RHVoice
  and Kokoro were never recorded), off the GTK thread; nothing when off or
  stopped. Entries are newest first, save_text=False keeps no text, the
  folder is private (0700), SQLite connections are closed (one fd leak per
  saved reading).
- espeak-ng streams long texts in chunks like Piper (20k chars: first audio
  0.04 s, was 1.37 s); its fallback reads the text from stdin (no option
  injection, no 128 KiB limit). One streaming routine for both engines; a
  chunk file lives until its player ends, at most two at a time.
- A player started after Stop is terminated; simultaneous readings are
  tracked so Stop and Pause reach all of them.
- MPRIS replay, the shortcut, the tray and "Test voice" share one set of
  options: the character limit and text settings apply everywhere.
- SIGTERM/SIGINT/SIGHUP quit cleanly; koko's text never reaches the logs.

Text
- Rules follow the voice's language, not the system's.
- Abbreviations: no single letters or real words, not inside e-mails/URLs,
  titles drop their period; one precompiled pattern per language.
- Feminine hours, seconds; HTML only removes real tags; numbered lists and
  paragraph breaks kept; "www." URLs removed, or read as their domain.
- The character limit cuts at a sentence or word boundary.

Cleanup
- Removed the unreachable speech-dispatcher backend (settings move to
  RHVoice), the PyTorch Kokoro path (lang_code bug), the khotkeys file and
  chain, launcher pinning and other dead code (~1300 lines).

Interface and translations
- Sidebar selectors show the value as subtitle (no more "P…"); icons that
  exist in Adwaita, Breeze and BigLinux themes; readable history badges and
  voice names; the tray holds a steady icon under reduced motion.
- i18n follows GNU gettext precedence with per-message fallback; language
  and country names come from iso-codes; every string is a literal that the
  pipeline's xgettext extracts.

Version 4.1.0; authors Rafael Ruscher, Bruno Gonçalves, Tales A. Mendonça.
Every catalog has all 322 strings. pt corrected to European Portuguese.
scripts/sync_translations.py extracts like the CI (plain xgettext), keeps
existing translations, and --check validates placeholders.
- epoch=1 pkgver=4.1.0 pkgrel=1 (26.10.08 > 4.1.0 for vercmp without the
  epoch); prepare() refuses mismatched versions.
- Dependencies only from core/extra: wl-clipboard (wl-clipboard-rs provides
  it), alsa-lib added; BigLinux-only packages are optdepends. Built,
  installed, run and removed in a clean Arch container; upgrade from
  26.10.08 keeps user settings.
- tts_engine.so in /usr/lib/tts-biglinux (namcap); bytecode compiled in
  package() with installed paths.
- ci.yml: Python, Rust and PKGBUILD checks in an Arch container. The
  translation workflow pins actions, limits permissions and tmate, and
  discards catalogs that fail the check.
- LICENSE (GPL-3.0-or-later); ruff rules pinned.
Installation without the BigLinux repositories, dependencies, i18n, tests,
CI, release process, third-party licenses, authors; new screenshots of the
real application. The benchmark script finds the engine again.
Why History looked empty or lost entries:
- RHVoice and Kokoro readings were never recorded, and Piper/espeak-ng long
  readings had no audio: only one code path saved history.
- A database migration and WAL switch raced between the save worker and the
  History page ("duplicate column", "database is locked"): saves were lost.
- The Kokoro engine (`koko pipe`) played by itself, so its audio could not
  be kept.

Now each speak() is a reading (_Reading) that owns its processes, files,
threads and recording, so simultaneous and queued readings never mix, and
_finish_reading is the one place that records it (completed / stopped /
error), only if it was heard, in a worker (first audio measured equal with
history on and off).

Audio kept is the audio played: RHVoice and `koko stream` write WAV to
stdout and a relay passes the same bytes to aplay and to the recording;
espeak-ng/Piper chunk files are appended as they start playing. Recordings
go straight into the history folder (.rec-…part) and are finalized there.

history_db: schema 2 (processed text, status, duration, audio file) added
in place; filters, full-text search, paging; serialized migration; JSON
migration without duplicates. history_service: atomic saves that never
overwrite; delete to the Trash; repair_history rebuilds a damaged index
from the files (kept aside), recovers orphan files and crash recordings,
fills durations, marks missing audio; never deletes a recording.

Tests use real processes (fake koko/RHVoice/aplay) and can no longer touch
the user's history, Trash or settings (autouse + session isolation).
… at start

With the tray icon off, the state handler returned early: queued readings
never played, notifications and the cold-start hold were skipped (since
4.0.0). History is repaired in a worker two seconds after start.
Tests: shortcut/tray, media Play key and queue mode all reach the History.
…ettings

- The main menu showed History only while "Save history" was on, and saving
  was off by default: for most people the History never appeared. It is
  now always available; turning saving off keeps every saved reading and a
  banner says new ones are not kept.
- Saving is on for new installations; settings from earlier versions keep
  their value (a file without the key stays off, never turned on silently).
- Advanced options: Keep the audio, Keep the text, Keep at most (retention),
  and where it is stored (only on this computer).
- The page: cards with expandable text, engine, voice, date, duration,
  outcome (stopped / error), player with the known duration, copy, read
  again, save audio as, open the folder; search by text, voice, engine or
  date; date and engine filters; newest/oldest; list or grid; selection to
  save to a folder or delete; pages of 50 loaded on scroll, in a worker;
  refreshes itself when a reading is saved; clear empty states.
- Deleting: one entry with Undo, a selection after confirmation (it used to
  delete everything at once, without asking, and permanently); files go to
  the Trash.
64 new strings (History page, history options, outcomes). pt-BR and pt by
hand; the others validated for placeholders and line breaks. "History"
corrected to the desktop term in hu, es, it, el and is (it was translated
as history in the sense of past events).
… deleting

New History and Advanced options screenshots; test count.
The package still builds biglinux/tts-biglinux by default (BigLinux build
service); testers can install a version that is not published yet.
History: every reading recorded with its audio, always in the menu, recovery (includes 4.1.0)
koko stream writes its log lines ("Detected language…", "CALLING
PHONEMIZE ON…") into stdout among the WAV bytes: the audio relayed to
aplay was garbage and nothing was heard. koko pipe plays by itself and
writes everything it plays to -o as it goes, so that file is the history
recording itself (or a per-reading scratch file, deleted afterwards).
Sound start comes from its "Streaming audio" stderr line.

koko synthesizes ahead of playback: a stopped reading keeps only the time
actually heard (pauses not counted).
fix(kokoro): sound again — koko pipe -o instead of koko stream
@ruscher
ruscher merged commit 036d3ff into biglinux:main Oct 9, 2026
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant