Extreme Stretch

after Nasca Octavian Paul

Paul's Extreme Sound Stretch, rebuilt as a JUCE 8 plugin, standalone app and command-line renderer — with five algorithms, ratios up to 1015×, and a destructive half the original never had.

Hear it

Every clip below is the same six seconds of source, so the only thing that differs is what the engine did to it. Start here:

How far you can push it

Smooth algorithm throughout. Listen to it stop being a stretch and become a place.

The five algorithms

All at 20×, same window. Only the resynthesis differs.

The destructive half

This is the part that isn't paulstretch.

Source: “It’s Your Birthday!” by Monk Turner + Fascinoma, CC BY 3.0, time-stretched. One global trim was applied across all clips so nothing clips — the level differences you hear between them are real.

The plugin

The Extreme Stretch plugin: waveform, spectrum, and two rows of knobs on a dark interface.
Standalone build, mid-playback. The teal row is paulstretch proper; the row below it is the destruction.
The same plugin in Grain mode, with the spectral controls greyed out and SHAPE renamed to SPRAY.
Grain mode. SHAPE has renamed itself SPRAY, and the five spectral controls have greyed out — grain works in the time domain, so blur, rot, scramble and the cuts genuinely do nothing. The interface would rather admit that than lie to you.

Ships as VST3, a standalone app, and extremestretch-render, a headless CLI — every clip on this page was made with the CLI. There is also a self-test binary that asserts 97 things about the DSP and has to print ALL PASS.

How it works

Take a long window of input, window it, FFT, throw the phases away and replace them with noise, IFFT, window again, overlap-add at 50%. The output hop is windowSize/2; the input hop is (windowSize/2) / stretch, and that is the only place the stretch ratio appears anywhere in the code. Nothing is interpolated and nothing is time-warped — the frames simply overlap more.

Why the window is not a Hann

This is the detail that catches people. Because the phases are random, overlapping frames add incoherently — in power, not in amplitude. So the condition the window must satisfy is sum(w²) ≈ constant, not the usual COLA condition.

A Hann window applied twice at 50% overlap swings 6 dB and tremolos audibly. Paul's window, sqrt(1 − |x|^2.5), ripples 2.16 dB in power.

Its mean(w²) of 0.714 times the mean overlap sum of 1.429 comes to 1.02 — which is why paulstretch is unity-gain with no normalisation anywhere in the signal path. The self-test asserts all three numbers, and a real render measures +0.05 dB against its input.

There are actually three windows, because the algorithms add differently: Paul's for random phase, sqrt(Hann) for the coherent vocoder (which is a perfect reconstructor at ratio 1), and plain Hann for grains, which are windowed only once.

Why it never runs out of memory

A window can be 262144 points, so one FFT is tens of milliseconds — far too slow for an audio callback. A render thread keeps a FIFO topped up and processBlock only ever memcpys out of it. Playback therefore starts instantly and stays memory-bounded no matter how absurd the ratio: a 60-second file at 1015× is 1.9 billion years of audio that is never materialised anywhere.

Controls

Paulstretch
STRETCH1× – 1015×, on a biased-log knob so the musical range keeps most of the travel. Or type a target length — “2h”, “1000 years”, “9.5 billion years” — and the ratio follows.
WINDOW5 ms – 5 s, snapped to a power of two. Short is grainy, long is glassy.
SHAPEOne knob wearing five hats; it renames itself per algorithm — SENSITIVITY, COHERENCE, SPRAY, HOLD.
FREEZEPins the read head. The drone hangs on one moment forever.
WIDTH0 = channels share a phase per bin, 1 = fully decorrelated. This is where the huge paulstretch stereo comes from.
Destruction
PITCH±24 semitones by resampling the magnitude spectrum. Artefact-free, because there are no phases left to smear.
BLURSmears magnitudes across neighbouring bins. The radius grows with frequency, so the smear is constant in octaves rather than in hertz, and the energy is put back afterwards.
ROTKills bins, and the damage persists between frames. At 1.0 nothing heals and the drone collapses to whatever survives; below that, damage and healing find an equilibrium. Back it off and it grows back.
SCRAMBLEDisplaces bins locally, with the same swap map on every channel so the stereo image survives.
LOW / HIGH CUT24 dB/oct gating done in the magnitude domain.

Build it

Needs JUCE 8 and CMake. No other dependencies.

git clone https://github.com/willbearfruits/extremestretch
cd extremestretch
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

# must print ALL PASS
./build/ExtremeStretchSelfTest_artefacts/Release/extremestretch-selftest

The VST3 is copied into ~/.vst3/ after a successful build; pass -DES_COPY_PLUGIN=OFF to keep everything inside build/.

From the command line

extremestretch-render in.wav out.wav --stretch 50 --window 0.5
extremestretch-render in.wav out.wav --length "2h"          # ratio worked out for you
extremestretch-render in.wav out.wav --algorithm vocoder --shape 0.7
extremestretch-render in.wav out.wav --stretch 1e14 --max-seconds 60

It prints the full output length before writing anything, so you can see what you are asking for. It will happily tell you the answer is 9.5 billion years.

Credit

The algorithm is Nasca Octavian Paul's. He wrote Paul's Extreme Sound Stretch (and ZynAddSubFX), and the idea at the heart of this — throw the phases away, replace them with noise, overlap enormous windows — is entirely his. It is one of those rare techniques that is trivial to state and sounds like nothing else.

This is an independent reimplementation written from the algorithm, not a port or a translation of his code. Credit for the invention is his; any bugs in this version are ours.