@maruaudio/dsp/oscillators/lissajous-duo is a stereo pair of oscillators whose frequencies hold an exact integer ratio. One f32 master accumulator advances by f32(baseFreq / (sampleRate × ratioDen)) per sample, and both channel phases are pure functions of it: X (left) is frac(master × ratioDen) at baseFreq, Y (right) is frac(master × ratioNum + phaseOffset) at baseFreq × ratioNum / ratioDen. Because neither channel has its own accumulator, the X:Y ratio is exactly ratioDen:ratioNum and the traced figure closes on itself instead of precessing. Saw and square use the shared PolyBLEP stage functions.
Parameters
| Path | Setter | Range as coded | Default | Unit |
|---|---|---|---|---|
waveform | setLissajousDuoNodeWaveform | Rounded, then 0..2: sine, saw, square | 0 | index |
baseFreq | setLissajousDuoNodeBaseFreq | 0 to 20000 | 220 | Hz (X) |
ratioNum, ratioDen | setLissajousDuoNodeRatio | Each rounded, then 1 to 64 | 1, 1 | integer |
amp | setLissajousDuoNodeAmp | 0 to 1 | 0.8 | linear |
phaseOffset | setLissajousDuoNodePhaseOffset | 0 to 1 | 0 | cycles (Y) |
Lifecycle
initLissajousDuoNode(sampleRate) → setters → per sample, lissajousDuoXSample and lissajousDuoYSample, then lissajousDuoAdvance → resetLissajousDuoNode, which zeroes the master accumulator only.
When to use it
Drawing just-intonation intervals on an oscilloscope or XY display, where a 3:2 fifth should hold one still figure. An equal-tempered interval is irrational and cannot be expressed here.
Limits
- Stereo, sample tick. The channel reads do not apply
amp; the caller does, as the Graph nodelissajous-duodoes for both channels. - The master accumulator is f32, so a closed figure carries the f32 residual the tests pin (7.15 × 10⁻⁷ after 96 samples at 100 Hz, 4.8 kHz, 3:2).
- Waveform indices outside 0..2 read as sine in
lissajousDuoWaveSample. - Conditional clamps: a NaN setting passes through.