Releases: CrispStrobe/CrispASR
Release list
v0.8.10 — MOSS-TTS-v1.5 + moss-diarize; #218 long-audio root-caused; TTS perf
CrispASR v0.8.10
Headline: the #218 long-audio arc root-caused and fixed (qwen3-asr / glm-asr now
match their Python blueprints; loop mitigation across all LLM backends), new
backends/models (MOSS-TTS-v1.5, canary-qwen, OmniVoice, Voxtral-TTS,
kyutai-stt-2.6b, bananamind-tts), raw CTC logits access across every language
binding, per-token streaming in the C ABI, a GPU graph-cache use-after-free
fix across 7 backends, a class of multi-model-in-one-process correctness bugs
fixed (a second model no longer reads the first's cached weights/vocab),
OmniVoice's silent-synthesis root cause fixed plus a TTS perf pass
(OmniVoice ~1.6-2×, qwen3-tts codec 3× on Metal), a generation-health regression
gate (empty/looping/trailing-silence output caught in CI), and a CUDA long-audio
speedup (qwen3-asr manual-attn default-on, 3.2×).
New backends / models
- MOSS-TTS-v1.5 (#249) —
OpenMOSS-Team/MOSS-TTS-v1.5(MossTTSDelay): a
Qwen3-8B backbone autoregressively emits 32 RVQ audio codebooks under a
staggered delay pattern, decoded to 24 kHz by a 1.6B pure-transformer codec.
Ported onto CrispASR's in-house Qwen3 runtime (no libllama) by grafting
pwilkin/openmoss's codec + delay logic. Newsrc/moss_tts.{h,cpp}(backbone- 32 embed/head aux graphs + delay state machine) and
src/moss_tts_codec.{h,cpp}
(weight-norm-reconstructed projections → 4 sliding-window ProjectedTransformer
stages → 24 kHz). Voice cloning via--voice ref.wav(codec encoder +
reference splice; validated by ASR + speaker-cosine roundtrip). GGUFs at
cstr/moss-tts-v1.5-GGUF(Q4_K backbone + F16 codec). Validated on Kaggle
P100: Q4_K decoded round-trip is intelligible + correct on the real 8B weights.
Code-parity note: the greedy code stream is not byte-identical to the HF
BF16 reference and is not expected to be — a fixed tokenizer bug made the prompt
byte-identical, but the residual frame-0 divergence is a Q4_K near-tie argmax
flip cascading through the AR loop (the reference's greedy pick is the runtime's
rank-1 runner-up at a 0.135-logit gap), so the ASR round-trip is the acceptance
gate, not exact codes.
- 32 embed/head aux graphs + delay state machine) and
- moss-diarize (#242) —
MOSS-Transcribe-Diarize-0.9B: transcription with
speaker diarization (SRT with speaker labels). Registry auto-download,
diff-harness reference backend, quantization rules. - bananamind-tts — added to the model registry (EN + DE auto-download).
- canary-qwen (#233) —
nvidia/canary-qwen-2.5bSALM: FastConformer
encoder → Qwen3-1.7B decoder with merged LoRA. English ASR. GGUFs at
cstr/canary-qwen-2.5b-GGUF(F16/Q8_0/Q4_K; Q8_0 registry default). - OmniVoice TTS (#234) —
k2-fsa/OmniVoice: Qwen3-0.6B + SoundStorm-style
masked-iterative 8-codebook generation with classifier-free guidance,
HiggsAudioV2 codec decoder → 24 kHz PCM. Voice cloning, 600+ languages.
GGUFs atcstr/omnivoice-GGUF. - Voxtral-TTS (#93) — Mistral Voxtral-based TTS end to end in ggml: LLM AR
backbone → flow-matching ODE → codec decoder, proper Tekken
pre-tokenization; multi-voice, EN+FR validated by ASR roundtrip. - kyutai-stt 2.6B (#238) —
kyutai/stt-2.6b-ensupport in the kyutai-stt
backend: model-scaled silence prefix/tail conditioning (2.6B has 3.5 s
lookahead), registry auto-download, diff-harness reference backend. - cohere-transcribe-arabic (#231) —
--backend cohere-arshorthand wired
into the factory (defaults-l ar), registry auto-download, GGUFs at
cstr/cohere-transcribe-arabic-07-2026-GGUF.
#218 — long-audio repetition loops / empty output: mitigated AND root-caused
- Mitigation everywhere: n-gram
fix_loopsapplied to all LLM-decoder
backends (incl. granite), mirrored into the session C-ABI; word-level dedup
alongside the text collapse; long-run + phrase-repeat regression fixtures. - qwen3-asr root cause: the q4_k GGUFs quantized the audio tower below
8-bit; compounding encoder drift flipped greedy decode into loops /
"language none" on long clips.crispasr-quantizenow floors qwen3-asr
audio.*at Q8_0 (re-baked GGUFs live for 0.6b, 1.7b, ja-anime). Runtime
half: forced language is now an assistant-turn prefill
(language <Name><asr_text>, the blueprint contract — structurally prevents
empty output), tail-pad frames dropped before the encoder, KV grows on
demand (a fixed 4096 capped un-chunked audio at ~5 min),max_newfallback
512. Un-chunked 145 s decodes clean with the loop-fix disabled. - glm-asr root cause: no quantization involved — the GGUF carried no BPE
merges, so every plain-text instruction silently tokenized to nothing (the
model never saw the mandatory "Please transcribe this audio into text"), and
audio was truncated to one 30 s window. Now: real byte-level BPE (merges
baked by the converter;tools/gguf-add-merges.pybackfills — published
GGUFs updated) and the blueprint multi-window prompt (up to 21×30 s = 655 s
single-pass). q4_k matches the bf16 reference near-verbatim on the 145 s
repro clip. - mega-asr: verified against its blueprint — the long-form degeneration
reproduces in the bf16 LoRA-merged reference itself (base model clean), so
it is model-inherent.--chunk-seconds 0is unsupported for mega; the
default 30 s-chunked path works as before. - Experimental:
CRISP_AUDIO_WINDOWED_ATTN=1— FA2-style block-diagonal
windowed encoder attention for qwen3-asr, O(N·W) memory instead of O(N²).
Opt-in escape hatch for >10-min single-pass audio (keep the loop fix on);
evaluated and deliberately not the default. - Diagnostics:
CRISPASR_NGRAM_LOOPFIX_OFF=1raw-decode gate, qwen3
stages incrispasr-diff, encoder-cosine quant audit tool
(qwen3-asr-enc-dump), and a stderr warning when non-silent audio produces
an empty transcript (#240).
Bindings / API
- Raw CTC logits accessor across Python, Go, Ruby, Java, C#, Dart, and
JavaScript bindings, plus a CTC vocabulary accessor for token→word
detokenization — enables forced alignment on wav2vec2 / canary-ctc and the
rest of the CTC set (community contribution by Michael J. Culbertson, #232). - Per-token streaming callback in the session C-ABI.
- Dart: replace deprecated
Pointer.elementAt; Go: cgo LDFLAGS sync.
Fixes
- OmniVoice silent synthesis (#234): the C++ generation-config fallbacks
didn't match the blueprint'sOmniVoiceGenerationConfig(guidance scale,
class/position temperature, layer-penalty and t-shift unmask schedule), so
the masked-iterative decode degenerated into near-constant silence codes on
every platform and precision — the codec then faithfully rendered silence.
With blueprint defaults it produces real audio (whisper roundtrip verbatim). - Multi-model-in-one-process correctness (PR #244 + follow-ups): several
backends cached per-model data in process-global, pointer-keyed maps that
outlived the model. After freeing model A and loading model B, the allocator
commonly hands back the same addresses, so B read A's data. Fixed by scoping
each cache to its model: the wav2vec2 GPU dequant cache and pocket_tts F16
cache (community contribution by Michael J. Culbertson), the greedy-tokenizer
vocab maps in kugelaudio/vibevoice, and the voxcpm2 VAE-encode memo. - Per-session streaming buffers: the default segment/token callbacks (Dart
FFI polling path) pushed into process-global buffers, so two sessions —
concurrent or sequential — interleaved and drained each other's output.
Scoped to the owning session (and capped so a non-draining consumer can't
grow them without bound). The persistent CPU threadpool is now released when
its backend is freed, instead of leaking worker threads per model. - canary-qwen instruction echo (#247): on a too-short audio window the SALM
decoder echoed its task framing as a meta word ("Transcript", "Transcription",
"PASS") instead of transcribing. Root-caused against the NeMo SALM reference:
the FastConformer subsamples 8x, so a window with only a few encoder frames
(T_enc<=5, ~<=0.4 s) gives the Qwen3 LLM decoder no acoustic content to ground
on and it falls back to its language prior — NeMo emits the identical tokens
("Okay" on a 0.1 s clip, "Transcript" on a 0.3 s clip), so this is inherent to
the model, not a port bug (the prompt is byte-identical to NeMo's, and full-
utterance output matches exactly). Earlier theories (framing tokens; string
stripping) did not fix it. Fixed in the pipeline: a degenerate-window gate
returns empty for sub-gate windows, plus a backend-agnostic safety net that
strips any leading instruction-echo token from both the text and the
tokens array (the old workaround left the tokens array inconsistent — #218).
Both paths are env-gated (CRISPASR_CANARY_QWEN_MIN_ENC_FRAMES,
CRISPASR_CANARY_QWEN_NO_ECHO_STRIP) for A/B. - kugelaudio no-voice synthesis (#248): no voice packs were ever published
upstream, so unconditioned synthesis produced noise. Implemented VibeVoice's
zero-tensor neutral-speaker fallback (1-frame zero VAE latent through the
acoustic connector) so it produces intelligible speech without a voice GGUF. - moonshine ran CPU-only from the CLI: the adapter never forwarded the
--gpupreference, so every moonshine run (including the §232 "GPU"
benchmarks) used the CPU backend. Now forwards it — encoder is 4-6× faster on
Metal, transcript identical,--no-gpustill opts out. (moonshine-streaming
and piper stay on CPU deliberately: their tiny per-frame graphs are
launch-bound and measurably slower on GPU.) - f5-tts was broken and CPU-only: the DiT transformer (the model's dominant
compute) was hardcoded to run on the CPU backend regardless of--gpu, and a
gallocr input-aliasing bug corrupted the RoPE positions from the first ODE
step on — so synthesis produced degenerate audio on both backends (the prior
"f5 CPU is a dud" state). Both fixed: the DiT now runs on ...
CrispASR v0.8.9
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.
v0.8.8 — Japanese long-form ASR (issue #89 close-out)
CrispASR v0.8.8
This release closes out issue #89 — Japanese long-form transcription with
parakeet-tdt-0.6b-ja no longer silently drops half the speech. Content
recall on the reporter's own clips goes from 56–64 % to 96–97 % (measured
against a whisper-large-v3-turbo reference with reading normalization), which
is the inter-model agreement ceiling — an independent SenseVoice run scores
the same recall on the same audio. It also picks up the MOSS-Transcribe
long-audio fixes (#218).
Japanese long-form ASR — issue #89 (parakeet-ja)
The JA FastConformer encoder is unstable past ~12 s of attention context on
real speech, and blanks whole utterances whenever enough context follows them
— upstream NeMo fails identically on the same audio (its plain,
local-attention, and buffered long-form modes score 1–51 % content recall on
the reference clip; our runtime is character-identical to NeMo in the
comparable modes). The new default pipeline works around the model:
- VAD slice cap — VAD/energy slices are capped at 12 s and re-split at
energy minima (never mid-word); each slice decodes in one NeMo-exact pass. - Gap-fill second pass — any span ≥ 1 s the first pass left empty inside
a slice is re-transcribed in isolation and the recovered words merged back.
CRISPASR_GAP_FILL=0disables;CRISPASR_GAP_FILL_MIN_CStunes. - Applied everywhere: CLI, session ABI (all language bindings), and
the OpenAI-compatible server (/v1/audio/transcriptions) via a shared
implementation. - Regression guard: new live test (
test-parakeet-ja-longform) pins the
behavior on a triple-length fixture through the session ABI. - New runtime gate
CRISPASR_PARAKEET_ATT_CONTEXT="L,R"— the equivalent of
NeMo'schange_attention_model("rel_pos_local_attn"), verified
char-identical to NeMo at [128,128].
Measured (phonetic char-bigram recall vs whisper-large-v3-turbo): 60 s clip
97.2 % (was 64.2 %), 120 s 96.9 % (was 61.3 %), 300 s 95.9 %;
precision 90–93 %. Verified on Metal and Vulkan (MoltenVK: 95.1 % on
the same clip — the reporter's backend class).
parakeet-ja GGUFs refreshed (cstr/parakeet-tdt-0.6b-ja-GGUF)
- All files now include the hybrid model's CTC head —
--parakeet-decoder ctcworks (earlier GGUFs lacked the tensors and fell
back to TDT silently). - New q8_0 (TDT output byte-identical to F16 at half the size) — now the
auto-download default forparakeet-ja. - q4_k guidance: TDT decode degrades to repetition loops at q4-class
quantisation on this model (autoregressive decode compounds the quant
noise; pre-existing) — but CTC decode over the same q4_k file is clean.
The runtime now prints a load-time warning suggesting
--parakeet-decoder ctcor the q8_0.
MOSS-Transcribe (#218)
- Degenerate greedy n-gram repetition loops collapsed via the shared
core_ngram::fix_loopspass. - Overlap-save disabled on long-audio slices for this backend (seam
duplicates); long-audio path is 3.3× faster.
Tools
tools/asr_coverage_score.py— char-bigram recall/precision of ASR output
vs a stronger-model reference; separates "silently drops speech" from plain
WER.--strip-latin,--reading(kana/kanji-variant-erasing hiragana
normalization),--per-lineloss localization.tools/nemo_parakeet_blueprint.py— run upstream NeMo's inference modes
(plain / CTC / local attention / buffered) on a.nemocheckpoint to
establish blueprint parity before hunting port bugs.
Docs
docs/cli.md— parakeet long-form section rewritten (JA pipeline, env-var
table incl.CRISPASR_PARAKEET_VAD_SLICE_CAP, gap-fill knobs).--align-onlystandalone CTC forced alignment documented (#217).PERFORMANCE.md— final #89 coverage table;LEARNINGS.md— four
transferable lessons from the #89 audit.
v0.8.7 — new backends (BananaMind-TTS, MOSS-Transcribe, M2M-100) + Granite decode up to 12x + imatrix quant + VibeVoice music-onset fix
CrispASR v0.8.7
This release adds two new backends (BananaMind-TTS-V2.1, MOSS-Transcribe-preview-2B ASR
and M2M-100 translation), a much faster Granite decode path (up to ~12× RTFx via
CUDA-graph capture, in-graph argmax, and fused embedding lookup), a full imatrix
quantization pipeline (producer + consumer, IQ4_NL/XS, per-tensor overrides), and a large
batch of correctness fixes across TADA, MOSS/Vulkan, Granite long-audio, Parakeet, and
VibeVoice TTS.
Highlights: the VibeVoice TTS quantized GGUFs no longer produce a spurious "music"/hum onset
(the diffusion prediction head is now kept at full precision), native-Vulkan segfaults on the
MOSS/MOSS-Audio encoders are fixed, and the Mimi codec now defaults to causal + sliding-window
masking (a measured WER/quality win).
New backends & models
- BananaMind-TTS-V2.1 — new TTS backend (Tacotron-lite acoustic model + HiFi-GAN vocoder),
wired end-to-end perdocs/contributing.md(CLI, C-API, bindings, quantization, tests). - MOSS-Transcribe-preview-2B — new ASR backend (Qwen3-Omni encoder + Qwen3-1.7B LM).
- M2M-100 —
m2m100-f16registered for exact HF translation parity. - Qwen3-ASR-1.7B-JA-Anime-Galgame — auto-download registry entry (#212); the Qwen3-ASR
converter now accepts both-hfand non--hfmodel layouts.
Performance — Granite decode
- CUDA-graph-capture bucketed decode — up to 6.4× faster on CUDA.
- In-graph argmax — up to 12× RTFx, +32% on Q4_K.
- Fused embedding lookup into the captured decode graph (F16); raw-gallocr
allocate-once decode on non-capture backends (Metal). - Measured finding: the Metal ICB graph-replay path is a DUD (decode is GPU-bound); probe
left in behindCRISPASR_METAL_PROFILE.
Quantization
- imatrix (importance-matrix) pipeline — producer + consumer, activation-weighted k-quants,
IQ4_NL / IQ4_XS, and re-quantization directly from an already-quantized GGUF. --tensor-type <regex>=<type>per-tensor overrides, an A/B CER metric, and a
published CC0 calibration set.CRISPASR_QUANT_LMHEAD+ alignerlm_head-at-F16 option (q8-everything aligner is
bit-identical, #192).- VibeVoice diffusion-head carve-out (#171) — for any
vibevoice-*arch the quantizer now
keeps the diffusion prediction head (pred.*), connectors (at_conn.*,se_conn.*), EOS
classifier (tts_eos.*) and speech-type table at source precision; only the Qwen2 backbone
and the deterministic VAE decoder are quantized. This prevents quantization error in the
CFG-driven diffusion head from compounding into a spurious non-speech "music"/hum onset
before the voice. Overridable withCRISPASR_VIBEVOICE_QUANT_ALL=1; guarded by a regression
test. The publishedvibevoice-realtime-0.5b,vibevoice-1.5bandvibevoice-7bGGUFs have
been regenerated with this recipe — re-download to pick up the fix.
Mimi codec
- Causal + sliding-window masking is now the default for
kyutai_sttandcsm_tts
(Mimi decoder transformer) — a measured TTS→ASR / WER A/B win (e.g. csm_tts 9.3% vs 12.0%
WER). SymmetricCRISPASR_MIMI_CAUSALgate to A/B either direction.
Fixes
VibeVoice TTS (#171)
- Voice-prompt KV per-head stride leak that corrupted the speaker prompt on server
multi-request runs (1st/2nd request fine, later requests garbled). - The quantization carve-out above (music/hum onset).
MOSS / MOSS-Audio native Vulkan (#215)
- Root-caused a segfault to a conv graph cached across slices (use-after-free) and to
flash_attn_exton the encoder; fixes drain the queue beforevkResetCommandPool, use
manual masked attention on the encoders, and restore GPU execution on native Vulkan.
- Query-time inline
.wavvoice cloning and config-parity fixes;--make-refreachable and
fails loudly on unresolved--voice;--alignforced-alignment word timestamps;
auto-download oftada-encoder/tada-aligner; generation-loop parity fixes (fixed-step
loop, candidate scoring, default candidates) so words are no longer truncated.
Granite long-audio & templates (#205)
- Recovered dropped chunk-context slices and spaceless text rebuilds; byte-exact chat template
(system turn); route the-plusmodel through the control-token template for real word
timestamps; honour--max-lenon text-only backends.
Parakeet long audio (#208)
- Overlapping-window merge recovers dropped sections; bounded session long-audio encode and
fixed a repeated-call encoder-cache collapse.
Other
- VAD returns empty for silent audio instead of hallucinating (#213).
- Respect
--gpu-backendpreference across all backends (#214). - Kokoro built-in G2P technical-token normalization (#216).
- GLM-ASR / FireRed-ASR warn on unsupported
-linstead of silently ignoring (#199). - PCS/aligner: dequantize FC-head weights (q4_k previously crashed on every inference).
- Central f16→f16 GQA-REPEAT guard for all
kv_self_attncallers on Vulkan (#200); dots-tts
F32 KV read on Vulkan (#200).
Platform & bindings
- Android: native Opus decoding enabled (#26); Media NDK made optional for Termux builds
(#210); CUDA 13 build variant. - Windows: portable
setenv/unsetenvshim for MSVC. - Go bindings: cgo
LDFLAGSsynced (adds-lbananamind-tts) so the static link and the
drift check stay green. - All bindings: expose
transcribe_chunked+ long-form progress callbacks (#208).
v0.8.6 — dots.tts TTS + Higgs-STT / ARK-ASR / Japanese-CTC / Gemma-4 ASR + TADA query-time control
CrispASR v0.8.6
This release adds one new TTS backend and four new ASR/multimodal backends,
makes TADA fully controllable at query time, hardens the native-Vulkan TADA
path, and adds consent-gated speaker identification to diarization — plus a
batch of GPU-stability, server, and build/CI fixes.
What's new
dots.tts — 2B continuous-AR TTS backend (#200)
A new text-to-speech backend for rednote-hilab/dots.tts, a 2B continuous
autoregressive TTS model (Llama-style LLM + flow-matching DiT + BigVGAN vocoder).
- End-to-end synthesis —
"Hello world."and longer text round-trip to
ASR-verbatim audio. The full pipeline is ported and validated against the
PyTorch reference (DiT forward cos = 0.9999, LLM forward cos = 0.999). - CAM++ voice cloning — clone a speaker from a reference clip with
--voice
(encoder cos 0.9996 / global-cond 0.9999 vs reference). - Mixed-quant packaging — the DiT stays F16 while the LLM and PatchEncoder
quantize to Q8/Q4_K (quantizing the DiT derails generation). Published as
f16/q8(3.1 GB) /q4_k(2.3 GB) on
cstr/dots-tts-soar-GGUF. - Incremental PatchEncoder — streaming
O(N²)→O(N)patch encoding so long
text reaches EOS in reasonable time (the earlierO(N³)recompute made long
text too slow to terminate — it was never an EOS bug). - Metal GPU backend — single-backend raw-gallocr compute (no sched hazards),
5.5× faster on long text, ASR-verbatim. Opt out with
CRISPASR_DOTS_TTS_CPU=1. (CUDA path untested.) - Root-cause fix along the way: the LLM step was missing the attention scale
(attn_scale=0→ uniform attention → garbage prefill).
Higgs-Audio v3 STT — Whisper-LV3 + Qwen3-1.7B ASR backend
A new ASR backend for bosonai/higgs-audio-v3-stt (Whisper-large-v3 encoder
- Qwen3-1.7B decoder).
- Chunked Whisper encoder — audio is encoded in independent 4 s chunks with
chunk-local positions and concatenated, matching the upstream blueprint. (A
single padded 30 s window let global attention over the silence-pad derail the
decoder.) Transcribes JFK and a 45 s / 12-chunk clip verbatim vs the bf16
reference at F16 / Q8 / Q4. - Custom prompt —
--ask "<prompt>"steers the decoder (e.g. translation or
Q&A over the audio), with an-l <lang>/params.languagehint. CAP_UNBOUNDED_INPUT | CAP_INTERNAL_CHUNKING— the backend chunks long audio
internally (no CLI window-split duplication).- Published on
cstr/higgs-audio-v3-stt-GGUF.
ARK-ASR-3B — experimental Whisper-RoPE + Qwen2.5-3B ASR backend
A new experimental ASR backend (Whisper-large-v3 encoder with partial RoPE +
MLP adapter + stock Qwen2.5-3B decoder).
- GPU by default (Metal-validated; opt out with
CRISPASR_ARKASR_CPU=1). - Single-pass whole-audio decode — kills the language drift that came from
our 30 s chunking (not the model). Capped by
CRISPASR_ARKASR_MAX_SINGLE_PASS_S=300. - Optional language steering + a live test; diff-harness-validated
(mel cos 0.999993, logits cos 0.999646). - Published as
f16/q8_0/q4_kon
cstr/ark-asr-3b-GGUF. Marked
experimental/WIP.
Parakeet CTC 1.1B (Japanese) — FastConformer-CTC ASR backend
A new Japanese ASR backend for grider-transwithai/parakeet-ctc-1.1b-ja — a
42-layer FastConformer with a CTC decoder.
- Published as
f16/q8_0/q4_kon
cstr/parakeet-ctc-1.1b-ja-GGUF,
with a model card and architecture docs.
Gemma-4 E4B — multimodal ASR model variant (#196)
- Added the
gemma4-e4bmodel (samegemma4architecture as E2B, larger
decoder) to the registry, with a Kaggle conversion kernel and README. Published
oncstr/gemma4-e4b-it-GGUF. - The 12B
gemma4_unifiedvariant is explicitly rejected by the converter with a
clear message (not yet supported).
TADA TTS — query-time control + reliability (#197, #201)
- Single-pass whole-text generation (#197) — TADA now generates the whole
text in one pass like the upstreamtada.py, instead of splitting on
punctuation. Splitting an isolated"Hi."produced a 9.4 s pause + hum; the
whole-text path removes the spurious pauses and hums. - Per-request flow-matching knobs (#197) — expose the acoustic FM controls at
query time:num_fm_steps(accuracy vs speed),acoustic_cfg, and a new
noise_temp. The talker sampler (top_k/do_sample/
num_acoustic_candidates, temperature, rep-penalty) is now per-request and
wired through every consumer (CLI, session ABI, server). - Switch voice per request without a restart (#201) — the HTTP/session path
can change the voice reference between requests (chatterbox-style cached
last-voice key); previously only a restart picked up a new voice.
Diarization — consent-gated speaker identification
- New
--diarize-speakersconvenience alias (enables diarization with
session-scoped speaker clustering → transient(speaker N)labels). - A named, persistent 1:N voiceprint database (
--speaker-db/
--enroll-speaker) is now off by default behind an explicit
--speaker-db-consentflag (GDPR Art. 9 / biometric-data scoping). Session
clustering needs no consent flag; only the persistent named DB does.
Server — diarized JSON output (#205, #206)
- New
diarized_jsonresponse format (#206) — structured per-segment speaker- text output over HTTP.
- Fixed
--max-lenhandling for the granite backend on the server (#205).
Bug fixes & hardening
| Area | Fix |
|---|---|
| TADA / Vulkan (#192) | Native-Vulkan garbled/empty output was the codec, not the FM head — run the DAC codec on CPU when GPU = Vulkan (the codec graph miscomputes at length under MoltenVK; the talker/FM keep their native-Vulkan path). Gated CRISPASR_TADA_VULKAN_NATIVE=1, default CPU-fallback. |
| TADA / Vulkan (#192) | Force F32 KV read on the native-Vulkan path to unblock the GQA REPEAT-f16 abort; direct-on-backend (gallocr) compute for the talker/FM graphs to avoid sched cross-backend corruption; cap codec expansion to prevent a runaway allocation. |
| TADA codec | Dropped 805 MB of dead precomputed attention masks — the codec GGUF shrank from ~1055 MB to ~250 MB (byte-identical output); re-uploaded to cstr/tada-tts-{1b,3b-ml}-GGUF and updated registry size hints. |
| lfm2-audio (#199) | GPU-safe embed + decode — fixes a CUDA ACCESS_VIOLATION crash. |
| dots.tts | Vocoder compute-graph node budget sized for the 6×3 ResBlocks + MI-LSTM at 1024 frames; numerous PatchEncoder / DiT / KV-cache load + graph-size fixes during the port. |
| dots.tts (#200) | Feed the whole text as a single chunk (no sentence-splitting) — removes the per-chunk repeated spoken-disclaimer and split artifacts. |
| dots.tts (#200) | Fix a Metal residency-set teardown abort in the per-stage GPU diff harness (missing free_weights(rw) in 5 functions). |
| Build (#191) | Robust link against system libopusfile; .opus support is now truly optional. |
| crispasr-sys (#203) | build.rs auto-uses Ninja + ccache when available and passes --parallel to cmake --build. |
| CI | Install hipBLAS / rocBLAS and set the ROCm prefix for HIP release builds. |
| CI | Sync the Go cgo LDFLAGS for the new higgs-stt / dots-tts / ark-asr static libs (fixes the Go bindings link + the cgo-ldflags-drift check). |
| Static analysis | Guard an all_times[i] index in the TADA decode expansion (cppcheck containerOutOfBounds). |
Upgrading
No breaking changes to the C ABI, bindings, or CLI flags — all additions.
- Diarization named speaker DB is now opt-in. Session-scoped clustering
(--diarize/--diarize-speakers) is unchanged. The persistent named
voiceprint database (--speaker-db/--enroll-speaker) now requires
--speaker-db-consent; without it those flags are inert. This is a deliberate
privacy default, not a regression. - TADA generates whole text in one pass by default (#197). If you relied on
the previous punctuation-split behaviour, note that single-pass matches the
upstream reference and removes spurious pauses/hums. - New per-request TADA knobs (
num_fm_steps,acoustic_cfg,noise_temp,
talker sampler) and per-request voice switching are additive; older bindings
without the setters soft-no-op.
Full changelog
git log v0.8.5..v0.8.6 --oneline --no-merges
v0.8.5 — TADA multilingual TTS + ReazonSpeech JA ASR + CosyVoice3 GPU + C# bindings
CrispASR v0.8.5
This release makes TADA multilingual TTS production-ready, adds a new
Japanese RNNT ASR backend (ReazonSpeech), moves CosyVoice3 onto the GPU
with batched CFG, and ships C# bindings for the Session C ABI.
What's new
TADA TTS — multilingual, reliable, GPU-accelerated
The bulk of this release. TADA (Llama-3.2 backbone + per-token flow-matching
duration/acoustic head + TADA codec → 24 kHz) went from "English demo" to a
dependable multilingual TTS backend.
Reliable multilingual timing (num_acoustic_candidates)
- TADA's per-token duration head is noise-sensitive: a single unlucky noise
draw can collapse token durations into rushed, garbled speech (a property of
the model — the PyTorch reference behaves identically with the same noise). - Ported the reference's
num_acoustic_candidatesranking: several
flow-matching candidates are drawn per token and the best is kept by
reconstruction likelihood. Default 4 on the CLI and through the C ABI;
override withTADA_NUM_CANDIDATES=N. - All candidates for a step solve in one batched flow-matching forward
(~13N small forwards → ~13), so raising the count adds little wall-clock. - Validated by ASR roundtrip in German and French (single-candidate runs
sometimes garble; candidates=4 is reliable). - Wired through the full session C ABI + every binding (Python, Go, Rust,
Dart, Java, C#, Ruby, JS/WASM) via the new
crispasr_session_set_tts_num_candidates(n)setter — bindings and the HTTP
server get robust timing out of the box, not just the CLI.
Voice references — create your own with --make-ref (no Python)
- New in-tree TADA encoder runtime + converters: build a voice-reference
GGUF directly from a C++ pipeline with--make-ref, no PyTorch required. - Auto-download language voice refs on
-l <lang>: the multilingual 3B-ml
model pulls a matching reference (ar/ch/de/es/fr/it/ja/pl/pt) automatically. - Language-reference GGUFs published to
cstr/tada-tts-{1b,3b-ml}-GGUF.
GPU + quantization
- TADA now runs on the GPU runtime path (Metal/CUDA/Vulkan), sharing the
backend with the codec. - Pos/neg CFG batched into a single B=2 graph per Euler step; prefill tokens
batched and pos→neg KV copied. - Quantized FM Metal fallback + a mixed-precision Q4_K quantizer that
matches the reference's BF16 noise rounding. - Vulkan:
ggml_contmaterialises contiguous copies before the B=2 FM ops.
Timing-embedding correctness (#192)
- Fixed time-embedding during prompt-phase prefill and the time-transition
boundary; only generated acoustic frames (not prompt-phase frames) are passed
to the codec. Together these removed spurious trailing silence and rushed
starts. 1b= English-only;3b-ml= multilingual — now documented, with the voice
cloning +-lauto-download workflow.
Diff harness fairness
crispasr-difffor TADA is now a fair C++-vs-Python comparison (reseed before
generate, store the prompt transcript), confirming the C++ forward pass
matches the reference (time_beforecos=1.0, codec cos=0.99998).
ReazonSpeech — Japanese RNNT ASR
- New backend for
reazon-research/reazonspeech-nemo-v2, a Japanese RNNT
(transducer) ASR model.
CosyVoice3 — GPU generation + perf
- GPU generation enabled (downloads colocated).
- Batched CFG and lazy-loaded cloning encoders (only loaded when voice
cloning is requested). - Right-sized autoregressive KV cache — lower memory, lower latency.
- Full session wiring; latency-tuning + KV-sizing docs added.
C# bindings
- New C# bindings for the CrispASR Session C ABI, with unit tests
(InternalsVisibleTowired so the test project can reachNativeMethods).
Qwen3-TTS
- Encoder transformer is chunked to fix OOM on long reference audio (#187).
Bug fixes
| Area | Fix |
|---|---|
| TADA | Noise-sensitive duration collapse → candidate ranking (default 4) |
| TADA | Time embedding during prompt-phase prefill + time-transition boundary (#192) |
| TADA | Codec fed prompt-phase frames instead of only generated frames |
| TADA | PyTorch-compatible MT19937 noise + BF16 rounding parity |
| TADA | Skip FM solver during prefill to avoid RNG offset |
| TADA | Encoder Conv1d stride padding + tensor layout; float32 cast; transformers 5.x |
| TADA | Language-ref converter: gated Llama → unsloth mirror, HF-token pass, tokenizer dict→str |
| Windows | Guard setenv with _WIN32/_putenv_s in the crispasr-diff TADA path |
| CosyVoice3 | Enable GPU generation; session wiring + formatting |
| Qwen3-TTS | OOM on long reference audio — chunked encoder (#187) |
| Build | Fully fix building against system libopusfile (#191) |
| Registry | Add qwen3-forced-aligner to the model registry (#190) |
| CI | Repair HIP checkout + Android mediandk link |
Upgrading
No breaking changes to the C ABI, bindings, or CLI flags — all additions.
- TADA now ranks 4 timing candidates per token by default (CLI, bindings,
and server). SetTADA_NUM_CANDIDATES=1(orset_tts_num_candidates(1)) to
restore the previous single-draw behaviour. - The new
crispasr_session_set_tts_num_candidates(n)setter is additive; older
bindings without the symbol soft-no-op.
Full changelog
git log v0.8.4..v0.8.5 --oneline --no-merges
v0.8.4
CrispASR v0.8.4
Note: v0.8.3 was tagged before the VERSION file was bumped (binary
self-identified as 0.8.2). v0.8.4 supersedes it and fixes the version
mismatch. All features described here were already in v0.8.3 binaries;
this release adds the Qwen3-TTS one-breath fix, VibeVoice long-input GPU
crash fix, and the release-process hardening.
What's new
Audio format expansion — no ffmpeg required
CrispASR now decodes a much wider range of audio containers and codecs
without any dependency on ffmpeg:
- Opus (
.opus, bare Ogg-Opus): via libopus + libopusfile (FetchContent, auto-downloaded; opt-out with-DCRISPASR_OPUS_FETCH=OFF) - WebM: Ogg-demuxed Opus stream via the same path
- AU / µ-law / AIFF: Sun Audio and classic broadcast formats
- AMR-NB / AMR-WB (
.amr): via opencore-amr FetchContent fork (-DCRISPASR_AMR_FETCH=ON; decoder-only, MIT-compatible) - M4A / AAC / ALAC / CAF on Apple platforms: via AudioToolbox — zero extra dependencies, native OS decode
- M4A / AAC on Linux/Windows: via libfdk-aac loaded at runtime via dlopen — binary stays MIT-clean; falls back gracefully if the library is absent
Go and Ruby bindings expose the same set via their FetchContent link flags.
WASM/Emscripten builds use Opus with x86 SIMD disabled for portability.
Qwen3-TTS improvements
GQA_NATIVE + chunked codec decode (#183)
- Switched attention kernel to
GQA_NATIVEmode — O(N²)→O(N) scaling on Vulkan for long texts - Codec decode is now chunked: VRAM peak stays flat regardless of text length; RTF remains ~0.5×
- Scratch scheduler reset between requests prevents cross-request memory bloat
1.7B small_to_mtp graph fold (#161)
- The
small_to_mtpprojection that previously launched 16 separate GPU graphs per frame is now fused into thecode_predgraph — ~12–15% faster on Metal, ~5–6% on CUDA P100 - Opt-out via
QWEN3_TTS_CP_MTP_NOFUSE=1
CUDA codec chunk cap
- CUDA builds no longer OOM on very long inputs due to oversized codec batches; chunk size is now bounded
One-breath synthesis fix
- Restored single-forward-pass synthesis path that was accidentally broken; multi-sentence inputs no longer stutter at sentence boundaries
VibeVoice TTS fixes
Long-input GPU crash (#171)
- Fixed illegal memory access on CUDA when synthesising long text inputs
Vulkan / RDNA4 segfault (#184)
- Fixed segfault on AMD RDNA4 GPUs caused by strided
AdaLNviews passed directly to Vulkan ops —ggml_contnow materialises contiguous copies before compute - Applies to all Vulkan backends (the
ggml_conton stridedview_2dfix is backend-agnostic)
Bucket scheduler stabilisation (#184)
- Bucket-cache LM step is re-enabled on GPU after fixing the gallocr state lifetime; bucket sched is always reset+alloc'd before use to prevent stale-pointer crashes
Cohere ASR
- Added
CRISPASR_COHERE_LEGACY_SAenv flag to fall back to the pre-#161 self-attention path for users who hit the perf regression on non-GQA architectures
Orpheus GGUF consolidation
All Orpheus 3B GGUF variants (F16, Q8_0, Q4_K) are now consolidated in a single canonical repo cstr/orpheus-3b-0.1-ft-GGUF; the old cstr/orpheus-3b-base-GGUF repo shows a deprecation notice pointing to the new location. Model registry, regression manifest, test harness, and all HF READMEs updated.
iOS / visionOS / tvOS xcframework
- AudioToolbox and CoreAudio frameworks added to xcframework slices (required for AAC/M4A decode on-device)
- Opus and AMR disabled on iOS (FetchContent-built static libs are missing from
libtool -staticcombined archives) - visionOS and tvOS slices skip Opus explicitly to avoid link failures
- Per-slice failure markers added to
build-xcframework.shso partial failures surface individually in CI
Release process hardening (fixes #189)
validate-versionCI job:release.ymlnow checks that theVERSIONfile matches the pushed tag beforepublishruns. A mismatched tag (the v0.8.3 mis-tagging root cause) now fails CI before any artifacts are published.scripts/bump-version.sh: one-step helper that writesVERSION, runssync-version.pyto propagate toCargo.toml/package.json/pyproject.toml/pubspec.yaml, commitsrelease: bump VERSION to X.Y.Z, and creates an annotated tag — eliminating the manual bump-and-forget pattern.
Bug fixes
| Area | Fix |
|---|---|
| VibeVoice | GPU crash on long inputs (#171) |
| VibeVoice | Vulkan/RDNA4 segfault — strided AdaLN views |
| VibeVoice | Stale gallocr bucket sched state |
| Qwen3-TTS | One-breath synthesis regression |
| Qwen3-TTS | CUDA OOM on long codec batches |
| Audio | Windows Media Foundation mfapi.h include order (MSVC) |
| Audio | MinGW uint32_t missing — <cstdint> before miniaudio |
| Build | libopusfile private dependency not linked transitively |
| Build | iOS xcframework FetchContent static lib path |
| CMake | AMR FetchContent URL corrected to CrispStrobe fork |
| CI | Go LDFLAGS sync script missing OPUS_FETCH=ON |
| CI | clang-format on miniaudio_libopus.c |
Upgrading
No breaking changes to the C ABI, Python binding, or CLI flags.
Packages that vendor cstr/orpheus-3b-base-GGUF should switch to
cstr/orpheus-3b-0.1-ft-GGUF. The model files are identical; only the
HuggingFace repo name changed.
Full changelog
git log v0.8.2..v0.8.4 --oneline --no-merges
v0.8.3 — audio format expansion + Vulkan/CUDA fixes + qwen3-tts perf
CrispASR v0.8.3
Patch release — audio format expansion, Vulkan/CUDA fixes, qwen3-tts performance.
New features
-
Audio format support: Opus, WebM, AU, AMR, M4A/AAC (#219).
crispasr_audio_load
now decodes.opus(via libopus/opusfile, BSD-3-Clause),.webm(Opus-in-WebM),
.au(Sun/NeXT),.amr(AMR-NB/WB via opencore-amr), and.m4a/.aac(via
fdk-aac dlopen on Linux, AudioToolbox on Apple). No ffmpeg dependency — all
decoders are either statically linked or dlopen'd at runtime. -
Apple AudioToolbox integration. On macOS/iOS, AAC/M4A/ALAC/CAF/AIFF files
are decoded natively via AudioToolbox — zero additional dependencies.
Performance
-
qwen3-tts: GQA_NATIVE removes O(N^2) scaling (#183). Switching the talker
and code-predictor attention fromGQA_MANUAL_CONTtoGQA_NATIVEeliminates
CPU-siderepeat_4dops that forced 6658 backend switches per request on Vulkan.
RTF stays ~0.5 regardless of text length (was climbing past 1.0 on long texts).
Reported and measured by @proAkdag on AMD RDNA4/Vulkan. -
qwen3-tts: chunked codec decode. The codec decoder now processes in chunks
ofQWEN3_TTS_CODEC_CHUNKframes (default 150) with left-context overlap, so
peak VRAM depends on chunk size, not total sequence length. Env-tunable via
QWEN3_TTS_CODEC_CHUNKandQWEN3_TTS_CODEC_CTX. -
qwen3-tts: scratch scheduler reset. Codec and talker scratch schedulers are
freed after each synthesis request, preventing the galloc high-water-mark from
persisting across requests (3-12 GB VRAM bloat on long sequences). -
qwen3-tts: 1.7B small_to_mtp fold (#161). The 1.7B model's
small_to_mtp
projection is folded into the code-predictor graph, removing a separate compute
pass.
Fixes
-
vibevoice TTS segfault on Vulkan/RDNA4 and CUDA (#184). Two issues fixed:
(1) Non-contiguousggml_view_2dresults in the diffusion prediction head's
AdaLN split caused segfaults on Vulkan when passed toggml_mul/ggml_add—
fixed withggml_contwrappers. Same pattern fixed across all backends
(voxtral4b, zonos, indextts, kugelaudio).
(2) The Lk-bucketed LM step cache skippedsched_reset+alloc_graphwhen
reusing the same bucket, leaving stale gallocr compute buffer state after
ctx->schedran other graphs between calls — causingMUL_MATillegal memory
access on CUDA. Fixed by always resetting+reallocating (cached graph topology
preserved, ~0.1 ms overhead). Reported by @logiclove. -
iOS xcframework opus link errors. FetchContent-built static libraries
(opus, ogg, opusfile) were not included incombined.abecause the
build-xcframework.shglob missed the_deps/directory. Fixed. -
System opusfile pkg-config link (#185).
PkgConfig::OPUSFILEonly included
libopusfile itself, missing private dependencies (libopus, libogg). Fixed by
using${OPUSFILE_STATIC_LIBRARIES}for full transitive linking. Thanks
@BergmannAtmet. -
Cohere legacy self-attention fallback (#161). Added
CRISPASR_COHERE_LEGACY_SAenv var for users who experience performance
regression with the new attention path.
Upgrade
Drop-in for v0.8.2. No model re-download required.
v0.8.2 — chatterbox long-text fixes + long-form chunking + turbo emotion tags
CrispASR v0.8.2
Patch release — chatterbox robustness + chatterbox-turbo emotion tags.
Fixes
-
chatterbox: segfault on very long text (#182). A prompt longer than the
model's text-position table (2050 positions for base T3; the char-level base
tokenizer hits this on a ~4.5 KB paragraph, multibyte scripts with far less)
read past the table and crashed. The token sequence is now bounded to the
model's positional capacity (with a warning), with a defensive clamp at the
embedding site. Five prefill sites (cond + uncond CFG, base + GPT-2 paths) were
affected. -
chatterbox: use-after-free in the long-form chunk loop. Reallocating the KV
cache for a longer chunk left the cached decode step-graphs pointing at freed
tensors → intermittent crash on the 2nd+ chunk (also affected the server
/v1/audio/speechchunk loop). Cached bucket graphs are now invalidated on KV
realloc.
Improvements
-
chatterbox CLI long-form
--tts(§218). Long input is now sentence-chunked
before synthesis (the same pipeline the server already used) — each chunk
synthesises within the model's healthy horizon and the audio is concatenated
with short pauses, so long prompts render in full instead of being truncated. -
chatterbox-turbo emotion/style tags (§217). You can drive turbo prosody with
bracketed tags in the input text:[laugh] [chuckle] [sigh] [gasp] [cough] [groan] [sniff] [shush] [clear throat] [whispering] [angry] [happy] [crying] [fear] [surprised] [sarcastic] [dramatic] [narration] [advertisement]. The
tokenizer now emits these as their special token id (requires the re-uploaded
cstr/chatterbox-turbo-GGUFfiles with the full 50276-token vocab; the
converter now includesadded_tokens.json).
Upgrade
Drop-in for v0.8.1. No model re-download required for the #182 fixes; the turbo
emotion tags need the refreshed turbo T3 GGUFs (re-uploaded to HF).
v0.8.1 — chatterbox-turbo load fix (#181)
CrispASR v0.8.1
Patch release — fixes a chatterbox-turbo loading regression introduced in v0.8.0.
Fixes
- chatterbox-turbo: vocab-mismatch load regression (#181). v0.8.0 added a
strict tokenizer↔embedding consistency check that rejected the published
cstr/chatterbox-turbo-GGUFmodels with
tokenizer has 50257 tokens, T3 text_vocab_size=50276. These files ship the
stock 50257-token GPT-2 tokenizer against a 50276-row text embedding (19
reserved rows) and loaded fine on v0.7.x. The mismatch is benign in this
direction — BPE only emits ids< 50257, and special text tokens are added
by id and bounds-checked againsttext_vocab_size, so the extra rows are never
indexed out of range. The check is now directional: it hard-errors only
whentokenizer > text_vocab_size(a real out-of-bounds risk) and warns +
loads whentokenizer < text_vocab_size. No re-download needed — the turbo
GGUFs already on disk load again. Reported by @niksedk (Subtitle Edit).
Upgrade
Drop-in for v0.8.0. chatterbox-turbo users blocked by the v0.8.0 load failure
should upgrade; everything else is unchanged.