feat(desktop): add pitch-preserving TTS playback speed - #3194
feat(desktop): add pitch-preserving TTS playback speed#3194johnmatthewtennant wants to merge 53 commits into
Conversation
f62db77 to
8de8b63
Compare
5a78f33 to
6fca35f
Compare
4891a92 to
c118f5a
Compare
6fca35f to
f78b065
Compare
|
🤖 New review-intent sweep completed on the frozen stacked candidate.
Published DCO-signed head: Manual validation still outstanding: listen to Mary and Marius preview plus active-huddle speech at 0.75x, 1.25x, and 1.50x; verify pitch, first phoneme, tail, cancellation, persistence after restart, and Reset to 1.00x. |
7cc0804 to
acb302e
Compare
a513946 to
5b74959
Compare
5b74959 to
6aebd8f
Compare
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <jtennant@block.xyz>
Signed-off-by: John Tennant <johnmatthewtennant@gmail.com>
Signed-off-by: John Tennant <johnmatthewtennant@gmail.com> Signed-off-by: John Tennant <jtennant@block.xyz> Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <johnmatthewtennant@gmail.com>
Signed-off-by: John Tennant <johnmatthewtennant@gmail.com>
Signed-off-by: John Tennant <johnmatthewtennant@gmail.com>
Signed-off-by: John Tennant <jtennant@block.xyz>
6aebd8f to
347ab73
Compare
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Restack after #3910 relanded #2467+#3208 onto main. Logical-base merge (base 6186fc2, rerere disabled); tree matches the pre-verified merge-tree prediction 799cc15. Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Co-authored-by: npub12gtutshhh76rx0jx697f32f9tffd4hhp3hx58fp4x6u4uemkm7sqf8f757 <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz> Signed-off-by: npub12gtutshhh76rx0jx697f32f9tffd4hhp3hx58fp4x6u4uemkm7sqf8f757 <5217c5c2f7bfb4333e46d17c98a9255a52dadee18dcd43a43536b95e6776dfa0@buzz.block.builderlab.xyz>
Restack after #3910: brings #3259's content under this PR so the 3259×3194 interaction is resolved once, here. Hand-resolved the two predicted conflicts (rerere disabled, logical base 6186fc2): - huddle/tts_settings.rs preview_pocket_voice: keep #3259's pocket_voice_reference() resolution + #3194's playback_speed thread-through into TtsPipeline::new_with_voice. - testing/e2eBridge.ts: union of #3259's import/delete-voice arms and #3194's get/set playback-speed arms; 245 unique case labels, zero duplicates (checked programmatically). MERGE ORDER CONSTRAINT: #3259 must land before this PR. Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
Retack after #3259 landed on main as squash c104eec. The squash severed ancestry from this branch's previous merge parent (3259 head 0ef85c2), manufacturing phantom conflicts in exactly the two known 3259x3194 interaction files. Main's blobs for both files are byte-identical to 3259's head blobs, so the resolution re-applies the already-blessed union from e8b00d4 unchanged (verified by blob hash): - huddle/tts_settings.rs: 099e6ad (3259 pocket_voice_reference + 3194 playback_speed plumbing) - testing/e2eBridge.ts: a58b760 (union arms, 245 unique labels) Also brings in #3751 (avatars fix), previously verified zero overlap with this PR's surface. Co-authored-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz> Signed-off-by: npub1qyvc0c5kl4gqv2fd97fsk46tu378sqgy35vc83rvgfwne90sel7s0ed67d <011987e296fd5006292d2f930b574be47c7801048d1983c46c425d3c95f0cffd@buzz.block.builderlab.xyz>
wesbillman
left a comment
There was a problem hiding this comment.
The pitch-preserving speed control is useful, and the branch is now cleanly shaped against main (19 files, mergeable). Two correctness issues still need resolution before approval: the stretcher resets at hidden Pocket model-unit boundaries, and component-local persistence can discard the user's latest speed when Settings unmounts. Details are inline.
Cancellation is rechecked under the player-operation lock before append, so cancelled processed audio is rejected. The accessibility wiring also looks sound. The new target-wide MSVC CXXFLAGS affect every C++ dependency, so the current Windows CI result is important evidence for the final candidate; it was still running when I submitted this review.
Reviewed at exact head 9ff70fff53f4c9c21d061fbf6ce92838560dd89b.
— Carl, reviewing on Wes's behalf
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>
Signed-off-by: John Tennant <jtennant@squareup.com>

Context
Generated speech currently plays at a fixed 1x rate. Rodio's speed control shifts pitch, while Pocket synthesis rate changes model generation rather than playback. Playback speed needs to remain independent from Pocket voice selection and preserve the existing per-chunk streaming path.
Summary
This adds a locally persisted generated-speech playback setting with pitch-preserving Signalsmith time stretching. The slider covers 0.5x to 2x, the editable value accepts 0.25x to 4x, and Reset restores 1x. The control lives in Voice settings but remains independent from Pocket synthesis and voice selection.
Changes
ssstretch0.1.0 and the Signalsmith DSP implementation under the MIT license. Both are bundled at build time; normal use performs no download.Related issue
None found.
Testing
Manual validation in the combined daily-driver build covered the 0.5x to 2x slider, typed values across the 0.25x to 4x accepted range, stable voice pitch, immediate cancellation, Reset to 1x, and persistence after restart. The production DSP probe measured 60 ms of compensated lookahead and processing below 0.21% of realtime at the sampled speeds.
Screenshots
The Voice settings control combines the bounded slider, editable value, and Reset action.
Reviewer-reproducible examples
For a repeatable DSP measurement, run:
CARGO_HOME=$PWD/.hermit/rust cargo run --offline --release \ --manifest-path desktop/src-tauri/Cargo.toml \ --example tts_speed_probeObserved output:
Pocket still submits the first completed synthesis chunk immediately rather than rendering the full response.