Skip to content

Math & Logic ​

These are the basic building blocks for doing simple maths and making decisions inside your patch (your connected setup of nodes). The Math nodes work with numbers: they can add, multiply, compare, rescale, turn a musical note into a pitch, and more. The Logic nodes handle the "what happens next" side: they route signals, count, switch things on and off, add small delays, and react to incoming messages and events. Most of the number nodes are flexible about what you feed them: give them a plain number, a one-off event (a trigger or message), or a fast-changing control signal (an audio-rate CV signal, the kind used to move things automatically), and they adjust on their own. So the same node can do a single quick calculation or smoothly shape a moving signal moment by moment. Every node below shows its current value or result right on the node, and most let you wire other parts of your patch into their settings so those settings can be controlled automatically.

Very large numbers

The Math nodes keep every whole number exact up to 16,777,216. Above that, results are rounded, so adding or subtracting 1 can change nothing. See Number ranges and precision.

CV Edge Split ​

Takes an on/off signal (a gate) and splits it into two separate triggers: one fires the moment the signal turns on (note-on), and the other fires the moment it turns off (note-off). This is handy when you want the start and the end of a note to do different things.

CV Edge Split

Inputs: In (gate or boolean signal, accepts a stream or events). Outputs: On True (pulse on the rising edge), On False (pulse on the falling edge).


CV Counter ​

Counts each trigger it receives and sends out the running total as a steady control value. Choose to count Up, Down, or Up/Down (bouncing back and forth like a ping-pong ball). Useful for stepping through patterns, picking which item is active, or building up a value over time.

CV Counter

ParameterRangeDefaultDescription
ModeUp / Down / UpDownUpCounting direction. Up wraps from Max back to Min, Down wraps from Min back to Max, UpDown bounces between the two.
Min-1024 to 10240Lower bound of the counter range.
Max-1024 to 102415Upper bound of the counter range.

Inputs: Trigger (each rising edge advances the count), Reset (returns the count to Min, or Max in Down mode). Outputs: Count (the current value, held as a continuous CV stream).


If ​

This node compares two values and then sends out one of two results depending on the answer. When the comparison A op B is true, the Then output sends the Then value; when it is false, the Else output sends the Else value. For the "is equal" check there is an adjustable wiggle room, so signals that move in small fixed steps (like MIDI knob movements) still count as matching reliably.

If

ParameterRangeDefaultDescription
AAny value0Left operand of the comparison.
BAny value0Right operand of the comparison.
Op== / != / < / <= / > / >===The comparison operator.
ThenAny value1Value routed to Then Out when the comparison is true.
ElseAny value0Value routed to Else Out when the comparison is false.
Tol0 and up1/127Equality tolerance used by == and !=. Set 0 for exact float equality. Ordering operators ignore this.
Pass ThroughOn / OffOffSends A itself out of whichever output the comparison picks, instead of the Then and Else values.

Inputs: A, B, Then, Else, Op, Tol (every value input accepts a value, an event, or a CV stream). Outputs: Then Out (the Then value while the comparison is true), Else Out (the Else value while it is false).

Only the side the comparison picks sends anything, so an Event, a Trigger or a Counter wired to the other one does not fire. For a value that goes up and down, wire both outputs into the same input: Then Out sends Then while the comparison holds, Else Out sends Else while it does not, and whatever is listening always has the current answer. With CV it works differently, because there every sample carries a value: both outputs run all the time and the side that is not chosen sits at 0.

Pass Through turns the If into a switch: the signal on A goes out of Then Out while the comparison holds and out of Else Out while it does not. It is always A that travels, on either side, so it chooses where a signal goes, not which of two values to keep. For the larger or the smaller of two values, use Max or Min.

To fire something at the moment a moving signal reaches a value, such as a counter getting to 0, use CV To Event instead of comparing it here. It watches every sample and sends an event on the crossing, while a value brought over with CV To Data is only read a few dozen times a second, so an exact match can fall between two readings and a rounded one can match twice.


Logic ​

Combines two on/off conditions into one answer. Pick a gate: AND, OR, XOR, NOT, NAND, NOR or XNOR. An input counts as true when it is above 0 (a 1 is true, a 0 is false), which is what an If node gives when its Then Out and its Else Out both go into the same input, so you can feed A and B from two Ifs and pick AND or OR. Out is 1 when the gate is true and 0 when false. An unconnected input is ignored (AND or OR of a single wired input is just that input), and you can chain Logic nodes together for more than two conditions.

Logic

ParameterRangeDefaultDescription
ModeAND / OR / XOR / NOT / NAND / NOR / XNORANDThe boolean operation applied to A and B.
AAny value0First condition. Counts as true when above 0.
BAny value0Second condition. Counts as true when above 0.

Inputs: A, B, Mode (every input accepts a value, an event, or a CV stream; Mode also takes the gate by CV/Data). Outputs: Out (1 when the gate is true, 0 when false).


Addition ​

Adds two values together. Output = A + B. Use it to combine two control sources, shift a value up by a fixed amount, or blend signals together.

Addition

Inputs: A, B (stream-capable). Outputs: Result (A + B).


Subtract ​

Takes one value away from another. Output = A - B. Handy for finding the gap between two control sources, lowering a value by a fixed amount, or cancelling a signal out.

Subtract

Inputs: A, B (stream-capable). Outputs: Result (A - B).


Multiply ​

Multiplies two values. Output = A * B. When one input is audio, it works like a volume control (turning the sound up or down). You can also use it to scale a control signal up or down.

Multiply

Inputs: A, B (stream-capable). Outputs: Result (A * B).


Divide ​

Divides one value by another. Output = A / B. Useful for scaling things down, working out ratios, or reducing the volume by a set amount. If you try to divide by zero, the output is 0.

Divide

Inputs: A, B (stream-capable). Outputs: Result (A / B, or 0 when B is 0).


Min ​

Sends out whichever of the two values is smaller: Min(A, B). Useful for setting a ceiling on a signal, keeping things from going too high, or always picking the lowest of several control sources.

Min

Inputs: A, B (stream-capable). Outputs: Result (the smaller of A and B).


Max ​

Sends out whichever of the two values is larger: Max(A, B). Useful for setting a floor on a signal, picking the loudest of several signals, or having one sound automatically lower another (ducking).

Max

Inputs: A, B (stream-capable). Outputs: Result (the larger of A and B).


Power ​

Raises A to the power of B. Output = A^B. Good for bending a control signal into a curve, creating exponential responses, and building your own custom shapes.

Power

Inputs: A (base), B (exponent), both stream-capable. Outputs: Result (A raised to B).


Modulo ​

Gives you the remainder after dividing A by B. Use it to wrap values around so they stay inside a range, build repeating ramps, or loop a control pattern. If B is zero, the output is 0.

Modulo

Inputs: A, B (stream-capable). Outputs: Result (remainder of A / B, or 0 when B is 0).


Abs ​

Gives the absolute value: it drops the minus sign so negative numbers become positive. Handy for turning a signal that swings both above and below zero into one that only goes positive, or for getting how far a value is from zero regardless of direction.

Abs

Inputs: X (stream-capable). Outputs: Result (the absolute value of X).


Negate ​

Flips the sign (positive becomes negative and the other way round). Output = -X. Use it to reverse the direction of a control signal, mirror a signal, or flip its phase (turn it upside down).

Negate

Inputs: X (stream-capable). Outputs: Result (-X).


Sqrt ​

Gives the square root of X, and never goes below 0 so it stays safe. Useful for turning even, straight-line values into ones that feel more natural to the ear, or for gently softening the shape of a control signal.

Sqrt

Inputs: X (stream-capable; negative inputs are treated as 0). Outputs: Result (square root of X).


Exp ​

Calculates e^X (an exponential curve). Turns an even, straight-line control into a curved one, which makes sweeps and timing feel more natural to the ear.

Exp

Inputs: X (stream-capable). Outputs: Result (e raised to X).


Log ​

Calculates the natural logarithm, which does the opposite of Exp. It squeezes a very wide range of values down into a smaller, easier-to-handle range.

Log

Inputs: X (stream-capable). Outputs: Result (natural logarithm of X).


Linear To dB ​

Converts a plain volume amount into decibels (dB, the usual way of measuring loudness): 20 * log10(amplitude). Useful for showing a level in dB or for feeding controls that expect dB. Values very close to zero are pinned to -144 dB.

Linear To dB

Inputs: Linear (linear amplitude; 1.0 = 0 dB, 0.5 = -6 dB). Outputs: dB (the level in decibels).


dB To Linear ​

Converts decibels back into a plain volume amount: 10^(dB / 20). This is the reverse of Linear To dB, handy when you have a dB setting and need to turn it into an actual volume factor.

dB To Linear

Inputs: dB (a level in decibels; 0 dB = 1.0, -6 dB = 0.5). Outputs: Linear (the linear amplitude).


Sin ​

Gives the sine of X, where X is measured in radians (a way of measuring angles). Use it to shape values into smooth, repeating waves, to drive oscillators by their phase, or to create gentle cyclic shapes.

Sin

Inputs: X in radians (stream-capable). Outputs: Result (sine of X).


Phase Sine ​

Like Sin, but it reads X as a phase position instead of an angle: 0 to 1 means one full cycle, and the output swings from -1 to 1. Feed it a repeating ramp (a phasor) and a smooth sine wave comes out, with no need to scale anything into radians first. Handy for phase-driven oscillators and cyclic shapes built from ramps.

Phase Sine

Inputs: X (the phase, where 0 to 1 is one full cycle; stream-capable). Outputs: Result (the sine of the phase, -1 to 1).


Cos ​

Gives the cosine of X, where X is measured in radians (a way of measuring angles). Pair it with Sin to make two LFOs that move a quarter-step apart, or for smooth equal-volume crossfades.

Cos

Inputs: X in radians (stream-capable). Outputs: Result (cosine of X).


Tan ​

Gives the tangent of X, where X is measured in radians (a way of measuring angles). It makes steep, dramatic curves that shoot off toward infinity, good for bold, experimental sound-shaping.

Tan

Inputs: X in radians (stream-capable). Outputs: Result (tangent of X).


Floor ​

Rounds a number down to the nearest whole number. Use it to snap a smoothly changing value down onto whole-number steps.

Floor

Inputs: X (stream-capable). Outputs: Result (X rounded down).


Ceil ​

Rounds a number up to the nearest whole number. Use it to snap values upward, or to make sure a value always lands on or above a whole-number step.

Ceil

Inputs: X (stream-capable). Outputs: Result (X rounded up).


Round ​

Rounds a number to the nearest whole number the normal way (down if it is below halfway, up if it is at or above). Use it to snap a control signal onto whole-number steps.

Round

Inputs: X (stream-capable). Outputs: Result (X rounded to the nearest integer).


Greater Than ​

Compares two values and asks "is A bigger than B?". It sends out 1 when A > B, and 0 otherwise. Use it to react when a signal goes above a certain level, or to switch something on past a threshold.

Greater Than

Inputs: A, B (stream-capable). Outputs: Result (1 when A > B, otherwise 0).


Less Than ​

Compares two values and asks "is A smaller than B?". It sends out 1 when A < B, and 0 otherwise. This is the mirror image of Greater Than, for reacting when a signal drops below a level.

Less Than

Inputs: A, B (stream-capable). Outputs: Result (1 when A < B, otherwise 0).


Equal ​

Checks whether two values match, with a little built-in wiggle room so near-matches still count. It sends out 1 when A and B are equal, and 0 otherwise. Use it to spot a particular value or to recognise a pattern.

Equal

Inputs: A, B (stream-capable). Outputs: Result (1 when A and B are equal, otherwise 0).

This compares numbers. Text arriving here reads as 0, so any two words come out equal: use Text Equal for that.


Text Equal ​

Checks whether two texts are the same and sends out 1 when they match, 0 when they do not, so a Branch or a Gate can act on it. The Equal node above cannot do this, because it compares numbers and text reaching it reads as 0, which makes any two words look equal. Type into A or B to test a wired input against a fixed word, or wire both. Numbers are compared as their text, so 5 matches "5". The match is exact, spaces included, since text that looks the same and is not is the thing this is here to catch; Match Case off ignores capitals only, so Cubase and cubase match but "Cubase " still does not. An event on any input re-answers without changing anything.

Text Equal

ParameterRangeDefaultDescription
AtextemptyFirst text. Editable on the node.
BtextemptySecond text. Editable on the node.
Match Caseon / offonCompare capitals as well.
EqualYes / No-Read-only. The pin sends 1 or 0.

Inputs: A, B (text, or a number compared as its text; an event re-emits the answer), Match Case. Outputs: Equal (1 when the two match, otherwise 0).


Text Contains ​

New in MNodes 1.1.5

This node does not exist in older versions of MNodes. A project that uses it will not work there until you update.

Looks for one text inside another. Found sends 1 when Find is somewhere in Text and 0 when it is not, Position says where it first starts, counting from 0, or -1 when it is not there, and Count says how many times it appears. Position counts the same way as Sub Text's Start, so the two work together: find where a word is, then cut the text there. Found is sent after Position and Count, so whatever acts on Found already has the position of the same text. Index picks which time Found and Position answer for: 0 is the first, 1 the second, and a negative Index counts back from the end, so -1 is the last; Count is always every time. A Counter into Index walks them one by one. Type into Text or Find, or wire either one. With Match Case off, capitals are ignored. An empty Find finds nothing, and an event on any input answers again without changing anything.

Text Contains

Needs: a Text Contains node looking for "C" in "C4 E4 G4 C5", with Found, Position and Count showing.

ParameterRangeDefaultDescription
TexttextemptyThe text to look in. Editable on the node.
FindtextemptyThe text to look for. Editable on the node.
Match Caseon / offonTell capitals apart.
Indexwhole number0Which time Find appears to answer for: 0 the first, 1 the second, -1 the last.
FoundYes / No-Read-only. The pin sends 1 or 0.
Positionwhole number-Read-only. Where the match at Index starts, from 0, or -1.
Countwhole number-Read-only. How many times Find appears, without overlaps.

Inputs: Text, Find (text, or a number searched as its text; an event re-emits the answer), Match Case, Index. Outputs: Found (1 or 0), Position (from 0, or -1), Count.


Clamp ​

Keeps X between a Min and a Max, leaving values that are already inside that range untouched. Useful for making sure a value never strays outside a safe range.

Clamp

ParameterRangeDefaultDescription
XAny value0The input value to clamp.
MinAny value0Lower bound of the clamp range.
MaxAny value1Upper bound of the clamp range.

Inputs: X, Min, Max (all stream-capable). Outputs: Result (X limited to the Min..Max range).


For Range ​

This node repeats a step over and over (a loop). Each time you trigger it, it counts from a Start number to an End number, sending out each number along the way plus a Done signal when it reaches the end. Use it to run loops, fill in lists, or play back scripted sequences. Step is always a positive amount; the direction (up or down) is worked out automatically from your Start and End numbers.

For Range

ParameterRangeDefaultDescription
StartWhole numbers0The index the loop starts from.
EndWhole numbers7The index the loop runs to (inclusive).
Step1 and up1Step size between iterations (always positive; direction follows Start and End).

Inputs: Trigger (any message starts the loop), Start, End, Step. Outputs: Index (the current loop index for each step), Event (one event per iteration), Done (fires once after the full range completes).


Once ​

A one-time pass. It lets the very first message through, then blocks everything after that until you reset it. Use it for things that should happen once and then stop.

Once

ParameterRangeDefaultDescription
ArmedOn / OffOnShows whether the node is ready to pass the next message.

Inputs: In (passes only once while armed), Reset (any message re-arms the node). Outputs: Out (the first message, then nothing until reset).


Every ​

This thins out a stream of triggers. It counts the messages coming in and sends out one Event for every N of them. Use it to slow a busy stream of triggers down to a steadier pace. It keeps going forever; if you only want the very first trigger, add a Once node after the Event output.

Every

ParameterRangeDefaultDescription
Steps1 and up1How many messages are needed before Event fires. Stream-capable, so the period can be modulated.

Inputs: In (any message counts, including events), Steps, Reset (any message resets the count to 0). Outputs: Count (the current count), Event (fires every time the count reaches Steps).


Data Delay ​

Holds onto an incoming message for a set amount of time, then sends it on. Use it to space out triggers, line events up in time, or add a delayed reaction. The wait time is set in milliseconds and can be controlled by a CV signal. Several messages can be waiting their turn at the same time.

Data Delay

ParameterRangeDefaultDescription
Delay (ms)0 to 10000100Time in milliseconds before the message is forwarded. Values below 1 ms pass through immediately. Stream-capable.

Inputs: In (any message to delay), Delay, Cancel (any message flushes all waiting messages without sending them). Outputs: Out (the delayed message), Pending (how many messages are currently waiting).

This is a timer for messages, not an echo effect for sound. It is accurate to about 1 ms; if you want a delay on actual audio, use a dedicated audio delay node instead.


Probability ​

A chance-based gate. Each message that comes in has a set chance of getting through. Use it to add random variation to patterns, randomly drop some notes, or sprinkle in a bit of controlled randomness. If you connect a CV signal instead, it decides whether each individual moment of the signal passes.

Probability

ParameterRangeDefaultDescription
Chance0 to 100 %100The probability that each incoming message or stream sample passes through.

Inputs: In (messages or a CV stream), Chance (stream-capable). Outputs: Out (the message or stream, only when the roll passes).


Gate ​

An on/off switch that works for both messages and CV signals. When it is open it lets things through, and when it is closed it blocks them. Use it to mute a path or to switch routing on and off. The Enable input accepts a CV signal, so you can open and close the gate rhythmically, even on audio.

Gate

ParameterRangeDefaultDescription
EnabledOn / OffOnWhen on, In passes to Out; when off, Out is blocked (or silent for CV). Events on Enable are ignored.

Inputs: In (message or CV, stream-capable), Enable (non-zero opens, zero closes; stream-capable). Outputs: Out (the forwarded message or CV when enabled).


Select ​

Watches an input value and fires an Event the moment it matches a value you choose. Use it to spot a specific state or to trigger something when a pattern reaches a certain point. Both inputs can be controlled at audio rate for precise timing.

Select

ParameterRangeDefaultDescription
TargetAny value0The value X is compared against.

Inputs: X (the value to check), Target (both stream-capable). Outputs: Match (an Event when X equals Target exactly).


Branch ​

A simple "yes or no" router. It looks at the incoming message and treats it as true or false: if it is true it fires the True output, otherwise it fires the False output. A quick way to send things down one of two paths. The node shows the last message it received.

Branch

Inputs: In (any message; numbers are true when non-zero, a bool passes through, text and events evaluate to false). Outputs: True (an Event when the input is true), False (an Event when the input is false).


Toggle ​

A simple on/off switch. Each trigger that comes in flips it to the opposite state and sends out the new value. Use it to build switches that stay set until flipped again.

Toggle

ParameterRangeDefaultDescription
StateOn / OffOffThe current on/off value. Flip it with a trigger, or force it with the Set input.

Inputs: Trigger (any message flips the state), Set (0/1 or false/true forces the state). Outputs: State (the current on/off value, sent on every change).


Latch ​

Remembers a value and only sends it out when you trigger it. Use it to grab a value and hold it, then pass it along whenever you want. Triggering it never changes the value it is holding; to change that, use the Set input. The held value is saved with your project.

Latch

Inputs: Set (stores the incoming value, does not output), Trigger (any message outputs the stored value). Outputs: Value (the stored value, emitted when triggered).


Counter ​

Counts the messages coming in, staying within a Min and a Max. Choose Up, Down, or Up/Down (bouncing back and forth) counting to drive step sequencers, count actions, or build pattern positions. The In trigger never sets the count directly; to set it, use the Set input. Its state is saved with your project.

Counter

ParameterRangeDefaultDescription
Mode0 = Up, 1 = Down, 2 = UpDownUpCounting direction. Stream-capable.
MinWhole numbers0Lower bound of the counter range. Stream-capable.
MaxWhole numbers127Upper bound of the counter range. Stream-capable.
SetWhole numbers0Forces the current count (no output). Stream-capable.
WrapOn / OffOnOn, the count wraps round at the ends (Max to Min, Min to Max). Off, it stops at Min and Max. UpDown always bounces either way.

Inputs: In (any message outputs the count then advances), Mode, Min, Max, Set, Wrap, Reset Min (any message sets the count to Min), Reset Max (any message sets the count to Max).

Outputs:

OutputDescription
CountThe current count, output on each trigger.
Min HitTrue when the current count equals Min.
Max HitTrue when the current count equals Max.

Stepper ​

A manual up and down counter, like the little + and - spinner buttons on a form. Any message on Up adds 1, any message on Down subtracts 1, and the new count is sent out each time. The count stays between Min and Max: with Wrap on, stepping past Max jumps back to Min (and past Min back to Max); with Wrap off, the count simply stops at the edge. Use it to build your own spinners, value pickers, or anything that counts button presses. It is the hands-on sibling of Counter: Counter is the sequencer-style one, stepping through a pattern from a single trigger, while Stepper gives you separate Up and Down controls. The count is saved with your project.

Stepper

ParameterRangeDefaultDescription
WrapOn / OffOffWhat happens at the edges: on wraps around, off stops at Min or Max.
MinWhole numbers0Lower bound of the count.
MaxWhole numbers127Upper bound of the count.
SetWhole numbers0Forces the current count (no output).

Inputs: Up (any message adds 1 and outputs the new count), Down (any message subtracts 1 and outputs the new count), Wrap, Min, Max, Set, Reset Min (any message jumps the count to Min and outputs it), Reset Max (any message jumps the count to Max and outputs it).

Outputs:

OutputDescription
CountThe current count, sent on each step or reset.
Min HitTrue when the current count equals Min.
Max HitTrue when the current count equals Max.

OnChange ​

Only passes a value along when it is different from the one before it. This filters out repeated messages, saves the rest of your patch from needless work, and lets things react only when something genuinely changes. The first value after you create or reset the node always passes, and an event always passes.

OnChange

Inputs: In (any message; duplicates of the previous value are suppressed), Reset (any message clears the history so the next value always passes). Outputs: Out (the value, only when it changed).


Is Number ​

Checks whether what came in is a real number, and passes the number along when it is. Made for checking things people type: it accepts a minus or plus sign and decimals (-5.67, +3, .5), and a single decimal comma also counts ("1,5" reads as 1.5), while text with extra characters is rejected. Valid answers on every input, but Value only fires when the input really is a number, so a control fed from Value keeps its last good value when something wrong is typed. Pair it with a Text Input widget to accept typed numbers safely. A value that is already a number passes straight through.

Is Number

Inputs: In (text or a number to test). Outputs: Valid (true when the input is a valid number, false when not), Value (the parsed number, only when valid).


Is Hex ​

Checks whether the incoming text is a valid hex colour code. Codes with or without a leading # are accepted, in 3, 6 or 8 digit form (0af, ff8800, aaff8800). When the code is valid, Hex sends out a cleaned-up version (lowercase, no #, short 3-digit codes expanded to 6 digits) that the Colour node accepts directly, so someone can type a colour into a Text Input widget and recolour your patch with it. Valid answers on every input; Hex only fires when the code is valid.

Is Hex

Inputs: In (text to test as a hex colour). Outputs: Valid (true when the text is a valid hex colour), Hex (the cleaned hex code, only when valid).


Is Note ​

Checks whether the incoming text is a valid note name like C3, A#4 or Gb2, and turns it into the matching MIDI note number (C3 is note 60). Sharps and flats both work, and a plain number from 0 to 127 counts as a valid note too. Valid answers on every input; Note only fires when the input is a real note, so bad input never disturbs whatever comes after. Wire Note into Note To Freq to get a pitch in Hz, or pair the node with a Text Input widget so notes can be typed by name.

Is Note

Inputs: In (text with a note name, or a note number to test). Outputs: Valid (true when the input is a valid note), Note (the MIDI note number, only when valid).


Integer to Bits ​

Takes a whole number and turns it into one on/off output per bit, the way a number is written in binary. Feed it 5 at a width of 8 and Bit 0 and Bit 2 come on while the rest stay off. Use it to drive several gates or switches from one number, to unpack a value someone sent you as a single number, or to read a number one bit at a time.

Integer to Bits

Width sets how many bits, and so how many outputs: 8, 16 or 24. The outputs appear and disappear as you change it, so a 24-bit node is a tall node. The ceiling is 24 on purpose: numbers travel around a patch as whole numbers with a sign, so a 32-bit width would turn the top bit into a minus sign and hand you negative results, and 24 is also the last width where every value stays exact even if something in the chain treats it as a decimal. For anything wider, divide the number with the maths nodes and use two of these.

Bit Order decides what each pin is worth, never what it is called. The pins are always Bit 0 upwards in both settings, so switching it re-reads the patch you already wired instead of asking you to move cables. LSB First (the default) means Bit 0 is the ones column and the last pin counts the most; MSB First is the opposite.

Numbers too big for the width are clamped, so at 8 bits anything above 255 arrives as 255 and negatives arrive as 0. Every bit is sent on every input, not only the ones that changed, so a node you wire up later gets the full picture straight away. Pairs exactly with Bits to Integer.

ParameterTypeDefaultWhat it does
Integernumber0The number to split. Type it here or feed it through the pin.
Widthchoice8 BitsHow many bits, and how many outputs: 8, 16 or 24.
Bit OrderchoiceLSB FirstWhether Bit 0 is the ones column or the largest one.

Inputs: Integer (the number to split). Outputs: Bit 0 upwards (one on/off output per bit).


Bits to Integer ​

Takes one on/off input per bit and combines them into a whole number. Turn on Bit 0 and Bit 2 at a width of 8 and the output is 5. It is the exact opposite of Integer to Bits: wire one into the other and you get back what you put in.

Bits to Integer

Each input remembers its last value, so the number updates the moment any single bit changes rather than waiting for all of them, and an input that has never been fed counts as off. A number arriving on a bit input counts as on from 0.5 up, so a control signal and a plain on/off behave the same.

Width and Bit Order work exactly as they do on Integer to Bits, and the two nodes must agree on both for the round trip to come back the same. The Integer box is a readout rather than a control: the bits own the value.

ParameterTypeDefaultWhat it does
Widthchoice8 BitsHow many bits, and how many inputs: 8, 16 or 24.
Bit OrderchoiceLSB FirstWhether Bit 0 is the ones column or the largest one.

Inputs: Bit 0 upwards (one on/off input per bit). Outputs: Integer (the combined number, sent whenever any bit changes).


Number Base ​

New in MNodes 1.1.5

This node does not exist in older versions of MNodes. A project that uses it will not work there until you update.

Shows the same number in binary, decimal or hex. Type or send text on In, say which base it is written in with From, and Text writes the number in the To base, while Value sends it on as a plain number. 01000001 in binary, 65 in decimal and 41 in hex are the same byte.

Number Base

Needs: screenshot of the Number Base node on the graph, reading 01000001 from Binary into Hex.

Valid answers on every input and says whether the text really is a number in the From base, so with From set to Binary it tells you whether a text is made of 0s and 1s only. Value and Text only fire when it is, so whatever they feed keeps its last good value. A number arriving on In is read as a number whatever From says, so Bits to Integer can feed it directly.

Binary may start with 0b and hex with 0x or #, any base may start with a minus, and underscores between digits are fine (0100_0001). Spaces are not: two bytes with a space between them are two numbers, so split a line of bytes with Text Split first. Numbers go up to 32 bits. Hex comes out in capitals, without a prefix.

To light eight LEDs from one byte, feed Value into Integer to Bits.

ParameterTypeDefaultWhat it does
IntextemptyThe text to read. Type it here or send it through the pin.
FromchoiceBinaryThe base In is written in: Binary, Decimal or Hex.
TochoiceHexThe base Text writes the number in.
Digitsnumber0Pads Text with zeros to at least this many digits: 8 for a byte in binary, 2 in hex.

Inputs: In (text or a number; an event answers again), From, To, Digits. Outputs: Valid (true when In is a number in the From base), Value (the number, only when valid), Text (the number written in the To base, only when valid).


Map ​

Takes a value from one range and rescales it into another. For example, turn 0..1 into MIDI notes, MIDI notes into Hz, a 0..127 knob into dB, or anything into anything else. With Clamp on, values outside the input range are pulled back in first; with Clamp off, the rescaling keeps going past the output range. All number pins can take a control signal. An event on X sends out the last mapped value again.

Map

ParameterRangeDefaultDescription
In MinAny value0Start of the source range.
In MaxAny value1End of the source range.
Out MinAny value0Start of the destination range.
Out MaxAny value1End of the destination range.
ClampOn / OffOnWhen on, X is limited to the input range before mapping.

Inputs: X (the value to remap), In Min, In Max, Out Min, Out Max, Clamp (all stream-capable). Outputs: Out (the remapped value).


Note To Freq ​

Turns a MIDI note number into a pitch in Hz (cycles per second), using 440 * 2^((note - 69) / 12). It can take a control signal, so a moving CV note coming in stays a moving CV pitch on the way out.

Note To Freq

ParameterRangeDefaultDescription
Note0 to 12760The MIDI note number. 60 is middle C, which is about 261.63 Hz. Stream-capable.

Inputs: Note (MIDI note number). Outputs: Hz (the frequency in Hz; emitted as CV when the input is CV).


Pattern File ​

Stores a sequencer pattern (saved as JSON text), works out what kind it is, and lets you save it to disk or load it back. Connect a sequencer's Pattern Out to this node's Pattern In, and the node shows when it is ready, the kind of pattern it found, and an optional name read from the pattern. From there you can save it to a file or send it out again whenever you like.

Pattern File

ParameterRangeDefaultDescription
Pattern NameTextemptyAn editable name stored with the pattern and written on export. Read from the pattern when available.
FileFile pathemptyPick a pattern file to load it immediately.

The node also shows three read-only readouts: Pattern Type (the kind of pattern it found, which decides the file ending used when saving), Name (the pattern name plus the suggested file ending), and Status (Empty until a pattern is stored, then Ready). Export Dialog opens a save window, and Emit Pattern sends the stored pattern out again. The file endings used when saving are .mnriff for a MIDI Riff, .mnsliderseq for a Slider Sequencer, and .mntoggleseq for a Toggle Sequencer.

Inputs: Pattern In (Pattern JSON from a sequencer), Pattern Name (optional name), File (optional file path to load), Emit Pattern (re-sends the cached pattern). Outputs: Pattern Out (the loaded Pattern JSON, ready to reconnect into a sequencer's Pattern In).


Makes a handful of separate buttons behave as one group: turn one on and the others go off. The Radio Group widget already does this, but it draws its own segments, so they sit in a row, touching, all the same size and all wearing the same look. This node does the behaviour and none of the drawing, so the buttons can be ordinary Widget Toggles placed anywhere on the panel, at any size, each with its own picture.

Radio Link

One pair of cables per button:

  • the button's State output goes to Button n on this node
  • Button n on this node goes back to the button's Set input

Set rather than State In, because Set applies the value without announcing it again, so the ring never chases its own tail. State In works too, it is just chattier: the echo comes straight back, gets recognised and is dropped.

ParameterRangeDefaultDescription
Buttons2 - 164How many buttons are in the group. The pins follow. Lowering it drops the cables of the ones that go away
ModeSingle / Multi / Multi (min 1)SingleSingle keeps exactly one on, and clicking the one that is already on leaves it on, which is the radio contract. Multi allows any combination including none. Multi (min 1) allows any combination but never none
Index0 to Buttons-10The button that is on, counting from 0. In Multi it is the one that changed last. Writing to it turns to that button

The buttons count from 0 as well, so Button 0 is the one Index reads as 0 and there is no arithmetic to do between a pin and the number that comes out of it.

Each button is a page. Button n says 1 for the button that is on and 0 for the others, every time the group moves, so wire it to what belongs to page n as well as to its button: an Appearance Changer setting Visible on the widgets of that page, or a Scene Group's Scale and Opacity, and the panel changes page. Index is the page number, and an input as well, so a preset, the host or another control can turn to a page without anybody pressing a button; a bare trigger into Select re-sends everything, which is how a patch shows the right page and lights the right button when it opens.

An event on a button input means "this one", so a plain Widget Button can join the group: it has no state to report, only a click, and a click is a perfectly good way to pick a page.

Inputs: Button 0..N-1 (each button's State output, or an event to pick it), Select (turn to a button by number, or a trigger to re-send). Outputs: Button 0..N-1 (what each button should be showing, sent whenever the group moves: wire it to its Set input and to what goes with it), Index (the button that is on), Changed (fires whenever the group actually moves).


Script ​

New in MNodes 1.1.5

This node does not exist in older versions of MNodes. A project that uses it will not work there until you update.

A small program in JavaScript between cables: what arrives on its inputs calls the code, and the code sends what it likes out of its outputs. Use it for the logic no node has, for text another node reads (a Scene, whose Script input takes a whole canvas from one cable, or its Zones or Set; a Shader's Code), for sequences, rules and counters that remember. It runs modern JavaScript in a sandbox: it reaches no files and no network, and a call that runs for more than a quarter of a second is stopped, so a loop that never ends cannot hold MNodes up. Each Script runs its code on a thread of its own, so a slow program holds back only itself: the sound, the other Data cables and the screen go on as they were. It can also play CV and MIDI, each change landing on the exact sample it asks for (see CV and MIDI out, below).

Script connected to Scene in a complete Help example

The code is written in the editor on the node. With Live on, it starts again a moment after you stop typing; Run (or Ctrl + Enter, Cmd + Enter on a Mac) does it at once. Examples has eleven to start from: Start, Counter, Scale, Zones Grid (knob zones for a Scene), Scene Set (zone values for a Scene), Scene in Code (a whole Scene written in the Script, its picture, zones and movement, sent over one cable into the Scene's Objects input), Scene Drawing (an interface the Script draws on a Scene with no GLSL: two knobs, a switch and a row of steps), Scene Controls (a synth panel in a few lines, with the ready-made controls), Scene Sound (bars, a ring and a mark sweeping round with a trail, on a Scene, following the sound on its In A with no code running), LFO and Random Melody. The one you pick opens over your code, to read and to copy from (select with the mouse or Ctrl + A, then Ctrl + C), and your code changes only if you press Replace; Ctrl + Z then brings yours back. When the code is one you wrote, Replace and New ask first. With Preview on, as it starts, the example also runs in place of your code while it is open, through the same outputs, so the Scene it draws on shows what it does; closing it starts your code again, with its state. Turn Preview off to only read. The cross or Esc closes the example. What the code prints, and its mistakes with the line they are on, show in the console under the code; Clear empties it, and the mouse wheel over it goes back through what it said. A mistake while it runs leaves the rest of the code running for the next message. New starts again from the smallest program there is (Ctrl + Z brings back what you had), and Reference lays a sheet over the code with everything the code can use (the node's calls, drawing on a Scene, changing what is drawn, 3D and the controls), each with a button that writes it where the cursor is. Edit Outside opens the code in another editor, such as VS Code (see Writing the code in another editor, below). The whole node is the code's while you work in it: a click anywhere on it gives the code the keys, so Ctrl + A, C, V, X, Z and Y (Cmd on a Mac) act on the text, never on the graph, and Ctrl + mouse wheel makes the text bigger or smaller, the console's too.

What the code can define, and use:

NameWhat it is
onInput(n, value)Called for every message on In n (In 1 is 1): value is a number, text, true or false, or undefined for an Event.
onTick(dt)Called Tick times a second, when Tick is on: dt is the seconds since the last. With the picture, once each time the screen refreshes.
onStart()Called when the code starts, and again after every edit or Restart.
out(n, value)Sends value out of Out n: a number, text, true or false as they are, an array or an object as JSON text.
out(n)If out's second parameter is empty, it sends an Event (a trigger) out of Out n: if (value === 3) out(1); fires whatever is wired to Out 1, with no Equal or Event node in between.
print(...)Writes a line in the console; objects are written as JSON.
stateAn object kept with the project, and across edits: what the code puts in it is still there when the project opens.
time()The seconds since the code started.
canvas(n)The Scene that Out n is wired into, to draw on: see Drawing on a Scene, below.
cv(n, value, { at, glide })Moves CV n to value, now or at the time at, at once or gliding over glide seconds. CV Outputs says how many there are.
note(n, pitch, velocity, length, { at, channel })Plays a note out of MIDI n: pitch 60 is middle C, velocity 1 to 127, length in seconds. MIDI Outputs says how many there are.
noteOn, noteOff, cc, bend, allNotesOffThe rest of MIDI: a note held until its off, a controller (0 to 127), pitch bend (-1 to 1), and every note off. Each takes { at, channel } too.
now()The clock at is on, in seconds.
transport()The tempo and where the song is: playing, bpm, beat, beatInBar, beatsPerBar.
atBeat(beat)The time a beat falls at, for at.
onKey(name, down)Called for every key of the computer keyboard pressed (down is true) and let go (false): name is "Left", "Space", "A" and so on. See Keys, below.
keyDown(name)Whether that key is down now.
gamepad(n)What game controller n (1 to 4, 1 if not said) is doing now: connected, the buttons A, B, X, Y, LB, RB, Back, Start, LS, RS, Up, Down, Left, Right (true while down), the sticks lx, ly, rx, ry (-1 to 1, up and right positive) and the triggers lt, rt (0 to 1). See Keys, below.
app.quit(), app.fullScreen(on)In the standalone app, for a game's menu: quit leaves MNodes (asking to save first); fullScreen(true) fills the screen, fullScreen(false) gives it back, fullScreen() turns it the other way round; app.isFullScreen() says which. Never in the code's first moment and a half, and nothing in a DAW. See the App node.
onButton(name, down, pad)Called for every button of a game controller pressed (down is true) and let go, with the pad's number.
ParameterRangeDefaultDescription
RestartbuttonStarts the code again: onStart runs, and the state stays.
FilepathA .js or text file the code is taken from, every time it is saved: see Writing the code in another editor, below.
Inputs1 to 82In the Inspector. How many inputs the node has.
Outputs1 to 82In the Inspector. How many outputs.
CV Outputs0 to 80In the Inspector. How many CV outputs the code moves with cv().
MIDI Outputs0 to 40In the Inspector. How many MIDI outputs the code plays with note() and the rest.
TickOff / 10 / 30 / 60 / 120 a second / With the pictureOffIn the Inspector. How often onTick runs, if the code has it. With the picture runs it once each time the screen refreshes, so what the code moves on a Scene goes forward by the same amount in every picture: the one to choose for a game. With the window closed it goes on at the same rate. New in MNodes 1.1.6.
CodetextStartThe program. It can also be edited in the Inspector.
Liveon / offonStarts the code again as you type, once it has no mistake to stop at.
Text Size9 to 2813How big the code and the console are drawn; Ctrl + mouse wheel over the node does the same.

Inputs: In 1 to In 8 (as many as Inputs says), each calling onInput; Restart, which starts the code again on any message; File, the path of a code file to follow, where an Event reads the file again at once.

Outputs: Out 1 to Out 8 (as many as Outputs says): what the code sends with out(). Wired into a Scene's Objects input, Out n is also where canvas(n) draws. CV 1 to CV 8 and MIDI 1 to MIDI 4 (as many as CV Outputs and MIDI Outputs say): what cv() and note() play.

Writing the code in another editor ​

New in MNodes 1.1.6

Older versions of MNodes do not have File and Edit Outside.

The editor on the node is made for short programs. For a longer one, write it in a code editor such as VS Code, and the Script follows it:

  • Edit Outside, on the node's toolbar, asks where to keep the code (next to the project, unless you pick another place), writes it there as a .js file and opens it in your code editor: VS Code, Cursor or VSCodium if you have one, else Notepad++ or Sublime Text, else Notepad on Windows or TextEdit on a Mac. Once the file is linked, Edit Outside opens it again.
  • Or give File a .js or text file you already have: drop it on File, pick it with the folder button, or type its full path.

From then on, every time you save the file, the Script reads it and starts again with it, whatever Live says, and its state stays; a mistake shows in the console as usual. The line under the code says which file the Script follows. While it follows one, the editor on the node shows the file and cannot change it, New does nothing, and the buttons on the Examples and Reference sheets copy what they would write, to paste in your editor. Clear File to write on the node again: the code stays as the file left it.

The code is saved in the project too, so the project opens the same where the file is not, and Collect All & Export puts the file in the bundle. On the File input, a path links a file and an empty one stops following.

CV and MIDI out ​

New in MNodes 1.1.6

Older versions of MNodes do not have CV Outputs and MIDI Outputs.

Set CV Outputs or MIDI Outputs in the Inspector and the Script gets those outputs: a CV it moves, and MIDI it plays, into anything that takes CV or MIDI, a filter's cutoff, an envelope's gate, a Poly Module. A CV holds the last value it was given; with glide it slides there over that many seconds instead of jumping.

Every one of them can take a time: { at: t }, on the clock now() reads, in seconds. The change then lands on that exact sample, however busy the code's thread is, so the way to play in perfect time is to schedule a little ahead. With Tick at 30 a second, this plays a note on every beat and moves CV 1 to a new height with it:

js
let next = 0;   // the next beat to play
function onTick() {
  const t = transport();
  if (!t.playing) return;
  if (next < t.beat) next = Math.ceil(t.beat);
  // what falls in the next tenth of a second, scheduled now
  while (atBeat(next) < now() + 0.1) {
    const at = atBeat(next);
    note(1, 60 + (next % 4) * 3, 100, 0.2, { at: at });
    cv(1, Math.random(), { at: at, glide: 0.1 });
    next += 1;
  }
}

Without a time, a change plays at the start of the next block, a few milliseconds on. Scheduling ahead also keeps a sequence steady while the code does something long: a call that builds a big interface again holds back the next tick, but never what was already scheduled. For a sequence that has to stay perfectly even beside a big interface, give each its own Script. A Restart (or an edit) holds things back the longest: the code runs again from the top, and what comes in meanwhile waits until it has, about a tenth of a second with a big interface. So a Script that plays a sequence should not restart itself to change its look (a light or dark theme, say): keep the sequence in a Script that nothing restarts. A note never sounds twice at once on the same output: a second note on for a note that is already sounding ends it first. When the code starts again (an edit, Restart), what it had scheduled is forgotten and its notes end; when the node is bypassed its notes end and its CV outputs hold. Inside a Poly Module the CV and MIDI outputs play once, from the first voice: the code is one for all the voices. A mistake in using them (an output the node does not have, a value that is not a number) is said once in the console.

Keys, for a game ​

New in MNodes 1.1.6

Older versions of MNodes do not have onKey and keyDown.

A Script hears the computer keyboard by itself, with no Keyboard node: write onKey(name, down) and it runs for every key pressed and let go, or ask keyDown(name) whether a key is down right now. Names are the ones the Keyboard node gives: "Left", "Right", "Up", "Down", "Space", "Enter", "Escape", letters as "A" to "Z", digits as "0" to "9". With Tick on, this moves a dot on a Scene with the arrows, as smoothly as the Tick runs:

js
const c = canvas(1);
c.size(480, 300);
const dot = c.circle({ x: 240, y: 150, r: 12, fill: "#4fd1ff" });
let x = 240, y = 150;
function onTick(dt) {
  const speed = 200 * dt;
  if (keyDown("Left")) x -= speed;
  if (keyDown("Right")) x += speed;
  if (keyDown("Up")) y -= speed;
  if (keyDown("Down")) y += speed;
  dot.set({ x: x, y: y });
}
function onKey(name, down) {
  if (name === "Space" && down) dot.animate({ r: 20 }, { duration: 0.15, yoyo: true, repeat: 1 });
}

A game controller works the same way: gamepad(1) says what pad 1 is doing now (its buttons by name, its sticks lx, ly, rx, ry from -1 to 1 and its triggers lt, rt from 0 to 1, still sticks at 0), and onButton(name, down, pad) runs for every press and release. In the example above, x += 200 * dt * gamepad().lx moves the dot with the left stick. On Windows any pad that speaks XInput works (Xbox pads and most others), on a Mac those the system knows (Xbox, PlayStation, MFi); the pads are read only while a Script uses them.

Keys reach the Script while the MNodes window has the keyboard, and not while you type in a text box, the Script's own editor included, so writing code never moves your game. A Script whose code has neither onKey nor keyDown does not take the keys. Shortcuts keep working: a key that is also a shortcut, such as B for bypass with a node selected, does both, so play a game in Perform, where nothing is selected.

Drawing on a Scene ​

canvas(n), or scene(n), which is the same, draws on the Scene that Out n is wired into, through the Scene's Objects input. The code makes shapes, text and pictures, changes them, moves them over time and hears what the mouse does to them, with no GLSL at all. The canvas's own picture can stay underneath, or give way to a plain background.

js
const c = canvas(1);              // the canvas wired to Out 1
c.size(480, 300);                 // lay things out on 480 x 300, fitted to the canvas
c.background("#101018");          // a plain background: the canvas's own picture is hidden

const dot = c.circle({ x: 240, y: 150, r: 40, fill: "#223", stroke: "#4fd1ff", strokeWidth: 3 });
dot.on("drag", e => dot.set({ x: dot.get("x") + e.dx, y: dot.get("y") + e.dy }));
dot.on("click", () => dot.animate({ r: 60 }, { duration: 0.4, ease: "outBack" }));

Places count from the canvas's top left corner, in the units c.size() sets (the canvas's own size when the code sets none), and the whole scene is scaled to fit whatever size the canvas has.

A place or a size can also be a share of what it is in, written as a text: c.rect({ x: "10%", y: "100% - 50", w: "80%", h: 40 }) stays across the foot of the canvas whatever its size. "50%" is half the width for a place across or a width, half the height for a place down, a height or a text's size, and half the smaller side for a radius; "50%w", "50%h", "50%min" and "50%max" name the side, and terms add and take away ("100% - 20", "calc(50%w + 10)"). They count from the canvas (the units c.size() sets, or its own), from a group given a w and an h (what it holds counts from its box), or, for a label, from its 3D view. A binding or a change over time can go to a share too: bind: { x: ["p1", "0%", "100%"] }. Sizes in a 3D world are the world's own units.

Each maker takes the object's properties and gives the object back, to keep in a variable:

MakerWhat it drawsIts own properties
c.rect({...})A rectanglex, y (its top left), w, h, radius (round corners)
c.circle({...})A circle, or an ellipsex, y (its middle), r, or rx and ry
c.arc({...})Part of a ring, as a knob shows its valuex, y (its middle), r, width, start and end (in degrees, 0 at the top, going clockwise), cap
c.line({...})A straight linex1, y1, x2, y2, width, cap (round, butt or square)
c.polyline({...})Lines through pointspoints ([[x, y], ...] or [x, y, x, y ...]), closed, width, cap
c.triangle({...})A trianglex1, y1, x2, y2, x3, y3
c.text({...})Text, one line or several (\n)x, y, text, size, align (left, center, right), baseline (top, middle, bottom), lineHeight
c.image({...})A picture from a filex, y, w, h, src (the file's whole path, or image1 or image2 for the canvas's own Image 1 and Image 2), fit (contain or cover), radius
c.polygon({...})A shape through points, filledpoints ([[x, y], ...] or [x, y, x, y ...]), counted from its x and y
c.path({...})Any outline, written as SVG writes a pathd, such as "M 0 0 L 100 0 Q 150 50 100 100 Z" (see below), or points and closed; counted from its x and y
c.star({...})A star, its first point at the topx, y (its middle), r, sides (how many points), inner (how far its inner corners are, a share of r)
c.ngon({...})A regular polygon, its first corner at the topx, y (its middle), r, sides (6 unless you say)
c.wave({...})The sound on the Scene's In A or In B, as it playsx, y, w, h, input ("a" or "b"), shows ("wave" or "spectrum"), style (line, fill, bars or mirror), bars (how many), gain, log (false spreads a spectrum's frequencies evenly instead of by octaves)
c.group({...})A group of objectsx, y: what it holds counts from there; w, h: a box its shares count from; clip: [x, y, w, h], or [x, y, w, h, radius] for round corners, cuts what it holds to that box (true: its own box, round by its radius); reveal: 0 to 1, shows only so much of its box from one side, revealFrom "left" ("right", "bottom", "top"), for a fill or a meter made of any drawing

A path's d is written as SVG and drawing programs write it: M x y moves the pen there, L x y draws a straight line to there, H x and V y go straight across and down, C draws a curve through two control points (x1 y1 x2 y2 x y), S a curve that carries on smoothly from the last one, Q a curve with one control point, T one that carries on from it, A an arc (rx ry turn large sweep x y), and Z closes the outline back to where it started. A small letter counts from the last place instead of from the top left. A path with several outlines leaves the inside of an inner one empty, so an "O" has its hole. A wave reads the sound on the graphics card, so it is drawn on every frame however much it moves, and costs about what a rectangle does.

In a group, g.rect({...}) and the other makers put the new object inside it. Every object also takes:

PropertyWhat it does
fillIts colour: "#4fd1ff", "#4fd1ff80" (the last two digits its alpha), "rgb(79, 209, 255)", "rgba(79, 209, 255, 0.5)", a colour's name, or a gradient: { from: "#000", to: "#fff", angle: 90 } (0 goes left to right, 90 top to bottom), { from: "#000", to: "#fff", radial: true } from the middle out, or { from: "#000", to: "#fff", conic: true, angle: -135, span: 270 } round the middle, starting at angle (in degrees, 0 at the top, going clockwise) and reaching to after span degrees (360 when there is none). A picture's fill tints it.
fill with a pattern{ from: "#101820", to: "#4fd1ff", pattern: "stripes", size: 8, weight: 0.5, angle: 45 }: the pattern in to, over from. The patterns are stripes, dots, checker, grid and noise; size is how wide each cell is, in units, weight how much of a cell the pattern takes (a stripe's width, a dot's, a grid line's, 0 to 1), and angle turns it. patternX and patternY move it, so animate or bind them to make it slide.
stroke, strokeWidthIts outline, and how thick. A line and an arc are drawn in their stroke.
glow, glowColorA soft light round it, so many units wide, in that colour.
shadowA shadow under it: a colour ("#00000080"), or { color: "#00000080", x: 0, y: 4, blur: 12 } to move it (in units, the same way down the canvas however the object is turned) and soften it. false takes it away. An outline alone casts a ring.
blurSoftens its edges over so many units. On text, blur, shadow and glow soften over a short distance only, about a fifth of the letters' size.
trailWhere it has been stays behind it and fades to a tenth over so many seconds, so a moving object draws a streak. On a group, everything in it leaves its trail. A canvas keeps 8 trails at most; the canvas's Reset empties them.
opacityFrom 0 (not seen) to 1. A group's goes for everything in it.
rotation, scaleTurned (in degrees, clockwise) and sized round its middle; originX and originY move that point (0 to 1 across the object).
visiblefalse hides it, and what it holds.
blend"add" adds its light to what is under it.
cursorThe pointer over it: pointer, grab, crosshair, text, move, ns-resize, ew-resize or none.
tooltipA text shown when the pointer rests on it.
interactivefalse lets the mouse through it; true makes it take clicks even with no handler.
idA name to find it again with c.find(id). One is made when you give none.

Changing what is there:

CallWhat it does
o.set({ x: 100, fill: "red" })Changes it at once.
o.animate({ x: 300, fill: "#fff" }, { duration: 0.5, ease: "outBack", delay: 0, repeat: 0, yoyo: false }, then)Changes it over time: the canvas moves it on every frame, however often the code runs. A number in place of the options is the duration. Numbers and colours move; anything else is set at once. then(), if you give it, runs when the change is over.
o.stop()Stops its changes over time where they are.
o.get("x")The last value given to it.
o.front(), o.back()Over, or under, the objects next to it.
o.remove()Takes it away, with everything in it.
g.clear(), g.redraw(fn)Empties a group; or empties it and lets fn(g) fill it again, to draw a layer anew on every tick.
c.clear()Takes away everything the Script drew.
c.find(id)The object with that id.

The easings: linear, inQuad, outQuad, inOutQuad, inCubic, outCubic (the default), inOutCubic, inSine, outSine, inOutSine, inExpo, outExpo, inOutExpo, inBack, outBack, inOutBack, outElastic and outBounce.

The mouse: o.on(event, fn) calls fn when the mouse does something to the object, or to anything in it for a group: enter, leave, move, press, release, click, doubleclick, dragstart, drag, dragend, wheel, rightclick, and animationend when a change over time is over. fn is given what happened: e.x and e.y (where, in the scene's units), e.u and e.v (where on the object, 0 to 1 across it), e.dx and e.dy (how far a drag moved since the last one), e.totalX and e.totalY (how far since the press), e.delta (the wheel), e.shift, e.ctrl and e.alt, and e.target (the object). It goes to the object, then to the groups it is in, then to c.on(...), until one of them calls e.stop(). An object that listens takes the press, so the canvas's zones under it get nothing; one that only listens to enter and leave lets the press through.

The canvas: c.size(width, height, fit) sets the units the scene is laid out in (fit is contain, which keeps its shape, stretch, which fills the canvas, or cover, which fills it and cuts what goes past). c.background(colour) gives the canvas a plain background and hides its own picture, and its zones, which then leave the mouse alone; c.showCode(true) brings them back under the scene.

What a Script draws is its own: it is drawn again whenever the code starts, it is not saved with the canvas, and it goes when the cable does. The canvas's own picture, zones and inputs work as they always do, under it. A mistake in what the code draws (a property that does not exist, a colour that is not one) shows in the console once, and the rest is drawn.

In three dimensions ​

c.view3d({...}) puts a 3D view on the canvas: a box (x, y, w, h, as a rectangle's, with its radius, outline, glow and shadow) with a world inside it, drawn by the graphics card with light as metals and plastics catch it, smoothed edges and fog. What you make inside it is in that world: v.box(), v.sphere(), v.cylinder(), v.cone(), v.torus(), v.plane(), v.mesh() for a model from an OBJ or glTF file (src, and for a glTF one with animations animation, its name, and animationTime, in seconds: animate animationTime to play it), v.light(), v.sound({ name }) for where a sound is (a Scene 3D Sound with that name as its Script Sound plays from there) and v.listener() for where it is heard from (a Scene 3D Listener with Script Room set to "room" hears it), v.zone({ w, h, d, roomMix, roomSize, roomDecay }) for a place that sounds like a room (that listener gives what it hears its reverb), v.group() to move and turn several together, v.clones() to copy what it holds many times, and v.particles().

js
const c = canvas(1);
const v = c.view3d({ x: 20, y: 20, w: 440, h: 260, fill: "#101820", orbit: true,
                     environment: "studio" });                         // lit by a studio, which shines in the metal
v.plane({ w: 8, d: 8, y: -0.5, texture: "image1", tile: 4 });          // the canvas's Image 1, 4 times each way
const ring = v.torus({ r: 0.8, tube: 0.25, fill: "#e8b64a", metal: 1, rough: 0.3,
                       bind: { rotY: ["time", 0, 360, 0.2] } });      // turns by itself
v.sphere({ r: 0.4, segments: 6, flat: true, fill: "#4fd1ff",         // a gem
           bind: { scale: ["bass", 0.8, 1.4] } });                   // swells with the bass
v.light({ type: "spot", x: 0, y: 4, z: 2, cone: 25, intensity: 20 }); // aimed at the middle

In the world y is up, x across and z towards you, in its own units: a box 1 across seen from 5 away fills about a fifth of the view.

PropertyOnWhat it does
x, y, zsolids, lights, groupsWhere it is. A group's contents count from it. A light with no place of its own is at x -2, y 4, z 3, up and to the left, as a sun; a point or spot light made inside a group starts at the group's middle instead, so a lamp in a group is where the group is.
rotX, rotY, rotZsolids, groupsTurned round each axis, in degrees (rotation is rotZ).
scale, scaleX, scaleY, scaleZsolids, groupsIts size: 2 twice as big.
w, h, dbox, plane, meshIts width, height and depth. A mesh is fitted into a box 1 across first.
r, hsphere, cylinder, coneIts radius, and a cylinder's or a cone's height.
r, tubetorusIts ring's radius, and its tube's.
srcmeshThe OBJ file's whole path.
fill, opacitysolidsIts colour; under 1, what is behind it shows through.
metal, roughsolids0 a plastic, 1 a metal; 0 polished, 1 matt.
glow, glowColorsolidsThe light it gives of its own, for a lamp or a screen: glow times its colour, so over 1 it is brighter than white.
flatsolidstrue shades each face as one.
segmentssphere, cylinder, cone, torusIts sides round: 0 smooth. A few, with flat: a gem, a prism, a pyramid (a cone of 4).
texture, normalMapsolidsA picture on it, and a normal map's bumps that catch the light: a file's whole path, "image1" or "image2" for the canvas's own pictures, or a pattern made here by its name (pictures: "checker", "grid", "stripes", "dots", "bricks", "tiles", "wood", "marble", "noise"; bumps: "bricks", "tiles", "noise", "waves", "dimples", "brushed"). A solid one's clear parts are cut away.
tile, tileU, tileV, offsetU, offsetVsolidsHow many times its pictures repeat across it (tile for both ways), and how far they are moved: animate offsetU to slide them along.
bumpsolidsHow strong the normal map's bumps are: 0 none, 1 as drawn.
mirrorplaneHow much it reflects the world as a mirror does (1: a perfect mirror), blurred as it is rough, rippled by its normal map; what is under it is not seen in it. A view takes 4.
type, intensity, fill, rlight"directional" (as the sun, from x, y, z towards the middle), "point" (a lamp at x, y, z, reaching r away), "spot" (a stage light at x, y, z), "panel" (a glowing rectangle w by h at x, y, z, facing tx, ty, tz) or "environment" (the light from all round: its environment, envYaw and showEnvironment, as a view's; with environment "" an even light of its fill); how bright; its colour. A view takes 32 lights; the first that cast shadows, as many as its shadows have room for, cast them.
tx, ty, tz, cone, softlightWhere a spot points (in its group's units), how wide its light is from its middle to its edge (in degrees), and how much of that fades out (0 a sharp circle).
shadows, blurlightEvery light casts shadows unless shadows is false, a point all round it, as soft as blur says (texels of its shadows' picture; 1.5 unless said). A view keeps 16 views of them: from far away or a spot one, a point six. A see-through solid casts a lighter shadow, a picture's clear parts none.
yaw, pitch, distanceview3dIts camera: turned round what it looks at, raised above it (in degrees), and how far from it.
tx, ty, tz, fovview3dWhat the camera looks at, and how much it sees, top to bottom, in degrees.
orthoview3dtrue sees it straight on, with no perspective, as in a plan.
fill, ambientview3dIts background (none shows the canvas behind), and the light from all round when it has no surroundings, more from above than below.
environmentview3dIts surroundings: "studio", "sky", "sunset", "night", or a panorama's whole path (an .hdr, or any picture twice as wide as it is tall). Their light falls on everything, and what is smooth shines with them, sharp or blurred as it is rough.
showEnvironment, intensity, envYawview3dtrue shows the surroundings behind the world; how bright their light is; how far they are turned round, in degrees.
exposureview3dHow much light the camera takes in: 2 twice as bright.
bloom, bloomThreshold, bloomSizeview3dHow strongly what is brighter than bloomThreshold (1: white) glows round it, and how far the glow spreads (0 a tight halo, 1 a wide haze).
focus, focusDistance, focusRange, tiltShiftview3dDepth of field: how blurred what is out of focus is (0 to 1), how far from the camera it is sharp (0: where the camera looks), how deep the sharp part is; tiltShift 1 makes it a band across the middle of the picture instead, as a photo of a miniature (focusRange then its height).
ao, aoRadiusview3dAmbient occlusion: corners, creases and contact with the ground darker (0 to 1), looking aoRadius units round each point.
saturation, contrast, warmth, vignetteview3dThe picture graded: colour strength (1 as it is), contrast (1 as it is), warmth (-1 cool to 1 warm), corners darker (0 to 1).
edges, edgeWidth, edgeColorview3dOutlines where what is drawn ends or turns sharply (0 to 1), how wide in pixels, their colour.
fog, fogColorview3dHow thick the air is (0 for none), and what the distance fades into.
orbitview3dtrue lets the mouse turn the camera round (drag), slide what it looks at (Shift and drag) and bring it nearer (the wheel).
count, layout, spacing, columns, r, turnsclonesHow many copies of what it holds, laid out as "line", "grid", "circle", "spiral", "sphere" or "random": spacing apart in a line or a grid (columns across), r out on a circle, a spiral or a sphere (turns times round), anywhere in a box 2r across at random.
turnEach, riseEach, growEach, jitter, seedclonesEach copy turned (degrees), raised and grown this much more than the one before; moved, turned and sized at random by jitter (0 to 1), as seed says.
spectrum, inputclonesEach copy as tall as its band of the spectrum of In A ("A") or In B ("B"), spectrum times at full level; what it holds grows from its foot at 0.
rate, life, speed, spread, gravity, dragparticlesHow many a second, how long each lives, how fast they leave along its up within spread degrees, and how they are pulled down and slowed. p.burst(n) makes n at once.
size, sizeEnd, fill, colorEnd, glow, blend, shape, countparticlesEach one's size and colour when made and at the end of its life (no colorEnd: its colour fading out), the light it gives, "add" (the default) or "normal", "sphere" or "box", and how many can be alive at once.

Anything flat made in a 3D world (a text, a circle, a control) is a label: it is drawn over the view where the middle of its 3D group is seen (the world's middle if it is in none), following it as the camera turns, its own x and y moved from there in canvas units, and hidden when that point is behind the camera. v.group({ y: 1.2 }).text({ text: 'Ring', align: 'center' }) names what is under it; in clones, each copy has one. A group with label: true is flat as a whole, one label with everything in it (as the canvas's controls are). A view with hideLabels: true hides a label while a solid stands between it and the camera.

Everything moves as on the flat canvas: animate(), and bind to the sound, the P controls, the time or a zone, so a world can turn and pulse with no code running. A solid hears the mouse too: sphere.on("click", ...) is told when the pointer is on it, found by a ray from the camera.

Physics ​

A solid or a 3D group with body becomes a body that falls, collides, bounces and comes to rest in its view's world: body: "dynamic" falls and is pushed, "static" stays where it is put (the ground, a wall), "kinematic" goes where its x, y and z say (set them, or animate them), pushing what is in its way. A group is one body of all it holds. Its x, y, z and turns are then the world's: set them to put it somewhere else, and it carries on from there.

js
const c = canvas(1);
const v = c.view3d({ x: 0, y: 0, w: 480, h: 300, environment: "sky", yaw: 30, pitch: 25, distance: 14 });
v.light({ type: "directional", x: -4, y: 8, z: 3, shadows: true });
v.plane({ w: 20, d: 20, fill: "#7fb069", body: "static" });
for (let i = 0; i < 8; ++i)
  v.sphere({ x: i - 3.5, y: 4 + i, r: 0.4, fill: "#ffd166", body: "dynamic", bounce: 0.6 })
   .on("hit", e => { if (e.strength > 0.1) note(1, 60 + 2 * i, Math.round(127 * e.strength), 0.3); });
PropertyOnWhat it does
bodya solid, a 3D group"dynamic", "static" or "kinematic" (none: no body).
massa bodyHow heavy it is, in kilograms (0, the default: from its size, as water).
bounce, frictiona body0 a thud to 1 a superball; 0 ice to 1 rubber (0.5 unless said).
damping, gravitya bodyHow much the air slows it (0.05); how much gravity pulls it (1; 0 floats, below 0 rises).
sensora bodytrue: it stops nothing and only feels what comes in and goes out (bodyenter, bodyexit).
uprighta bodytrue: it never turns over (a character).
fasta bodytrue: thrown very fast, it does not pass through thin walls.
collidera solid bodyIts shape round it in place of its own: "box", "ball", "capsule" (a character), "cylinder". A model is otherwise the box it is fitted into.
gravity, speed, pausedphysicsv.physics({...}) sets its view's: how hard everything is pulled down (9.81), how fast its time goes (1), stopped or not.
namea bodyIts name, for joints of other owners (a node's) to find it by.
joint, a, bjointv.joint({...}) joins body a to body b (an Item, an id, or a body's name), or with no b to the world where the joint is: "hinge" (the default), "spring", "rope", "ball", "fixed" or "slider". The two do not collide with each other.
x, y, z, axisjointWhere it holds them, and which way a hinge turns round or a slider slides: "x", "y" or "z" (the default, swinging in the plane facing you), tilted with rotX, rotY, rotation.
min, maxjointA hinge's limits in degrees (min 0 to -180, max 0 to 180; its angle is 0 with body a turned as the joint is), a slider's in units; 0 and 0, none.
speed, strength, frictionjointA motor: degrees a second round a hinge, units a second along a slider; the most it pushes with (0: as much as it takes; with no speed, a brake); how stiffly it turns or slides.
stiffness, damping, lengthjointA spring's bounce, times a second (2; 0: a rigid rod), how soon it settles (0.1), its length at rest; a rope's longest (no length: as far apart as when made).

A body's events, with on(): hit each time it begins to touch something (e.other is what it hit, the Item when it is this Script's, and e.otherId its id; e.strength how hard, 0 to 1; e.speed how fast they met, in units a second; e.point and e.normal where, and which way from it); bodyenter and bodyexit when a body comes into or leaves a sensor (both are told); bodymove every frame it moves (e.point where it is, e.speed how fast); and a joint's jointmove whenever it moves (e.value a hinge's angle in degrees, a slider's place, a spring's or a rope's length; e.speed how fast that changes). A joint changes as it goes: wheel.set({ speed: 180 }).

js
// A pendulum: a ball held 3 from a pin, swinging, its angle out of CV 1.
const bob = v.sphere({ x: 3, y: 6, scale: 0.5, fill: "#ffd166", body: "dynamic" });
v.joint({ joint: "hinge", a: bob, x: 0, y: 6, axis: "z" })
 .on("jointmove", e => cv(1, e.value / 90));

Its methods: push(x, y, z) adds to its speed (or push({ x, y, z, spinX, spinY, spinZ }), the spins in degrees a second), velocity(x, y, z) sets it, body() says where it is and how fast it goes now ({ x, y, z, vx, vy, vz, awake }, in its view's world), restart() puts every dynamic body of its view back where it was put, and a view's ray(from, to) finds the first body a straight line meets ({ item, id, x, y, z, normal, distance }, or null). Hidden (visible: false), a body is in no world; one with opacity 0 is unseen but still solid, an invisible wall. The worlds go on with the plug-in's window closed, or the Scene on no screen: their hits are still told to the code, and what it does with them (a note, a CV) still plays.

Following the sound with no code ​

bind ties a number or a colour of an object to something that changes, and the canvas moves it on every frame by itself, while the code does nothing:

js
c.circle({ x: 240, y: 150, r: 20, fill: "#4fd1ff",
           bind: { r: ["levelA", 20, 80],                  // bigger as In A gets louder
                   fill: ["bass", "#203040", "#4fd1ff"],   // lighter with the bass
                   rotation: ["time", 0, 360, 0.25] } });  // round once every 4 seconds

Each one is [source, from, to]: the source goes from 0 to 1, and the property goes from from to to with it (two colours for a colour). The sources:

SourceWhat it follows
levelA, levelBHow loud the Scene's In A or In B is: 0 at -60 dB and under, 1 at 0 dB. It rises at once and falls back over a quarter of a second.
bass, mid, trebleIn A's lows (up to about 250 Hz), mids (up to 4 kHz) and highs (up to 16 kHz).
P1 to P60The canvas's P controls, and whatever is wired into them.
timeThe canvas's clock, going from 0 to 1 over and over, as many times a second as a fourth number says (once when there is none): ["time", 0, 360, 0.5] turns it round every two seconds.
a zone's nameThat zone's value: one of the canvas's own, or a control's made with param: true. "Pad.y" is the Y of an XY pad or a drag, and "zone:time" reads a zone that is called time.

Numbers such as x, y, w, h, r, rotation, scale, opacity, strokeWidth, glow, blur, shadowX, shadowY, shadowBlur, patternX, patternY, sides and gain can be bound, and so can the colours fill, stroke, glowColor and shadowColor. While a property is bound, the source decides it, whatever the code sets. A new bind replaces the last one, and o.set({ bind: null }) lets them all go.

A text can show the number: bind: { text: ["levelA", -60, 0, { decimals: 1, suffix: " dB" }] } writes the source's value, laid from from to to, with so many decimals (2 when it does not say), after a prefix and before a suffix, on every frame. The same options can hold the time's rate: ["time", 0, 10, { rate: 0.1 }]. And smooth, in seconds, makes what is bound glide after its source instead of jumping: { smooth: 0.1 } follows most of the way in a tenth of a second, so a meter falls softly and a switch slides.

Ready-made controls ​

The canvas also has controls ready to place, one line each, drawn and played the same way whatever you build around them:

js
const c = canvas(1);
c.size(480, 300);
c.background("#0d1017");

c.knob({ x: 70, y: 110, name: "Cutoff", min: 20, max: 20000, log: true, unit: " Hz", decimals: 0, out: 2 });
c.slider({ x: 180, y: 80, w: 200, name: "Drive", out: 3 });
c.toggle({ x: 180, y: 140, name: "Glide", out: 4 });
c.meter({ x: 420, y: 60, h: 120, input: 1 });
MakerWhat it isIts own options
c.knob({...})A knob: drag up or down (Shift for fine steps), turn the wheel, or double-click for its defaultsize
c.slider({...})A slider: press anywhere on it, and dragw, h, vertical (it stands up when it is taller than wide)
c.button({...})A buttonw, h, mode: "trigger" sends an Event when it is pressed, "momentary" sends true while it is held and false when it is let go
c.toggle({...})A switch a click turns on and offw, h
c.xy({...})A pad with a point you drag: its value is [x, y]w, h, outX, outY (each on its own output)
c.meter({...})A level to watch, set from an input, with a line that holds the highestw, h, vertical
c.steps({...})A row of cells a click turns on and off: its value is the list of themcount, w, h, gap; steps.light(i) lights cell i as the one playing
c.select({...})A row of choices, one lit: its value is its number, from 0options (their names), w, h

Every control also takes x and y (its top left, or a knob's middle), name (shown under it, and the name its value is kept under with the project, so it is where you left it when the project opens), label (shown instead of the name; "" shows none), value (where it starts), default (what a double-click brings back), min and max (its range, 0 to 1 unless you say), step, log (a range for frequencies), unit, decimals, color (its own accent), tooltip, out: n (its value goes out of Out n whenever it changes, and once when the code starts), input: n (a message on In n sets it, and goes on out, as a Knob's In does) and onChange (a function called with each new value). g.knob({...}) and the others put a control inside a group.

With param: true a control is also one of the canvas's zones, by its name: the canvas gets an output named after it, your DAW gets a parameter to automate (with the canvas's Expose to DAW on), and its value is saved with the canvas and kept in its States. The control starts from that zone, and follows it when the DAW, a State or the canvas's Set input moves it; grabbing the control is a gesture for the DAW, so its touch and latch automation record what you play. Such zones have no place of their own on the canvas and do not show in Edit Zones: the Script's drawing is what the mouse plays. A meter and steps cannot be one.

Each maker gives the control back: its value can be read or set (knob.value = 0.3), knob.on("change", fn) calls fn with each new value, knob.group is the group it is drawn in (to move it, or animate it), and knob.remove() takes it away. c.theme({ accent: "#ff7a45" }) changes the look of the controls made after it: accent, body, edge, track, text, label and font (the size of their text).

A control of your own is a class built on canvas.Component: build() makes its drawing in this.group once, and draw() shows this.value; this.set(v) gives it a new value, which is kept, sent and drawn like any control's.

js
class Lamp extends canvas.Component {
    build() {
        this.bulb = this.group.circle({ r: 12, fill: "#333" });
        this.group.on("click", () => this.set(this.value ? 0 : 1));
    }
    draw() {
        this.bulb.set({ fill: this.value ? "#ffcc33" : "#333" });
    }
}

c.add(Lamp, { x: 400, y: 200, name: "Lamp", out: 5 });

MNodes Documentation