Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
f6493dd
Upgrade Desktop Pocket TTS to April INT8
Jul 28, 2026
5abdb4a
fix(desktop): preserve Pocket token split continuity
Jul 28, 2026
9f9c535
fix(desktop): stream Pocket model units without seams
Jul 28, 2026
d3cec37
fix(desktop): continue TTS after unit errors
Jul 28, 2026
92e5425
test(desktop): split Pocket token boundary tests
Jul 28, 2026
211d17c
fix(desktop): cushion Pocket playback underruns
Jul 28, 2026
ace19c6
refactor(voice): extract reusable Pocket primitives
johnmatthewtennant Jul 28, 2026
fc61d30
feat(desktop): add Pocket voice settings
johnmatthewtennant Jul 27, 2026
5e70797
fix(desktop): persist mocked voice settings
johnmatthewtennant Jul 27, 2026
68d9c37
fix(desktop): serialize Pocket voice transitions
johnmatthewtennant Jul 27, 2026
648b135
refactor(desktop): split Pocket voice transitions
johnmatthewtennant Jul 27, 2026
c3e03bb
Cancel in-flight Pocket synthesis
johnmatthewtennant Jul 28, 2026
ed87750
Preserve ordered huddle TTS reconnect replay
johnmatthewtennant Jul 28, 2026
145e051
Fix first-event reconnect replay baseline
johnmatthewtennant Jul 28, 2026
c08885c
Test agent TTS routing in settings layer
johnmatthewtennant Jul 28, 2026
a20a671
feat(desktop): complete Pocket voice settings
johnmatthewtennant Jul 28, 2026
18fec8c
fix(desktop): preserve TTS route outcomes
johnmatthewtennant Jul 28, 2026
8d31bf7
fix(desktop): group TTS worker controls
johnmatthewtennant Jul 29, 2026
8a25584
refactor(desktop): satisfy file size ratchets
johnmatthewtennant Jul 29, 2026
6186fc2
fix(desktop): keep agent speech live-only
johnmatthewtennant Jul 29, 2026
4e6570a
Add pitch-preserving TTS playback speed
johnmatthewtennant Jul 27, 2026
41e9bc4
Fix TTS stretcher pre-roll compensation
johnmatthewtennant Jul 27, 2026
eaa0d32
Test TTS time-stretch onset alignment
johnmatthewtennant Jul 27, 2026
d373e55
Support TTS speed in desktop screenshot harness
johnmatthewtennant Jul 27, 2026
681e959
Place playback speed in Voice settings
johnmatthewtennant Jul 27, 2026
eec0a41
Serialize playback speed updates
johnmatthewtennant Jul 27, 2026
3111425
Guard playback speed initialization
johnmatthewtennant Jul 27, 2026
abe3ca4
Use cross-platform playback settings writes
johnmatthewtennant Jul 27, 2026
613dd82
Keep playback state within file limits
johnmatthewtennant Jul 28, 2026
80899ba
Preserve TTS lead-in through speed processing
johnmatthewtennant Jul 28, 2026
f5a2005
Split TTS playback speed regression test
johnmatthewtennant Jul 28, 2026
64ca856
fix(build): report C++ standard correctly on MSVC
johnmatthewtennant Jul 28, 2026
752101d
Remove unused playback speed exports
johnmatthewtennant Jul 28, 2026
8b87b09
Adapt playback speed to chunk audio boundary
johnmatthewtennant Jul 29, 2026
e914b1c
Test the production speed boundary directly
johnmatthewtennant Jul 29, 2026
9c85e19
Normalize the restacked playback diff
johnmatthewtennant Jul 29, 2026
5caf01e
Keep playback settings within file limits
johnmatthewtennant Jul 29, 2026
347ab73
Cancel stale playback speed saves
Jul 29, 2026
49c03af
feat(desktop): import local Pocket voices
johnmatthewtennant Jul 28, 2026
c2ccdb7
test(desktop): automate imported voice audio workflow
johnmatthewtennant Jul 28, 2026
5402eef
Clarify voice registry documentation
johnmatthewtennant Jul 28, 2026
66de788
test(voice): update importer workflow for Pocket engine
johnmatthewtennant Jul 29, 2026
d1d9ffc
fix(voice): reconcile imported voice mutations
johnmatthewtennant Jul 29, 2026
53db71d
Expand speech playback speed controls
johnmatthewtennant Jul 30, 2026
a612c19
Accept common audio formats for Pocket voices
johnmatthewtennant Jul 30, 2026
d39ca4a
Merge main (post-#3910) into Pocket voice import
Jul 31, 2026
0ef85c2
chore: retrigger CI
Jul 31, 2026
e8b00d4
Merge Pocket voice import branch (PR #3259) into TTS playback speed
Jul 31, 2026
9ff70ff
Merge main (post-#3259 squash) into TTS playback speed
Jul 31, 2026
ac342dd
fix(desktop): preserve playback speed continuity
johnmatthewtennant Jul 31, 2026
3805b3e
Merge main into TTS playback speed
johnmatthewtennant Jul 31, 2026
283e177
chore(desktop): allow diagnostic DSP subset
johnmatthewtennant Jul 31, 2026
d80ad3e
fix(desktop): retain playback audio in release builds
johnmatthewtennant Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,10 @@ debug = "line-tables-only"
# cmake_minimum_required < 3.5; audiopus_sys's vendored opus declares 3.1.
# Same workaround CI uses. A value already set in the environment wins.
CMAKE_POLICY_VERSION_MINIMUM = "3.5"

# MSVC otherwise reports the legacy C++98 value for `__cplusplus`, even when
# cc-rs selects C++14. sstretch uses that macro to gate its C++11
# `std::make_unique` polyfill, which collides with the MSVC standard library.
# Match sherpa-onnx's static MSVC runtime so both native audio libraries can
# link into the same Tauri binary without LNK2038 RuntimeLibrary mismatches.
CXXFLAGS_x86_64_pc_windows_msvc = "/Zc:__cplusplus /MT"
119 changes: 119 additions & 0 deletions desktop/src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions desktop/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ regex = "1"
rusqlite = { version = "0.37", features = ["bundled"] }
axum = "0.8"
rodio = "0.22"
ssstretch = "0.1.0"
earshot = "1.0"
rubato = "3.0"
audioadapter-buffers = "3.0"
Expand Down
32 changes: 32 additions & 0 deletions desktop/src-tauri/examples/tts_speed_probe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::time::Instant;

#[path = "../src/huddle/playback_speed_dsp.rs"]
mod playback_speed_dsp;

const SAMPLE_RATE: u32 = 24_000;
const TONE_SECONDS: f64 = 10.0;

fn main() {
let tone: Vec<f32> = (0..SAMPLE_RATE * TONE_SECONDS as u32)
.map(|index| {
(2.0 * std::f32::consts::PI * 220.0 * index as f32 / SAMPLE_RATE as f32).sin() * 0.25
})
.collect();

let compensated_lookahead = playback_speed_dsp::compensated_output_latency_samples(SAMPLE_RATE);
let compensated_lookahead_ms = compensated_lookahead as f64 * 1_000.0 / SAMPLE_RATE as f64;

for speed in [0.75_f32, 1.25, 1.5] {
let started = Instant::now();
let output = playback_speed_dsp::process_complete_chunk(&tone, speed, SAMPLE_RATE)
.expect("process synthesized model audio");
let elapsed = started.elapsed();
println!(
"{speed:.2}x: processing={:.2}ms, {:.3}% realtime, output={} samples, compensated \
DSP lookahead={compensated_lookahead_ms:.1}ms",
elapsed.as_secs_f64() * 1_000.0,
elapsed.as_secs_f64() / TONE_SECONDS * 100.0,
output.len(),
);
}
}
8 changes: 4 additions & 4 deletions desktop/src-tauri/src/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ pub struct AppState {
pub managed_agent_processes: Mutex<HashMap<ManagedAgentRuntimeKey, ManagedAgentPairRuntime>>,
pub huddle_state: Mutex<HuddleState>,
pub huddle_audio: crate::huddle::tts_settings::HuddleAudioSettingsState,
/// Tauri app handle — stored after setup so huddle commands can emit
/// `huddle-state-changed` events without needing the handle threaded
/// through every call site.
///
/// Tauri app handle, stored after setup so huddle commands can emit
/// `huddle-state-changed` without threading it through every call site.
/// Set once during `setup()` in `lib.rs`; never cleared.
pub app_handle: Mutex<Option<AppHandle>>,
pub tts_playback_speed: crate::huddle::playback_speed::PlaybackSpeedControl,
/// Port of the localhost media streaming proxy (set during setup).
pub media_proxy_port: AtomicU16,
/// Set when identity resolution detected a "keyring-locked" state: the
Expand Down Expand Up @@ -219,6 +218,7 @@ pub fn build_app_state() -> AppState {
huddle_state: Mutex::new(HuddleState::default()),
huddle_audio: Default::default(),
app_handle: Mutex::new(None),
tts_playback_speed: crate::huddle::playback_speed::PlaybackSpeedControl::default(),
media_proxy_port: AtomicU16::new(0),
prevent_sleep: Arc::new(Mutex::new(
crate::prevent_sleep::PreventSleepState::default(),
Expand Down
1 change: 1 addition & 0 deletions desktop/src-tauri/src/huddle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ pub mod audio_output;
pub mod jitter;
pub mod models;
pub mod pipeline;
pub mod playback_speed;
pub mod playout;
pub mod pocket;
pub mod preprocessing;
Expand Down
2 changes: 2 additions & 0 deletions desktop/src-tauri/src/huddle/pipeline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,13 +451,15 @@ pub(crate) async fn maybe_start_tts_pipeline(state: &AppState) -> Result<bool, S
// Construct outside the lock — this spawns the TTS worker thread and
// loads ONNX sessions (~200ms). If this fails, clear the sentinel.
let constructed_voice = initial_voice.clone();
let playback_speed = state.tts_playback_speed.clone();
let constructed = tokio::task::spawn_blocking(move || {
tts::TtsPipeline::new_with_voice(
model_dir,
tts_active,
tts_cancel,
&initial_voice,
output_device,
playback_speed,
)
})
.await;
Expand Down
Loading