| |
| |
| #pragma once |
|
|
| #include <cmath> |
| #include <complex> |
| #include <random> |
| #include <vector> |
|
|
| namespace hift { |
|
|
| constexpr int kSr = 24000; |
| constexpr int kTMel = 198; |
| constexpr float kPadVal = -11.0f; |
| constexpr int kNfft = 16; |
| constexpr int kHop = 4; |
| constexpr int kHarmonics = 9; |
| constexpr float kSineAmp = 0.1f; |
| constexpr float kNoiseStd = 0.003f; |
| constexpr float kVoicedTh = 10.0f; |
| constexpr int kUpsample = 480; |
| constexpr int kSrcLen = kTMel * kUpsample; |
| constexpr int kStftFrames = kSrcLen / kHop + 1; |
| constexpr float kAudioLimit = 0.99f; |
|
|
| using Cx = std::complex<float>; |
|
|
| inline std::vector<float> Hann16() { |
| std::vector<float> w(kNfft); |
| for (int i = 0; i < kNfft; ++i) { |
| w[i] = static_cast<float>(0.5 - 0.5 * std::cos(2.0 * M_PI * i / kNfft)); |
| } |
| return w; |
| } |
|
|
| |
| inline void Fft16(std::vector<Cx>& a, bool inverse) { |
| const int n = 16; |
| for (int i = 1, j = 0; i < n; ++i) { |
| int bit = n >> 1; |
| for (; j & bit; bit >>= 1) j ^= bit; |
| j ^= bit; |
| if (i < j) std::swap(a[i], a[j]); |
| } |
| for (int len = 2; len <= n; len <<= 1) { |
| const double ang = (inverse ? 2.0 : -2.0) * M_PI / len; |
| const std::complex<double> wlen(std::cos(ang), std::sin(ang)); |
| for (int i = 0; i < n; i += len) { |
| std::complex<double> w(1.0, 0.0); |
| for (int j = 0; j < len / 2; ++j) { |
| Cx u = a[i + j]; |
| Cx v = a[i + j + len / 2] * |
| Cx(static_cast<float>(w.real()), static_cast<float>(w.imag())); |
| a[i + j] = u + v; |
| a[i + j + len / 2] = u - v; |
| w *= wlen; |
| } |
| } |
| } |
| if (inverse) { |
| for (auto& x : a) x /= static_cast<float>(n); |
| } |
| } |
|
|
| |
| |
| inline std::vector<float> SourceFromF0(const std::vector<float>& f0, |
| const std::vector<float>& phase, |
| const std::vector<float>& noise, |
| const std::vector<float>& linear_w, |
| float linear_b) { |
| std::vector<float> f0_up(kSrcLen); |
| for (int i = 0; i < kTMel; ++i) { |
| const float v = f0[i]; |
| for (int j = 0; j < kUpsample; ++j) f0_up[i * kUpsample + j] = v; |
| } |
| |
| std::vector<float> sine_wavs(kHarmonics * kSrcLen); |
| for (int h = 0; h < kHarmonics; ++h) { |
| |
| |
| float phase_acc = 0.0f; |
| const double twopi = 2.0 * M_PI; |
| for (int n = 0; n < kSrcLen; ++n) { |
| |
| phase_acc += f0_up[n] * static_cast<float>(h + 1) / static_cast<float>(kSr); |
| double th = twopi * std::fmod(static_cast<double>(phase_acc), 1.0) + phase[h]; |
| sine_wavs[h * kSrcLen + n] = |
| static_cast<float>(kSineAmp * std::sin(th)); |
| } |
| } |
| std::vector<float> s(kSrcLen, 0.0f); |
| for (int n = 0; n < kSrcLen; ++n) { |
| const bool voiced = f0_up[n] > kVoicedTh; |
| const float noise_amp = voiced ? kNoiseStd : kSineAmp / 3.0f; |
| float merged = 0.0f; |
| for (int h = 0; h < kHarmonics; ++h) { |
| const float sw = sine_wavs[h * kSrcLen + n] * (voiced ? 1.0f : 0.0f) + |
| noise_amp * noise[h * kSrcLen + n]; |
| merged += linear_w[h] * sw; |
| } |
| s[n] = std::tanh(merged + linear_b); |
| } |
| return s; |
| } |
|
|
| |
| inline void SourceStft(const std::vector<float>& s, |
| const std::vector<float>& hann, |
| std::vector<float>& s_stft) { |
| constexpr int pad = kNfft / 2; |
| std::vector<float> xp(kSrcLen + 2 * pad); |
| |
| for (int i = 0; i < pad; ++i) { |
| xp[pad - 1 - i] = s[i + 1]; |
| xp[kSrcLen + pad + i] = s[kSrcLen - 2 - i]; |
| } |
| for (int i = 0; i < kSrcLen; ++i) xp[pad + i] = s[i]; |
| s_stft.assign(2 * (kNfft / 2 + 1) * kStftFrames, 0.0f); |
| std::vector<Cx> frame(kNfft); |
| for (int t = 0; t < kStftFrames; ++t) { |
| for (int k = 0; k < kNfft; ++k) { |
| frame[k] = Cx(xp[t * kHop + k] * hann[k], 0.0f); |
| } |
| Fft16(frame, false); |
| for (int b = 0; b < kNfft / 2 + 1; ++b) { |
| s_stft[b * kStftFrames + t] = frame[b].real(); |
| s_stft[(9 + b) * kStftFrames + t] = frame[b].imag(); |
| } |
| } |
| } |
|
|
| |
| inline std::vector<float> Istft16(const std::vector<float>& mag, |
| const std::vector<float>& ph, |
| const std::vector<float>& hann) { |
| constexpr int pad = kNfft / 2; |
| const int n = (kStftFrames - 1) * kHop + kNfft; |
| std::vector<double> out(n, 0.0), wsum(n, 0.0); |
| std::vector<Cx> spec(9); |
| std::vector<Cx> frame(kNfft); |
| for (int t = 0; t < kStftFrames; ++t) { |
| for (int b = 0; b < 9; ++b) { |
| const double m = std::exp(static_cast<double>(mag[b * kStftFrames + t])); |
| const double p = std::sin(static_cast<double>(ph[b * kStftFrames + t])); |
| spec[b] = Cx(static_cast<float>(m * std::cos(p)), |
| static_cast<float>(m * std::sin(p))); |
| } |
| |
| for (int k = 0; k < 9; ++k) frame[k] = spec[k]; |
| for (int k = 9; k < kNfft; ++k) frame[k] = std::conj(spec[kNfft - k]); |
| Fft16(frame, true); |
| const int st = t * kHop; |
| for (int k = 0; k < kNfft; ++k) { |
| const double v = frame[k].real() * hann[k]; |
| out[st + k] += v; |
| wsum[st + k] += static_cast<double>(hann[k]) * hann[k]; |
| } |
| } |
| std::vector<float> y(kSrcLen); |
| for (int i = 0; i < kSrcLen; ++i) { |
| double v = wsum[pad + i] > 1e-8 ? out[pad + i] / wsum[pad + i] : 0.0; |
| v = std::max(-static_cast<double>(kAudioLimit), |
| std::min(static_cast<double>(kAudioLimit), v)); |
| y[i] = static_cast<float>(v); |
| } |
| return y; |
| } |
|
|
| |
| inline std::vector<float> Synth(const std::vector<float>& mel_80xf, |
| int frames, |
| const std::vector<float>& linear_w, |
| float linear_b, |
| const std::vector<float>& f0, |
| const std::vector<float>& raw_mag, |
| const std::vector<float>& raw_ph) { |
| |
| (void)mel_80xf; (void)frames; (void)linear_w; (void)linear_b; (void)f0; |
| (void)raw_mag; (void)raw_ph; |
| return std::vector<float>(); |
| } |
|
|
| } |
|
|