File size: 4,906 Bytes
5eee449 | 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 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | #include "inflect_tts.h"
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include "host_chain.h"
namespace {
// The compiled AXMODELs take S32 token inputs at runtime: the S64
// input_processors of the ONNX graphs are folded into the model at compile
// time (COMPILE_NOTES §3, confirmed by SIMULATE §1).
using token_t = int32_t;
// Index of tensor `name` in `names`; falls back to `fallback` when names are
// unavailable (older runtimes may not report tensor names).
size_t name_index(const std::vector<std::string>& names, const char* name,
size_t fallback) {
const auto it = std::find(names.begin(), names.end(), name);
if (it != names.end()) {
return static_cast<size_t>(it - names.begin());
}
return fallback;
}
} // namespace
InflectTTS::InflectTTS(const std::string& encoder_path,
const std::string& decoder_path)
: encoder_(encoder_path), decoder_(decoder_path) {}
std::vector<float> InflectTTS::synthesize_tokens(
const std::vector<int64_t>& token_ids, float speed, float variation,
uint64_t seed) {
if (speed < 0.5f || speed > 2.0f) {
throw std::invalid_argument("speed must be between 0.5 and 2.0");
}
if (variation < 0.0f || variation > 1.0f) {
throw std::invalid_argument("variation must be between 0.0 and 1.0");
}
// intersperse(add_blank): N phonemes -> 2N+1 tokens.
const int x_len = static_cast<int>(token_ids.size()) * 2 + 1;
if (x_len > inflect::kEncoderT) {
throw std::invalid_argument(
"token sequence exceeds encoder static T=256 (split the text)");
}
// ---- encoder: tokens [1,256] zero-padded + x_lengths [1] -------------
std::vector<token_t> tokens(inflect::kEncoderT, 0);
for (size_t i = 0; i < token_ids.size(); ++i) {
tokens[2 * i + 1] = static_cast<token_t>(token_ids[i]);
}
token_t x_lengths[1] = {static_cast<token_t>(x_len)};
const auto enc_in_names = encoder_.input_names();
std::vector<std::pair<const void*, size_t>> enc_feeds(2);
enc_feeds[name_index(enc_in_names, "tokens", 0)] =
{tokens.data(), tokens.size() * sizeof(token_t)};
enc_feeds[name_index(enc_in_names, "x_lengths", 1)] =
{x_lengths, sizeof(x_lengths)};
auto enc_out = encoder_.run(enc_feeds);
if (enc_out.size() != 3) {
throw std::runtime_error("encoder must produce 3 outputs (m_p, logs_p, logw)");
}
// ---- host chain: durations + generate_path + expansion + noise -------
const auto enc_names = encoder_.output_names();
const float* m_p = reinterpret_cast<const float*>(
enc_out[name_index(enc_names, "m_p", 0)].data());
const float* logs_p = reinterpret_cast<const float*>(
enc_out[name_index(enc_names, "logs_p", 1)].data());
const float* logw = reinterpret_cast<const float*>(
enc_out[name_index(enc_names, "logw", 2)].data());
auto priors = inflect::expand_priors(logw, m_p, logs_p, inflect::kEncoderT,
x_len, 1.0f / speed);
std::vector<float> z_p = inflect::inject_noise(priors, variation, seed);
// ---- decoder: Tp=512 chunks, overlap crossfade, tail trim ------------
const int t_prime = priors.t_prime;
const auto starts = inflect::decoder_chunk_starts(t_prime);
std::vector<float> out;
int prev_end = 0;
for (size_t k = 0; k < starts.size(); ++k) {
const int start = starts[k];
const int take = std::min(inflect::kDecoderTp, t_prime - start);
std::vector<float> z_chunk(
static_cast<size_t>(inflect::kHiddenChannels) * inflect::kDecoderTp, 0.0f);
for (int c = 0; c < inflect::kHiddenChannels; ++c) {
const float* src =
z_p.data() + static_cast<size_t>(c) * t_prime + start;
float* dst =
z_chunk.data() + static_cast<size_t>(c) * inflect::kDecoderTp;
std::memcpy(dst, src, static_cast<size_t>(take) * sizeof(float));
}
std::vector<float> wav = run_decoder_chunk(z_chunk);
if (k == 0) {
out = std::move(wav);
} else {
inflect::crossfade_append(out, wav, prev_end - start);
}
prev_end = start + inflect::kDecoderTp;
}
out.resize(static_cast<size_t>(t_prime) * inflect::kHopLength);
inflect::edge_fade(out);
inflect::clip_inplace(out);
return out;
}
std::vector<float> InflectTTS::run_decoder_chunk(
const std::vector<float>& z_chunk) {
auto dec_out = decoder_.run(
{{z_chunk.data(), z_chunk.size() * sizeof(float)}});
if (dec_out.size() != 1) {
throw std::runtime_error("decoder must produce 1 output (wav)");
}
const size_t n = dec_out[0].size() / sizeof(float);
std::vector<float> wav(n);
std::memcpy(wav.data(), dec_out[0].data(), dec_out[0].size());
return wav;
}
|