File size: 2,685 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 | #pragma once
// Host-side chain between encoder.axmodel and decoder.axmodel, pure C++17
// (no Eigen, no torch). Mirrors export/export_onnx.py:host_expand, which
// replicates origin/runtime/models.py:546-558:
//
// w = exp(logw) * x_mask * length_scale
// w_ceil = ceil(w); T' = max(sum(w_ceil), 1)
// attn = generate_path(w_ceil, mask) -- pure integer interval logic
// m_p' = attn @ m_p^T ; logs_p' = attn @ logs_p^T
//
// generate_path produces a 0/1 alignment with exactly one 1 per output frame,
// so the "matmul" is implemented as an exact per-frame gather (same integer
// cumsum intervals, provably identical result).
#include <cstdint>
#include <vector>
namespace inflect {
constexpr int kSampleRate = 24000;
constexpr int kHopLength = 256;
constexpr int kHiddenChannels = 192;
constexpr int kEncoderT = 256; // encoder static token length (0-padded)
constexpr int kDecoderTp = 512; // decoder static frame length per chunk
constexpr int kDecoderOverlap = 64; // frames of overlap between decoder chunks
struct ExpandedPriors {
int t_prime = 0; // T'
// channel-major [kHiddenChannels * t_prime]: element (c, t) at c*t_prime+t
std::vector<float> m_p;
std::vector<float> logs_p;
};
// logw: [t_total] (encoder output logw[0,0,:])
// m_p: [192 * t_total] channel-major (encoder output m_p[0])
// logs_p: [192 * t_total] channel-major
// x_len: number of valid (unpadded) token frames
ExpandedPriors expand_priors(const float* logw, const float* m_p,
const float* logs_p, int t_total, int x_len,
float length_scale);
// z_p = m_p' + randn * exp(logs_p') * variation, channel-major [192 * T'].
// NOTE: std::mt19937_64 + normal_distribution — deterministic within this SDK
// for a given seed, NOT bit-identical to the PyTorch reference.
std::vector<float> inject_noise(const ExpandedPriors& priors, float variation,
uint64_t seed);
// Frame offsets of Tp-sized decoder chunks covering [0, t_prime) with
// >= kDecoderOverlap overlap (EXPORT_NOTES §5.3).
std::vector<int> decoder_chunk_starts(int t_prime);
// Crossfade-append `wav` (samples of chunk starting at `start_frame`) onto
// `out`, overlapping the previous chunk tail by ov_frames frames.
void crossfade_append(std::vector<float>& out, const std::vector<float>& wav,
int ov_frames);
// 5 ms raised-linear edge fade, as origin/inference.py.
void edge_fade(std::vector<float>& waveform, float milliseconds = 5.0f);
void clip_inplace(std::vector<float>& waveform, float lo = -1.0f, float hi = 1.0f);
} // namespace inflect
|