File size: 3,985 Bytes
a44ca9d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | #include "inflect_tts.hpp"
#include "ax_engine.h"
#include "ax_sys.h"
#include <cstring>
#include <stdexcept>
#include <cmath>
#include <algorithm>
// ---------------------------------------------------------------------------
// TTSEngine β NPU lifecycle
// ---------------------------------------------------------------------------
TTSEngine::TTSEngine(const std::string& encoder_path,
const std::string& decoder_path) {
auto* eng = ax_engine_init();
if (!eng)
throw std::runtime_error("ax_engine_init failed");
enc_engine_ = ax_engine_load_model(eng, encoder_path.c_str());
dec_engine_ = ax_engine_load_model(eng, decoder_path.c_str());
if (!enc_engine_ || !dec_engine_)
throw std::runtime_error("Failed to load AX models");
}
TTSEngine::~TTSEngine() {
if (enc_context_) ax_engine_destroy_context(enc_context_);
if (dec_context_) ax_engine_destroy_context(dec_context_);
}
// ---------------------------------------------------------------------------
// encode β run encoder NPU inference
// tokens [token_len] β 4 output tensors {m_p, logs_p, x, x_mask}
// ---------------------------------------------------------------------------
std::vector<float> TTSEngine::encode(const int64_t* tokens, int token_len) {
// 1) Embedding placeholder β in production, port PyTorch emb via libtorch.
// For now, zeros (caller must supply pre-computed x_emb).
(void)tokens; (void)token_len;
std::vector<float> empty;
return empty; // caller fills via direct x_emb
}
// ---------------------------------------------------------------------------
// decode β run decoder NPU inference
// z_p [kInterChannels * mel_len] β waveform [mel_len * kHopLength]
// ---------------------------------------------------------------------------
std::vector<float> TTSEngine::decode(const float* z_p, int mel_len) {
auto* engine = static_cast<ax_engine_t*>(dec_engine_);
ax_engine_io_t io;
ax_engine_get_io(engine, &io);
// Zero-pad inputs to fixed shapes
std::vector<float> z_p_padded(kInterChannels * kMaxMelFrames, 0.0f);
std::vector<float> y_mask_padded(kMaxMelFrames, 0.0f);
for (int i = 0; i < std::min(mel_len, kMaxMelFrames); ++i) {
for (int c = 0; c < kInterChannels; ++c)
z_p_padded[c * kMaxMelFrames + i] = z_p[c * mel_len + i];
y_mask_padded[i] = 1.0f;
}
std::memcpy(io.inputs[0].data, z_p_padded.data(),
kInterChannels * kMaxMelFrames * sizeof(float));
std::memcpy(io.inputs[1].data, y_mask_padded.data(),
kMaxMelFrames * sizeof(float));
ax_engine_run(engine, &io);
int out_len = std::min(mel_len, kMaxMelFrames) * kHopLength;
std::vector<float> waveform(out_len);
std::memcpy(waveform.data(), io.outputs[0].data, out_len * sizeof(float));
return waveform;
}
// ---------------------------------------------------------------------------
// synthesize β full pipeline
// ---------------------------------------------------------------------------
std::vector<float> TTSEngine::synthesize(const std::string& text,
float speed, float variation) {
// Full pipeline requires:
// 1. Text β phonemes β token IDs (CPU, Python frontend port)
// 2. Token IDs β embedding (CPU, libtorch)
// 3. Embedding β NPU encoder β stats (NPU)
// 4. Duration prediction + alignment (CPU, libtorch)
// 5. z_p β NPU decoder β waveform (NPU)
//
// For a complete C++ pipeline, build with libtorch and the
// Python frontend logic ported to C++. See model_convert/ for
// ONNX sources and compile configs.
//
// This skeleton demonstrates the NPU API β plug in your text
// processor and return raw waveform.
(void)text; (void)speed; (void)variation;
return {}; // skeleton β fill with your full pipeline
}
|