Skip to content

Make synth fallback check all other synths, not just later ones#19603

Merged
SaschaCowley merged 8 commits into
betafrom
synthFallback
Feb 13, 2026
Merged

Make synth fallback check all other synths, not just later ones#19603
SaschaCowley merged 8 commits into
betafrom
synthFallback

Conversation

@SaschaCowley

@SaschaCowley SaschaCowley commented Feb 12, 2026

Copy link
Copy Markdown
Member

Link to issue number:

None

Summary of the issue:

If the default speech synthesizer is set to a synth that can't be loaded for some reason, and the only working synth(s) are before that synth in synthDriverHandler.defaultSynthPriorityList, NVDA will fall back to silence.

That is, as reported in #19582, if the default synth is eSpeak and it can't be loaded, NVDA doesn't produce speech at all.

Description of user facing changes:

If eSpeak is set as the default synth and it can't be loaded, NVDA will first try to use OneCore before falling back to no speech.

Description of developer facing changes:

synthDriverHandler.setSynth and findAndSetNextSynth now optionally take an internal-only keyword-only _leftToTry list of synth names (in reverse order of priority). The behaviour of findAndSetNextSynth has changed to find the first working synth in defaultSynthPriorityList, rather than only considering synths after currentSynthName. As a result, setSynth may fall back to a synth anywhere in defaultSynthPriorityList, and will preference synths earlier therein.

Description of development approach:

Update synthDriverHandler.setSynth and findNextSynth to take an optional list of synth names. If None, it is calculated in findAndSetNextSynth from currentSynthName and defaultSynthPriorityList.

In findAndSetNextSynth, rather than finding the index of currentSynthName in defaultSynthPriorityList and attempting to use the next synth, pop a synth name from leftToTry and attempt to use that synth. as findAndSetNextSynth calls setSynth with the popped name and the remainder of leftToTry, and setSynth calls findAndSetNextSynth with what it received as leftToTry, this will consume leftToTry tail-first until either a working synth is found or leftToTry is exhausted.

If findAndSetNextSynth receives None as the value of leftToTry, it uses defaultSynthPriorityList in reverse order, excluding currentSynthName. Otherwise, currentSynthName is ignored.

Since, if unspecified, leftToTry defaults to defaultSynthPriorityList, and findAndSetNextSynth consumes leftToTry in reverse, we try synths from defaultSynthPriorityList in order (axiomatically, reverss(reverse(sequence)) = sequence).

Testing strategy:

Raised RuntimeError from synthDrivers.espeak.SynthDriver.__init__ and/or synthDriverHandler.OneCore.OneCoreSynthDriver.__init__. Observed the following behaviour:

  • Default synth OneCore:
    • OneCore raises: eSpeak NG is used at startup
    • oneCore does not raise: OneCore is used at startup
  • Default synth eSpeak NG:
    • eSpeak NG raises: oneCore is used at startup
    • eSpeak NG does not raise: eSpeak NG is used at startup
  • Default synth OneCore or eSpeak NG:
    • OneCore and eSpeak NG raise: No speech is used at startup
  • Default synth SAPI 5:
    • eSpeak NG raises: when attempting to select eSpeak NG, SAPI 5 continues to be used and an error is shown.

Known issues with pull request:

None known

Code Review Checklist:

  • Documentation:
    • Change log entry
    • User Documentation
    • Developer / Technical Documentation
    • Context sensitive help for GUI changes
  • Testing:
    • Unit tests
    • System (end to end) tests
    • Manual testing
  • UX of all users considered:
    • Speech
    • Braille
    • Low Vision
    • Different web browsers
    • Localization in other languages / culture than English
  • API is compatible with existing add-ons.
  • Security precautions taken.

@SaschaCowley SaschaCowley marked this pull request as ready for review February 12, 2026 08:20
@SaschaCowley SaschaCowley requested a review from a team as a code owner February 12, 2026 08:20
@seanbudd seanbudd added this to the 2026.1 milestone Feb 13, 2026
@SaschaCowley SaschaCowley merged commit e1c7618 into beta Feb 13, 2026
73 of 75 checks passed
@SaschaCowley SaschaCowley deleted the synthFallback branch February 13, 2026 04:52
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.

2 participants