Nodes/ꘇ Genereti/ꘇ chop.speed
ComfyUI Node

ꘇ chop.speed

The integrator, and a free stopwatch

By languel·Created about a month ago·Updated 3 days ago· 1
ꘇ chop.speed
  • input
  • channels
  • value

ꘇ chop.speed accumulates. Each output sample is the running total of everything that came before it, divided by the sample rate - so a constant input of 1 becomes a ramp climbing one unit per second. It's the integral to ꘇ chop.slope's derivative, and the pair of them means you can move between "how fast" and "how far" anywhere in a chain.

What it is

Most of the CHOP processors are stateless filters: value in, value out. Speed is one of the three that remember something (the others being ꘇ chop.slope and ꘇ chop.lag), which changes how you think about the node. It's not transforming a signal, it's accumulating one. The plainest use is the stopwatch: feed it a constant 1 and you have a counter of elapsed seconds that runs while the graph runs, no expressions involved.

The second use is position from velocity. If ꘇ chop.slope on a slider gives you how fast you're turning a knob, speed on that gives you total travel - which is a surprisingly good driver for anything you want to feel "wound up" rather than "set", a filter amount that keeps climbing while you keep moving, a texture rotation that accumulates drift instead of oscillating.

How it works

Per sample: multiply by nothing, divide by nothing, add value / sample_rate to the running total. That's the whole mechanism, and the units fall out of it - sum of (input per sample) divided by samples per second gives input-units per second of accumulation. Feed a 0..1 signal and after ten seconds at 1.0 you're at 10.0. Feed a −1..1 oscillating signal and you get a wandering walk rather than a rise.

State is where the subtlety lives. Live, the node keeps its accumulator per channel between blocks, so a chain of 1-sample blocks behind an oscillator integrates smoothly. Queued, it does not: the whole block is summed from zero, so the first sample of a queued run is whatever the first input sample is worth, and there's no history from previous runs. Re-seek the project timeline and the accumulator resets with it; the ↺ button clears it manually.

There is no wrap, no clamp and no reset input. A gate that sticks on, or a constant with a positive value, makes the output climb forever - and since the only network here is the FLOAT socket downstream, an unbounded value can look like a broken parameter rather than a runaway integral.

The inputs and outputs that matter

  • input - the GENERETI_CHOP to integrate. Channel names pass through untouched.
  • channels out - the accumulating block, one accumulator per channel, same sample rate and start time as the input.
  • value out - FLOAT, the last sample of the first channel: your running total. This is the socket you'd wire into a converted numeric input, and because it's monotonic it's a good fit for "amount of work done" style controls and a terrible fit for anything that needs to stay in range.

No parameters at all - no gain, no rate multiplier, no reset port. If you need a bounded version, put ꘇ chop.math with clamp after it (low/high), or fit to remap into a range. That's the intended composition: generators and processors stay single-purpose, and the range wrangling happens downstream.

Install

All these operators ship in one pack. Manager → search genereti (title "ꘇ Genereti") → install → restart ComfyUI → hard-refresh the browser tab. 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 the Python that belongs to your ComfyUI. The requirement is comfyui-frontend-package>=1.53.6 and nothing else, so there's no model download and no chance of a dependency fight with your other packs. Workflows → Genereti → ꘇ-OpenTouch-Operators-and-Lessons shows the processors in a real chain, and ꘇ-Performance-Timeline is where time and seeking are explained.

Common issues

It resets when you queue. By design - a queued block has no history. If you want accumulation inside a batch run, generate more samples per block upstream and integrate within one block.

It climbs off the map. With any input that isn't roughly zero-mean, the accumulator only goes one way. Clamp downstream, or put ꘇ chop.logic in front so you're integrating a 0/1 curve (which gives you time spent on, in seconds - a genuinely useful measurement).

Stale total after rewiring. Speed keeps its accumulator across graph edits, so a chain that looked sane can carry an old offset. The ↺ reset button clears memory for Speed, Slope and Lag; a project seek does the same.

Nothing moves on Queue but your parameter did earlier. Live delivery is capped at roughly one update per browser frame, so a 1-sample block at 60 samples a second accumulates one step per frame. Cranking sample_rate to 1000 changes the units on the output, not the number of updates you get.

Alpha status. The README calls the pack super alpha with early classroom testing: back up workflows before updating, expect interfaces to move under you.

CategoryGenereti / CHOP

Inputs (1)

NameTypeDefaultDescription
inputGENERETI_CHOP—

Outputs (2)

NameTypeDescription
channelsGENERETI_CHOP—
valueFLOAT—