@@ -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+
112317Status today (the 7 wired TTS profiles in `docs/tts_cli.md`): the
113318output-side audio path is well-covered for both `parallel_heads_delay`
114319and `residual_depth_ar` kinds. **There is no audio-input adapter, no
0 commit comments