cmake_minimum_required(VERSION 3.22)
project(kazeia-jni)

set(JNILIBS_DIR ${CMAKE_SOURCE_DIR}/../jniLibs/${ANDROID_ABI})

# --- External source paths (for kazeia_llm llama.cpp backend) ---
set(KAZEIA_LLM_DIR    /opt/Kazeia/kazeia-llm)
set(LLAMA_UPSTREAM    /opt/Kazeia/llama-upstream)

# --- Genie JNI bridge (legacy QNN backend, kept for fallback) ---
add_library(genie_jni SHARED genie_jni.cpp)

add_library(Genie SHARED IMPORTED)
set_target_properties(Genie PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libGenie.so)

target_link_libraries(genie_jni Genie android log)
target_compile_options(genie_jni PRIVATE -std=c++17 -O2)

# Whisper.cpp JNI fallback supprimé 2026-05-02 (frozen stack — STT = NPU only).
# Les libggml IMPORTED restent ci-dessous : utilisées par tts_talker_cpu et tts_cp_cpu.

add_library(ggml SHARED IMPORTED)
set_target_properties(ggml PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libggml.so)

add_library(ggml-base SHARED IMPORTED)
set_target_properties(ggml-base PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libggml-base.so)

add_library(ggml-cpu SHARED IMPORTED)
set_target_properties(ggml-cpu PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libggml-cpu.so)

# --- TTS Pipeline: built externally via ExecuTorch cmake, copied to jniLibs ---
# Build with: cd /opt/Kazeia/executorch/build-android && cmake --build . --target tts_pipeline_jni -j$(nproc)
# Then copy to jniLibs/arm64-v8a/libtts_pipeline.so

# --- NEON optimized ops for TTS heads ---
add_library(neon_ops SHARED neon_ops.cpp)
target_link_libraries(neon_ops log)
target_compile_options(neon_ops PRIVATE -std=c++17 -O3 -march=armv8.2-a+fp16)

# --- Mel Extractor (HuggingFace-compatible, no whisper.cpp dependency) ---
add_library(mel_extractor SHARED mel_extractor.cpp)
target_link_libraries(mel_extractor android log)
target_compile_options(mel_extractor PRIVATE -std=c++17 -O2)

# --- TTS Talker CPU runner (chantier ggml-cpu, Phase 1 in-process JNI) ---
# In-process llama.cpp Talker forward, CPU NEON only (n_gpu_layers=0).
# Loads talker_f16.gguf via libllama.so. Headers vendored in include/
# pour autonomie post-purge llama-upstream. Lib output: libtts_talker_cpu.so
add_library(llama SHARED IMPORTED)
set_target_properties(llama PROPERTIES IMPORTED_LOCATION ${JNILIBS_DIR}/libllama.so)

add_library(tts_talker_cpu SHARED tts_talker_cpu.cpp)
target_include_directories(tts_talker_cpu PRIVATE
    ${CMAKE_SOURCE_DIR}/include
)
target_link_libraries(tts_talker_cpu llama ggml ggml-base ggml-cpu android log)
target_compile_options(tts_talker_cpu PRIVATE
    -std=c++17 -O3 -march=armv8.2-a+fp16
    -Wno-unused-parameter -Wno-unused-variable)

# --- TTS CP (Code Predictor) CPU runner ---
# 17-step interleaved decode + 15 dot_argmax NEON classifications per call.
# Loads cp_f16.gguf + cp_heads.bin + cp_codec_embs.bin (125 MB each).
add_library(tts_cp_cpu SHARED tts_cp_cpu.cpp)
target_include_directories(tts_cp_cpu PRIVATE
    ${CMAKE_SOURCE_DIR}/include
)
target_link_libraries(tts_cp_cpu llama ggml ggml-base ggml-cpu android log)
target_compile_options(tts_cp_cpu PRIVATE
    -std=c++17 -O3 -march=armv8.2-a+fp16
    -Wno-unused-parameter -Wno-unused-variable)

# --- TTS Decoder pur ggml C++ (remplace .pte ExecuTorch) ---
# IMPORTANT : link STATIQUE de ggml-base/ggml-cpu/ggml depuis whisper.cpp/ggml
# avec ARM features Optim #1 (armv8.6-a+i8mm+dotprod+fp16+bf16). Le .so résultant
# est autonome, NE DÉPEND PAS des libggml*.so partagées (qui sont en armv8.2 et
# servent à libllama.so pour le talker). Cela évite tout conflit ABI/symboles.
# Build des .a : /opt/Kazeia/kazeia-tts-decoder-ggml/build-android-static/
set(TTS_DECODER_DIR /opt/Kazeia/kazeia-tts-decoder-ggml/src)
# Build static-chraac : ggml depuis chraac-llama (RTF 0.96 mesuré 2026-05-02
# vs 1.47 avec llama-upstream). chraac-llama branche dev-refactoring a un
# ggml-cpu plus récent + repack/sgemm optimisés ARM. Backup ancienne version
# disponible via build-android-static.
set(TTS_DECODER_STATIC_DIR /opt/Kazeia/kazeia-tts-decoder-ggml/build-android-static-chraac)

add_library(tts_ggml_base STATIC IMPORTED)
set_target_properties(tts_ggml_base PROPERTIES
    IMPORTED_LOCATION ${TTS_DECODER_STATIC_DIR}/ggml-build/src/libggml-base.a)
add_library(tts_ggml_cpu STATIC IMPORTED)
set_target_properties(tts_ggml_cpu PROPERTIES
    IMPORTED_LOCATION ${TTS_DECODER_STATIC_DIR}/ggml-build/src/libggml-cpu.a)
add_library(tts_ggml STATIC IMPORTED)
set_target_properties(tts_ggml PROPERTIES
    IMPORTED_LOCATION ${TTS_DECODER_STATIC_DIR}/ggml-build/src/libggml.a)

add_library(tts_decoder_ggml SHARED
    tts_decoder_ggml.cpp
    ${TTS_DECODER_DIR}/decoder.cpp
    ${TTS_DECODER_DIR}/gguf_loader.cpp
)
target_include_directories(tts_decoder_ggml PRIVATE
    ${TTS_DECODER_DIR}
    /opt/Kazeia/whisper.cpp/ggml/include
    /opt/Kazeia/whisper.cpp/include
)
# Static linking : the order matters (ggml depends on ggml-cpu and ggml-base).
# Wrap in --whole-archive to force inclusion of backend register globals.
# -fopenmp pour résoudre __kmpc_* / omp_get_*. libomp.so doit être présent
# dans jniLibs/arm64-v8a/ (copié depuis NDK r27d aarch64).
target_link_libraries(tts_decoder_ggml
    -Wl,--whole-archive tts_ggml_cpu -Wl,--no-whole-archive
    tts_ggml tts_ggml_base
    -fopenmp -static-openmp
    android log m)
target_compile_options(tts_decoder_ggml PRIVATE
    -std=c++17 -O3 -march=armv8.6-a+dotprod+fp16+i8mm+bf16 -fopenmp
    -Wno-unused-parameter -Wno-unused-variable -Wno-unused-function)

