Nodes/ꘇ Genereti/ꘇ mod.scale
ComfyUI Node

ꘇ mod.scale

Twelve numbers that keep a whole patch in key

By languel·Created about a month ago·Updated 3 days ago· 1
ꘇ mod.scale
    • music json
    ◄root0►
    ◄scaleminor►
    ◄tuning440.00►

    mod.scale is the smallest node in this batch and possibly the most useful one, because it's the thing that stops a generated melody from sounding random. You pick a root note, a scale, and a tuning reference; it emits a small JSON blob describing that musical context. Anything downstream that quantizes pitch - chop.quantize is the obvious partner - reads it, and your arpeggiator stops wandering into F# minor.

    It lives in the "Performance" family of ꘇ Genereti (languel/genereti, by Liuboto, MIT, super-alpha). That family is the workflow-scoped music brain: shared browser clock, scale, quantization, timeline, monitor. Read that as "the pack's toy music theory layer that makes its noisy control signals behave musically," which is precisely the job.

    What comes out of it

    One output: music json, a STRING. The contents are a small object - root, scale, degrees (the semitone offsets), tuning, and referenceNote. That's it. No audio, no channels, no side effects. It's a config record, and its consumers are what make it worth wiring.

    The three inputs map straight onto it. root is an INT from 0 to 11 (pitch class - 0 is C, 11 is B, so 9 is A minor's root). scale is a COMBO with six options, and these are exactly the ones supported:

    • chromatic - all twelve, which is to say "quantize nothing"
    • major, minor
    • harmonicMinor, melodicMinor
    • pentatonic - the five-note one, which is the forgiving choice when you're feeding in motion-capture pitch data

    tuning is a FLOAT (default 440, range 1–1000) - the A4 reference in Hz. It's stored in the JSON for consumers that convert pitch to frequency; changing it doesn't retune anything by itself.

    Note the naming collision you'll trip over once: this node displays as ꘇ mod.scale but its node class is GeneretiPerformanceScale, and it lives in the Performance category, not with the mod.* audio-bus family. The mod. prefix is the pack's legacy answer to "this belongs with the musical stuff" - the node catalogue groups it under performance controllers.

    How to use it in practice

    Wire music json into chop.quantize's optional music input, and now every note channel arriving at that node gets snapped to the nearest degree of your chosen scale. Or leave it unwired: chop.quantize falls back to the project's performance snapshot, which carries a music document too, so an unattended scale node still gives you the default minor scale. If you use the Livecode/p5 side of the pack, the same scale context shows up as __.root, __.tuning and __.music inside code - one setup, two places it takes effect.

    The pleasant surprise here is how well this pairs with the messy stuff. Perception features, chaotic oscillators, hand-tracked pitch - all of it lands in-tune if you drop a scale node and a quantizer in between. Pitch quantization is a one-line trick that makes procedural music sound intentional.

    Install

    Manager → search "Genereti" → install ꘇ Genereti → restart ComfyUI → refresh the browser. Manual path:

    git clone https://github.com/languel/genereti.git custom_nodes/genereti
    ./.venv/bin/python -m pip install -r custom_nodes/genereti/requirements.txt
    

    The pack pins comfyui-frontend-package>=1.53.6; everything else comes from ComfyUI's own environment. Target is ComfyUI 0.38.2+, Python 3.11+, current browser. The performance-family examples ship with the package under Workflows → Genereti - ꘇ-Performance-Timeline is the entry point, and Alt+Shift+T opens the docked timeline once you're in.

    Gotchas

    This node is only as useful as its consumer. On its own it produces a string you can look at with ꘇ dat.inspect and nothing else - if your notes still sound off, check that the quantizer is actually receiving it, since a connected input wins over the performance snapshot, and an empty string falls back to the snapshot.

    Second, the scale list is fixed. Six scales, no custom interval sets. If you need something exotic you're doing it in a CHOP expression, not by editing this node's options.

    And the usual boundary: Queue evaluates these control nodes from a frozen snapshot of the project's performance document. mod.scale itself is deterministic - the same root/scale/tuning produces the same JSON - so it behaves identically Live and queued, which is more than you can say for most of the family.

    CategoryGenereti / Performance

    Inputs (3)

    NameTypeDefaultDescription
    rootINT00–11—
    scaleCOMBOminor6 options: chromatic, major, minor, harmonicMinor, melodicMinor, pentatonic
    tuningFLOAT440.001–1000—

    Outputs (1)

    NameTypeDescription
    music jsonSTRING—