Skip to content

Transient Shaper

Tier: Color | ComponentType: 43 | Params: 6

Dual envelope follower for independent attack and sustain gain control via transient detection.

Overview

TransientShaper separates a signal's transient (attack) content from its sustained body using two envelope followers with different time constants. A fast follower tracks rapid amplitude changes (transients), while a slow follower tracks the overall signal level (sustain). The difference between these two envelopes indicates when a transient is occurring -- during an attack, the fast envelope rises above the slow envelope, and this gap is used to crossfade between two independent gain values.

This technique allows surgical control over the percussive character of any signal. Boosting the attack gain relative to sustain gain makes drums punchier, brings out pick attack on guitars, and adds definition to transient-rich material. Reducing the attack gain softens transients, creating a smoother, more sustained sound without altering the overall dynamics like a compressor would.

The four envelope time parameters provide full control over the detection behavior. Faster attack/release on the fast envelope captures shorter transients with greater precision. Slower attack/release on the slow envelope determines how quickly the "sustain reference" adapts. The gain crossfade is normalized relative to the signal level, so the transient detection works consistently regardless of input amplitude.

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Color/TransientShaper.h
Implementation Sources/FolioDSP/src/Color/TransientShaper.cpp
Tests Tests/FolioDSPTests/TransientShaperTests.swift
Bridge Sources/FolioDSPBridge/src/FolioDSPBridge.mm (TransientShaperBridge)

Parameters

Index Name Description Min Max Default Min Default Max Default Unit
0 Attack Gain Gain applied during detected transients 0.0 5.0 0.0 3.0 1.0
1 Sustain Gain Gain applied during sustained portions 0.0 5.0 0.0 3.0 1.0
2 Fast Attack Fast envelope attack time 0.01 5.0 0.1 1.0 0.3 ms
3 Fast Release Fast envelope release time 1.0 200.0 5.0 50.0 20.0 ms
4 Slow Attack Slow envelope attack time 5.0 200.0 10.0 50.0 20.0 ms
5 Slow Release Slow envelope release time 20.0 1000.0 50.0 300.0 100.0 ms

Processing Algorithm

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

1. Envelope Coefficient Computation

Envelope follower coefficients are derived from time constants in milliseconds:

\[\alpha = 1 - e^{-2\pi / (t_{\text{ms}} \cdot 0.001 \cdot f_s)}\]

Four coefficients are maintained: fast attack \(\alpha_{fa}\), fast release \(\alpha_{fr}\), slow attack \(\alpha_{sa}\), slow release \(\alpha_{sr}\).

2. Fast Envelope

The fast envelope follower tracks transients with short time constants:

\[\alpha_f = \begin{cases} \alpha_{fa} & \text{if } |x| > E_f \\ \alpha_{fr} & \text{otherwise} \end{cases}\]
\[E_f[n] = E_f[n-1] + (|x| - E_f[n-1]) \cdot \alpha_f\]

3. Slow Envelope

The slow envelope follower tracks the sustain level with longer time constants:

\[\alpha_s = \begin{cases} \alpha_{sa} & \text{if } |x| > E_s \\ \alpha_{sr} & \text{otherwise} \end{cases}\]
\[E_s[n] = E_s[n-1] + (|x| - E_s[n-1]) \cdot \alpha_s\]

4. Transient Detection

The transient amount is the gap between fast and slow envelopes:

\[T = \max(E_f - E_s,\; 0)\]

This is normalized relative to the fast envelope to make the detection amplitude-independent:

\[T_{\text{norm}} = \begin{cases} \min\left(\dfrac{T}{E_f},\; 1\right) & \text{if } E_f > 10^{-6} \\ 0 & \text{otherwise} \end{cases}\]

5. Gain Computation

The output gain crossfades between sustain gain and attack gain based on the normalized transient amount:

\[G = G_s + (G_a - G_s) \cdot T_{\text{norm}}\]

During sustained portions (\(T_{\text{norm}} \approx 0\)), the gain equals \(G_s\). During transients (\(T_{\text{norm}} \approx 1\)), the gain approaches \(G_a\).

6. Output

\[y = x \cdot G\]

Core Equations

\[E_f[n] = E_f[n-1] + (|x| - E_f[n-1]) \cdot \alpha_f\]
\[E_s[n] = E_s[n-1] + (|x| - E_s[n-1]) \cdot \alpha_s\]
\[T_{\text{norm}} = \min\left(\frac{\max(E_f - E_s, 0)}{E_f}, 1\right)\]
\[G = G_s + (G_a - G_s) \cdot T_{\text{norm}}\]

Snapshot Fields

Field Type Range Unit Description
Input Level Float 0--1 Smoothed input amplitude
Output Level Float 0--2 Smoothed output amplitude (can exceed 1.0 with gain > 1)
Fast Envelope Float 0--1 Current fast envelope value
Slow Envelope Float 0--1 Current slow envelope value
Transient Amount Float 0--1 Normalized transient detection (fast - slow)
Attack Gain Float 0--5 Current attack gain (smoothed)
Sustain Gain Float 0--5 Current sustain gain (smoothed)
Current Gain Float 0--5 Instantaneous applied gain

Implementation Notes

  • Envelope coefficients are recomputed via updateCoefficients() whenever the time parameters change, not per-sample. This avoids redundant exponential calculations on the audio thread.
  • ParamSmoother is used for attack gain and sustain gain to prevent zipper noise on rapid parameter changes. The envelope time parameters are not smoothed (they update coefficients directly).
  • Normalized transient detection divides by the fast envelope rather than absolute amplitude, making the transient/sustain separation work consistently at any signal level.
  • Guard against division by zero: the normalization only occurs when \(E_f > 10^{-6}\), preventing NaN from silent passages.
  • With both gains set to 1.0 (default), the component is unity gain and passes audio through unchanged.
  • Setting attack gain to 0 and sustain gain to 1 creates a "transient remover" that ducks during attacks.
  • Setting attack gain to 3 and sustain gain to 0.5 creates aggressive transient emphasis.
  • Level tracking uses exponential smoothing with coefficient 0.01 for display-rate visualization.
  • All atomic parameters use std::memory_order_relaxed for lock-free thread safety.
  • Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).

Equation Summary

y = x * blend(sustain, attack, transient)