Kazeia-engine/dist/jni/kazeia_tts_jni.cpp

106 lines
3.9 KiB
C++

// JNI bridge pour libkazeia_tts.so. Thin wrapper autour de tts_engine.{h,cpp}.
// Le handle exposé côté Kotlin est un jlong = (jlong)(TtsEngine*).
//
// Signatures (à matcher dans le .kt) :
// nativeLoad(talkerGguf, vocabGguf, dumpDir, useHtp, nThreads, cpUseCache) : Long
// nativeSynthesize(handle, text, outWavPath, maxSteps, seed,
// cpTemp, cpTopK, cpTopP, cpRepPenalty,
// talkerTemp, talkerTopK, talkerTopP, talkerRepPenalty)
// : IntArray { err, frames, total_ms, prefill_ms, talker_ms, cp_ms, decoder_ms }
// nativeFree(handle)
#include "tts_engine.h"
#include <jni.h>
#include <string>
namespace {
// Helper : récupère une C-string UTF-8 depuis un jstring (rendre à java avec release).
struct JStr {
JNIEnv * env;
jstring j;
const char * c;
JStr(JNIEnv* e, jstring s) : env(e), j(s), c(s ? e->GetStringUTFChars(s, nullptr) : nullptr) {}
~JStr() { if (j && c) env->ReleaseStringUTFChars(j, c); }
};
} // namespace
extern "C" {
JNIEXPORT jlong JNICALL
Java_com_kazeia_tts_TtsJni_nativeLoad(JNIEnv* env, jobject /*thiz*/,
jstring talker_gguf, jstring vocab_gguf,
jstring dump_dir,
jboolean use_htp, jint n_threads,
jboolean cp_use_cache) {
JStr talker(env, talker_gguf);
JStr vocab (env, vocab_gguf);
JStr dump (env, dump_dir);
TtsEngineLoadCfg lc;
lc.talker_gguf = talker.c;
lc.vocab_gguf = vocab.c;
lc.dump_dir = dump.c;
lc.use_htp = (use_htp == JNI_TRUE);
lc.n_threads = n_threads;
lc.cp_use_cache = (cp_use_cache == JNI_TRUE);
auto * eng = tts_engine_load(lc);
return (jlong)(uintptr_t)eng;
}
JNIEXPORT jintArray JNICALL
Java_com_kazeia_tts_TtsJni_nativeSynthesize(JNIEnv* env, jobject /*thiz*/,
jlong handle,
jstring text, jstring out_wav_path,
jint max_steps, jint seed,
jfloat cp_temp, jint cp_top_k, jfloat cp_top_p, jfloat cp_rep_penalty,
jfloat talker_temp, jint talker_top_k, jfloat talker_top_p, jfloat talker_rep_penalty) {
auto * eng = (TtsEngine*)(uintptr_t)handle;
JStr text_s(env, text);
JStr wav_s (env, out_wav_path);
TtsSynthesizeCfg sc;
sc.text = text_s.c;
sc.out_wav_path = wav_s.c;
sc.max_steps = max_steps;
sc.seed = (uint32_t)seed;
sc.cp_temp = cp_temp;
sc.cp_top_k = cp_top_k;
sc.cp_top_p = cp_top_p;
sc.cp_rep_penalty = cp_rep_penalty;
sc.talker_temp = talker_temp;
sc.talker_top_k = talker_top_k;
sc.talker_top_p = talker_top_p;
sc.talker_rep_penalty = talker_rep_penalty;
TtsSynthesizeResult R{ -100, 0, 0, 0, 0, 0, 0, 0 };
if (eng) R = tts_engine_synthesize(eng, sc);
// Pack résultats dans IntArray :
// [0] err
// [1] frames
// [2] total_ms (audio_s codé séparément si besoin = frames/12)
// [3] prefill_ms
// [4] talker_loop_ms
// [5] cp_loop_ms
// [6] decoder_ms
jint out[7];
out[0] = R.err;
out[1] = R.frames;
out[2] = (jint)(R.total_s * 1000.0);
out[3] = (jint)(R.prefill_s * 1000.0);
out[4] = (jint)(R.talker_loop_s * 1000.0);
out[5] = (jint)(R.cp_loop_s * 1000.0);
out[6] = (jint)(R.decoder_s * 1000.0);
jintArray arr = env->NewIntArray(7);
env->SetIntArrayRegion(arr, 0, 7, out);
return arr;
}
JNIEXPORT void JNICALL
Java_com_kazeia_tts_TtsJni_nativeFree(JNIEnv* /*env*/, jobject /*thiz*/, jlong handle) {
auto * eng = (TtsEngine*)(uintptr_t)handle;
tts_engine_free(eng);
}
} // extern "C"