Skip to content

Transformer Color

Tier: Color | ComponentType: 29 | Params: 5

Low-frequency saturation with high-frequency rolloff and resonance bump, modeling the nonlinear behavior of audio transformers.

Overview

TransformerColor simulates the tonal character of iron-core audio transformers found in vintage mixing consoles, tape machines, and microphone preamps. These transformers exhibit two key behaviors: the ferromagnetic core saturates low-frequency content (introducing soft, warm distortion), while parasitic capacitance and winding inductance create a natural high-frequency rolloff with an optional resonance peak just before the cutoff.

The implementation splits the input signal into low and high frequency bands using a one-pole crossover filter. The low band is processed through tanh saturation scaled by the drive parameter, adding subtle harmonic content that increases with signal level. The high band passes through a separate one-pole rolloff filter that progressively attenuates upper frequencies. An optional resonance bump near the rolloff frequency, created via a bandpass approximation from two cascaded one-pole filters, recreates the characteristic "air" peak found in many transformer-coupled circuits.

At low drive settings, the effect adds subtle weight and presence. At higher drive values, the low-end saturation becomes more pronounced, compressing transients and thickening the bass. The crossover frequency determines where saturation begins, and the rolloff frequency controls the high-frequency character from dark (low rolloff) to open (high rolloff).

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Color/TransformerColor.h
Implementation Sources/FolioDSP/src/Color/TransformerColor.cpp
Tests Tests/FolioDSPTests/TransformerColorTests.swift
Bridge Sources/FolioDSPBridge/src/FolioDSPBridge.mm (TransformerColorBridge)

Parameters

Index Name Description Min Max Default Min Default Max Default Unit
0 Drive Saturation intensity applied to the low band 1.0 20.0 1.0 5.0 2.0
1 Crossover Frequency dividing low (saturated) and high (rolloff) bands 50 2000 100 1000 300 Hz
2 Rolloff One-pole lowpass cutoff applied to the high band 2000 20000 4000 16000 10000 Hz
3 Resonance Peak gain near the rolloff frequency 0.0 12.0 0.0 6.0 2.0 dB
4 Mix Dry/wet blend 0 100 0 100 100 %

Processing Algorithm

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

1. Crossover Split

A one-pole lowpass filter separates the signal into low and high bands:

\[\alpha_c = 1 - e^{-2\pi \cdot f_{\text{cross}} / f_s}\]
\[\text{lpState} = \text{lpState} + \alpha_c \cdot (x - \text{lpState})\]
\[x_{\text{low}} = \text{lpState}, \quad x_{\text{high}} = x - x_{\text{low}}\]

2. Low Band Saturation

The low band is passed through tanh saturation with a normalization factor:

\[y_{\text{sat}} = \frac{\tanh(x_{\text{low}} \cdot d)}{\max(\tanh(d \cdot 0.5),\; 0.1)} \cdot 0.5\]

where \(d\) is the drive parameter. The denominator normalizes the output level so that increasing drive does not dramatically change the overall level, only the saturation character.

3. High Band Rolloff

A one-pole lowpass filter attenuates upper harmonics in the high band:

\[\alpha_r = 1 - e^{-2\pi \cdot f_{\text{roll}} / f_s}\]
\[\text{rollState} = \text{rollState} + \alpha_r \cdot (x_{\text{high}} - \text{rollState})\]
\[y_{\text{roll}} = \text{rollState}\]

4. Resonance Bump

When resonance is greater than 0 dB, a bandpass approximation adds a peak near the rolloff frequency. Two cascaded one-pole filters create the bandpass:

\[G_{\text{lin}} = 10^{R_{\text{dB}} / 20} - 1\]
\[s_0 = s_0 + \alpha_r \cdot (x_{\text{high}} - s_0)\]
\[s_1 = s_1 + \alpha_r \cdot (s_0 - s_1)\]
\[\text{bp} = s_0 - s_1\]
\[y_{\text{roll}} = y_{\text{roll}} + \text{bp} \cdot G_{\text{lin}}\]

The bandpass signal \((s_0 - s_1)\) has peak gain near the rolloff frequency and falls off on both sides, mimicking a transformer's resonance hump.

5. Recombine

\[y_{\text{combined}} = y_{\text{sat}} + y_{\text{roll}}\]

6. DC Blocker

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

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

7. Dry/Wet Mix

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

Core Equations

\[y_{\text{sat}} = \frac{\tanh(x_{\text{low}} \cdot d)}{\max(\tanh(0.5d),\; 0.1)} \cdot 0.5\]
\[y_{\text{roll}} = \text{LP}(x_{\text{high}},\; f_{\text{roll}}) + (s_0 - s_1) \cdot G_{\text{res}}\]
\[y = y_{\text{sat}} + y_{\text{roll}}\]

Where \(x_{\text{low}}\) and \(x_{\text{high}}\) are the crossover-split bands, \(d\) = drive, and \(G_{\text{res}}\) = linear resonance gain.

Snapshot Fields

Field Type Range Unit Description
Input Level Float 0--1 Smoothed input amplitude
Output Level Float 0--1 Smoothed output amplitude
Low Band Level Float 0--1 Smoothed low band amplitude
High Band Level Float 0--1 Smoothed high band amplitude
Drive Amount Float 1--20 Current drive value
Gain Reduction Float -60--0 dB Output-to-input ratio in dB, clamped to non-positive
Transfer Curve Float[16] -1--1 16-point saturation transfer function

Implementation Notes

  • Gain reduction is computed as \(20 \log_{10}(\text{outputLevel} / \text{inputLevel})\), clamped to \(\leq 0\), with a guard against division by zero.
  • Transfer curve is computed in the snapshot emission path (not per-sample), sampling 16 points from \(x = -1\) to \(+1\) through the current saturation function.
  • DC blocker uses the standard first-order highpass: y = x - xprev + R * y where R = 1 - (2pi*10/sr).
  • Level tracking uses exponential smoothing with coefficient 0.01 for display-rate visualization.
  • The resonance bandpass is only computed when resLin > 0, avoiding unnecessary work when resonance is at 0 dB.
  • 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 = sat(lo) + rolloff(hi) + resonance