@maruaudio/dsp/modulation/tremolo modulates the level of one signal with a non-amplifying LFO gain, y = fround(x × (1 − depth/2 + depth/2 × wave)). Depth 0 is transparent and depth 1 swings from silence to unity. The wave is a sine (the default), the canonical PolyBLEP triangle integrator of @maru/voices-stages clamped to ±1, or a square smoothed by a 2 ms one-pole so a shape choice never makes an instant gain step.
Parameters
| Setter | Range the setter enforces | Default |
|---|---|---|
setTremoloRate | 0.1 to 20 Hz | 5 Hz |
setTremoloDepth | 0 to 1 | 0.5 |
setTremoloShape | Clamped to 0 to 2, rounded; NaN → sine: TREMOLO_SHAPE_SINE, TRIANGLE, SQUARE | Sine |
setTremoloPhaseOffset | −180 to 180 degrees, stored as 0 to 1 cycles | 0° |
The phase offset is also the reset point and is applied at once. A shape change keeps the phase and clears the shaped-only state; repeating the current shape changes nothing.
Lifecycle
initTremoloNode → prepareTremoloNodeSampleRate when the rate changes → setters → tremoloNodeTick → resetTremoloNode, which returns the phase to the offset and clears the square smoother and triangle integrator. Prepare re-derives the square smoother's coefficient; the LFO follows the rate because it advances by rate / sampleRate. Ticks allocate nothing and do no I/O.
When to use it
Rhythmic level movement on a guitar, keys or pad. Two states with phase offsets 180° apart form a phase-locked stereo pair.
Limits
- Mono sample tick; one state per channel.
- The phase accumulator is f32 and wraps into [0, 1).
- Rate and depth changes apply at once, with no smoothing.
- The clamps are the kernel node's conditional clamp, not the
math/rangepolicy.