# VoiceStudio: local dubbing that holds up, on a default voice you can't sell

> Satyajit Ghana — Head of Engineering @ Inkers Technology
> canonical: https://ai.thesatyajit.com/articles/voicestudio
> date: 2026-10-12
> tags: tts, speech, asr, audio, licensing, safety

The post that sent me here was in Spanish and in capitals: "ADIÓS A ELEVENLABS". A developer had built an open-source alternative that clones voices, dubs videos into other languages, makes audiobooks, transcribes, lets you pick between several speech engines, and runs "desde tu propio ordenador". The repo link was in the follow-up post: [debpalash/VoiceStudio](https://github.com/debpalash/VoiceStudio).

I expected a thin Gradio wrapper around F5-TTS or XTTS with a dubbing script bolted on, because most "ElevenLabs killers" turn out to be exactly that. VoiceStudio is not that. It is an Electron desktop app over a FastAPI backend, created on 9 April 2026, and in six months it has collected 59,301 stars, 4,076 commits and 42 releases. I cloned it and read the code as well as the README. Two things surprised me. The dubbing pipeline is more careful than I expected. And the repository's own licence files contradict the post more directly than any critic could.

<RepoCard repo="debpalash/VoiceStudio" />

## What is in the box

The size first, because it changes how you read the rest. Outside tests there are 133,655 lines of Python. The tests are 138,966 lines, with 6,895 test functions, so the test code is bigger than the product code. The Electron renderer and the small Rust desktop helper add another 249,572 lines of TypeScript, JavaScript and Rust, and `docs/` holds 36,137 lines of Markdown. The repo carries a `CLAUDE.md`, an `AGENTS.md` and its own agent skills, and twenty-odd commits a day is the pace of a project written largely with coding agents. I don't mean that as a criticism, but it shows in the style: almost every module opens with a long comment explaining which issue it fixes.

The backend is a set of services (`backend/services/`, about a hundred files) behind HTTP routes, with each TTS engine either imported in-process or run as a sidecar in its own virtualenv. A bundled Python package, `omnivoice/`, holds the default speech model's code. The app is AGPL-3.0. Contributors sign a CLA in favour of Yupcha Softwares, which sells a commercial licence for closed-source embedding and a "Pro" tier. The changelog's unreleased section says remote compute and GPU sharing "moved to VoiceStudio Pro and are no longer included in the open-source app".

<Figure src="https://ai.thesatyajit.com/articles/voicestudio/fig2.png" alt="VoiceStudio's voice cloning workspace: a sidebar with Saved voices and a VoiceStudio Demo Voice, navigation for Clone, Design, Saved, Gallery, Stories, Dubbing, Transcribe, Projects, Tools and Integrations, a script reading 'Every voice has a story. Bring yours to life with VoiceStudio, created on your machine, in your own way.', and a Synthesize audio button. A bottom bar shows integration logos for Twilio, Plivo, Telnyx, n8n, Zapier, Make and GitHub." caption="The voice cloning workspace: pick a voice, type a script, synthesize. Cloning a new voice means adding a reference recording (VoiceStudio README, voice-cloning.png)." />

## The engines are not the ones you would guess

The post says you can choose between several text-to-speech engines without naming them. The names I expected from this genre were F5-TTS, XTTS, Kokoro and Chatterbox, so I grepped for all four. F5-TTS is not an engine; it appears in the project's competitive notes, which pass on it because its "code is MIT but pre-trained weights are CC-BY-NC". Hold on to that sentence. XTTS is not there at all; every hit for `xtts` was the end of the word "IndexTTS". Kokoro and Chatterbox are there, but only through `mlx-audio`, which runs on Apple Silicon and nowhere else.

What actually ships is in `docs/engines/README.md` and `backend/config/models.yaml`. Seventeen speech generators: OmniVoice (the default, branded "VoiceStudio"), an OmniVoice GGUF build and an OmniVoice subprocess mode, CosyVoice 3, VoxCPM2, IndexTTS 2.5, MOSS-TTS-Nano and MOSS-TTS v1.5, dots.tts, Confucius4-TTS, GPT-SoVITS through its own server, KittenTTS, Supertonic-3, Kyutai's PocketTTS (the model behind [Pocket TTS with drifting](/articles/pocket-tts-drifting)), Sherpa-ONNX, the MLX family, and audio.cpp running [Breeze TTS 2](/articles/breeze-tts-2). Most of these are separate installs. A fresh install gets OmniVoice.

Transcription defaults to WhisperX with `large-v3`, with Faster-Whisper, MLX Whisper, PyTorch Whisper, NVIDIA's Parakeet TDT, Moonshine, FunASR's SenseVoice and any OpenAI-compatible endpoint as alternatives. If you have read my piece on [Whisper's hallucinations](/articles/whisper-hallucination-projection), note that dubbing inherits them: a hallucinated line in the transcript becomes a translated, voiced line in the dub.

So the honest summary of the engine story is one default, OmniVoice, and a long tail of opt-ins. Everything interesting about the default experience is therefore about OmniVoice, and it is worth understanding before the pipeline.

## OmniVoice, the model doing the talking

[OmniVoice](https://arxiv.org/abs/2604.00688) is a zero-shot TTS model from Han Zhu and colleagues at Xiaomi and k2-fsa (the Next-gen Kaldi group). The paper calls it "a diffusion language model-style discrete non-autoregressive (NAR) architecture", which is a mouthful for a simple idea.

Audio is first turned into tokens by Boson AI's Higgs Audio v2 tokenizer: at every time step there are 8 codebooks, 8 discrete tokens stacked on top of each other, coarse at the bottom and fine at the top. Generating speech means filling in that grid. An autoregressive model would fill it left to right, one time step at a time. OmniVoice fills it the way a masked language model fills blanks. It starts with every target token set to a mask id, runs a bidirectional transformer over the instruction, the transcript, the reference clip's tokens and the masked target, and commits the predictions it is most confident about. Then it runs again with those filled in. After 32 rounds, every cell is filled.

<Figure src="https://ai.thesatyajit.com/articles/voicestudio/fig4.png" alt="Diagram: a row of inputs at the bottom, Instruct and Transcript as text tokens, a Prompt Segment of three stacked rows of acoustic tokens fully filled in, and a Target Masked Segment where only some acoustic tokens are present. A wide Bidirectional Transformer sits above them, and at the top a Predicted Target grid fills in the tokens that were masked." caption="OmniVoice: text tokens and the reference clip's acoustic tokens condition a bidirectional transformer that predicts the masked tokens of the target segment, all codebooks at once (OmniVoice paper, Figure 1)." />

I read the loop in `omnivoice/models/omnivoice.py`. Each step computes how many tokens to unmask from a shifted time schedule (`t_shift` 0.1), scores every masked position by its log-probability under classifier-free guidance at a scale of 2.0, subtracts a penalty of 5.0 per codebook layer so the coarse layers settle before the fine ones, and takes the top-k. Committed tokens are never revisited. The backbone is initialised from Qwen3-0.6B, which the paper credits for the model's intelligibility.

The paper puts the whole system at 0.8B parameters. I checked that against the files. Reading the safetensors headers over HTTP range requests, `model.safetensors` holds 612,577,288 parameters and the audio tokenizer another 201,400,553, which is 813,977,841 together. Both are stored in float32: the main file alone is 2.45 GB, for a model the app runs in fp16 on CUDA.

The property that matters for dubbing is that duration gets set before generation starts. Because the target is a fixed-size grid of masks, the model has to be told how many frames to fill before it starts. `generate()` takes a `duration` argument and converts it straight into a frame count (`target_tokens = int(duration * frame_rate)`). An autoregressive TTS decides when to stop. OmniVoice is told. Keep that in mind; the dubbing timing modes lean on it.

### 646 languages, most of them thin

The README's "646 languages" comes from OmniVoice. I counted the model card's language list and got exactly 646, and `docs/languages.md` lists the same 646 with training hours per language, adding up to the paper's 581k hours. The distribution is the story. English alone has 206,061 hours, about 35% of the data. The top ten languages hold 84% of it. The median language has 10.2 hours, 528 of the 646 have fewer than 20, and 11 have under one hour. The paper's own histogram, below, says the same thing with a long flat shelf at about ten hours. For a few dozen languages this is a strong cloning model; for most of the 646 it is a model that has heard the language for an afternoon.

<Figure src="https://ai.thesatyajit.com/articles/voicestudio/fig5.png" alt="Bar chart of training hours per language on a log scale against language rank from 1 to 646. A steep head from about 200,000 hours falls to around 100 hours by rank 80, then a long flat shelf near 10 hours runs to about rank 570 before dropping below 1 hour. A legend reads: at least 100K hours: 2; at least 10K hours: 10; at least 1K hours: 33; at least 100 hours: 76; at least 10 hours: 381; at least 1 hour: 635." caption="Training hours per language in OmniVoice's 581k-hour dataset. Only 76 languages have 100 hours or more; most sit on the shelf near ten hours (OmniVoice paper, Figure 3)." />

## Dubbing, traced through the code

Dubbing is the feature that makes VoiceStudio more than a TTS front end, and it is spread over four routers (`dub_core.py`, `dub_translate.py`, `dub_generate.py`, `dub_export.py`, 8,412 lines together) and a dozen services. I followed one video through them, in order.

<Figure src="https://ai.thesatyajit.com/articles/voicestudio/fig1.png" alt="The Video Dubbing Studio screen. The left panel has three numbered sections: Upload and Transcribe with a Choose file button and a field to paste a YouTube or video URL; Dub into, set to Spanish, with a Translator choice between Translate with Agent and NLLB-200 (Local, Heavy); and collapsed Timing and Production overrides sections. The main area shows a demo comparing an English original and a Spanish dub side by side with waveforms, and the transcript of each: 'VoiceStudio is a desktop app for voice cloning, video dubbing, and voice design. It runs entirely on your machine. No accounts, no cloud, no API keys.'" caption="The dubbing workspace, with the bundled English-to-Spanish demo. Note the translator picker in the sidebar: the choice there decides whether this stage stays on your machine (VoiceStudio README, dubbing.png)." />

It starts with ingest. A local file is copied into a job directory; a URL goes through yt-dlp, which can also pull the site's own caption track and skip speech recognition. FFmpeg extracts the audio twice: 16-bit PCM for speech, and a full-quality copy for separation, because separating the downmixed file used to leave the music bed in mono.

Then separation. `ingest_pipeline()` shells out to `python -m demucs.separate --two-stems vocals -n htdemucs` with a 1,800-second timeout. The vocals stem is what every later stage listens to; the rest becomes the background bed for the final mix. If Demucs fails, the job carries on with the full mix as "vocals" and no background, which quietly makes everything downstream worse. On videos, a second FFmpeg pass finds scene cuts (`select='gt(scene,0.3)'`) so later stages can avoid splitting a line across a cut.

Transcription comes next. WhisperX gives word timestamps, which the code treats as the thing lip timing depends on. Speaker labels come from pyannote's `speaker-diarization-3.1`, which is MIT-labelled but gated on Hugging Face, so you have to accept its terms and install it separately. Without it, speakers are guessed from silence gaps, and the app warns you that per-speaker clones need pyannote.

Before anything is translated, the voices are cut. `speaker_clone.py` is where "same speaker, new language" happens. For each speaker it takes clean passages from the separated vocals, rejecting any slice under 1.5 s and any that comes within 0.3 s of another speaker's turn, and concatenates them to between 5 and 15 seconds, aiming for 8. Per-line references are cut too, when the line is at least 3 seconds long, so a shouted line can be dubbed with the prosody of its own source. These clones are scoped to the job and are not saved as voice profiles unless you choose to.

Translation is where locality is decided. The translator registry in `translation_engines.py` has nine providers. The one the dubbing screen starts on is Argos Translate (`useState('argos')` in `useDubWorkflow.js`), which is offline and CPU-only. NLLB-200 600M is the "heavy" offline choice. Google (a free web endpoint through `deep_translator`, no key), DeepL, Microsoft, Amazon, Google Cloud and MyMemory send your dialogue to a service. Any OpenAI-compatible LLM can translate too, and it stays local only if that LLM is Ollama or LM Studio on your machine. The newest option, "Translate with Agent", hands the full ordered dialogue, glossary and per-line time budgets to an installed Claude Code, Codex, OpenCode or Pi CLI. It is careful engineering (strict id-preserving output, no filesystem write access for the agent), and also the least local thing in the app.

The LLM modes do more than translate. Each line has a time budget, and `speech_rate.py` estimates how long a translation will take to say from a per-language characters-per-second table (15 for English, 6 for Chinese, 17 for Hindi, whose combining vowel marks inflate the character count). If a line is predicted to overrun, the LLM is asked for a shorter rewrite, up to 3 attempts, until the predicted ratio sits between 0.92 and 1.08. After a first render, measured durations replace the table.

Each line is then synthesized with its speaker's reference. The app's production defaults are 16 unmasking steps, guidance 2 and speed 1. OmniVoice's own config and paper use 32 steps; the paper's Table 8 shows why the app halves that, with a real-time factor of 0.0319 at 16 steps against 0.0598 at 32 on an H20, batch size 1.

Fitting the result to the picture is the part I enjoyed reading most, and it gets its own section below.

Last comes the mix. Inside each dialogue interval the dub is mixed over the separated background with 10 ms transitions; outside dialogue the original stereo track is kept untouched, so laughter and music between lines survive. If the background is missing, export stops rather than shipping speech alone. FFmpeg muxes the result, and SRT, VTT and ASS subtitle sidecars come from the same segment table.

The widget below is that chain, one stage at a time, with the options each stage offers. It starts on the app's defaults. Change a stage and the footer tells you what leaves your machine and which licences you have just signed up to.

<DubChain />

With the defaults, nothing leaves the machine except the model downloads. That part of the pitch is true. Swap Argos for Google, or the translator for an agent, and your script is on someone else's server; nothing in the UI hides that, but the post does.

## Fitting a translation into a mouth-sized hole

Translations are rarely the length of their source. Spanish and German tend to run long and Chinese short, and a dub line that overruns its slot either talks over the next speaker or keeps talking after the actor's mouth has stopped. Every dubbing tool has to do something about this. VoiceStudio offers four timing strategies, and the one selected by default is labelled "Lip sync".

I expected a lip-sync model behind that button, something like Wav2Lip moving the actor's mouth. There is none. In `DubRightColumn.jsx` the label "Lip sync" is the display name for `strict_slot`, and strict slot uses the property of OmniVoice described above: it passes the original line's duration to the TTS as a target (`_dur_for_tts = seg_duration if strategy == "strict_slot"`), so the model is asked to say the translation in exactly that time, and any remaining mismatch is fixed with a pitch-preserving FFmpeg `atempo` stretch. The dub always lands in the slot. A long translation is simply spoken faster, which the docs admit "can still sound unnaturally fast or slow". It is a sensible default with a misleading name; nobody's lips are synced.

Smart Fit is the interesting one. `backend/services/fit_planner.py` is a pure function, no I/O and no torch, that takes each line's natural-rate TTS duration and its slot, and decides how to reconcile them. Its docstring says it is a clean-room reimplementation from a published description of the audio speed-up and video slow-down approach. First the slot is extended into the silence before the next line, leaving a 50 ms guard. Then it computes `need`, the natural duration divided by that slot:

- up to 1.0, the line fits; if it fills less than 95% of the slot it is slowed toward it, never below 0.85x, so the dub does not go quiet while the face keeps moving;
- up to 1.2, only the audio is sped up, by exactly `need`;
- beyond that, the overrun is split geometrically: the audio is sped up by the square root of `need` (capped at 1.5x) and that stretch of video is slowed by whatever is left (capped at 2x);
- with video retiming off, the audio alone may go up to 1.8x.

The square root is the clever bit. Speeding audio by 1.26x and slowing the picture by 1.26x is far less noticeable than either at 1.6x, and the planner's comment calls it "equal perceptual burden". The caps come with reasons in the code: 1.2x audio is "imperceptible", 1.5x is "the intelligibility cap", 2x video is "the limit before motion looks syrupy". Every slowed segment shifts all later ones, so the planner keeps a cursor and emits a new timeline that `dub_export.py` turns into an FFmpeg filter graph.

<SmartFit />

There is one place where I expected the code to do one thing and it does another. When even the caps cannot absorb a line (above 3x the slot with video retiming on), the planner labels it `overflow_trimmed` and its docstring says the excess is "trimmed at mix time". But the route that calls it, `dub_generate.py` around line 1691, checks the fitted audio against its new slot and, if it runs more than 20 ms over, stops the render with "Speech exceeds the fitting limits. Shorten the translation or choose Strict Slot or Stretch Video before exporting." The planner's docstring is out of date and the behaviour is the better one: VoiceStudio would rather fail than publish a dub with words cut off. Concise mode, which speaks at natural rate and never stretches, makes the same choice.

There is a predictive half too. `duration_planner.py` classifies each translated line before any GPU time is spent: "fits" up to 1.2x, "tight" up to what the caps can absorb, "impossible" beyond, and for impossible lines it can ask the configured LLM for a shorter rewrite. Measuring after synthesis, predicting before it, and refusing to cut words is a better timing story than I have seen in other open dubbing tools.

## Local, yes. Free to sell, no

This is where the post and the repository part ways. "ADIÓS A ELEVENLABS" reads as: you can stop paying for this. For a hobbyist, true. For anyone dubbing a client's video, the repository's own `LICENSE-NOTICE.md` says otherwise.

The app is AGPL-3.0, and commercial use of the app is allowed under it. The weights are a different matter. The default model's card says "The pre-trained model is licensed under the CC-BY-NC due to constraints from its training data (e.g., Emilia)". Its audio tokenizer brings Boson's Higgs Audio 2 terms and Meta's Llama 3 community licence with it. NLLB-200, the best offline translator, is CC-BY-NC-4.0. So the out-of-the-box "best quality, fully offline" chain, OmniVoice plus NLLB, is non-commercial twice over. Remember the competitive notes that passed on F5-TTS because its weights are CC-BY-NC? The default engine has the same licence.

The project knows this, and it says so with unusual care. `backend/config/model_licenses.json` (checked 2026-10-03) records 56 model repositories plus 7 asset families whose licence is unresolved: Demucs's `htdemucs`, AudioSeal's watermark weights, WhisperX's per-language alignment models and VAD, Argos's language packs and others. Of the 56 records, 4 are known non-commercial: OmniVoice, its GGUF build, NLLB and Llama-OuteTTS. The other 52 are "unreviewed", meaning the licence field is whatever the model card says. And the inventory's own summary: "No record currently makes that claim", the claim being commercial clearance. Since the latest changes (#2689), models without a plainly commercial licence, the default included, must have their licence accepted once in the app before first use.

You can assemble a chain from permissively labelled parts: Whisper (MIT on the CTranslate2 conversions), Argos, CosyVoice 3 or VoxCPM2 (both Apache-2.0 on their cards). The widget above shows how much that costs you. You lose OmniVoice's language coverage, Argos is the weakest translator in the list, the separation and alignment weights are still unresolved, and nobody, including VoiceStudio, has reviewed the result. You would have to do that due diligence yourself. ElevenLabs sells you a licence; VoiceStudio hands you a list of licences and a checkbox.

## Consent, watermarks and what the code does not check

Voice cloning is the feature with victims, so I looked for the safeguards.

The watermark is real. `backend/services/watermark.py` routes every path that produces synthetic speech through one function, `mark_synthetic`, which embeds an inaudible AudioSeal watermark carrying a 16-bit message, the ASCII for "OM". A test (`test_watermark_route_coverage.py`) fails if a new synthesis route skips it, which the comment says was added after a fourth route had shipped unmarked. The docstring cites EU AI Act Article 50(2), applicable from 2 August 2026. Two caveats. It is a user preference (`watermark.invisible`, on by default) that anyone can switch off, and it fails open: if AudioSeal is missing or errors, the audio passes through unmarked rather than blocking generation. In open source that is about all a watermark can be, since anyone can delete the call.

The consent lock is weaker than its name. A voice profile becomes "verified own voice" when its owner records themselves reading "I confirm that this voice profile is my own voice, and I consent to VoiceStudio cloning it on my behalf." The backend checks that the recording is over 1,000 bytes and the statement is not empty. It does not compare the speaker of the consent recording with the voice being cloned; the code comment says outright that "The recording is provenance, not a voiceprint check". And the UI states the scope: "Verification will be required for agentic features and community sharing — never for local synthesis." Gallery sharing and personas check the flag. Cloning does not, and dubbing auto-clones every speaker it finds in a video, whoever they are, with no prompt at all. The README's line on the subject is "Clone voices only with permission."

For contrast, the repository's own competitive analysis describes ElevenLabs' voice library as "consent-heavy": a live-read voice captcha, human review, sharing limited to professional clones. I would not expect a local tool to enforce consent, and it cannot; the person at the keyboard owns the process. But a local tool could at least make the dub screen ask, and this one does not.

## What it takes to run

The default engine's guide recommends 6 GB of VRAM on a dedicated GPU, and says 4 GB cards page to system RAM and turn seconds into minutes. The most concrete measurement in the repo is a Tesla T4 note: OmniVoice peaked at 2,487 MiB in `nvidia-smi` (2.050 GB allocated by PyTorch), and once the checkpoint was cached a request took about a second, 0.911 s to 1.574 s over five runs. The first request on a fresh install can fail outright, because the 2.3 GB checkpoint downloads inside the 300 s generation timeout.

Dubbing is heavier, since WhisperX `large-v3` and the TTS model contend for the same GPU. The ASR code budgets 5 GB of VRAM for full `large-v3` and moves the TTS model to CPU while transcription runs. On disk, the "Max" model pack for Linux and CUDA in the screenshot below is five models and 8.5 GB: OmniVoice 2.4 GB, Whisper `large-v3` 2.9 GB, NLLB 2.4 GB, and two small dictation models. CPU-only machines are supported with a CPU PyTorch build (about 5 GB of disk), at a speed the docs describe as several times slower. Intel Macs get the UI only and need a remote backend.

<Figure src="https://ai.thesatyajit.com/articles/voicestudio/fig3.png" alt="VoiceStudio Settings, Models page. A Model packs card titled Tuned for Linux x64 + CUDA offers Fast, Balanced, Quality and Max tiers. Max is selected and lists five installed models: VoiceStudio TTS (k2-fsa/OmniVoice) 2.4 GB, Whisper large-v3 (faster-whisper) 2.9 GB, Whisper Tiny (sherpa-onnx) 0.104 GB, Parakeet TDT v3 (sherpa-onnx) 0.67 GB and NLLB-200 distilled 600M 2.4 GB, totalling 5 models and 8.5 GB installed size. Below are category buttons for TTS, ASR, Dictation, Diarisation, Translation and LLM." caption="The model packs screen: the Max tier for Linux with CUDA is five models and 8.5 GB, two of them (OmniVoice and NLLB) under non-commercial terms (VoiceStudio README, models.png)." />

What the repo does not have is a speed table. `docs/benchmarks.md` describes a careful measurement harness and then says "No verified rows yet". There is no published time-to-dub for a ten-minute video on any GPU, so I cannot give you one either.

## How mature is it

Six months old, and moving fast: version 0.5.7 shipped on 7 October, GitHub counts 93 contributor identities, and the main branch was pushed this morning. The test suite is large, but the docs are candid about what it covers. The dubbing guide ends its verification note with "These checks establish UI wiring, not a completed real model-backed dubbing run", and says multi-speaker timing and voice consistency in a real render "remain unverified". I trust a project more for writing that sentence. I also take it at its word: the pipeline is well engineered on paper and has not been shown end to end on real media in its own test suite.

My read, then. As a local voice-cloning and dubbing workbench for personal projects, it is the most complete open one I have looked at, and its timing code is genuinely thoughtful. As an ElevenLabs replacement for paid work, it is not one out of the box. The default voice and the best offline translator are non-commercial, the rest is unreviewed by the project's own account, and the safety rails stop at a watermark you can switch off. If you need commercially clean dubbing, use the chain widget above to see what you give up, and read the licences yourself.

For neighbouring reading: [Index-Translate](/articles/index-translate) trains one model for text, speech and dubbing translation, [Fish Audio S2](/articles/fish-audio-s2) and [Paradee](/articles/paradee-tiny-tts) are two very different takes on TTS, and [PersonaPlex](/articles/personaplex-full-duplex) and [AuK](/articles/auk-speech-editing) go deeper into single speech models than this piece does.

<ModelCard repo="k2-fsa/OmniVoice" />

## How I checked

I shallow-cloned VoiceStudio at commit `7703ca66` (12 October 2026) and read the backend services and routers named above, the bundled `omnivoice/` model code, the Electron dubbing hooks and components, the engine, performance, hardware and licensing docs, `LICENSE-NOTICE.md` and the changelog. I did not run any of it. Line counts are `wc -l` over `.py` files inside and outside test paths, and over TypeScript, JavaScript and Rust under `electron/` and `native/`; the test-function count is a grep for `def test_`. Stars, forks, creation date, the commit count and the contributor count come from the GitHub API on 12 October. OmniVoice's parameter counts come from reading both safetensors headers on Hugging Face with range requests; the 646 languages and the hour distribution come from counting the model card's language list and summing the hours column of `docs/languages.md`. The paper's numbers (0.8B, 581k hours, 32 steps, guidance 2, RTF 0.0319 and 0.0598) are from the arXiv HTML of 2604.00688v3. Licence labels are from `backend/config/model_licenses.json` and the Hugging Face API. The X post and its thread were read through the fxtwitter mirror. Nothing here measures dubbing quality or speed; there is no published number for either to check.
