// Engine TTS Qwen3 in-process : load une fois (modèles + fixtures + tokenizer), // synthesize N fois (texte FR -> WAV). Conçu pour être appelé depuis : // - tts_pipeline.cpp (CLI dev) // - kazeia_tts_jni.cpp (bridge Kotlin) // - test_jni_tts.cpp (harness sans VM Java) // // État load-once (poids talker ~1.6 GB, CP ~250 MB, decoder ~325 MB, vocab ~50 MB, // fixtures text_embed ~1.2 GB) = ~3.5 GB cumulé sur tablette. Une seule instance // par process recommandée. #pragma once #include #include struct TtsEngine; // opaque struct TtsEngineLoadCfg { const char * talker_gguf = nullptr; // talker_f32.gguf const char * vocab_gguf = nullptr; // ex: Qwen3-4B-Q4_0.gguf (vocab_only) ; nullptr -> pas de tokenize const char * dump_dir = nullptr; // contient cp_f16.gguf, cp_heads.bin, cp_codec_embs.bin, // qwen3tts_decoder.gguf, text_embed.bin, tp_fc1/2_*, talker_tok_embd.bin, // damien_xvector.bin, manifest_text.txt bool use_htp = false; // true -> HTP0 prefill (option C), false -> CPU pur int n_threads = 6; bool cp_use_cache = true; // KV cache CP (cp_predict_cached) ; false -> cp_predict oracle }; struct TtsSynthesizeCfg { const char * text = nullptr; const char * out_wav_path = nullptr; int max_steps = 256; uint32_t seed = 42; // Sampling : défauts validés à l'écoute (panel A/B) sur tts_engine + chraac subproc. // top_p=0.95 + rep_penalty=1.10 : sweet spot moins robotique, moins de pauses 690 // doublées sur CB0 (cf TU.2 attracteurs identifiés). Ancien défaut top_p=1.0 // rep=1.05 disponible en surcharge via env KZTTS_REPP / KZTTS_TOPP. float cp_temp = 0.9f; int cp_top_k = 50; float cp_top_p = 0.95f; float cp_rep_penalty = 1.10f; float talker_temp = 0.9f; int talker_top_k = 50; float talker_top_p = 0.95f; float talker_rep_penalty = 1.10f; }; struct TtsSynthesizeResult { int err = 0; // 0=ok ; <0 erreur (load/tokenize/decode) int frames = 0; // N frames audio (12.5 Hz) double audio_s = 0; // = frames/12 double total_s = 0; // prefill + talker_loop + decoder (hors writing WAV) double prefill_s = 0; double talker_loop_s = 0; double cp_loop_s = 0; double decoder_s = 0; // Streaming TTFB (Time To First Byte audio) : si KZTTS_STREAM_CHUNK > 0, mesure le // délai entre le début de tts_engine_synthesize et le 1er chunk audio prêt à écrire. // 0 si streaming désactivé. Pour comparer à total_s : audio commence à sortir bien // avant que tout soit fini si streaming actif. double ttfb_s = 0; int n_chunks = 0; // nombre de chunks decoder exécutés (1 = pas de streaming) }; // Charge tout. Retourne nullptr en cas d'échec. // IMPORTANT : llama_backend_init() est appelé en interne (idempotent). TtsEngine * tts_engine_load(const TtsEngineLoadCfg & cfg); // Synthétise une phrase. Réinitialise la KV cache talker avant le prefill, donc // les appels sont indépendants (pas d'état conversationnel). TtsSynthesizeResult tts_engine_synthesize(TtsEngine * eng, const TtsSynthesizeCfg & cfg); // Libère tout. void tts_engine_free(TtsEngine * eng);