ꘇ mod.lissajous
See your stereo image as an XY trace
- input
- audio
- channels
- rms
- peak
- image
ꘇ mod.lissajous plots left against right and draws the result as an XY trace - the vectorscope view every mixing engineer knows. In Genereti it's also another source of left/right control channels and an IMAGE you can route into the visual half of your workflow, which is the more useful half of the story for a ComfyUI user.
What it is
The mod.* nodes are a live Web Audio patching layer that runs in the browser tab, alongside chop.* control signals, named after TouchDesigner's top/chop/dat convention. mod.lissajous is one of four inline analysis taps - with mod.scope, mod.spectrum and mod.analyze - that share an identical socket set: audio through, channels out, rms and peak floats, plus a drawing.
What distinguishes it is the drawing. Instead of amplitude over time, you get a phase portrait of the stereo field, and phase relationships are the one thing a waveform and a spectrum both fail to show you.
How it works
The bus is split into two AnalyserNodes and read as time-domain samples. Each sample pair becomes a point: left on one axis, right on the other. What you see is diagnostic:
- A vertical or diagonal line means the channels are correlated - mono-ish content, or a pan that keeps the two sides in phase.
- A fattened blob or a horizontal spread means the sides disagree, which is what stereo widening, a wide delay, or a phase-inverted element looks like.
- A perfect diagonal circle is the classic Lissajous of two tones at a stable frequency ratio - something this node will happily produce from a pure synth note.
The channels output gives the same left and right waveform blocks the scope produces, at the AudioContext sample rate. fft_size sets the analyser buffer, smoothing is the spectral smoothing constant, and display_gain scales only the drawing - never the sound, never the reported measurements. The drawing is a 512×512 IMAGE (the analyzer taps output 256-high images; the Lissajous is the taller one).
One nice detail: the audio path is untouched. Modules are reused rather than rebuilt per frame, so dropping a Lissajous into a busy patch costs you a split and two analysers, nothing more.
The inputs and outputs that matter
Inputs: input (GENERETI_AUDIO_BUS, passed through), fft_size (256/512/1024/2048/4096, default 1024), smoothing (0–0.99, default 0.5), display_gain (0.1–20, default 2 - the demo patches push this to 16–20 for visibility).
Outputs: audio (keep chaining to mod.output), channels (CHOP: left, right), rms (FLOAT), peak (FLOAT), image (the XY trace as an IMAGE).
Practical wiring: put the Lissajous inline, take image off to whatever draws images in your graph, and take rms onto a converted numeric input if you want a control value. If all you need is a level, save yourself the node and use mod.analyze. If what you actually want is a visual that reacts to the stereo field, this is the only tap that shows you phase.
Install
Manager → search Genereti, or from your ComfyUI directory:
git clone https://github.com/languel/genereti.git custom_nodes/genereti
./.venv/bin/python -m pip install -r custom_nodes/genereti/requirements.txt
Restart ComfyUI, then reload the browser page; the analysis nodes need that round trip to register. No heavy dependencies: requirements.txt is a single line (comfyui-frontend-package>=1.53.6), with the rest supplied by ComfyUI itself, and no model downloads anywhere in the audio family. Comfy ≥ 0.38.2, Python ≥ 3.11. The ꘇ-Livecode-Audio-Visual and ꘇ-Sound-Analysis workflows under Workflows → Genereti both wire a Lissajous already.
Common issues
A dot or a flat line instead of a shape. You queued. Queued runs of these taps return silent channels, zero floats and a placeholder image; they don't read live audio. Start mod.output and watch it run.
The trace is a shapeless cloud. That's usually correct for a mix - it's the point of the node. Feed it a single panned source (solo one channel on mod.mixer) and you'll get the clean diagonal that makes the diagnostic obvious.
The shape won't sit still. A trace only closes into a stable figure when the content is periodic and both channels agree on the periodism. Sequenced notes, drummer noise and delay tails all smear it. Try it on one sustained mod.synth note.
display_gain won't make it louder. It's a drawing scale only. Sound and measurements are unaffected by design - the docs are explicit about it, and it's the node's most commonly misread control.
Panic zeroes it. Stopping clears all measurements, so expect the trace to collapse when you hit Panic.
Standing note for the whole pack: a solo MIT alpha by Liuboto, currently v0.1.4, self-described as "super alpha - early classroom testing", with a README warning to back up workflows before updating.
Inputs (15)
| Name | Type | Default | Description |
|---|---|---|---|
| input | GENERETI_AUDIO_BUS | — | |
| fft_size | COMBO | 1024 | 5 options: 256, 512, 1024, 2048, 4096 |
| smoothing | FLOAT | 0.500–0.99 | — |
| display_gain | FLOAT | 2.000.1–20 | — |
| channel_viewopt | COMBO | stereo | 2 options: stereo, split |
| signal_viewopt | COMBO | level | 2 options: level, delta |
| widthopt | INT | 51264–2048 | — |
| heightopt | INT | 51264–2048 | — |
| x_axisopt | COMBO | left | 12 options: left, right, mid, side, left_delta, right_delta, +6 |
| y_axisopt | COMBO | right | 12 options: left, right, mid, side, left_delta, right_delta, +6 |
| x_gainopt | FLOAT | 1.000.01–100 | — |
| y_gainopt | FLOAT | 1.000.01–100 | — |
| rotationopt | FLOAT | 0.00-180–180 | — |
| trailopt | FLOAT | 0.000–0.98 | — |
| line_widthopt | FLOAT | 1.500.25–8 | — |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| audio | GENERETI_AUDIO_BUS | — |
| channels | GENERETI_CHOP | — |
| rms | FLOAT | — |
| peak | FLOAT | — |
| image | IMAGE | — |