Skip to content

Tube Warmth

Tier: Color | ComponentType: 27 | Params: 5

Even and odd harmonic generation with controllable balance, modeling the nonlinear behavior of vacuum tube amplification stages.

Overview

TubeWarmth generates harmonic distortion by blending two distinct nonlinear processes: a quadratic (x²) path that produces even harmonics (2nd, 4th, 6th...) and a hyperbolic tangent path that produces odd harmonics (3rd, 5th, 7th...). This mirrors real tube behavior — triode stages tend toward even harmonics while push-pull configurations emphasize odd harmonics.

The Even/Odd balance control crossfades between these two distortion characters. At 0.0, the output is pure even-harmonic distortion (warm, "musical" coloring). At 1.0, it's pure odd-harmonic saturation (harder, more compressed). The default 0.3 gives a triode-like voicing with predominantly even harmonics and a touch of odd-order edge.

A DC blocker is essential because the x² term converts any signal into a unipolar (positive-only) waveform, generating a DC offset proportional to signal level. The one-pole lowpass tone filter rolls off harsh high-frequency harmonics, and a normalization stage compensates for the level increase from distortion.

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Color/TubeWarmth.h
Implementation Sources/FolioDSP/src/Color/TubeWarmth.cpp
Tests Tests/FolioDSPTests/TubeWarmthTests.swift
Bridge Sources/FolioDSPBridge/src/FolioDSPBridge.mm (TubeWarmthBridge)

Parameters

Index Name Description Min Max Default Min Default Max Default Unit
0 Drive Distortion intensity — scales the nonlinear terms 1.0 20.0 1.0 5.0 2.0
1 Even/Odd Balance between even (x²) and odd (tanh) harmonics 0.0 1.0 0.0 1.0 0.3
2 Bias DC offset added before distortion, shifts operating point -0.2 0.2 -0.1 0.1 0.02
3 Tone One-pole lowpass cutoff, tames harsh upper harmonics 1000 20000 3000 12000 8000 Hz
4 Mix Dry/wet blend 0 100 0 100 100 %

Processing Algorithm

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

1. Bias Offset

A small DC offset is added to shift the signal's operating point on the transfer curve:

\[x_b = x + \text{bias}\]

With the default bias of 0.02, the signal sits slightly off-center, which causes the even-harmonic (x²) path to produce asymmetric distortion — a characteristic of single-ended triode stages.

2. Even Harmonic Generation (x²)

The quadratic path adds the square of the biased signal, scaled by drive:

\[a_{\text{even}} = (1 - \text{bal}) \cdot (\text{drive} - 1)\]
\[y_{\text{even}} = x_b + a_{\text{even}} \cdot x_b^2\]

The x² term produces exclusively 2nd harmonic content (and DC). The drive - 1 factor means at drive = 1.0, no distortion is added. The (1 - bal) factor fades this path out as Even/Odd approaches 1.0.

3. Odd Harmonic Generation (tanh)

The hyperbolic tangent path provides soft-clipping saturation:

\[a_{\text{odd}} = \text{bal} \cdot (\text{drive} - 1)\]
\[y_{\text{odd}} = \tanh(x_b \cdot (1 + a_{\text{odd}}))\]

The tanh function symmetrically compresses the signal, generating odd-order harmonics (3rd, 5th, 7th...). Higher drive values push the signal further into saturation.

4. Blend

The two paths are crossfaded using the Even/Odd balance:

\[y_{\text{blend}} = (1 - \text{bal}) \cdot y_{\text{even}} + \text{bal} \cdot y_{\text{odd}}\]

5. DC Blocker

A first-order highpass filter removes the DC offset introduced by the x² term:

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

The 10 Hz cutoff preserves all audible content while removing subsonic drift.

6. Tone Filter

A one-pole lowpass filter smooths harsh upper harmonics:

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

7. Normalization

A level correction compensates for the gain increase from distortion:

\[k = \frac{1}{\max(\tanh(1 + (\text{drive} - 1) \cdot 0.5),\ 0.1)}\]
\[y_{\text{norm}} = y_{\text{tone}} \cdot k\]

8. Dry/Wet Mix

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

Core Equations

\[y_{\text{even}} = x_b + (1-b)(d-1) \cdot x_b^2\]
\[y_{\text{odd}} = \tanh(x_b \cdot (1 + b(d-1)))\]
\[y_{\text{blend}} = (1-b) \cdot y_{\text{even}} + b \cdot y_{\text{odd}}\]

Where \(x_b = x + \text{bias}\), \(b\) = Even/Odd balance, \(d\) = drive.

Snapshot Fields

Field Type Range Unit Description
Input Level Float 0–1 Smoothed input amplitude
Output Level Float 0–1 Smoothed output amplitude
Even Harmonic Level Float 0–1 Level of even-harmonic contribution
Odd Harmonic Level Float 0–1 Level of odd-harmonic contribution
Bias Float -0.2–0.2 Current bias value
Tone Frequency Float 1000–20000 Hz Current tone filter cutoff
Transfer Curve Float[16] -1–1 16-point input→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 essential — without it, the x² path generates a DC offset that grows with signal level.
  • Level tracking uses exponential smoothing with coefficient 0.01 for display-rate visualization.
  • Transfer curve is computed in the snapshot emission path (not per-sample), sampling 16 points from x = -1 to +1 through the current distortion function.
  • All parameters use std::atomic<float> for lock-free thread safety.
  • Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).

Equation Summary

y = (1-b)·(xb + a_even·xb²) + b·tanh(xb·(1+a_odd)) where xb = x + bias