Tremolo
Tier: Color | ComponentType: 17 | Params: 2
Amplitude modulation via an internal Oscillator LFO, with a rate range spanning sub-Hz tremolo through audio-rate AM synthesis.
Overview
Tremolo modulates a signal's amplitude using a low-frequency oscillator (LFO). The LFO is a full Oscillator instance running at the specified rate, which means it inherits all of the Oscillator's waveform capability. At low rates (0.5--8 Hz), this produces the classic tremolo effect heard in guitar amplifiers and electric pianos. As the rate increases past 20 Hz, the modulation enters the audio range and the effect transitions from rhythmic pulsing into amplitude modulation (AM) synthesis, generating sum and difference sidebands around the input frequency.
The depth parameter controls how much the LFO attenuates the signal. At depth = 0, the signal passes through unmodified. At depth = 1.0, the signal is fully modulated, dropping to silence at the LFO trough. The gain formula ensures the signal is always attenuated (never boosted), keeping the output bounded.
Unlike most components in FolioDSP, Tremolo processes audio as a buffer rather than a single sample, via process(float* buffer, int numSamples). The LFO ticks once per sample inside the buffer loop, ensuring phase-accurate modulation even at audio rates.
File Locations
| Path | |
|---|---|
| Header | Sources/FolioDSP/include/FolioDSP/Color/Tremolo.h |
| Implementation | Sources/FolioDSP/src/Color/Tremolo.cpp |
| Tests | Tests/FolioDSPTests/TremoloTests.swift |
| Bridge | Sources/FolioDSPBridge/src/FolioDSPBridge.mm (TremoloBridge) |
Parameters
| Index | Name | Description | Min | Max | Default Min | Default Max | Default | Unit |
|---|---|---|---|---|---|---|---|---|
| 0 | Rate | LFO frequency -- sub-Hz for slow tremolo, audio-rate for AM synthesis | 0.01 | 20000 | 0.5 | 15 | 4.0 | Hz |
| 1 | Depth | Modulation depth -- 0 = no effect, 1 = full silence at trough | 0.0 | 1.0 | 0.0 | 1.0 | 0.5 |
Processing Algorithm
The process() function iterates over the buffer, applying per-sample LFO modulation:
1. LFO Tick
The internal Oscillator advances by one sample, producing the current LFO value in the range \([-1, 1]\):
The Oscillator's frequency is set to the current rate before the buffer loop begins.
2. Gain Calculation
The LFO value is rescaled from \([-1, 1]\) to \([0, 1]\), then used to compute the amplitude gain:
Where \(d\) is the depth parameter. When \(\text{lfoValue} = -1\), the parenthesized term is 0 and \(g = 1\) (no attenuation). When \(\text{lfoValue} = 1\), the term is 1 and \(g = 1 - d\) (maximum attenuation).
3. Apply Gain
Each sample in the buffer is multiplied by the gain:
Core Equations
Where \(r\) = rate (Hz), \(d\) = depth, \(t\) = time.
Snapshot Fields
| Field | Type | Range | Unit | Description |
|---|---|---|---|---|
| Rate | Float | 0.01--20000 | Hz | Current LFO frequency |
| Depth | Float | 0--1 | Current modulation depth | |
| Gain | Float | 0--1 | Instantaneous amplitude gain | |
| LFO Phase | Float | 0--1 | Normalized LFO phase position |
Implementation Notes
- Buffer-based processing: Unlike most components that process single samples, Tremolo takes a
float*buffer and sample count. The bridge wraps this as a 1-sample buffer call for chain mode compatibility. - Full Oscillator as LFO: The LFO is an
Oscillatorinstance, inheriting its waveform generation (sine by default). This is deliberate -- it enables future waveform selection for the LFO shape. - Phase normalization: The snapshot reports
lfoPhaseas the Oscillator's raw phase divided by \(2\pi\), yielding a 0--1 range for UI display. - No parameter smoothing on depth: Both rate and depth use
std::atomic<float>for lock-free thread safety. Both are marked as smoothed in ParamInfo for bridge-level smoothing. - Snapshot emission is decimated to ~60 fps (every 735 samples at 44.1 kHz).
Equation Summary
y = x · (1 - depth·(1/2+1/2·sin(2πrt)))