ꘇ mod.synth
A real polyphonic synth hiding inside a ComfyUI node
- notes
- audio
ꘇ mod.synth is a polyphonic subtractive synthesizer living in a ComfyUI node. Four voice types, a full ADSR, a resonant filter, glide, vibrato and up to 32 voices - and no model, no checkpoint, no download. It plays notes that arrive as control data, and it plays them live in your browser.
What it is
The Genereti pack is a realtime creative-coding layer for ComfyUI: browser-side shaders, textures, capture and audio, wired with top.* (textures), chop.* (control signals) and mod.* (audio) nodes in TouchDesigner's naming convention. mod.synth is the instrument in that family. It takes a notes control block - usually from mod.sequence or from chop.* generators - and turns it into a GENERETI_AUDIO_BUS you can run through gain, filter, delay and mixer before hitting mod.output.
Why you'd reach for it: a workflow that already animates visuals from sound, or a demo where you need music that responds to parameters you're already automating. chop.lfo into a filter cutoff is three nodes and no assets.
How it works
Each note spawns a voice: an oscillator (plus a filter and an envelope gain) that gets released when the note ends. That's textbook synthesis, and it explains the parameter list.
sine- plain oscillator.subtractive- a sawtooth through the filter, which is wherecutoffandresonanceearn their place.fm- a sine carrier with a modulator running at twice the note frequency, for metallic and bell-ish tones.reed- a square-wave approximation of a reed instrument. The docs are honest that it's an approximation, not physical modelling.
glide only applies to held pitches changing - the browser side ramps the existing oscillator instead of retriggering. Sequenced notes are scheduled as separate events and ignore glide, which surprises people the first time. Voices are capped by polyphony; the oldest get destroyed when you exceed it, so a runaway arpeggio won't eat the machine.
The inputs and outputs that matter
notes is the only input that isn't a knob: a GENERETI_CHOP block with note, gate and velocity channels. Pitch is raw MIDI (fractional allowed), velocity is 0–1, and gate counts as on above 0.5.
Then the ones you'll actually turn:
voice- the four options above.level- 0 to 1, default 0.35. Quiet on purpose; the browser scales it down further internally, and you lean onmod.gainandmod.outputfor real volume.attack/decay/sustain/release- ADSR, defaults 0.02 / 0.15 / 0.6 / 0.3. The default envelope is a short pluck; a longreleaseis what makes a pad out of a sine.cutoff(default 2200) andresonance(0.7) - the filter, most useful onsubtractive.glide(0.015),vibrato(0 by default) andvibrato_rate(5 Hz) - performance feel.polyphony- 1 to 32, default 8.
One output: audio, a bus. Chain it into mod.gain, mod.filter, mod.delay, mod.mixer, then mod.output. Don't try to feed it into a Save Audio node - buses are live browser routes, not Comfy tensors.
Install
Manager → search Genereti, or:
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 and refresh the browser tab. The dependency story is unusually light for an audio pack: that requirements file is one line (comfyui-frontend-package>=1.53.6), and torch/NumPy/Pillow/aiohttp already ship with ComfyUI. No model files. Comfy ≥ 0.38.2, Python ≥ 3.11. Start from Workflows → Genereti → ꘇ-Modular-Audio.
Common issues
No sound after queueing. Queueing never plays - the synth returns a route description. Press ▷ on the downstream mod.output; the browser needs that click before it will open an audio context.
The node has an audition keyboard that does nothing. The little keys under the node are labelled "Audition · requires mod.output Start" for a reason. No started output, no sound; that's the whole rule of this family.
Notes hang or overlap into mush. Check polyphony and your release. A long release with a dense sequence stacks voices until the cap starts eating the oldest ones; you'll hear it as a thinning or gating artefact rather than an error. Transport/pattern changes cancel pending voices, so a seek or loop jump can cut a note mid-envelope - that's intentional.
Pitch changes not sliding. glide is for held notes only.
Background tab weirdness. Web Audio keeps running, but event lookahead can be affected by browser throttling in a background tab; keep the tab focused when timing matters. And note the pack's own warning: it's a solo MIT alpha (Liuboto, v0.1.4), "super alpha - early classroom testing", so back up workflows before you update.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| notes | GENERETI_CHOP | — | |
| voice | COMBO | 4 options: sine, subtractive, fm, reed | |
| level | FLOAT | 0.350–1 | — |
| attack | FLOAT | 0.020.001–5 | — |
| decay | FLOAT | 0.150.001–5 | — |
| sustain | FLOAT | 0.600–1 | — |
| release | FLOAT | 0.300.005–5 | — |
| cutoff | FLOAT | 2200.0020–18000 | — |
| resonance | FLOAT | 0.700.1–12 | — |
| glide | FLOAT | 0.010–1 | — |
| vibrato | FLOAT | 0.000–2 | — |
| vibrato_rate | FLOAT | 5.000.1–20 | — |
| polyphony | INT | 81–32 | — |
| wave | COMBO | auto | Oscillator waveform; auto follows the voice. |
| filter_mode | COMBO | lowpass | 3 options: lowpass, highpass, bandpass |
| detune | FLOAT | 0.00-100–100 | — |
| filter_env | FLOAT | 0.000–1 | — |
| fm_ratio | FLOAT | 2.000.1–10 | — |
| fm_index | FLOAT | 0.700–10 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| audio | GENERETI_AUDIO_BUS | — |