inline void init_time_stretch()

in pedalboard/TimeStretch.h [318:460]


inline void init_time_stretch(py::module &m) {
  m.def(
      "time_stretch",
      [](py::array_t<float, py::array::c_style> input, double sampleRate,
         std::variant<double, py::array_t<double, py::array::c_style>>
             stretchFactor,
         std::variant<double, py::array_t<double, py::array::c_style>>
             pitchShiftInSemitones,
         bool highQuality, std::string transientMode,
         std::string transientDetector, bool retainPhaseContinuity,
         std::optional<bool> useLongFFTWindow, bool useTimeDomainSmoothing,
         bool preserveFormants) {
        // Convert from Python arrays to std::vector<double> or double:
        std::variant<double, std::vector<double>> cppStretchFactor;
        if (auto *variableStretchFactor =
                std::get_if<py::array_t<double, py::array::c_style>>(
                    &stretchFactor)) {
          py::buffer_info inputInfo = variableStretchFactor->request();
          if (inputInfo.ndim != 1) {
            throw std::domain_error(
                "stretch_factor must be a one-dimensional array of "
                "double-precision floating point numbers, but a " +
                std::to_string(inputInfo.ndim) +
                "-dimensional array was provided.");
          }
          cppStretchFactor = std::vector<double>(
              static_cast<double *>(inputInfo.ptr),
              static_cast<double *>(inputInfo.ptr) + inputInfo.size);
        } else {
          cppStretchFactor = std::get<double>(stretchFactor);
        }

        std::variant<double, std::vector<double>> cppPitchShift;
        if (auto *variablePitchShift =
                std::get_if<py::array_t<double, py::array::c_style>>(
                    &pitchShiftInSemitones)) {
          py::buffer_info inputInfo = variablePitchShift->request();
          if (inputInfo.ndim != 1) {
            throw std::domain_error(
                "stretch_factor must be a one-dimensional array of "
                "double-precision floating point numbers, but a " +
                std::to_string(inputInfo.ndim) +
                "-dimensional array was provided.");
          }
          cppPitchShift = std::vector<double>(
              static_cast<double *>(inputInfo.ptr),
              static_cast<double *>(inputInfo.ptr) + inputInfo.size);
        } else {
          cppPitchShift = std::get<double>(pitchShiftInSemitones);
        }

        juce::AudioBuffer<float> inputBuffer =
            convertPyArrayIntoJuceBuffer(input, detectChannelLayout(input));
        juce::AudioBuffer<float> output;
        {
          py::gil_scoped_release release;
          output = timeStretch(inputBuffer, sampleRate, cppStretchFactor,
                               cppPitchShift, highQuality, transientMode,
                               transientDetector, retainPhaseContinuity,
                               useLongFFTWindow, useTimeDomainSmoothing,
                               preserveFormants);
        }

        return copyJuceBufferIntoPyArray(output, detectChannelLayout(input), 0);
      },
      R"(
Time-stretch (and optionally pitch-shift) a buffer of audio, changing its length.

Using a higher ``stretch_factor`` will shorten the audio - i.e., a ``stretch_factor``
of ``2.0`` will double the *speed* of the audio and halve the *length* of the audio,
without changing the pitch of the audio.

This function allows for changing the pitch of the audio during the time stretching
operation. The ``stretch_factor`` and ``pitch_shift_in_semitones`` arguments are
independent and do not affect each other (i.e.: you can change one, the other, or both
without worrying about how they interact).

Both ``stretch_factor`` and ``pitch_shift_in_semitones`` can be either floating-point
numbers or NumPy arrays of double-precision floating point numbers. Providing a NumPy
array allows the stretch factor and/or pitch shift to vary over the length of the
output audio.

.. note::
    If a NumPy array is provided for ``stretch_factor`` or ``pitch_shift_in_semitones``:
      - The length of each array must be the same as the length of the input audio.
      - More frequent changes in the stretch factor or pitch shift will result in
        slower processing, as the audio will be processed in smaller chunks.
      - Changes to the ``stretch_factor`` or ``pitch_shift_in_semitones`` more frequent
        than once every 1,024 samples (23 milliseconds at 44.1kHz) will not have any
        effect.

The additional arguments provided to this function allow for more fine-grained control
over the behavior of the time stretcher:

  - ``high_quality`` (the default) enables a higher quality time stretching mode.
    Set this option to ``False`` to use less CPU power.

  - ``transient_mode`` controls the behavior of the stretcher around transients
    (percussive parts of the audio). Valid options are ``"crisp"`` (the default),
    ``"mixed"``, or ``"smooth"``.
 
  - ``transient_detector`` controls which method is used to detect transients in the
    audio signal. Valid options are ``"compound"`` (the default), ``"percussive"``,
    or ``"soft"``.
 
  - ``retain_phase_continuity`` ensures that the phases of adjacent frequency bins in
    the audio stream are kept as similar as possible. Set this to ``False`` for a
    softer, phasier sound.
 
  - ``use_long_fft_window`` controls the size of the fast-Fourier transform window
    used during stretching. The default (``None``) will result in a window size that
    varies based on other parameters and should produce better results in most
    situations. Set this option to ``True`` to result in a smoother sound (at the
    expense of clarity and timing), or ``False`` to result in a crisper sound.
 
  - ``use_time_domain_smoothing`` can be enabled to produce a softer sound with
    audible artifacts around sharp transients. This option mixes well with
    ``use_long_fft_window=False``.
   
  - ``preserve_formants`` allows shifting the pitch of notes without substantially
    affecting the pitch profile (formants) of a voice or instrument.

.. warning::
    This is a function, not a :py:class:`Plugin` instance, and cannot be
    used in :py:class:`Pedalboard` objects, as it changes the duration of
    the audio stream.


.. note::
    The ability to pass a NumPy array for ``stretch_factor`` and
    ``pitch_shift_in_semitones`` was added in Pedalboard v0.9.8.

)",
      py::arg("input_audio"), py::arg("samplerate"),
      py::arg("stretch_factor") = 1.0,
      py::arg("pitch_shift_in_semitones") = 0.0, py::arg("high_quality") = true,
      py::arg("transient_mode") = "crisp",
      py::arg("transient_detector") = "compound",
      py::arg("retain_phase_continuity") = true,
      py::arg("use_long_fft_window") = py::none(),
      py::arg("use_time_domain_smoothing") = false,
      py::arg("preserve_formants") = true);
}