Nodes/ComfyUI-AudioReactive/Stretch (Audio Op)
ComfyUI Node

Stretch (Audio Op)

Stretch — punch up a driver curve with normalize → square → normalize

By dmarx·Created 3 years ago·Updated 2 years ago· 11
Stretch (Audio Op)
  • signal
  • SIGNAL

OpStretch (display name "Stretch (Audio Op)") is the pack's "make it punchier" button. It takes a signal, normalizes it, squares it, and normalizes again. Net effect: the loud parts stay near the top, the quiet parts get pushed down, and the whole thing lands back in a usable [0, 1] range. It's contrast shaping - the audio-reactive equivalent of turning up the curve's dynamic range.

It's one of the genuinely working operators ported from dmarx's video-killed-the-radio-star notebook, and the shape logic is easy to follow:

def stretch(y, sr):
    y = normalize(y, sr)
    return normalize(y**2, sr)

normalize takes the absolute value and divides by the peak, so the first call makes everything non-negative with a peak of 1. Then exaggerates the gap between peaks and valleys (this is the same trick Pow2 does on its own). The final normalize keeps the peak at 1 so downstream parameters see a proper 0..1 driver. Compare with its sibling Smoosh, which does the opposite - square-root compression, pulling the quiet parts up. Stretch = widen, smoosh = compress. They're the bookends of the pack's curve-shaping pair.

Why you'd reach for it

In a real audio-reactive workflow, the path is ARReadAudio → Rms → SignalToCurve → <your animation scheduler>. The problem: a raw RMS envelope is often too gentle - the quiet sections still sit at, say, 0.3, so your animation never really rests. Throw Stretch between Rms and SignalToCurve and the quiet passages collapse toward zero while the loud hits still reach 1. That's the whole job, and it's a one-node change that makes beat-driven motion feel dramatically more musical. It's also handy after almost any operator that leaves a signal in an awkward range, because of the built-in re-normalization.

Inputs and outputs

  • signal (SIGNAL) - typically an energy/feature curve (Rms, Novelty), though it'll happily take a raw waveform too (the output is then a folded, squared version of it).
  • SIGNAL - y replaced by the stretched curve, same length, non-negative, peak at 1. Wire into SignalToCurve or ARDrawSignal.

Installing it

Manager (search "AudioReactive") or:

cd ComfyUI/custom_nodes
git clone https://github.com/dmarx/ComfyUI-AudioReactive

Restart and let the first-start auto-install of scipy, scikit-learn, librosa, loguru run (librosa pulls numba, so give it a few minutes). ModuleNotFoundError: No module named 'keyframed' on load → pip install keyframed.

Common issues

  • Output is fully positive, not bipolar - expected: normalize applies abs(). Stretch is meant for envelopes, not for preserving waveform polarity.
  • Quiet sections go to (near) zero - that's the feature, not a bug; it's what "punchier" means here.
  • The pack is an early port - single commit, one-line README, some operators left as unwired stubs. Stretch is one of the working ones, so it's safe to build on. If a node name around here does something odd, the source (nodes/audio_utils.py) is short and worth a skim.
CategoryAudioReactive/Operators

Inputs (1)

NameTypeDefaultDescription
signalSIGNAL

Outputs (1)

NameTypeDescription
SIGNALSIGNAL