Ming-Omni-TTS#
Ming-Omni-TTS-16.8B-A3B
is a mixture-of-experts audio generation model from inclusionAI. The current SGLang-Omni
serving path supports text-to-speech and zero-shot voice cloning through the
OpenAI-compatible /v1/audio/speech endpoint and produces 44.1 kHz audio.

The serving pipeline keeps the SGLang autoregressive backbone and the Ming acoustic feedback loop in one generation stage:
preprocessing -> reference_encode -> tts_engine -> audio_decode
| ^
+-------+
latent feedback
reference_encode is a no-op for text-only requests. For voice cloning it extracts the speaker
embedding and prompt latents before the autoregressive loop starts. tts_engine runs the
SGLang backbone, FlowLoss/CFM acoustic tail, stop head, and feedback projection. audio_decode
converts the generated latent sequence into the final waveform with the Ming AudioVAE.
Prerequisites#
Install sglang-omni by following Installation, then download
the checkpoint:
hf download inclusionAI/Ming-omni-tts-16.8B-A3B
The provided configuration uses TP1 on GPU 0.
Server Configuration#
sgl-omni serve \
--model-path inclusionAI/Ming-omni-tts-16.8B-A3B \
--config examples/configs/ming_omni_tts.yaml \
--port 8000
The provided configuration enables the AR and acoustic-tail CUDA graphs and a fixed-width CUDA
graph for streaming AudioVAE transitions. Non-streaming full-sequence AudioVAE decode remains
compact eager, and requests are non-streaming unless stream is set.
For non-streaming requests, audio_decode sends the complete generated latent sequence through
one full-sequence AudioVAE decode. Streaming requests use the separate incremental AudioVAE path
with request-local cache and overlap state. Older configs need three changes, all enforced
during config loading: remove decode_mode from the audio_decode stageβs
factory group, because non-streaming chunked decode is no longer supported;
set tts_engine.stream_to to [audio_decode] to declare the latent stream edge; and set
audio_decode.can_accept_stream_before_payload to true so the consumer accepts latents that
arrive while generation is still running. The provided YAML already carries all three.
Cross-request non-streaming AudioVAE batching is not implemented yet. The only supported non-streaming batch configuration is max_batch_size: 1 with max_batch_wait_ms: 0, as shown in the provided YAML; other values are rejected before the server starts.
stream_slots is the maximum number of streaming requests that the AudioVAE decoder can keep active at the same time. Each active stream uses one slot to preserve its decoding progress between audio chunks. If all slots are occupied, additional streams wait until a slot is released. The provided configuration uses stream_slots: 8 to match its concurrency-8 workload. Increasing it supports more simultaneous streams but uses more GPU memory and fixed-graph work; reducing it lowers those costs but also lowers streaming concurrency. It does not change non-streaming batching.
Synthesizing Speech#
Text Only#
curl -X POST http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{
"model": "ming-omni-tts",
"input": "SGLang-Omni is a great project!",
"response_format": "wav"
}' \
--output output.wav
Voice Cloning#
Ming-Omni-TTS currently accepts one local reference clip and requires its transcript. Start the server with access to the directory containing the clip:
sgl-omni serve \
--model-path inclusionAI/Ming-omni-tts-16.8B-A3B \
--config examples/configs/ming_omni_tts.yaml \
--allowed-local-media-path /path/to/references \
--port 8000
Then submit the reference as a file:// URL:
curl -X POST http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{
"model": "ming-omni-tts",
"input": "Get the trust fund to the bank early.",
"references": [{
"audio_path": "file:///path/to/references/prompt.wav",
"text": "We asked over twenty different people, and they all said it was his."
}],
"response_format": "wav"
}' \
--output cloned.wav
ref_audio and ref_text are accepted as shorthand for the single references item.
Streaming#
Streaming returns headerless mono signed 16-bit little-endian PCM (s16le) at 44.1 kHz with
Content-Type: audio/pcm. The X-Sample-Rate, X-Channels, and X-Bit-Depth headers report the
sample rate, channel count, and bit depth; HTTP EOF ends the stream.
Ming AudioVAE uses separate initial and steady cadence settings. Its first non-terminal call
buffers stages.audio_decode.factory.initial_chunk_patches latent patches and emits no PCM; a
later call supplies the right-hand context needed to emit that initial group. Subsequent calls
consume steady_chunk_patches at a time. The provided configuration uses two initial patches and
four steady patches, and the terminal step flushes any remainder. Pipe the response to ffplay
to play it during generation:
curl -sS --fail --no-buffer -X POST http://localhost:8000/v1/audio/speech \
-H "Content-Type: application/json" \
-d '{
"model": "ming-omni-tts",
"input": "SGLang-Omni supports streaming speech generation.",
"stream": true,
"response_format": "pcm"
}' \
| ffplay -nodisp -autoexit -f s16le -ar 44100 -ac 1 -
To save the raw stream instead, use --output output.pcm. The file has no WAV header; convert it
with ffmpeg -f s16le -ar 44100 -ac 1 -i output.pcm output.wav.
Generation Parameters#
Parameter |
Default |
Notes |
|---|---|---|
|
(required) |
Non-empty text to synthesize |
|
|
At most one local reference clip with non-empty |
|
|
Shorthand for the reference clip and transcript |
|
|
Per-request upper bound on acoustic generation steps. The provided configuration accepts values from |
|
|
Non-negative SDE temperature used by the FlowLoss sampler |
|
|
Use |
|
|
Streams raw PCM audio when enabled |
|
|
Only the default voice selector is accepted |
|
|
Other speed values are not supported |
Advanced FlowLoss controls can be passed through stage_params.tts_engine:
{
"stage_params": {
"tts_engine": {
"cfg": 2.0,
"sigma": 0.25,
"temperature": 0.0
}
}
}
cfg must be at least 1e-5 and cannot equal 1.0; sigma and temperature must be
non-negative.
Benchmarking#
The benchmark uses Seed-TTS-Eval with concurrency 8. Run each row below for
both en and zh, replacing {lang} in the output directory:
Response mode |
Input mode |
Scenario flags |
Output directory |
|---|---|---|---|
Non-streaming |
Reference |
(none) |
|
Non-streaming |
Text-only |
|
|
Streaming |
Reference |
|
|
Streaming |
Text-only |
|
|
With the Ming-TTS server running on port 8000, generate each scenario by substituting its language, flags, and output directory in this command:
python -m benchmarks.eval.benchmark_tts_seedtts \
--generate-only --use-existing-server \
--base-url http://127.0.0.1:8000 \
--model ming-omni-tts \
--meta zhaochenyang20/seed-tts-eval-arrow \
--output-dir <output-directory> \
--lang <lang> --ref-format references \
--max-new-tokens 256 --max-concurrency 8 --warmup 8 \
<scenario-flags>
After generation finishes, stop the TTS server and start the ASR server in another terminal:
sgl-omni serve \
--model-path Qwen/Qwen3-ASR-1.7B \
--port 8100
Then transcribe each output directory with the same language and scenario flags used for generation:
python -m benchmarks.eval.benchmark_tts_seedtts \
--transcribe-only --use-existing-server \
--host 127.0.0.1 --port 8100 \
--model ming-omni-tts \
--meta zhaochenyang20/seed-tts-eval-arrow \
--output-dir <output-directory> \
--lang <lang> --ref-format references \
--max-new-tokens 256 --max-concurrency 8 --asr-concurrency 1 \
<scenario-flags>
Benchmark Results#
Recommended Single-H200 TP1#
The recommended TP1 configuration was evaluated on 1Γ H200 141 GB with concurrency 8, eight warmup requests, and the full Seed-TTS-Eval EN and ZH splits. Streaming used two initial patches followed by four-patch steady groups, with the AR, acoustic-tail, and streaming AudioVAE CUDA graphs enabled. Non-streaming requests continued to use compact full-sequence AudioVAE eager decode.
Streaming:
Slice |
Lang |
Samples |
Failed |
Corpus WER |
RTF Mean |
Latency Mean (s) |
First Audio Mean (s) |
Throughput (qps) |
Audio s/s |
|---|---|---|---|---|---|---|---|---|---|
text-only |
EN |
1088 |
0 |
0.95% |
0.2323 |
1.090 |
0.4601 |
7.325 |
34.423 |
text-only |
ZH |
2020 |
0 |
0.68% |
0.2305 |
1.154 |
0.4649 |
6.925 |
34.715 |
reference |
EN |
1088 |
0 |
1.00% |
0.2732 |
1.224 |
0.5948 |
6.526 |
29.586 |
reference |
ZH |
2020 |
0 |
0.75% |
0.2425 |
1.388 |
0.5502 |
5.757 |
33.006 |
Non-streaming:
Slice |
Lang |
Samples |
Failed |
Corpus WER |
RTF Mean |
Latency Mean (s) |
Throughput (qps) |
Audio s/s |
|---|---|---|---|---|---|---|---|---|
text-only |
EN |
1088 |
0 |
0.93% |
0.2162 |
1.019 |
7.838 |
37.071 |
text-only |
ZH |
2020 |
0 |
0.70% |
0.2096 |
1.048 |
7.625 |
38.224 |
reference |
EN |
1088 |
0 |
1.15% |
0.2380 |
1.061 |
7.523 |
33.989 |
reference |
ZH |
2020 |
0 |
0.76% |
0.2009 |
1.148 |
6.963 |
39.871 |
All 12,432 requests completed successfully. Streaming returned its first audio payload in 0.46-0.59 seconds, while non-streaming retained higher complete-response throughput. The worst corpus WER was 1.15%.
Streaming playback continuity:
Slice |
Lang |
Scored |
N/A |
Underrun P95 (s) |
Underrun P99 (s) |
C50 |
C100 |
C200 |
|---|---|---|---|---|---|---|---|---|
text-only |
EN |
1088 |
0 |
0.0000 |
0.0000 |
100.00% |
100.00% |
100.00% |
text-only |
ZH |
2020 |
0 |
0.0000 |
0.0000 |
100.00% |
100.00% |
100.00% |
reference |
EN |
1073 |
15 |
0.0000 |
0.0000 |
100.00% |
100.00% |
100.00% |
reference |
ZH |
2020 |
0 |
0.0000 |
0.0000 |
100.00% |
100.00% |
100.00% |
N/A means that a request returned one PCM payload, so it had no inter-payload seam to score.
All 11,587 later seams had zero measured playback underrun.
Known Limitations#
Serving optimizations. Prefix/radix cache and
torch.compileare not supported and remain disabled in the provided configuration.Reference inputs. The current request adapter accepts one local reference audio file with a non-empty transcript; remote URLs, data URLs, precomputed prompt latents, and speaker embeddings are not supported.
Generation controls. Request-local
seed, logits sampling fields (top_p,top_k,repetition_penalty), named voices, explicit language selection, instructions, and duration control are not supported.initial_codec_chunk_framesis rejected because AudioVAE cadence is a pipeline-level setting.Checkpoint coverage. The current serving implementation supports only the 16.8B-A3B MoE checkpoint; the dense 0.5B checkpoint is not supported.