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