Paulstretch — User Guide

Spectral time stretching by overlapping FFT frames, preserving each frame's spectral magnitudes while randomizing interior-bin phases, then overlap-adding the resynthesized frames on a slower-moving source trajectory.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 1.3 (2026) License: MIT License Repo: GitHub
Contents:

What this does

Paulstretch creates a new mono or stereo sound whose duration is approximately the requested stretch factor times the source duration. The engine first converts the selected source to mono, then analyzes overlapping Hann-windowed FFT frames. Spectral magnitudes are retained while interior-bin phases are randomized, and the resynthesized frames are overlap-added on an expanded output timeline.

Channel behavior: the original channel layout is not preserved. A stereo or multichannel source is folded to mono before processing. With Create_stereo off, the result is mono; with it on, the result is a newly synthesized stereo pair derived from the same mono engine source.

The process does not deliberately shift spectral frequencies. Its characteristic temporal smearing comes from the source/output hop relationship and phase randomization rather than varispeed resampling.

How the stretch works

The core timing relationship is:

overlap = Overlap_percent / 100 hopOut = effectiveWindow × (1 - overlap) hopIn = hopOut / Stretch_factor hopOut / hopIn = Stretch_factor

Successive analysis frames therefore move through the source by hopIn, while their resynthesized versions advance through the output by the larger or smaller hopOut. The output target is:

targetDuration = inputDuration × Stretch_factor

A factor above 1 expands time; a positive factor below 1 is also accepted and contracts the requested duration.

Frame-centre alignment

Frame i is centered at i × hopIn in the source and written at:

tOut = i × hopOut - effectiveWindow / 2

The output workspace extends half a window before time 0 and half a window after the target. After overlap-add, the result is trimmed to the requested 0…targetDuration interval. This keeps the first source frame centered on output time 0 rather than adding a half-window latency.

Quick start

  1. Select exactly one Sound object.
  2. Run Paulstretch.praat.
  3. Choose Custom, Subtle Stretch, Classic Paulstretch, Extreme Stretch, or Quick Test.
  4. Choose a Speed_mode.
  5. For Custom, set stretch factor, requested window size, overlap, mono/stereo output and stereo phase offset.
  6. Run the script. The result is named from the source and preset.
There is no random-seed control. Phase realizations are unpredictable between runs, so repeated processing with the same settings can produce a different waveform.

FFT window, edge handling & overlap-add

Power-of-two effective window

Window_size_s is a request. After the working sample rate is chosen, the requested sample count is rounded up to the next power of two:

requestedSamples = round(Window_size_s × workingSampleRate) windowSamples = smallest power of two >= requestedSamples effectiveWindow = windowSamples / workingSampleRate

The effective window must contain at least four samples. When the rounding changes the requested duration by more than 0.5 ms, the actual value is reported in the Info window.

The effective FFT window can differ substantially from the number typed into the form. For example, a 0.25 s request at a 22.05 kHz working rate is 5512 samples and is rounded to 8192 samples, about 0.3715 s.

Edge frames

At the start and end of the source, the available audio is extracted rectangularly and placed at the correct offset inside a complete zero-padded frame. Only after padding is the full Hann analysis window applied. This prevents a truncated edge frame from being incorrectly re-windowed as if its shorter duration were a complete FFT frame.

Double windowing

Every usable frame receives:

  1. a Hann window before FFT analysis;
  2. a second Hann window after inverse FFT.

Overlap-add normalization

The script accumulates the exact synthesis-Hann weights in a parallel normalization Sound. After all frames are added:

if OLAweight[n] > 1e-6: output[n] /= OLAweight[n] else: output[n] = 0

This compensates for the changing number and summed weight of overlapping synthesis windows. Overlap_percent therefore primarily changes frame density and processing load rather than being used as an output-gain control.

Spectral magnitude & phase randomization

Each Hann-windowed frame is transformed to a Spectrum and then to its two-row complex Matrix. For every interior frequency bin, the script first freezes the original magnitude:

magnitude[k] = sqrt(real[k]^2 + imag[k]^2)

It then draws one random phase and rebuilds the complex pair coherently:

phase[k] = uniform(-π, +π) + channelOffset × π real'[k] = magnitude[k] × cos(phase[k]) imag'[k] = magnitude[k] × sin(phase[k])

The first and final spectral bins are left unchanged. Thus the interior-bin magnitudes of each analyzed frame are retained while their phases are replaced.

“Magnitude preserved” refers to each individual FFT frame before inverse transformation and overlap-add. It does not mean that the completed output has an identical global magnitude spectrum to the input.

Stereo phase mode

When Create_stereo is enabled, L and R are not processed with unrelated randomness. Every frame receives one unpredictable integer seed. Both rendered channels reinitialize from that same seed, so they use the same base random phase sequence.

Left: phaseL = randomPhase Right: phaseR = randomPhase + Stereo_phase_offset × π

The parameter is validated only to be non-negative; values above 2 are mathematically periodic modulo 2 because the offset is multiplied by π.

This stereo result is generated from a mono fold. It does not preserve the source's original stereo or multichannel spatial image.

Speed modes

ModeWorking-rate ruleFinal sample rate
Full QualityUse the original sample rate.Original sample rate.
BalancedIf source rate > 22050 Hz, downsample the mono engine source to 22050 Hz. Otherwise keep the source rate.Upsample back to the original rate when downsampling occurred.
FastIf source rate > 11025 Hz, downsample the mono engine source to 11025 Hz. Otherwise keep the source rate.Upsample back to the original rate when downsampling occurred.

Both downsampling and final upsampling use Praat Resample with precision 50. The effective power-of-two FFT window is calculated after the working sample rate has been selected.

Presets

PresetStretchWindow requestOverlapOutputStereo offset
Subtle Stretch0.25 s75%Stereo0.2 × π
Classic Paulstretch0.25 s75%Stereo0.3 × π
Extreme Stretch16×0.50 s80%Stereo0.4 × π
Quick Test0.15 s75%Mono0
Custom defaults0.25 s75%Stereo0.3 × π

Named presets overwrite stretch, window, overlap, stereo creation and stereo offset. They do not overwrite Speed_mode, Draw_visualization or Play_result.

Parameters & limits

ParameterDefaultValidation / exact role
PresetCustomCustom plus four named presets.
Speed_modeBalancedFull source rate, max 22.05 kHz working rate, or max 11.025 kHz working rate.
Stretch_factor4.0Must be > 0. Sets both hop ratio and target duration.
Window_size_s0.25Positive request; converted to a power-of-two sample count at the working rate.
Overlap_percent75Must be > 0 and < 100.
Create_stereoOnOff = mono result; On = generated stereo pair.
Stereo_phase_offset0.3Non-negative right-channel phase offset in units of π.
Draw_visualizationOnDraw the v1.3 process view.
Play_resultOnPlay the completed Sound.

The requested settings are rejected if they imply more than 250,000 analysis frames.

Visualization

The v1.3 Picture output follows the current engine directly:

Output behavior

Duration

Before optional sample-rate restoration, the assembled result is trimmed to:

0 ... inputDuration × Stretch_factor

The resulting duration is therefore the requested stretch target subject only to ordinary sample-grid/resampling precision.

Peak safety

The final Sinc70 peak is attenuated only when it exceeds 0.95:

if peak > 0.95: output *= 0.95 / peak else: leave level unchanged

This is an attenuate-only safety ceiling. Quiet output is not normalized upward.

Naming

Stereo: <source>_PS_<preset>_stereo Mono: <source>_PS_<preset>

The source Sound is left unchanged. Temporary processing, normalization and visualization objects are removed.