Skip to content

feat(desktop): import local Pocket voices - #3259

Draft
johnmatthewtennant wants to merge 3 commits into
jtennant/pocket-tts-settings-v1from
jtennant/pocket-voice-import
Draft

feat(desktop): import local Pocket voices#3259
johnmatthewtennant wants to merge 3 commits into
jtennant/pocket-tts-settings-v1from
jtennant/pocket-voice-import

Conversation

@johnmatthewtennant

@johnmatthewtennant johnmatthewtennant commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Context

Pocket TTS currently offers only bundled reference voices. People need a local, private way to add another voice without sending audio through the renderer or a cloud service.

Summary

This adds a minimal Pocket voice import flow to the existing Voice settings card. Buzz opens the native file picker, validates and canonicalizes the selected WAV in the reusable buzz-voice crate, stores it in app data under a content-derived identity, selects it, and lets the user safely delete it later.

Changes

  • Adds a native WAV picker and validates mono PCM or float WAV files between 2 and 30 seconds.
  • Adds a reusable PocketVoiceLibrary to crates/buzz-voice; Desktop remains a thin Tauri picker and app-data adapter.
  • Canonicalizes accepted audio to mono 32 kHz PCM16 before hashing and storage.
  • Uses stable pocket:imported:<sha256> voice identities and content-addressed app-data files.
  • Keeps absolute file paths inside the native process and exposes only voice metadata to React.
  • Adds local imported voices to Pocket preview and live huddle playback.
  • Adds Add voice and delete controls to Voice settings, with Mary as the confirmed deletion fallback.
  • Preserves bundled voices if optional import metadata is unreadable and keeps failed deletion retryable.
  • Adds deterministic synthesis evidence, BlackHole loopback coverage, and a desktop E2E import, select, and delete flow.

Related issue

N/A. No related issue was supplied.

Testing

Passed:

  • cargo test -p buzz-voice imported --lib: 3 passed.
  • BUZZ_POCKET_MODEL_DIR="$HOME/.buzz/models/pocket-tts" cargo test -p buzz-voice --test pocket_import_audio objective_import_synthesis_delete_and_mary_fallback -- --ignored --nocapture: 1 passed. Imported synthesis produced 2.48 seconds of non-silent PCM, interruption discarded partial PCM, deletion selected Mary, and Mary fallback produced 2.56 seconds of non-silent PCM.
  • BUZZ_POCKET_MODEL_DIR="$HOME/.buzz/models/pocket-tts" BUZZ_VOICE_AUDIO_DEVICE="BlackHole 2ch" cargo test -p buzz-voice --test pocket_import_audio blackhole_playback_captures_generated_non_silent_pcm -- --ignored --nocapture: 1 passed. BlackHole captured 15,806 non-silent samples.
  • cd desktop && pnpm run build:e2e.
  • cd desktop && pnpm exec playwright test tests/e2e/voice-settings.spec.ts --project=smoke: 5 passed.
  • Final exact-head dead-code, timeless-comments, and stacked-diff review passes reported no findings.

Manual listening validation remaining:

  1. In Buzz, import a local WAV through the native picker and listen to Preview and a live huddle reply.
  2. Delete that selected voice and listen to Mary afterward.

Screenshots

Focused Voice settings screenshot. The image was captured after a fresh E2E build, visually inspected for clipping and layout regressions, and has SHA-256 3cee8ad0f42c0a69ab5fa927af16ba283c6b5c6f06c86c89d68040f2a9e247df.

Reviewer-reproducible examples

With Pocket TTS already downloaded to Buzz's normal model directory, exercise the full library workflow: import, persist, reload, synthesize, interrupt, delete, and synthesize with Mary fallback.

BUZZ_POCKET_MODEL_DIR="$HOME/.buzz/models/pocket-tts" \
  cargo test -p buzz-voice --test pocket_import_audio \
  objective_import_synthesis_delete_and_mary_fallback \
  -- --ignored --nocapture

Observed result:

1 passed
importedPreview: 2.48 seconds, 33,308 non-silent samples
interruption: partial PCM discarded
afterDelete: pocket:mary
maryFallbackPreview: 2.56 seconds, 53,885 non-silent samples

On macOS with BlackHole 2ch installed, verify that generated imported-voice PCM reaches the audio device and can be captured:

BUZZ_POCKET_MODEL_DIR="$HOME/.buzz/models/pocket-tts" \
BUZZ_VOICE_AUDIO_DEVICE="BlackHole 2ch" \
  cargo test -p buzz-voice --test pocket_import_audio \
  blackhole_playback_captures_generated_non_silent_pcm \
  -- --ignored --nocapture

Observed result:

1 passed
captured: 274,432 samples, 15,806 non-silent samples

Build the desktop E2E surface and exercise the settings import, selection, preview dispatch, deletion, cancellation, and invalid-file states:

cd desktop
pnpm run build:e2e
pnpm exec playwright test tests/e2e/voice-settings.spec.ts --project=smoke

Observed result:

5 passed
import_pocket_voice
delete_pocket_voice { voiceKey: "pocket:imported:<sha256>" }

The Playwright flow mocks the native picker boundary. The two manual listening steps above remain required to validate the real file dialog and perceived audio quality.

johnmatthewtennant added a commit that referenced this pull request Jul 28, 2026
@johnmatthewtennant
johnmatthewtennant force-pushed the jtennant/pocket-tts-settings-v1 branch from 4891a92 to c118f5a Compare July 28, 2026 04:48
@johnmatthewtennant
johnmatthewtennant force-pushed the jtennant/pocket-voice-import branch from c06a505 to 3fb3c74 Compare July 28, 2026 04:54
@johnmatthewtennant
johnmatthewtennant force-pushed the jtennant/pocket-voice-import branch from 3fb3c74 to c5832db Compare July 28, 2026 05:02
@johnmatthewtennant

johnmatthewtennant commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

🤖 ### Pocket voice import

The Voice settings card keeps the two bundled Pocket voices and adds the local Add voice action.

pocket-voices

johnmatthewtennant added a commit that referenced this pull request Jul 28, 2026
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.

1 participant