Tanh Soft Clipping — User Guide

Memoryless tanh waveshaping with input-reference options, oversampling, parallel dry/wet mixing, and explicit output-level policies.

Author: Shai Cohen Affiliation: Department of Music, Bar-Ilan University, Israel Version: 0.5.1 (2026) License: MIT License Repo: https://github.com/ShaiCohen-ops/Praat-plugin_AudioTools
Contents:

What this does

Tanh Soft Clipping applies a static nonlinear transfer function to every sample of the selected Sound. The wet waveshaper is:

y = Wet_level × tanh(Drive_amount × x)

As Drive_amount increases, the curve becomes progressively flatter near its positive and negative limits, compressing peaks smoothly rather than truncating them abruptly as a hard clipper would.

This is a memoryless, symmetric, odd waveshaper. It can be used for saturation and overdrive-like effects, but it is not a physical tube, tape, transformer, or magnetic-hysteresis model. It contains no bias, attack/release, hysteresis, head bump, frequency-dependent saturation, or deliberate even-harmonic mechanism.

For a symmetric sinusoidal input, the odd symmetry of tanh primarily generates odd harmonics. The nonlinear stage can also create components above Nyquist; oversampling is therefore available to reduce aliasing.

Quick start

  1. In the Praat Objects window, select exactly one Sound object.
  2. Run Tanh_Soft_Clip.praat.
  3. Choose a preset, or select Custom to use the Drive and Wet level fields directly.
  4. Choose whether Drive should follow the source's existing peak level or first use a normalized input reference.
  5. Leave Oversample = 4 for the default alias-reduced render; 1 disables oversampling. This script refuses 2× because of the documented round-trip phase offset on the tested Praat version.
  6. Set Dry/Wet and the desired output-level policy, then click OK.

Practical starting point: use a named preset, Input_reference = Use the source level, Oversample = 4, Dry_Wet = 1, and the default Normalize-to-target output mode. Switch to Normalize input peak before drive when you want the same Drive setting to behave more consistently across files with very different source levels.

Signal path

Selected Sound
   ↓
optional input-reference peak normalization
   ↓
optional oversampling
   ↓
tanh(Drive × x) × Wet_level
   ↓
anti-aliased downsampling to original rate
   ↓
Dry/Wet mix with the original Sound
   ↓
output policy
   ↓
Output_gain
   ↓
final Sound

The original duration, time domain, sample rate, and channel count are preserved. With multichannel Sounds, the same processing is applied channel by channel. Any global peak scaling uses one peak for the complete Sound object, so channel balance is linked rather than normalized independently per channel.

Input reference

Use the source level sends the source directly to the waveshaper. In this mode, saturation depth depends on both Drive and the source's existing amplitude: a quiet file may remain nearly linear at a Drive that heavily distorts a hot file.

Normalize input peak before drive first scales the copied source to a peak of 0.95 when its peak is above Silence_floor. This makes Drive more comparable across source files, at the cost of changing their original gain before waveshaping.

Oversampling

The wet branch can be processed at an integer multiple of the original sample rate and then resampled back. This gives nonlinear harmonics additional spectral headroom before downsampling removes out-of-band energy. It reduces aliasing; it does not make the process mathematically alias-free.

Supported effective range is 1–8×. Values below 1 are clamped to 1 and values above 8 to 8, with the effective value reported. 2× is explicitly disabled in this script because a frequency-dependent phase offset was measured for the 2× resampling round trip on Praat 6.1.38; this matters especially when wet and dry paths are mixed.

Parameters & presets

ParameterDefaultMeaning
PresetGentleNamed presets set both Drive_amount and Wet_level. Custom leaves the manual values unchanged.
Drive_amount8Input multiplier inside tanh. Larger values reach the flattened part of the curve sooner.
Wet_level0.7Gain applied to the saturated branch before Dry/Wet mixing. With partial Dry/Wet it changes the wet/dry ratio and cannot be undone by later peak normalization.
Input_referenceUse source levelUse the source's existing peak, or normalize the copied input to 0.95 before Drive.
Oversample4Wet-path oversampling factor. 1 = off; 2 is refused; effective range 1–8.
Output_modeNormalize to targetSelects final peak policy before Output_gain.
Scale_peak0.95Target used by Normalize and conditional Attenuate modes. It is ignored in Preserve mode.
Output_gain1.0Final post-policy makeup/trim gain. It survives every output mode.
Silence_floor1e-9Numerical guard used by Normalize mode and input-reference normalization. Peaks at or below the threshold are not raised.
Dry_Wet1.01 = fully processed branch; 0 = dry branch. The dry path returns at its original level only when the output policy is Preserve rendered level.
Draw_visualizationYesDraw the diagnostic AudioTools figure.
Play_resultYesPlay the final Sound when processing finishes.

Named presets

PresetDriveWet level
Gentle2.50.85
Medium40.80
Strong60.75
Very strong80.70
Heavy120.60

All five presets use the same tanh algorithm. They are not different analog models; they only choose different Drive and Wet-level values.

Output policies

The output policy is applied after waveshaping and Dry/Wet mixing. Output_gain is then applied last.

ModeBehavior
Normalize to targetIf the pre-output peak is above Silence_floor, globally scale the complete rendered Sound to Scale_peak. Peaks at or below the guard are left at their current level. This mode can therefore raise a quiet but non-negligible signal to the target.
Preserve rendered levelNo target-based scaling. The rendered level from waveshaping, Wet level, Dry/Wet mixing, and Input reference is preserved; only final Output_gain may change it.
Attenuate to target only if peak > targetGlobally scale down only when the rendered peak exceeds Scale_peak. A signal already at or below the target is unchanged. This is whole-file attenuation, not a sample-by-sample limiter.

Scale_peak is validated only in the two modes that use it and must be greater than 0 and no greater than 1.0. Output_gain is applied afterwards, so a gain above 1 can still produce a final peak above full scale; the script reports and warns about that condition.

Visualization

When enabled, the script draws a diagnostic figure rather than a generic effects display. It includes:

The transfer panel intentionally does not pretend to be a final sample-by-sample transfer function when oversampling is active. Resampling filters make each output sample depend on neighboring samples, so the complete oversampled chain is not a static y = f(x) mapping. Dry mixing and global peak scaling are therefore reported numerically rather than folded into a misleading curve.

Limitations and interpretation

Outputs