Skip to content

Commit c7e3f4e

Browse files
committed
docs(audio): MTMD streaming verdict + codec_lm completion plan
Verified MTMD's audio streaming support by reading tools/mtmd/mtmd-audio.{h,cpp} and tools/mtmd/mtmd.cpp: Findings: - Public API takes one complete audio bitmap via mtmd_bitmap_init_from_audio(n_samples, data) — no push_chunk surface. - Long audio is split *internally* by the Whisper preprocessor into fixed 30 s / 3000-frame chunks; each chunk runs through the encoder independently (no encoder-KV persistence across them). - mtmd_audio_streaming_istft exists but is for OUTPUT-side spectrogram→waveform reconstruction, not for input encoding. Conclusion: MTMD = whole-utterance input with internal 30 s chunking, fine for ASR / audio-QA / whole-utt chat. Truly-streaming chat (Moshi / Hibiki duplex, Kyutai STT, MiniCPM-o-2.6 TDM, Qwen2.5-Omni 2 s-block audio-in) needs Mimi-as-adapter (codec_encode → user audio codes) on the codec.cpp side instead — no MTMD involvement on input. Then write the codec_lm completion plan (§9), now framed as audio-OUT + coordination work after MTMD takes input off the table: Tier C-1 (≈1 wk): position_kind + step_text_logits + stop flexibility → LFM2-Audio chat (native, no HF fallback) Tier C-2 (≈2 wk): set_user_audio_codes + Mimi-as-adapter integration → Moshi duplex, Hibiki, Kyutai STT Tier C-3 (≈1.5-3 wk): TALKER_TRANSFORMER kind (MoE FFN optional) → Qwen2.5-Omni, Qwen3-Omni-MoE Tier C-4 (≈3 d): state lifecycle (kv_clear, state_clone) Tier C-5/6 (≈10-15 wk total, cherry-pickable): EnCodec, CosyVoice flow-matching dec, HuBERT-unit HiFiGAN, Seamless T2U, Stable Audio VAE, ChatTTS, YuE codec; then MusicGen, MAGNeT, Stable Audio Open, RVC, OpenVoice, Seed-VC, Diff-HierVC, StyleTTS-VC. Total scope for the audio-LM (TTS + chat + duplex + Talker) family post-MTMD: ~6–8 model-weeks (Tier C-1 → C-4). Everything else is opportunistic per-model work that doesn't block the core path.
1 parent 141987c commit c7e3f4e

1 file changed

Lines changed: 205 additions & 0 deletions

File tree

docs/audio_in_implementation.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,211 @@ Gemma-3n USM, Qwen3-Omni AuT). Those still need codec.cpp-side work
109109
`TALKER_TRANSFORMER` kind, dual user-audio-stream, streaming KV
110110
persistence. None of these are duplicated by MTMD.
111111
112+
### MTMD streaming verdict
113+
114+
Read of `tools/mtmd/mtmd-audio.{h,cpp}` and `tools/mtmd/mtmd.cpp`:
115+
116+
- Public API takes one complete audio bitmap via
117+
`mtmd_bitmap_init_from_audio(n_samples, data)`. **No
118+
`push_chunk` / `feed_incremental` surface.**
119+
- Long audio is split *internally* by the Whisper preprocessor into
120+
fixed 30 s / 3000-frame chunks (`frames_per_chunk = 3000` in
121+
`mtmd_audio_preprocessor_whisper::preprocess`). Each chunk runs
122+
through the encoder **independently** — no encoder-KV persistence
123+
between them.
124+
- `mtmd_audio_streaming_istft` exists but is *output-side* (frame-
125+
by-frame spectrogram → waveform reconstruction), not input.
126+
127+
So MTMD supports **whole-utterance input with internal 30 s chunking**.
128+
It does NOT support true incremental streaming where new audio
129+
samples arrive across many small inference steps with encoder state
130+
preserved.
131+
132+
Truly-streaming models (Moshi / Hibiki duplex, Kyutai STT,
133+
MiniCPM-o-2.6 TDM, Qwen2.5-Omni audio-in's 2 s blocks) therefore can't
134+
use MTMD as-is. Two options:
135+
136+
1. Buffer + re-encode periodically (high latency; OK for QA, bad
137+
for duplex).
138+
2. **Bypass MTMD and use Mimi-as-adapter (cluster G in §2.1)** —
139+
run `codec_encode` on incoming PCM chunks to produce Mimi codes,
140+
then feed those codes through `compose_user_audio_codes_embd`.
141+
We already have Mimi `codec_encode` shipped; only the codec_lm
142+
state-machine side needs work.
143+
144+
This means: **whole-utterance audio-in via MTMD is the universal path
145+
for ASR / audio-QA / whole-utt chat; truly-streaming chat uses the
146+
Mimi-as-adapter path entirely on codec.cpp's side**, with no MTMD
147+
involvement at all on the input.
148+
149+
## 9. codec_lm completion plan (audio-OUT side)
150+
151+
With MTMD covering most audio-IN encoder work, the remaining
152+
codec.cpp roadmap focuses on the **audio-OUT** side and the
153+
**semantic coordination** between input + output. Reorganised by
154+
implementation effort and dependency order.
155+
156+
### Tier C-1 — codec_lm semantic extensions (smallest blast radius)
157+
158+
These don't add new graphs; they add knobs to the existing
159+
`residual_depth_ar` runtime + state machine.
160+
161+
1. **`position_kind` per step** — already partially implemented as
162+
`step_mode` in `examples/tts.py`'s TTSSession; promote to a C-side
163+
`codec_lm_state_set_position_kind(state, kind)` so the same
164+
semantics work for Python and any future C client.
165+
- Kinds: `TEXT_ONLY` / `AUDIO_ONLY` / `BOTH` / `DUPLEX`.
166+
- Unlocks: LFM2-Audio chat mode (native), GLM-4-Voice,
167+
Spirit-LM, Mini-Omni-2.
168+
169+
2. **`step_text_logits` accessor** — when `position_kind ∈ {BOTH,
170+
DUPLEX}`, the codec_lm needs to expose a text-logits buffer (the
171+
text head's output for that step) so the caller can sample text +
172+
audio in the same step.
173+
- Unlocks: Moshi text+audio co-emission, Mini-Omni-2 delay-parallel.
174+
175+
3. **Stop-condition flexibility** — current detect_stop is profile-
176+
specific; codec_lm should expose `codec.lm.stop_token` /
177+
`codec.lm.stop_kind ∈ {audio_eos_in_cb_0, text_eos, max_frames}`
178+
so generic profile code can stop without special-casing.
179+
180+
**Implementation cost:** ~1 model-week if approached together. These
181+
are purely state-machine additions; no new ggml graph code.
182+
183+
### Tier C-2 — Duplex + dual-stream user audio
184+
185+
For Moshi / Hibiki / Kyutai STT where the user-audio side is fed in
186+
continuously alongside model emission.
187+
188+
4. **`set_user_audio_codes(state, codec_id, codes, frame_offset)`** —
189+
per-frame push of user-audio codes that the next `step_begin` will
190+
sum into the backbone input embed.
191+
- Internally adds a parallel embed-sum to the existing model-cb
192+
embed-sum. Same shape op, different table.
193+
- Requires the codec_lm GGUF to carry a second compose table
194+
(`lm.compose.user_audio_embd.weight`) when the model has a
195+
user-audio stream.
196+
- Unlocks: Moshi duplex, Hibiki S2S, Kyutai STT (user-only).
197+
198+
5. **Mimi-as-adapter integration on the C side** — `codec_encode`
199+
over PCM → user_audio_codes feeds `set_user_audio_codes`. No new
200+
ggml work; just a Python helper that chains
201+
`codec_decoder.encode(pcm)` → `state.set_user_audio_codes(codes)`.
202+
203+
**Cost:** ~2 model-weeks. Mostly converter + state-machine; the
204+
ggml graph for user-audio embed-sum is structurally identical to the
205+
existing audio-output embed-sum.
206+
207+
### Tier C-3 — Talker transformer (Qwen-Omni)
208+
209+
6. **`CODEC_LM_KIND_TALKER_TRANSFORMER`** new kind:
210+
- Persistent multi-step KV cache (not reset per backbone step,
211+
unlike `residual_depth_ar`).
212+
- `step_begin` *appends* one position; cache only clears on
213+
`codec_lm_state_kv_clear`.
214+
- Talker block is structurally a Qwen3 transformer layer (already
215+
supported by our existing `codec_op_lm_llama_depth_block`).
216+
- For Qwen3-Omni-MoE Talker: blocks are MoE (`qwen3_moe_decoder`
217+
layers). Lift our existing block builder to support MoE FFN,
218+
or wire a separate `talker_moe_block` op.
219+
- Unlocks: Qwen2.5-Omni-7B (non-MoE Talker), Qwen3-Omni-MoE
220+
(MoE Talker).
221+
222+
**Cost:** ~3 model-weeks if MoE FFN is in scope. Without MoE
223+
(Qwen2.5-Omni only) it's ~1.5 model-weeks.
224+
225+
### Tier C-4 — Streaming KV / state lifecycle
226+
227+
7. **`codec_lm_state_kv_clear(state)`** — explicit clear for end-of-
228+
utterance / start-of-new-conversation.
229+
8. **`codec_lm_state_clone(state)`** — copy-on-write KV clone for
230+
speculative-sampling / CFG cond+uncond branching.
231+
232+
**Cost:** ~3 days. Minor API extensions; the KV state is already
233+
heap-managed.
234+
235+
### Tier C-5 — Non-AR audio-output codecs (NEW codec_model converters)
236+
237+
Each of these is a new codec converter + decode graph in
238+
`src/models/`. Not `codec_lm` work; they only need the
239+
`codec.cpp/codec_model` shape.
240+
241+
9. **EnCodec 32 kHz** (4 cb @ 50 Hz) — needed for MusicGen / MAGNeT /
242+
AudioGen audio output. Well-documented AE + RVQ, structurally
243+
close to Mimi. **Easiest.**
244+
10. **CosyVoice-derived flow-matching decoder** — GLM-4-Voice audio
245+
output. Flow-matching ODE solver (similar to Chatterbox-S3G's
246+
CFM Euler steps).
247+
11. **HuBERT-unit HiFi-GAN** — SpeechGPT / Spirit-LM / Llama-Omni audio
248+
output. Unit-conditional vocoder; reuses our HiFiGAN-shaped
249+
infrastructure (Chatterbox-S3G shares it).
250+
12. **ChatTTS codec** — MiniCPM-o-2.6 audio output.
251+
13. **Seamless T2U + HiFi-GAN** — SeamlessM4T-v2 / StreamSpeech audio
252+
output. Two-stage: non-AR seq2seq (T2U) → HiFi-GAN.
253+
14. **Stable Audio VAE** — Stable Audio Open audio output. Diffusion
254+
VAE; pure decode (no AR).
255+
15. **YuE residual-VQ + upsampler** — YuE audio output.
256+
257+
**Cost per codec:** ~1–3 days for EnCodec / HuBERT-unit HiFi-GAN /
258+
ChatTTS / YuE; ~1 model-week for CosyVoice flow-matching dec and
259+
Seamless T2U (more novel graphs).
260+
261+
### Tier C-6 — Non-LM audio-output models (new full pipelines)
262+
263+
These don't fit `codec_lm` shape at all; each is a standalone graph
264+
pipeline under `src/models/`. Listed for completeness.
265+
266+
16. **MusicGen** — EnCodec codec + `parallel_heads_delay`-shaped AR
267+
with codebook-delay + T5 text cross-attention. Mostly fits
268+
existing infra; new is the cross-attention wiring.
269+
17. **MAGNeT** — masked NAR Transformer over EnCodec codes. Needs
270+
new `non_ar_masked_iter` kind.
271+
18. **Stable Audio Open** — DiT over VAE latents; pure diffusion.
272+
Needs DiT block builder.
273+
19. **RVC v2** — HuBERT content + RMVPE f0 + NSF-HiFiGAN. Reuses
274+
Chatterbox-S3G's NSF + STFT in-graph helpers.
275+
20. **OpenVoice v2** — MeloTTS base + ToneColorConverter (VITS).
276+
21. **Seed-VC / Diff-HierVC / StyleTTS-VC** — DiT flow-matching /
277+
diffusion VC variants.
278+
279+
**Cost per model:** 1–2 model-weeks each; large because each VC
280+
family has its own decoder architecture.
281+
282+
### Recommended order across tiers
283+
284+
Order chosen to maximise immediate unlocks per LOC, and to let each
285+
piece be validated by an existing model before depending on it:
286+
287+
1. **Tier C-1 (position_kind + text-logits + stop flexibility)** —
288+
one PR, ~1 model-week. **Unlocks LFM2-Audio chat (native, no HF
289+
fallback) immediately** — we already have all the GGUFs.
290+
2. **Tier C-2 (user-audio compose + Mimi-as-adapter)** — ~2 model-
291+
weeks. Unlocks Moshi duplex + Hibiki + Kyutai STT. Hibiki is
292+
the smallest model in this set (2B), good for smoke validation.
293+
3. **Tier C-4 (state lifecycle)** — ~3 days, can go in parallel.
294+
4. **Tier C-5 #9 (EnCodec)** — ~1 week. Unlocks the MusicGen output
295+
side which is then ~1 more week to wire as #16 in Tier C-6.
296+
5. **Tier C-3 (Talker)** — ~1.5–3 model-weeks depending on MoE scope.
297+
Unlocks Qwen-Omni family. Best done after Tier C-2 so the
298+
`set_user_audio_codes` pattern is already established (Talker uses
299+
a similar "feed accumulated codes back" mechanism).
300+
6. **Tier C-5 remainder + Tier C-6** — opportunistic, model-by-model.
301+
302+
### Total scope estimate
303+
304+
Tier C-1 → C-4 (codec_lm + codec_model semantic extensions, no new
305+
encoder graphs, no non-AR pipelines): **~6–8 model-weeks of focused
306+
work** for the full audio-LM (TTS / chat / duplex / Talker) coverage.
307+
308+
Tier C-5 + C-6 (new codecs + non-AR pipelines): **~10–15 additional
309+
model-weeks** for everything else (music / VC / S2S translation /
310+
diffusion-based output). Each tier-C-5/6 model is independent and
311+
can be cherry-picked based on demand.
312+
313+
Audio-IN: covered by MTMD for whole-utterance cases (~80% of demand);
314+
audio-IN for truly-streaming cases reuses our existing Mimi
315+
`codec_encode` (no new work).
316+
112317
Status today (the 7 wired TTS profiles in `docs/tts_cli.md`): the
113318
output-side audio path is well-covered for both `parallel_heads_delay`
114319
and `residual_depth_ar` kinds. **There is no audio-input adapter, no

0 commit comments

Comments
 (0)