35template <
typename SampleType =
float>
46 fft_size_ = round_to_pow2(
config.fft_size > 1 ?
config.fft_size : 2048);
48 config.synthesis_hop > 0 ?
config.synthesis_hop : fft_size_ / 4;
49 if (synthesis_hop_ < 1) synthesis_hop_ = 1;
51 fft_size_,
config.window, SampleType{0});
60 std::vector<SampleType>
time_stretch(
const std::vector<SampleType>& input,
61 double factor)
const {
62 const int N = fft_size_;
63 if (input.empty() || factor <= 0.0 || N <= 1)
return input;
66 factor = std::min(factor, kMaxStretch());
68 const std::size_t n_in = input.size();
70 const std::size_t target =
static_cast<std::size_t
>(
71 std::lround(
static_cast<double>(n_in) * factor));
73 const int Hs = synthesis_hop_;
74 int Ha =
static_cast<int>(std::lround(
static_cast<double>(Hs) / factor));
77 if (n_in <
static_cast<std::size_t
>(N)) {
82 return resample_linear(input, target);
85 const int num_frames =
86 static_cast<int>((n_in -
static_cast<std::size_t
>(N)) / Ha) + 1;
87 const std::size_t out_len =
88 static_cast<std::size_t
>(num_frames - 1) * Hs + N;
90 std::vector<SampleType> out(out_len, SampleType{0});
91 std::vector<SampleType> norm(out_len, SampleType{0});
94 std::vector<std::complex<SampleType>> buf(N);
95 std::vector<double> prev_phase(N, 0.0);
96 std::vector<double> sum_phase(N, 0.0);
98 for (
int frame = 0; frame < num_frames; ++frame) {
99 const std::size_t in_pos =
static_cast<std::size_t
>(frame) * Ha;
100 const std::size_t out_pos =
static_cast<std::size_t
>(frame) * Hs;
102 for (
int k = 0; k < N; ++k)
103 buf[k] = std::complex<SampleType>(input[in_pos + k] * window_[k],
106 fft.forward(buf.data());
108 for (
int k = 0; k < N; ++k) {
109 const double mag = std::abs(buf[k]);
110 const double phase = std::arg(buf[k]);
111 const double omega = kTwoPi() *
static_cast<double>(k) / N;
114 sum_phase[k] = phase;
116 const double expected =
static_cast<double>(Ha) * omega;
117 const double dev = princarg((phase - prev_phase[k]) - expected);
118 const double true_freq = omega + dev /
static_cast<double>(Ha);
119 sum_phase[k] +=
static_cast<double>(Hs) * true_freq;
121 prev_phase[k] = phase;
122 buf[k] = std::polar(
static_cast<SampleType
>(mag),
123 static_cast<SampleType
>(sum_phase[k]));
126 fft.inverse(buf.data());
128 for (
int k = 0; k < N; ++k) {
129 out[out_pos + k] += buf[k].real() * window_[k];
130 norm[out_pos + k] += window_[k] * window_[k];
134 for (std::size_t
i = 0;
i < out_len; ++
i)
135 if (norm[
i] >
static_cast<SampleType
>(1
e-8)) out[
i] /= norm[
i];
141 out.resize(target, SampleType{0});
149 std::vector<SampleType>
pitch_shift(
const std::vector<SampleType>& input,
150 double semitones)
const {
151 if (input.empty() || semitones == 0.0)
return input;
152 const double ratio = std::pow(2.0, semitones / 12.0);
156 return resample_linear(stretched, input.size());
160 static constexpr double kPi() {
return 3.14159265358979323846; }
161 static constexpr double kTwoPi() {
return 2.0 * kPi(); }
164 static constexpr double kMaxStretch() {
return 100.0; }
167 static int round_to_pow2(
int n) {
170 while (lower * 2 <= n) lower *= 2;
171 const int upper = lower * 2;
172 return (n - lower <= upper - n) ? lower : upper;
175 static double princarg(
double phase) {
176 return phase - kTwoPi() * std::round(phase / kTwoPi());
179 static std::vector<SampleType> resample_linear(
const std::vector<SampleType>& in,
180 std::size_t out_len) {
181 std::vector<SampleType> out(out_len, SampleType{0});
182 if (in.empty() || out_len == 0)
return out;
183 if (in.size() == 1) {
184 std::fill(out.begin(), out.end(), in[0]);
187 const double step =
static_cast<double>(in.size() - 1) /
188 static_cast<double>(out_len > 1 ? out_len - 1 : 1);
189 for (std::size_t
i = 0;
i < out_len; ++
i) {
190 const double pos =
static_cast<double>(
i) * step;
191 const std::size_t i0 =
static_cast<std::size_t
>(pos);
192 const std::size_t i1 = std::min(i0 + 1, in.size() - 1);
193 const SampleType frac =
static_cast<SampleType
>(pos -
static_cast<double>(i0));
194 out[
i] = in[i0] * (SampleType{1} - frac) + in[i1] * frac;
199 PhaseVocoderConfig config_{};
200 int fft_size_ = 2048;
201 int synthesis_hop_ = 512;
202 std::vector<SampleType> window_;
Definition phase_vocoder.hpp:36
PhaseVocoderT(const PhaseVocoderConfig &config)
Definition phase_vocoder.hpp:39
void configure(const PhaseVocoderConfig &config)
Definition phase_vocoder.hpp:41
const PhaseVocoderConfig & config() const noexcept
Definition phase_vocoder.hpp:54
std::vector< SampleType > time_stretch(const std::vector< SampleType > &input, double factor) const
Time-stretch input by factor (> 0).
Definition phase_vocoder.hpp:60
std::vector< SampleType > pitch_shift(const std::vector< SampleType > &input, double semitones) const
Pitch-shift input by semitones (positive = up), preserving duration.
Definition phase_vocoder.hpp:149
PhaseVocoderT()
Definition phase_vocoder.hpp:38
static std::vector< SampleType > generate(int size, Type type, SampleType param=SampleType{0.0f})
Definition windowing.hpp:56
Type
Definition windowing.hpp:43
@ hann
Definition windowing.hpp:45
Definition additive_bank.hpp:218
PhaseVocoderT< float > PhaseVocoder
Definition phase_vocoder.hpp:205
@ ratio
base_frequency_hz * ratio.
Definition fm_operator_engine.hpp:20
@ i
Definition formant_filter_bank.hpp:20
@ e
Definition formant_filter_bank.hpp:20
PhaseVocoderT< double > PhaseVocoder64
Definition phase_vocoder.hpp:206
Definition phase_vocoder.hpp:29
int fft_size
Analysis/synthesis frame size (power of two).
Definition phase_vocoder.hpp:30
int synthesis_hop
Output hop; 0 selects fft_size/4 (75% overlap).
Definition phase_vocoder.hpp:31
WindowFunction::Type window
Definition phase_vocoder.hpp:32