crispasr 0.8.22
crispasr: ^0.8.22 copied to clipboard
Lightweight on-device speech recognition via ggml. Supports Whisper, Qwen3-ASR, FastConformer, and more.
Changelog #
0.8.22 #
- TTS provenance opt-out now requires a marking attestation. Synthesis is provenance-marked by default; raw (unmarked) synthesis and an explicit marking-responsibility affirmation are exposed for callers that take responsibility for labeling AI-generated audio. Marked-output flows are unchanged.
- Native improvements that ship with this release (no Dart API change):
- Tiron — a new multi-speaker meeting-ASR model (Whisper large-v3 + inline
speaker markers,
--diarizecross-window speaker linking) is reachable viaCrispasrSession.open()on the whisper path. - Source separation ~26× faster on Linux/Windows —
CrispasrSession.separate()with mel-band-roformer no longer runs the naive scalar path (BLAS + FFT iSTFT- threading), output bit-identical.
- NaN-robust ASR decode — canary-qwen and 7 other backends no longer emit garbage when a quantized weight goes non-finite.
- Tiron — a new multi-speaker meeting-ASR model (Whisper large-v3 + inline
speaker markers,
- No breaking Dart API changes beyond the provenance gate above.
0.8.21 #
--max-new-tokensis honored across all ASR backends. Ten backends (moss-diarize, canary, canary-qwen, glm-asr, funasr, mimo-asr, moss-transcribe, mini-omni2, higgs-stt, higgs) previously hardcoded their decode cap, so a long single-pass transcription truncated. Each now forwards the value while keeping its own default, so nothing regresses.- MOSS TTS synthesis params wired — moss-tts / moss-tts-local now honor max-new-tokens, duration (max-speech-tokens), top-p, top-k, and repetition-penalty instead of staying at hardcoded defaults.
- Chunk-local speaker scope — diarized segments now carry a
chunk_id;(Speaker N)labels are chunk-local, so a consumer useschunk_idto tell continuity from an ID swap. - No Dart API changes.
0.8.20 #
- iOS is now supported. The release ships an Apple
crispasr.xcframework(device + simulator slices for iOS, plus macOS/tvOS/visionOS) for the first time, so a Flutter iOS app can link the native library. Earlier releases shipped no iOS artifact at all. - Prebuilt native library bundles load as delivered. The macOS and Linux
libcrispasrbundles had a broken embedded run-path and could not bedlopened after extraction; they now resolve their bundledggmllibraries relative to their own location. Android and the desktop bundles are laid out as a flatlib/directory. - canary-qwen long audio fixed. Clips longer than ~30 s no longer skip chunking, return near-empty transcripts, or grow memory without bound — the backend had advertised an internal chunker it did not implement (#290).
- No Dart API changes; existing code upgrades untouched.
0.8.19 #
- Beat and downbeat tracking:
CrispasrSession.beats()returns a beat grid from mono 22050 Hz float32 PCM, backed by the Beat This! backend. Adds theBeatrecord typedef (timeS,isDownbeat), abeatsSampleRatecapability probe and abeatsTempoBpmmedian-interval tempo estimate. Previously beat tracking was reachable only from the CLI and the C ABI. - Every downbeat is also reported as a beat: the postprocessor snaps each
downbeat onto its nearest detected beat, so downbeats are a strict subset —
filter on
isDownbeatfor the bar grid, and never merge two lists. - Beat This! is MIT for code and weights and uses no DBN (postprocessing is peak-picking only), so unlike most beat trackers this arm carries none of madmom's patent-encumbered, non-commercially-licensed machinery.
- The native GGUF architecture auto-detect recognises
beat-this, so plainCrispasrSession.open()works for beat models;backend: 'beat-this'remains valid and is required against an older native library.
0.8.17 #
- Source separation:
CrispasrSession.separate()splits interleaved stereo PCM into named stems (drums/bass/other/vocalsfor htdemucs), with theStemrecord typedef and aseparateSampleRatecapability probe. Previously separation was reachable only from the CLI, the C ABI and Python — never from Dart. - Note the input contract:
separate()takes interleaved stereo (L,R,L,R,…) at 44100 Hz, and the native side counts samples per channel. To feed a stem topitch(), downmix to mono and resample to 16 kHz first — the dartdoc has the recipe. - Piano transcription:
CrispasrSession.pianoNotes()returns structured note events —PianoNote = ({int midi, double onMs, double offMs, int velocity})— plus apianoSampleRateprobe. Previously the only route out of the piano backend wastranscribe(), whose segment text reads like"C4 v=80"; parsing that back was lossy. - Native fixes that ship with this release: htdemucs now segments long audio (7.8 s windows, 25% overlap, weighted overlap-add), so separating a full song no longer needs tens of GB — peak memory is flat instead of growing with length. And the htdemucs loader no longer silently zero-fills quantized tensors it cannot read, which had made the q4_k model produce garbage; unreadable weights are now fatal.
0.8.16 #
- Pitch (F0) estimation:
CrispasrSession.pitch()returns a monophonic pitch track from mono 16 kHz float32 PCM, backed by the CREPE backend. Adds thePitchFramerecord typedef (timeMs,f0Hz,voicedProb) and thepitchSampleRatecapability probe. - The native GGUF architecture auto-detect now recognises
crepe(andhtdemucs), so plainCrispasrSession.open()works for those models; previously only the CLI auto-detected them and every binding had to name the backend. Passingbackend: 'crepe'explicitly remains valid and is required against an older native library.
0.8.11 #
- Session introspection accessors: CTC vocab, Whisper
no_speech_prob, anddetected_language, mirrored across the language bindings. - Docs/quality: add an example, enable
lints/core, and apply the resulting fixes (flow-control braces + FFI typedef casing).
0.8.10 #
- Initial pub.dev release for the current CrispASR 0.8 line.
- Exposes Dart FFI bindings for the unified CrispASR session API, Whisper-shaped legacy API, audio decode helpers, language detection, diarization, chat/text helpers, grammar support and alt-token capture.
- Keeps the package pure Dart FFI: native
libcrispasrmust be installed or bundled separately.
0.5.13 #
- Whisper alt-token capture (
--alt Nparity) — per-token top-N alternative-candidate capture for whisper greedy decode. Closes the last open whisper-cli equivalent gap. NewWord.altslist (with a newAltTokenvalue class, defaultconst []so existing call-sites stay source-compatible) on both the low-levelSegmentshape (fromtranscribePcm) and the unified sessionSessionSegmentshape (fromCrispasrSession.transcribe). NewTranscribeOptions.altN(default 0 = off) plumbs through the low-level path; stickyCrispasrSession.setAltN(int)(matches thesetFallbackThresholds/setWhisperDecodeExtraspattern) threads through the session path. Pre-0.5.13 dylibs raiseUnsupportedErrorfor the session setter and reportWord.alts == []from both readers, so apps stay loadable and just hide the affordance. - Capture happens inside
whisper_sample_tokenso the alts are softmax probabilities at the same decode step as the chosen token. Beam search is excluded — siblings are beam-conditional rather than greedy alternatives. Chosen token is not included in the alt list; entries are sorted descending by probability. - Whisper session-transcribe path now also populates
SessionSegment.words(it previously returned only segment-level text) — closes a long-standing gap with the parakeet / canary backends as a side-benefit of needing per-token data for the word-alt mapping. Whisper sub-word BPE means a multi-token word's alts cover the first content token only (e.g. "kubectl" surfaces alts for "kub"); full word-level enumeration is deferred. - C-ABI symbols:
crispasr_params_set_alt_n,crispasr_session_set_alt_n,crispasr_token_n_alts/_alt_id/_alt_p/_alt_text,crispasr_session_result_word_n_alts/_alt_text/_alt_p. New whisper getterswhisper_full_get_token_n_alts/_alt_id/_alt_p(plus_from_statevariants). All nine symbols pinned inbindings_smoke_test.dart. - Live test
test/alt_tokens_live_test.dart(taggedlive) exercises the full stack againstggml-tiny.en.bin+samples/jfk.wav. Asserts ≥1 returned word has alts, every alt's p ∈ [0, 1] and the list is descending, chosen token excluded from its own alts, andsetAltN(0)on a re-decode actually clears them. Skips silently whenCRISPASR_LIB/CRISPASR_MODELaren't set. Representative dev-box result: 22/22 words on JFK get runner-ups (e.g. "Americans → America(4.85%), americ(3.84%), American(3.35%)").
0.5.12 #
- Audio enhancement (RNNoise pre-step) — new top-level
enhanceAudioRnnoise(Float32List pcm)runs xiph/rnnoise v0.1 on a 16 kHz mono float32 buffer (upsample to 48 kHz → RNNoise frame loop → downsample back) and returns a fresh same-lengthFloat32List. Backed by the new C-ABIcrispasr_enhance_audio_rnnoise; pre-0.5.12 dylibs raiseUnsupportedErrorso callers graceful-degrade. State is per-call so worker isolates can run enhancement concurrently without coordination.
0.5.11 #
- Whisper text-suppression + prompt-carry extras — three
more whisper-only
wparamsknobs the CLI surfaces (--suppress-nst,--suppress-regex,--carry-initial-prompt) now have Dart bindings. New sticky setterCrispasrSession.setWhisperDecodeExtras(suppressNonSpeechTokens:, suppressRegex:, carryInitialPrompt:). Empty regex clears any prior pattern (passesnullptrto wparams = whisper's "no suppression" sentinel). Pre-0.5.11 dylibs raiseUnsupportedErrorso callers can graceful-degrade. - Underlying C-ABI:
crispasr_session_set_whisper_decode_extras; three new sticky session fields default to whisper's upstream values so an unmodified session matches stock whisper.cpp.
0.5.10 #
- Whisper decoder-fallback thresholds —
wparamsknobs that decide when the decoder falls back to a higher temperature pass (hard audio, low logprob) or treats a segment as silence are now exposed via the session API:CrispasrSession.setFallbackThresholds(entropyThold:, logprobThold:, noSpeechThold:, temperatureInc:). Mirrors the CLI's--entropy-thold/--logprob-thold/--no-speech-thold/--temperature-inc/--no-fallbackflags.temperatureIncis clamped to[0, 1]; setting0.0disables the temperature-fallback loop entirely (= the CLI's--no-fallback). Defaults matchwhisper_full_default_paramsso an unmodified session behaves bit-identical to stock whisper.cpp. - Underlying C-ABI:
crispasr_session_set_fallback_thresholds. Pre-0.5.10 dylibs raiseUnsupportedError. Non-whisper backends silently ignore — none have an analog for these fields today.
0.4.9 #
- Initial pub.dev release.
- Dart FFI bindings for the CrispASR C ABI (
src/crispasr_c_api.cpp). - Supports all 17 backends: Whisper, Qwen3-ASR, FastConformer, Canary, Parakeet, Cohere, Granite-Speech, Voxtral (Mistral 1.0/4B), wav2vec2, GLM-ASR, Kyutai-STT, Moonshine, FireRed, OmniASR, VibeVoice-ASR, plus FireRedPunc post-processor.
- Unified
SessionAPI across all backends; legacyCrispASRWhisper-shaped API preserved. - Word-level alignment, speaker diarization, and language ID helpers.
- Auto-download of registered models via the model registry.