Kazeia-engine/dist/jni/tts_engine.h

97 lines
4.7 KiB
C++

// 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 <cstdint>
#include <string>
#include <vector>
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
// Clonage vocal embarqué (optionnel). Si renseignés, le speaker encoder est chargé en
// RAM (~17 MB f16) et permet de calculer un x_vector depuis n'importe quel WAV via
// tts_engine_encode_speaker_wav(). Sans ces deux fichiers, on garde le x_vector fixture
// (damien_xvector.bin) chargé une fois pour toutes.
const char * speaker_encoder_gguf = nullptr; // ex: speaker_encoder.gguf (17 MB f16)
const char * mel_basis_path = nullptr; // mel_basis_qwen3tts.bin (128*513 f32)
};
struct TtsSynthesizeCfg {
const char * text = nullptr;
const char * out_wav_path = nullptr;
int max_steps = 256;
uint32_t seed = 42;
// Override du x_vector pour ce synth (clonage vocal). Si non-nullptr ET de longueur
// hidden (1024 en pratique), remplace le x_vector chargé. nullptr -> on garde le
// fixture chargé au load. Mémoire owned par l'appelant pour la durée du synth.
const float * xvector_override = nullptr;
int xvector_override_len = 0;
// 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);
// Clonage vocal embarqué : encode un fichier WAV (mono 16-bit 24kHz) en x_vector[1024] f32.
// Requiert que tts_engine_load() ait reçu speaker_encoder_gguf + mel_basis_path.
// Renvoie vecteur vide si encoder non chargé ou échec.
std::vector<float> tts_engine_encode_speaker_wav(TtsEngine * eng, const char * wav_path);
// Idem mais depuis un buffer waveform en mémoire (mono 24kHz, f32 [-1..1]).
std::vector<float> tts_engine_encode_speaker_waveform(TtsEngine * eng, const float * wav, int n_samples);