Wavefolder (Foldback) — User Guide

Memoryless nonlinear wavefolding with input/output gain, repeated folds, optional asymmetric thresholds, continuous soft saturation, DC removal, and attenuation-only peak protection.

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

The script copies one selected Sound object and applies a static nonlinear transfer function. Samples that cross a fold threshold are reflected back with a slope controlled by Fold depth. The same fold can be reapplied for multiple iterations. Optional smoothing adds a continuous saturating curve after the folding stage.

The processor is sample-domain and memoryless apart from the file-level DC-removal and peak-protection stages. It does not analyse pitch or spectrum, and it does not model a specific analog circuit.

Terminology used by the script: when Bipolar folding is enabled, positive and negative sides may use different thresholds, so the Asymmetry control is active. When it is disabled, the script still folds both signal polarities, but uses one shared symmetric threshold; in that mode Asymmetry has no effect on the audio.

Quick start

  1. Select exactly one Sound object in Praat.
  2. Run Wavefolder_Foldback.praat.
  3. Choose a preset, or choose Custom (use settings below) to use the entered DSP values.
  4. Choose whether to remove DC, draw the visualization, and play the result.
  5. Click OK. The processed Sound remains selected.
Preset rule: presets 2–9 overwrite Threshold, Input gain, Fold depth, Asymmetry, Fold iterations, Bipolar folding, Smoothing, and Output gain. DC offset removal, Draw visualization, and Play result remain controlled by the form.

Processing pipeline

1. Gain and thresholds

inputGain = 10^(Input_gain_dB / 20) outputGain = 10^(Output_gain_dB / 20) if Asymmetry >= 0: threshold_pos = Threshold × (1 - Asymmetry) threshold_neg = Threshold else: threshold_pos = Threshold threshold_neg = Threshold × (1 + Asymmetry)

The input Sound is copied, then multiplied by inputGain.

2. Folding

For each fold iteration, the current sample value is transformed once.

Bipolar folding = yes if x > threshold_pos: y = threshold_pos - (x - threshold_pos) × Fold_depth else if x < -threshold_neg: y = -threshold_neg + (|x| - threshold_neg) × Fold_depth else: y = x Bipolar folding = no if |x| > Threshold: positive: y = Threshold - (x - Threshold) × Fold_depth negative: y = -Threshold + (|x| - Threshold) × Fold_depth else: y = x

The positive and negative branches in bipolar mode are mutually exclusive. A sample folded across zero is therefore not folded a second time by the opposite branch within the same iteration.

Fold depth sets the slope beyond a threshold. At 1.0 the excess is mirrored with slope −1; values below 1 reduce the return slope. The code does not clamp this field, so values outside the labelled 0–1 range are possible in Custom mode.

3. Continuous smoothing

If Smoothing > 0, the script applies a continuous odd-symmetric saturation after all fold iterations:

a = 2 × Smoothing s = max(0, 1 - a) if |x| <= s: y = x else if x > 0: y = s + (x - s) / (1 + (x - s) × a) else: y = -s - (|x| - s) / (1 + (|x| - s) × a)

For Smoothing = 0.5, s = 0 and the stage becomes x / (1 + |x|). A non-positive Smoothing value disables this stage.

4. Output conditioning

  1. Multiply by outputGain.
  2. If DC offset removal is enabled, run Praat's Subtract mean.
  3. Measure the final positive and negative extrema with Sinc70 interpolation.
  4. If the absolute peak is greater than 0.99, attenuate the complete Sound so that the peak becomes 0.99. If the peak is 0.99 or lower, no normalization is applied.

Presets

There are nine menu choices: Custom plus eight fixed presets. Values shown below are the exact assignments made by the script.

PresetThresholdIn gainDepthAsym.IterationsBipolarSmoothingOut gain
Customformformformformformformformform
Soft Fold (Subtle)0.70+3 dB0.600.001yes0.30−3 dB
Hard Fold (Aggressive)0.30+12 dB1.000.001yes0.00−6 dB
Bipolar Fold0.50+6 dB1.000.002yes0.10−4 dB
Asymmetric Fold0.60+8 dB0.85+0.601yes0.15−5 dB
Multi-Fold (Harmonics)0.40+10 dB1.000.003yes0.00−8 dB
Tape Saturation Style0.65+4 dB0.50+0.201yes0.50−2 dB
Digital Crush0.25+15 dB1.000.002no0.00−10 dB
Oscillating Fold0.55+7 dB0.90−0.302yes0.20−5 dB
Preset names are descriptive labels, not additional algorithms. “Tape Saturation Style” is not a tape/circuit model. “Digital Crush” performs foldback only; it does not reduce bit depth or sample rate. “Oscillating Fold” is a static preset with negative asymmetry; it contains no oscillator or time-varying modulation.

Parameters

GUI fieldTypeDefaultActual behavior
PresetoptionmenuCustomSelects Custom or one of eight fixed parameter sets.
Threshold_(0-1)real0.5Base fold threshold. The 0–1 text is a label, not a code clamp.
Input_gain_dBreal0.0Gain before folding.
Fold_depth_(0-1)real1.0Return slope magnitude beyond the threshold. The 0–1 label is not enforced.
Asymmetry_(-1_to_1)real0.0Changes positive/negative thresholds only when Bipolar folding is enabled. The labelled range is not clamped.
Fold_iterationsnatural1Number of times the same fold stage is reapplied; Praat's natural field requires a positive integer.
Bipolar_foldingbooleanyesYes = separate positive/negative thresholds; No = shared symmetric threshold.
Smoothing_(0-1)real0.0Controls the post-fold continuous saturation. Values ≤ 0 disable it; the 0–1 label is not clamped.
Output_gain_dBreal0.0Gain after folding and smoothing, before DC removal and peak protection.
DC_offset_removalbooleanyesRuns Subtract mean after output gain.
Draw_visualizationbooleanyesDraws the Picture-window diagnostic page.
Play_resultbooleanyesPlays the processed Sound after rendering.

Visualization

When enabled, the script draws a suite-style Picture page containing:

The transfer curve includes input gain → fold iterations → smoothing → output gain. It deliberately excludes DC removal and the final peak limiter because those depend on the complete file rather than on an individual input value. Its vertical range is expanded when needed instead of clipping the displayed transfer curve.

The full-waveform and zoom panels use Praat's automatic amplitude range independently. They show waveform shape, but their vertical sizes should not be read as a shared calibrated amplitude comparison.

Outputs and limits

Limits: the script has no oversampling or explicit anti-aliasing stage, so strong nonlinear settings can generate aliases. It also has no dry/wet mix, no frequency-dependent processing, and no internal modulation over time.