Dynamic Distortion — User Guide

Amplitude-contour-controlled tanh distortion with zero-phase or causal envelope tracking.

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

What this does

Dynamic Distortion applies a tanh nonlinearity whose drive changes sample by sample according to an amplitude contour derived from the input. The core relationship is:

drive(t) = Base_Drive + Sensitivity × envelope(t)
output(t) = Output_Gain × tanh( mono_input(t) × drive(t) )

With positive Base_Drive and positive Sensitivity, larger envelope values produce a larger drive magnitude and therefore stronger saturation. The form also permits zero and negative values, so Manual mode can reverse that relationship, cross through zero drive, invert polarity, or silence the result through Output_Gain = 0.

Mono processing: the selected Sound is converted to mono before both envelope extraction and distortion. Stereo and multichannel inputs therefore produce a mono output. The original Sound object is not modified.

The script offers two distinct ways to build the amplitude contour: the historical zero-phase smoothing mode, which is offline and acausal, and a causal attack/release follower. These are not interchangeable implementations of the same timing model; they have different temporal behavior.

Quick start

  1. Select exactly one Sound in Praat.
  2. Run Dynamic_Distortion.praat.
  3. Choose Manual or one of the four presets.
  4. Choose an Envelope_mode: zero-phase smoothing or causal attack/release.
  5. For zero-phase mode, set Response_Speed_Hz. For causal mode, set Attack_ms and Release_ms.
  6. Choose whether to Clamp_envelope_to_zero.
  7. Choose the Output_level behavior and run the script.
Preset scope: presets override Base_Drive, Sensitivity, Response_Speed_Hz, and Output_Gain. They do not change Envelope_mode, Attack_ms, Release_ms, Clamp_envelope_to_zero, Output_level, visualization, or playback. In causal mode, a preset's Response_Speed_Hz value is present but unused.

Signal path

Processing sequence

Selected Sound

Praat Convert to mono

Copy → absolute value |x|

[Zero-phase Hann-band smoothing] OR [Causal attack/release follower]

Optional envelope clamp: max(envelope, 0)

drive(t) = Base_Drive + Sensitivity × envelope(t)

y(t) = tanh(x(t) × drive(t)) × Output_Gain

Preserve / conditional attenuation / peak normalization

The output is named <source>_DynDist_<presetName>, using Manual, TouchSensitive, DrumPumper, PolarityCrossing, or ExpressiveLead.

Envelope modes

1. Zero-phase smoothing (default)

The mono signal is full-wave rectified with abs(), then processed by Praat's Filter (pass Hann band) from 0 Hz to Response_Speed_Hz with a 20 Hz transition width. In this mode, Response_Speed_Hz is a smoothing cutoff, not an attack or release time.

Acausal behavior: the frequency-domain zero-phase filter has a symmetric impulse response. Energy around a transient can therefore extend backward in time, so the drive can begin changing before the transient itself. The script's development tests measured approximately 17 ms of pre-response at 20 Hz and about 3 ms at 80 Hz on a synthetic onset. These figures describe those tests, not a universal attack-time law.

Response_Speed_Hz must be greater than 0 and below the Sound's Nyquist frequency. Higher values retain faster amplitude variation; lower values produce a smoother contour.

2. Causal attack/release follower

This mode uses a recursive one-pole follower with separate time constants for rising and falling values. The rectified input is processed from left to right:

aAttack = exp( -1 / (fs × Attack_seconds) )
aRelease = exp( -1 / (fs × Release_seconds) )

if input[n] > envelope[n-1]:
  envelope[n] = aAttack × envelope[n-1] + (1-aAttack) × input[n]
else:
  envelope[n] = aRelease × envelope[n-1] + (1-aRelease) × input[n]

Attack_ms and Release_ms must both be greater than 0. Unlike zero-phase smoothing, this mode does not anticipate future samples.

Clamp_envelope_to_zero

Rectification itself is non-negative, but the zero-phase Hann-band filter can ring below zero around sharp changes. With the clamp disabled (the default), those negative values remain part of the control contour. With the clamp enabled, the script applies:

envelope(t) = max(envelope(t), 0)

This distinction matters because a negative envelope can move the computed drive below Base_Drive when Sensitivity is positive. For that reason, Base_Drive is described as the nominal drive at zero envelope, not as an unconditional minimum.

Parameters & presets

Form parameters

ParameterDefaultBehavior
PresetManualManual or four parameter presets.
Base_Drive1.0Nominal drive when the envelope is exactly 0. Any real value is accepted.
Sensitivity5.0Envelope-to-drive multiplier. Any real value is accepted; negative values reverse the drive response.
Response_Speed_Hz20.0Zero-phase smoothing cutoff. Used only in zero-phase mode; must be >0 and below Nyquist.
Envelope_modeZero-phaseZero-phase acausal smoothing or causal attack/release follower.
Attack_ms5.0Causal-mode rise time constant; must be >0.
Release_ms50.0Causal-mode fall time constant; must be >0.
Clamp_envelope_to_zeroNoClamps negative envelope undershoot to 0 when enabled.
Output_Gain0.9Constant scalar after tanh. Negative values invert polarity; 0 silences the shaped signal.
Output_levelNormalize peak to 0.95Preserve, conditionally attenuate, or normalize the final mono result.
Draw_visualizationYesDraw the diagnostic 8×8-inch Picture-page visualization.
Play_resultYesPlay the result after processing.

Built-in presets

PresetBaseSensitivityResponseOutput Gain
Touch Sensitive Drive0.83.015 Hz0.9
Drum Pumper1.08.050 Hz0.8
Polarity-Crossing Crunch-0.510.080 Hz1.0
Expressive Lead1.24.010 Hz0.9

Negative and zero values

Negative Base_Drive is not a gate. When drive is negative, the tanh mapping changes polarity; it does not automatically mute the signal. If Sensitivity is nonzero, the drive crosses zero at envelope = -Base_Drive / Sensitivity. The output reaches zero at that control value and changes polarity across it. The script reports whether that crossing actually falls inside the measured envelope range of the current file.

Negative Sensitivity means larger envelope values lower the drive rather than raise it. Sensitivity = 0 makes the drive constant at Base_Drive. Output_Gain < 0 inverts the entire shaped result; Output_Gain = 0 makes it silent.

Output level

ModeExact behavior
Preserve shaped levelNo peak scaling. If the absolute peak exceeds 1.0, the script prints a warning.
Attenuate to 0.95 only if peak > 0.95If the shaped peak exceeds 0.95, the entire file is scaled globally so its peak becomes 0.95. This is peak attenuation, not a sample-by-sample limiter.
Normalize peak to 0.95For any non-silent result, globally scale the peak to 0.95. A zero-peak result is left unchanged and normalization is skipped safely.
Output_Gain and normalization: Output_Gain is a constant scalar after tanh. Peak normalization divides the magnitude of that scalar back out for any nonzero result, so positive gains do not set the final magnitude in Normalize mode. A negative Output_Gain still changes polarity, and Output_Gain = 0 still yields silence because the zero-peak guard prevents normalization from amplifying it.

Visualization

The 8×8-inch Picture display is diagnostic rather than decorative. It follows the Sound's actual time domain, including Sounds whose start time is not 0.

Panel A — Transfer curves
Two tanh mappings based on the measured envelope extremes are drawn over the same input range. The gray curve uses the envelope minimum and the red curve uses the envelope maximum. The curves include Output_Gain and any global output-level scaling actually applied to the render. Negative drive therefore appears as a polarity-inverted curve rather than being hidden.

Panel B — Envelope and computed drive
The upper sub-panel shows the measured envelope with min/max references. In v0.5.1, a negative zero-phase undershoot is included in the Y range rather than clipped from view. The lower sub-panel shows Base_Drive + envelope × Sensitivity, with zero and Base_Drive references when visible.

Panel C — Processing source vs result
Gray is the actual mono processing source; red is the distorted result. This is the correct comparison for stereo or multichannel inputs because processing occurs after the mono conversion.

Panel D — Output waveform
Final mono waveform across the complete Sound domain.

Panel E — Summary
Preset, envelope mode, level mode, Output_Gain, measured envelope range, measured drive range, mono-collapse note, duration, and final peak.

When an output-level stage has applied global scaling, Panel A uses that measured scale. The underlying normalization factor depends on the peak of the whole file, so the panel should be read as representative transfer curves for this render rather than as a self-contained memoryless description of the entire processor.

Behavioral notes and limitations

Applications

Useful applications include level-dependent saturation on instruments or voice, transient-sensitive distortion on percussion, inverted dynamic response with negative Sensitivity, and experimental polarity-crossing textures. These are creative uses of the control law; the processor is not a physical model of a tube amplifier, pedal, compressor, or noise gate.