Nodes/ꘇ Genereti/ꘇ chop.oscillator
ComfyUI Node

ꘇ chop.oscillator

A waveform you can wire into any FLOAT socket

By languel·Created about a month ago·Updated 3 days ago· 1
ꘇ chop.oscillator
    • channels
    • value
    ◄wave▾►
    ◄frequency1.00►
    ◄amplitude1.00►
    ◄offset0.00►
    ◄phase0.00►
    ◄channels1►
    ◄samples1►
    ◄sample_rate60.00►
    ◄time0.00►
    ◄offset_t0.00►

    ꘇ chop.oscillator is the simplest thing in the signal family and the one that teaches you the family: a wave, a frequency, an amplitude, and a FLOAT socket you can plug straight into a converted Comfy widget. Sine, triangle, saw, square and ramp, generated in the browser while the graph sits idle.

    What it is

    The plumbing doc's core case is repetition - one seed, five samplers, change it in one place. Genereti's CHOP chain is that idea with a clock attached: instead of a number, the source is a function of time, and the whole chain (scale it, gate it, smooth it, select a channel) runs live at frame rate. An oscillator is the canonical starter generator, and because it emits both a named channel block and a plain FLOAT, it works in two directions at once - control a parameter, and drive the CHOP operators that only accept CHOP wires.

    The obvious first move is a slow sine on a slider-adjacent parameter: amplitude 0.5, offset 0.5, frequency 0.1 gives you a 10-second breathing cycle between 0 and 1. The less obvious move is to use it as a clock - saw at 1 Hz is a linear ramp you can quantize or compare against.

    How it works

    Phase is time * frequency + phase, and every sample is that phase evaluated through the chosen shape: sine is sin(2π·phase), triangle runs −1..1, saw is phase mod 1 mapped to −1..1, square is ±1 split at the half cycle, and ramp is the unipolar phase mod 1 - the odd one out, 0..1 rather than bipolar. amplitude multiplies and offset adds, for both this node and the noise generator.

    The phase input is in cycles, not radians and not degrees: with frequency 1 and phase 0.5, a sine starts halfway through its cycle. frequency is cycles per second, since phase is built as seconds times frequency.

    Two things to know that aren't in the widget labels. All channels are identical. channels is available (up to 64) because the class inherits the shared generator parameters, but the phase calculation doesn't use the channel index, so a 4-channel oscillator gives you four copies of the same wave. If you want per-channel phase offset you need ꘇ chop.expression, whose c variable is the channel index - sin(t*tau + c) is the author's own default there, and that's what makes colour bands along a texture. Second, the optional offset_t port adds seconds to the local time domain before generation; unconnected it's zero, and it's there so you can nudge time from another scalar node without a parameter tab.

    The inputs and outputs that matter

    • wave - sine, triangle, saw, square, ramp. Defaults to sine.
    • frequency - default 1, range 0..10000. This is your rate control; leave it well under 60 unless you actually want audio-rate-ish content.
    • amplitude / offset - defaults 1 and 0. Set 0.5/0.5 for a 0..1 swing.
    • phase - default 0, range ±100000. Handy for making two oscillators offset from each other.
    • samples - samples per delivered block; the tooltip's advice is 1 for a responsive scalar, larger for high-rate signal content.
    • sample_rate - samples per second of signal timeline, not updates per second.
    • time - the domain offset used when nothing live is driving the node, i.e. on Queue.
    • channels / value out - channel names come out as chan0, chan1, …; value is the last sample of the first channel.

    Install

    One pack, all operators. Manager → search genereti (title "ꘇ Genereti") → install → restart ComfyUI → hard-refresh the browser. Manual:

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

    Use your ComfyUI's Python for the pip step. The requirements file is comfyui-frontend-package>=1.53.6 and that's it: no models, no Core ML, no separate server, so this is one of the cheapest packs you'll ever install. Open Workflows → Genereti → ꘇ-OpenTouch-Operators-and-Lessons for the guided version - a CHOP oscillator, smoothing, and a FLOAT wire controlling texture arithmetic - and ꘇ-Inspect-Values to watch the numbers live.

    Common issues

    The value doesn't move on Queue. Live runs use the project clock; the queue evaluates an explicit block from time. A queued graph is deterministic by design, not broken.

    Rate expectations. sample_rate 240 with samples 1 cannot deliver 240 updates a second, because live delivery rides browser animation frames. The docs are blunt about it: a one-sample 240 Hz configuration can't beat a 60 Hz display.

    Cycles throw. Loop an oscillator into its own upstream chain and the status line reports "CHOP cycles are not supported" instead of guessing.

    Channels won't phase-offset. Covered above, and it's the single most common surprise with this node: four channels are four identical waves. Wire an expression node when you need them to differ.

    Timeline binding. If the output looks like it ignored your time value, check whether the node is bound to project time - project binding feeds the project clock into time-based generators, and reading project time explicitly works even in free-time mode.

    Alpha. Super alpha, early classroom testing, per the README. Save your workflows under new names before pack updates.

    CategoryGenereti / CHOP

    Inputs (10)

    NameTypeDefaultDescription
    waveCOMBO5 options: sine, triangle, saw, square, ramp
    frequencyFLOAT1.000–10000—
    amplitudeFLOAT1.00-100000–100000—
    offsetFLOAT0.00-100000–100000—
    phaseFLOAT0.00-100000–100000—
    channelsINT11–64—
    samplesINT11–4096Samples per delivered block. Live updates/s = sample_rate / samples, limited by browser frames. Use 1 for responsive scalar control; 8 at 60 Hz delivers 7.5 blocks/s.
    sample_rateFLOAT60.001–1000Samples per second, not blocks per second. A block contains samples values; use samples=1 for updates near this rate.
    timeFLOAT0.00-100000–100000—
    offset_toptFLOAT0.00-100000–100000—

    Outputs (2)

    NameTypeDescription
    channelsGENERETI_CHOP—
    valueFLOAT—