DEV Community

prodbymarcu
prodbymarcu

Posted on

The vendor claimed RTF 0.39, my box ran 0.85

RTF shootout on my M4 mini

A model card's speed number describes two things at once, the vendor's hardware and their build of the runtime, and it says nothing about yours. On my machine the same MLX port came in more than twice as slow as its own card claims, and I adopted it anyway. What decides whether a local TTS model belongs on your box is the latency budget you're inside plus the controls your pipeline needs, neither of those lives on the spec sheet. Measured on 2026-10-28, two cached clips and one cold start, nothing tuned between runs.

What the runs actually cost

The challenger is inclusionAI/Ming-3.0-tts-0.5B, dense, a Qwen2.5-0.5B backbone with a DiT head, an audio tokenizer and a CAM++ speaker encoder, 44.1 kHz output. The port I ran is mlx-community/Ming-3.0-tts-0.5B-8bit, 1.5 GB on disk. Cached runs on my M4 mini: clip B took 6.29 s of generation for 7.40 s of audio, RTF 0.85, clip C took 6.37 s for 7.30 s, RTF 0.87. The first run was 33.0 s wall, 24 s of that HF download, which is why nobody should quote their first run as a benchmark. Output came back 44.1 kHz mono 16-bit. Sample size is honest at n=2 cached clips, the spread between them is 0.02 RTF and both land in the same half-second of budget.

First run against cached runs

Where the card's number came from

The port claims RTF 0.39 and peak 2.2 GB on an M4 Pro, I'm a plain M4 mini, so my measured 0.85 against their claimed 0.39 is a 2.2x gap, well outside anything rounding explains. Same with the quality tables, the HF card carries vendor-run benchmarks, Seed-TTS eval EN WER 1.584% and similarity 0.691 against CosyVoice3-1.5B at 1.45%/0.695, GLM-TTS 2.23%/0.672 and F5-TTS 1.83%/0.647, Qwen3-TTS-1.7B best 1.24%, plus a MiniMax multilingual set (DE 0.365%, ES 1.099%, FR 4.264%, KO 1.728%, JA 3.765%). None of it re-measured by me, one of those rows loses to FireRedTTS3 anyway. The card was created 2026-09-22 and last touched 2026-10-27, sitting at 161 likes and 6,316 downloads a month when I checked. Those tables are a lead you verify on your own hardware before quoting them, the only quality claim in this piece is the one I ran myself.

Why twenty times slower still took the slot

My baseline lane is Phonon S 31M q8, measured on this same machine, RTF 0.043, time to first chunk 8-23 ms, load 0.18 s warm against 4.5 s cold, 24 kHz, English only. Ming runs about twenty times slower there, and speed is where Phonon keeps the win. Capability is where it doesn't compete, add_voice wants .safetensors from Gradium Studio and there's no audio-prompt path at all, so no style instruction and no delivery control.

What Ming brings over that a fast small model doesn't have is zero-shot cloning from a short reference clip, Voice Design from a natural-language description, freeform delivery control, fourteen inline paralinguistic tags (breath, cough, sigh, laughter, hesitation, surprise), explicit emotion, speed, pitch and volume, built-in voices like UK_George and US_Emma, seven languages plus Sichuanese and Cantonese dialects. The adoption decision then reads as a match between controls and use cases, with RTF entering through whichever budget you're inside. A twenty-times gap that buys style direction and cloning opens a second lane next to the one you keep for speed.

Where the slower lane still loses

Live calls. At RTF 0.85 a seven second line costs roughly 6.4 seconds to render, so Ming is wrong for anything duplex or turn-critical, the speech lane on my call stack stays on the fast model. The port carries three known gaps, CAM++ speaker embeddings never got extracted in MLX so cloning runs off reference audio plus transcript only, text normalization is unported so numbers go in written as words, and the stop head occasionally fails behind real speech. That last gap gets a number on the record before any listening, the trailing second of a sample sits at RMS 1439 out of 32767, a non-zero tail your ears judge as artifact or breath.

The trap that cost more than the model

The port requires mlx-audio 0.6.1 or newer because 0.6.0 and earlier versions say the wrong words, that's the prompt-contract fix in mlx-audio #1047. No benchmark table catches it, no exception fires, the model speaks fluently in the wrong sentence. I installed 0.6.3 and checked the floor before benching anything. Version floors on ports deserve the same treatment as quantization, a mismatch there produces plausible audio that fails transcription against what you asked for.

What shipped

Three clips went to listening, ming_freeform at 6.4 s, ming_tags at 7.4 s, ming_pitch at 7.3 s, all from cached runs on this box, plus the two lanes sitting side by side with Phonon still the default for speed. Adoption waits on listening to those three clips here, the vendor WER table never enters the decision. The ASR siblings in the same family (Ming-3.0-asr-tiny, Ming-3.0-audio-flash, community GGUFs at 12,399 downloads a month) are where the GPU boxes get them, since NVIDIA's 34B Transcribe wants H100-class hardware while both my cards already sit at 23,494 and 23,503 MiB of 24,576 used.

The claim survives on one number pair, 0.85 measured against 0.39 claimed, and on one rule, check the dependency floor before you bench because the silent failure mode speaks fluent garbage. Does anyone fold the version-floor check into their bench script, or is that still folklore? And what's your bar before adopting something twice off its card number?

Top comments (5)

Collapse
 
prodbymarcu profile image
prodbymarcu •

The ratio checks out, which is the part I should have looked at before writing. 0.85 against your 2.2x bandwidth gap lands near their 0.39, so the vendor claim may be internally consistent and my box is simply the slower half. Keeping the headline honest: I never ran the port on Pro-class hardware here, so 0.39 stays vendor-reported in this article. Testing on a Pro comes before calling anyone wrong.

Collapse
 
ilragioniere profile image
Riccardo Vitali •

Your box is the slower half, and that is the receipt, not the doubt.

Take the product instead of the ratio. If weight reads dominate, RTF x bandwidth belongs to the model, not to the machine: bandwidth cancels, and what is left is bytes of weight traffic per second of audio.

Theirs: 0.39 x 273 = 106.
Yours: 0.85 x 120 = 102, and 0.87 x 120 = 104.

Three numbers, one constant, 4 percent spread, inside your own n=2. That is a better receipt than a Pro run, because it is a quantity a reader on any Mac can compute from their own box without trusting either of us.

It also closes your open question without a rental. That constant is decode passes per audio second times bytes per weight pass. Had their 0.39 come from a 4-bit build, k would land near 53, not 106. Had it come from a batched run, it would sit well below your 102 instead of on it. So the agreement is evidence they ran the same 8-bit port in the same regime, and sequence length barely touches it, because the traffic is weights and not attention.

The threshold worth publishing: a Pro-class run between 0.36 and 0.43 keeps the fit. Above 0.45 (k over 123) and the bandwidth story is incomplete rather than wrong. Near 0.30 and they were batching.

Collapse
 
prodbymarcu profile image
prodbymarcu •

That floor is where my note landed too. mlx-audio below 0.6.1 says the wrong words because their prompt contract changed in issue #1047, and pip with mlx-audio>=0.6.1 put me at 0.6.3 on first install. Silent output corruption means the version check belongs in front of the run, since nothing downstream looks wrong when the transcript drifts.

Collapse
 
ilragioniere profile image
Riccardo Vitali •

One division changes the headline. The card says M4 Pro, you are on an M4 mini, and that gap is 273 GB/s against 120, a ratio of 2.275. Your measured gap is 0.85/0.39 = 2.18. So the card's number converted to your machine is 0.39 x 2.275 = 0.887, and you measured 0.85 and 0.87. You are about 4 percent better than the conversion, not 2.2x worse than the claim.

That works because an 8-bit 0.5B model reads weights it cannot keep resident for every generated second, so the traffic per second of audio scales with the weights and RTF tracks memory bandwidth more or less one to one. Which means the card was not lying about its own box. "The vendor claimed 0.39, my box ran 0.85" is the wrong sentence for a comparison across two SoCs. The sentence that survives is: they claimed 0.39 on a part with 2.3x the bandwidth, the prediction for mine is 0.89, I got 0.85.

What would break the fit is if their 0.39 came from a different sequence length or a differently quantized build. Do you know their sequence length, and whether it was the same 8-bit port? Because if the two numbers meet the bandwidth ratio without being made to, your result is stronger than the piece claims: you reproduced a vendor benchmark on weaker hardware, and almost nobody does that. A card you can predict from spec is a card worth trusting; a card you cannot is the one to throw out, and yours is the first kind.

Collapse
 
jes_p_d4f61f7aa2ec405a418 profile image
Dev_PJS •

The version-floor trap is the part that stayed with me — mlx-audio 0.6.0 and earlier speaking fluently in the wrong sentence, with no exception firing, is much scarier than a slow benchmark because you could ship it without noticing. I also liked the honesty about the first run: 33 seconds wall with 24 seconds of that being a download should not count as a benchmark, and n=2 cached clips at 0.85 and 0.87 is still more useful than a big vendor table. Keeping two lanes makes sense to me — Phonon at 0.043 for live calls, and this one for zero-shot cloning and delivery control even at roughly twenty times slower. Do you actually fold the version-floor check into a bench script now, or is it still a manual check before the run?