tiger-speech 0.7.3
Four people reported four things this morning. They turned out to be one bug each, and every one of them was in the driver rather than the engine.
The pauses before links
Kara noticed it first: "the speech pauses between reading text on a webpage and a link." Johann confirmed within a minute — "way too long on certain things."
NVDA hands a synthesizer a speech sequence, and I had assumed each string in it was its own utterance. It is not. Reading NVDA's own speech/manager.py, an IndexCommand is inserted only where a callback sits or an utterance genuinely ends. So a line of a web page with a link in it arrives as several plain strings with nothing between them at all — and tiger-speech rendered each one separately.
That means every fragment got the falling intonation and the final lengthening of a completed sentence. Not a gap in the audio — a gap in the prosody. Measured on one line, splitting it cost 163 ms across two joins, and there was no silence anywhere to trim. The extra was in the speech itself.
The pieces are joined now, up to the next index. This costs nothing in index accuracy, because there was never an index between them to lose — which is also why say-all is completely unaffected, and why no index-ahead trickery was needed.
There is also a Pause between phrases setting now, Short / Medium / Long, for people who want the opposite of what Kara wanted.
Alex saying "AI"
Jerry: "when he reads a story, and if the author uses the — character, alex calls that AI." And the strange part he spotted himself — reading the same text word by word said "em dash" correctly, only say-all got it wrong.
That detail is the whole diagnosis. In review mode NVDA substitutes the symbol's name before the text ever reaches the synthesizer; say-all sends the raw character. And the driver was sending UTF-8, where the engine's front end reads a single-byte Mac encoding — so one em dash arrived as three bytes and was read a character at a time.
Transcribed, before and after:
before He paused, he eyed and left. She said, ah hello, I'm stuck.
after He paused, then left. She said hello and stopped.
MacRoman already has the em dash, the en dash, the curly quotes and the ellipsis, so encoding it properly is the entire fix. There is no table of symbol names to maintain, and adding one would have been the wrong repair. Characters MacRoman genuinely lacks become a space rather than "?", because the engine reads a question mark as a question and lifts the intonation of the whole sentence.
This bug was in every release so far, and in every voice.
Capitals
"Capital pitch change percentage" is 30 by default and did nothing here, at any value. NVDA expresses it as a PitchCommand in the sequence, and the driver kept IndexCommand and threw away everything else it was handed. BreakCommand went in the same bin — so the one place NVDA explicitly asked for a pause was the one place it never got one.
Both are honoured now.
Volume
There was no volume control at all, which people quite reasonably named as a gap.
Rather than scale the samples afterwards, I checked whether the engine could do it, and it can: Apple's own [[volm]] command is exactly linear — 0.5 halves the RMS, 0.2 fifths it. So the synthesizer does the arithmetic in floating point before it quantises to 16 bits, which is better than anything that can be done to the samples after the fact. Nothing at all is added at full volume.
Nothing else moved
Vicki still renders byte-for-byte identically to a file made before any of this week's work — the whole point of a change that touches the driver is that the engine's output should not shift underneath it. The test suite went from 19 to 29.
One of those new tests reads the driver's own source to confirm the encoder is actually called, not merely present and correct. It caught exactly that mistake in the sibling add-on within the hour. An encoder nobody calls is precisely as broken as no encoder.
Re-uploaded shortly after publishing
The first 0.7.3 asset made everyone slightly quieter, and Jerry caught it within minutes: "alex got quieter, not by a whole lot, but it was definitely noticeable."
Adding a volume control is what did it. NVDA's NumericDriverSetting takes defaultVal=50, that becomes the config spec's default, and NVDA writes it over whatever the driver set for itself. So the setting arrived at half.
It defaults to full now, which is the only defensible answer for a synthesizer that had no volume control at all the day before: upgrading should change nothing until you ask it to.
If you installed 0.7.3 in its first hour, NVDA will not offer you this as an update, because the version number has not changed. Either raise the volume slider once, or reinstall the add-on from this page.