Skip to content

Tape Saturation

Tier: Color | ComponentType: 26 | Params: 5

Asymmetric soft clipping with pre-emphasis, de-emphasis, and magnetic hysteresis modeling, simulating the nonlinear recording characteristics of analog tape.

Overview

TapeSaturation models the way analog tape records and plays back audio. Real tape has several nonlinear characteristics that together create its distinctive warm, compressed sound. The recording head applies pre-emphasis (boosting high frequencies before recording to improve signal-to-noise ratio), the magnetic medium introduces asymmetric saturation (positive and negative magnetization have slightly different limits), and the playback head applies de-emphasis (rolling off the high frequencies that were boosted during recording, restoring flat response while reducing tape hiss).

The asymmetry parameter controls the difference in saturation between positive and negative signal halves. At 1.0, the clipping is symmetric (same limit in both directions). As asymmetry decreases toward 0.5, the negative half is increasingly attenuated relative to the positive half, generating even-order harmonics that add warmth and fullness -- a characteristic of real tape where the magnetic coating saturates differently in each polarity.

Hysteresis models the magnetic memory of tape: the current magnetization depends not just on the current input but also on the previous magnetization state. This creates a subtle smearing or thickening of the sound, especially on transients, where the tape's magnetic state lags behind the signal. Higher hysteresis values increase this lag, producing a softer, more compressed feel.

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Color/TapeSaturation.h
Implementation Sources/FolioDSP/src/Color/TapeSaturation.cpp
Tests Tests/FolioDSPTests/TapeSaturationTests.swift
Bridge Sources/FolioDSPBridge/src/FolioDSPBridge.mm (TapeSaturationBridge)

Parameters

Index Name Description Min Max Default Min Default Max Default Unit
0 Drive Recording level -- higher values push deeper into tape saturation 1 50 1 10 3
1 Asymmetry Balance between positive and negative saturation (1.0 = symmetric) 0.5 1.0 0.6 1.0 0.8
2 Tone De-emphasis lowpass cutoff -- controls brightness of the output 500 16000 1000 8000 3000 Hz
3 Hysteresis Magnetic memory -- blends previous output state into current 0.0 0.5 0.0 0.3 0.1
4 Mix Dry/wet blend 0 100 0 100 100 %

Processing Algorithm

The process() function executes these steps for each input sample:

1. Pre-Emphasis

A first-order highpass filter boosts high frequencies before saturation, simulating the recording head's pre-emphasis circuit:

\[h = x - 0.85 \cdot x_{n-1}\]
\[x_p = x + 0.3 \cdot h\]

The 0.85 coefficient sets the highpass frequency, and the 30% blend controls how much pre-emphasis is applied.

2. Drive Gain

The pre-emphasized signal is multiplied by the drive factor:

\[x_d = x_p \cdot D\]

Where \(D\) is the drive parameter (linear, not dB).

3. Asymmetric Saturation

Hyperbolic tangent saturation with different behavior for positive and negative halves:

\[y_s = \begin{cases} \tanh(x_d) & \text{if } x_d \geq 0 \\ A \cdot \tanh\!\left(\dfrac{x_d}{\max(A,\; 0.01)}\right) & \text{if } x_d < 0 \end{cases}\]

Where \(A\) is the asymmetry parameter. When \(A = 1.0\), both halves saturate identically. When \(A < 1.0\), the negative half is scaled down, producing even harmonics.

4. Hysteresis

A one-sample feedback blend models the tape's magnetic memory:

\[y_h = y_s + H \cdot (s_{n-1} - y_s)\]
\[s_n = y_h\]

Where \(H\) is the hysteresis parameter and \(s_{n-1}\) is the previous hysteresis state. This is equivalent to a weighted average between the current saturated value and the previous output: when \(H = 0\), no memory; when \(H = 0.5\), equal weight between current and previous.

5. De-Emphasis (Tone Filter)

A one-pole lowpass filter rolls off high frequencies, undoing the pre-emphasis and shaping the final tone:

\[\alpha = 1 - e^{-2\pi \cdot f_{\text{tone}} / f_s}\]
\[y_t[n] = y_t[n-1] + \alpha \cdot (y_h - y_t[n-1])\]

6. DC Blocker

A standard first-order highpass filter removes any DC offset from the asymmetric saturation:

\[R = 1 - \frac{2\pi \cdot 10}{f_s}\]
\[y_{\text{dc}}[n] = y_t[n] - y_t[n-1] + R \cdot y_{\text{dc}}[n-1]\]

7. Normalization

The output is divided by \(\tanh(D \cdot 0.5)\) to roughly compensate for the level increase from drive:

\[y_n = \frac{y_{\text{dc}}}{\max(\tanh(D \cdot 0.5),\; 0.1)}\]

8. Dry/Wet Mix

\[y = x + (y_n - x) \cdot \frac{\text{mix}}{100}\]

Core Equations

\[y_s = \begin{cases} \tanh(x_p \cdot D) & x_p \cdot D \geq 0 \\ A \cdot \tanh(x_p \cdot D / A) & x_p \cdot D < 0 \end{cases}\]
\[y_h = y_s + H(s_{n-1} - y_s)\]
\[y = \text{deEmph}(\text{dcBlock}(y_h)) / \tanh(D/2)\]

Snapshot Fields

Field Type Range Unit Description
Input Level Float 0--1 Smoothed absolute input level
Output Level Float 0--1 Smoothed absolute output level
Drive Amount Float 1--50 Current drive setting
Saturation Amount Float 0--1 Ratio of saturated to driven level
Tone Frequency Float 500--16000 Hz Current de-emphasis cutoff frequency
Transfer Curve Float[16] -1--1 16-point input-to-output transfer function

Implementation Notes

  • DC blocker uses the standard first-order highpass: y = x - xprev + R * y where R = 1 - (2π·10/sr). This is the correct form (not the one-pole LP subtraction variant).
  • Asymmetry clamping: The denominator in the negative-half saturation is clamped to max(A, 0.01) to prevent division by zero when asymmetry approaches 0.5 (the parameter minimum).
  • Normalization: The divisor tanh(drive * 0.5) is clamped to a minimum of 0.1 to prevent excessive gain at very low drive values.
  • Transfer curve is computed in the snapshot emission path, sampling 16 points from \(x = -1\) to \(x = 1\) through the current drive and asymmetry settings.
  • Level tracking uses exponential smoothing with coefficient 0.01 for display-rate visualization.
  • Saturation amount in the snapshot is computed as \(|y_s| / \max(|x_d|, 0.001)\), measuring how much the saturation curve has compressed the signal.
  • All parameters are marked as smoothed in ParamInfo for bridge-level interpolation.
  • Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).

Equation Summary

y = tanh(preEmph(x)·drive); deEmph