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
}