| 513 | } |
| 514 | |
| 515 | std::vector<float> waveform_from_post( |
| 516 | const HiftVocoderWeights & weights, |
| 517 | const std::vector<float> & post, |
| 518 | int64_t frames, |
| 519 | const std::vector<float> & window) { |
| 520 | if (static_cast<int64_t>(post.size()) != kHiftStftChannels * frames) { |
| 521 | throw std::runtime_error("HiFT post shape mismatch"); |
| 522 | } |
| 523 | std::vector<float> complex_spec(static_cast<size_t>(kHiftStftBins * frames * 2), 0.0F); |
| 524 | for (int64_t f = 0; f < kHiftStftBins; ++f) { |
| 525 | for (int64_t t = 0; t < frames; ++t) { |
| 526 | float magnitude = std::exp(post[static_cast<size_t>(f * frames + t)]); |
| 527 | magnitude = std::min(magnitude, 1.0e2F); |
| 528 | const float phase = std::sin(post[static_cast<size_t>((kHiftStftBins + f) * frames + t)]); |
| 529 | const size_t complex_index = static_cast<size_t>((f * frames + t) * 2); |
| 530 | complex_spec[complex_index] = magnitude * std::cos(phase); |
| 531 | complex_spec[complex_index + 1] = magnitude * std::sin(phase); |
| 532 | } |
| 533 | } |
| 534 | const int64_t samples = weights.config.istft_hop * (frames - 1); |
| 535 | auto wav = audio::ISTFT().compute( |
| 536 | complex_spec, |
| 537 | window, |
| 538 | 1, |
| 539 | kHiftStftBins, |
| 540 | frames, |
| 541 | samples, |
| 542 | {weights.config.istft_n_fft, weights.config.istft_hop, weights.config.istft_n_fft}); |
| 543 | for (float & sample : wav.values) { |
| 544 | sample = std::clamp(sample, -weights.config.audio_limit, weights.config.audio_limit); |
| 545 | } |
| 546 | return wav.values; |
| 547 | } |
| 548 | |
| 549 | class F0Runner { |
| 550 | public: |