MayaFlux 0.3.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ pitch_shift()

std::vector< double > MayaFlux::Kinesis::Discrete::pitch_shift ( std::span< const double >  src,
double  semitones,
uint32_t  window_size = 2048,
uint32_t  analysis_hop = 512 
)

Pitch-shift by resampling around a phase vocoder stretch.

Stretches by 1/pitch_ratio, then resamples back to the original length using linear interpolation. This preserves duration while shifting pitch, which is the standard phase vocoder pitch-shift approach.

Parameters
srcInput samples
semitonesPitch shift in semitones (positive = up, negative = down)
window_sizeFFT frame size
analysis_hopAnalysis hop
Returns
Pitch-shifted output, same length as src

Definition at line 282 of file Spectral.cpp.

287{
288 if (src.empty() || semitones == 0.0)
289 return { src.begin(), src.end() };
290
291 const double pitch_ratio = std::pow(2.0, semitones / 12.0);
292 const double stretch_ratio = 1.0 / pitch_ratio;
293
294 std::vector<double> stretched = phase_vocoder_stretch(src, stretch_ratio, window_size, analysis_hop);
295
296 if (stretched.empty())
297 return {};
298
299 const size_t out_n = src.size();
300 std::vector<double> out(out_n);
301 const size_t in_n = stretched.size();
302 const double step = static_cast<double>(in_n - 1) / static_cast<double>(out_n - 1);
303
304 for (size_t i = 0; i < out_n; ++i) {
305 const double pos = static_cast<double>(i) * step;
306 const auto idx = static_cast<size_t>(pos);
307 const size_t idx1 = std::min(idx + 1, in_n - 1);
308 const double frac = pos - static_cast<double>(idx);
309 out[i] = stretched[idx] + frac * (stretched[idx1] - stretched[idx]);
310 }
311
312 return out;
313}

References phase_vocoder_stretch().

+ Here is the call graph for this function: