Wire up TTS voice selection dropdown in Narration popover#1660
Open
4rdii wants to merge 1 commit intojohnfactotum:gtk4from
Open
Wire up TTS voice selection dropdown in Narration popover#16604rdii wants to merge 1 commit intojohnfactotum:gtk4from
4rdii wants to merge 1 commit intojohnfactotum:gtk4from
Conversation
The Narration popover's tts-box.ui template has carried a commented-out Voice label and GtkDropDown for some time. This change uncomments the stub, wires it to Speech Dispatcher via a new SSIPClient.setVoice() method, and populates it lazily the first time the popover is shown. Behavior: - First time the user clicks the Narration (headphones) button, the dropdown is populated by querying `LIST SYNTHESIS_VOICES` from the currently-active Speech Dispatcher output module. If the user never clicks the button, SSIP is never initialized — Speech Dispatcher is not spawned at application startup as a side effect. - Selecting a different voice issues `SET SELF SYNTHESIS_VOICE <name>`. If TTS is currently playing it is briefly paused and then resumed from the same position with the new voice, matching the existing behavior of the Speed and Pitch scales. - Entries are labeled `<name> (<lang>)` when the module reports a language, otherwise just `<name>`. - A suppression flag prevents the initial model-population from firing a spurious notify::selected that would trigger setVoice on the default voice and briefly pause any in-flight speech. This complements the existing Speed and Pitch scales in the popover and does not add any new toolbar widgets. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Completes the commented-out voice dropdown stub that has been sitting in
src/ui/tts-box.uifor some time, by:SSIPClient.setVoice(name)insrc/speech.js(one-line method, mirrors the existingsetRate/setPitchpattern).GtkDropDownand its label insrc/ui/tts-box.ui.src/tts.jsonFoliateTTSBox.loadVoices()call fromsrc/navbar.jswhen the Narration popover is first shown.Design notes
show, not in the widget constructor. This preserves the current behavior where Speech Dispatcher is only spawned when the user explicitly uses TTS — users who never click the Narration button never incur an SSIP init.<name> (<lang>)whenLIST SYNTHESIS_VOICESreports a language, otherwise just<name>. Labels are derived from whatever the active output module returns, so the experience scales to whichever TTS backend the user has configured (espeak-ng, piper, mimic3, mary, etc.).#connectScalefor Rate/Pitch.modelfires anotify::selectedsignal that would otherwise triggersetVoiceon the default voice the first time the popover opens, unnecessarily interrupting any already-running speech. A small#suppressVoiceNotifyflag guards against that.Why this complements existing work
The commented-out stub at
src/ui/tts-box.uisuggests the dropdown was always intended but not finished. This PR finishes it with the minimum amount of new code (~40 lines) and does not introduce any new dependencies. It also removes a commented-out block, which theCONTRIBUTING.mdexplicitly calls out as something to avoid in PRs.Test plan
setVoiceis fired on initial model population.listSynthesisVoicesreturns an empty list, the dropdown stays empty and no error dialog is shown.Tested with four Piper voice models (en_US and en_GB, female and male) routed through a custom Speech Dispatcher generic module, as well as the default espeak-ng module.
🤖 Generated with Claude Code