CrispASR v0.8.9
138 commits since v0.8.8. Headline: a new Japanese TTS backend with real
zero-shot voice cloning, TTS output streaming everywhere, on-device browser
(WASM) TTS, MP3/AAC output, a shared reference-conditioning cache, ggml moved to
a shared submodule, and a broad ASR/TTS performance pass.
New backend — Irodori-TTS (Japanese, 48 kHz)
RF-DiT flow-matching TTS (500M) via the Semantic-DACVAE-Japanese-32dim codec,
integrated end to end:
- Zero-shot voice cloning from any reference WAV — ported the DAC-VAE encoder
(resample → −16 LUFS → latent) and wired the DiT speaker conditioning with
speaker CFG.--voice ref.wav --i-have-rights. Validated ~91% of the
reference implementation's speaker fidelity. - Emoji emotion control — the tokenizer now does SentencePiece
byte_fallback
(fixes acore_spmcollapse where OOV multibyte input dropped to<unk>), so
Irodori's emoji controls (whisper 👂, breath 😮💨, …) reach the model as the
byte sequences it was trained on. C++ tokenization is byte-for-byte identical
to the reference. - Duration predictor wired — output length comes from the model's predictor
instead of a chars/sec heuristic that truncated kanji-heavy text. - Overlap-save chunked codec decode — bounds peak decode memory for long
outputs, byte-identical to a whole decode (extracted a shared
core_dac::decode_overlap_savedriver, also wired into zonos). - GPU (Metal/CUDA) for the DiT/ODE + codec; codec-on-Vulkan validated clean on
MoltenVK (CRISPASR_IRODORI_CODEC_GPU=1). - Codec companion auto-download (3-tier resolution).
TTS output streaming (CLI + C ABI + server)
--tts-stream— the CLI streams raw s16le mono PCM to stdout per sentence
as it's synthesized (pipe straight into a player); logs stay on stderr.crispasr_session_synthesize_streaming— new C ABI entry point that fires a
callback per sentence chunk with watermarked PCM, for embedders/bindings.- The server already streamed per-sentence via
/v1/audio/speechstream:true;
this brings the same progressive delivery to the CLI and C ABI. See
docs/streaming.md.
Reference-conditioning cache (all consumers)
Voice cloning encodes the reference into a small conditioning blob (a DAC-VAE
latent for irodori, Conformer/Perceiver + ECAPA for indextts). It's now cached
content-addressed on the reference audio, in the runtime — so every entry
point (CLI, server, C ABI, language wrappers) skips the encode on a repeat
reference automatically, byte-identical to a fresh encode. On by default;
CRISPASR_TTS_REF_CACHE=0 disables, CRISPASR_TTS_REF_CACHE_DIR sets the
location. The helper (core/tts_ref_cache.h) is reusable by any runtime.
Browser / WebAssembly TTS
- On-device TTS in the browser —
ttsOpenExplicit, memory limits, and a
multithreaded demo.PROXY_TO_PTHREADbuild makes multithreaded browser TTS
deadlock-free; a single-threaded build option avoids the COOP/COEP
requirement. The WASM build (libwhisper.js/.wasm) is attached as a release
asset. - ggml-webgpu: ported
arange,pool2d,conv_transpose_2dops.
Audio output formats
- MP3 + AAC-LC output for TTS/S2S via an in-tree, vendored encoder core
(glint) —--tts-output out.mp3/out.aac,response_format=mp3|aacon the
server. Auto-synced from CrispStrobe/glint.
Build / packaging
- ggml de-vendored into a shared submodule (
CrispStrobe/ggml) — smaller
tree, shared with sibling projects. (Note for contributors:git submodule update --init ggmlafter checkout; git worktrees must init the submodule, not
symlink it.) - Ruby extsources updated for the submodule; release attaches the WASM build.
Performance
- FireRedASR — in-graph encoder attention by default (large-T guard),
encoder-on-GPU default withuse_gpu, and Q4_K beam-decode batching (~5.5×). - wav2vec2 — flash-style online-softmax CPU attention.
- silero-LID — ggml-graph forward (3–6× faster, GPU offload, 30 s slice cap).
- diarization — ggml-graph forwards for pyannote-seg + TitaNet.
- pocket-tts — batched the eager Mimi encoder through ggml (43 s → 5.6 s per
synthesis) + disk-cached voice-conditioning latents. - ecapa-LID — ASP + FC head in-graph (kills the 3 s scalar head off-Apple).
Fixes
- indextts — cap over-long reference to the Conformer positional-encoding
table (a 164 s reference aborted inggml_view_2d); reference cache moved into
the runtime. - VibeVoice — use-after-free when cached graphs share a scheduler (#171);
--tts-cfg-scaleknob;--contexthotword/metadata injection. - VibeVoice-ASR — chunk the encoder to avoid CUDA int32 overflow on long
audio. - cli-json — add ms
offsetsto full-JSON words/tokens (#228). - quantize — quantize irodori-tts MLP/attention weights.
- Windows/MSVC portability fix for the reference-cache directory.
Docs
- New Irodori-TTS + reference-conditioning-cache sections in
docs/tts.md;
streaming-out section indocs/streaming.md;--tts-streamindocs/cli.md;
streaming + caching notes indocs/bindings.md.