Aether Rhai Scripting Guide

Complete reference for scripting in Aether using the Rhai language. Scripts automate graph construction, sequencer programming, and live performance. Run scripts from the console (bottom panel), the script editor (Cmd+E), or headless (aether-headless --script file.rhai).

Quick Start

// Build a simple synth patch
let sink = AudioSink.first();
let synth = Polysynth.add("synth");
let reverb = Reverb.add("reverb");

synth.output("Audio Out").port().connect(reverb.input("Input").port());
reverb.output("Output").port().connect(sink.input("Audio In").port());

synth.waveform("Sawtooth");
reverb.room_size(0.7);
reverb.mix(0.3);

play();

Key Concepts

Type System

Every node type gets its own Rhai type, generated by the graph_node! proc macro. Each type has per-property setter methods and per-port property methods.

TypeCreated byExample
OscillatorScriptHandleOscillator.add("osc")osc.frequency(440.0)
MixerScriptHandleMixer.add("mix")mix.master_gain(0.5)
MixerInputPortHandlemix.input("Input 0")inp.gain(0.5)
MixerOutputPortHandlemix.output("Output")out.port() for connect
ScriptPortRefport.port()out.port().connect(inp.port())
ScriptTrackRefnode.add_track("name")t.add_note("C4", 0.0, 1.0)
ScriptRegionReftrack.add_region(0.0, 16.0)r.set_label("Intro")
ScriptNoteReftrack.add_note("C4", 0.0, 1.0)n.set_velocity(100)
ScriptEnvelopeadsr(), one_shot(), etc.synth.shape(adsr(0.01, 0.1, 0.7, 0.2))
ScriptCurvecurve(), linear_curve(), etc.set(node, "CurveData", c)

Methods on All Node Handles

Every node handle (regardless of type) has these shared methods:

Methods on All Port Handles

Every port handle has:

Discovering the API: .help()

Every registered type - macro-generated handles, typed port handles, and the hand-written types (ScriptCurve, ScriptEnvelope, etc.) - responds to .help(). In the console it auto-prints; in scripts pass it to print():

Oscillator.help();                     // node type: add/find/first
let osc = Oscillator.add("osc");
osc.help();                            // properties, ports, methods
osc.output("Audio Out").help();        // port type + methods
let c = curve();
c.help();                              // ScriptCurve builder methods

Style Guide

Use Typed Property Methods

Each node type has generated setter methods for its properties. Method names are snake_case of the property variant name (e.g. DelayTimedelay_time(), MasterGainmaster_gain()). This is the preferred way to set properties - it's type-safe and validated per node type.

// Preferred - typed, validated per node type
osc.frequency(440.0);
osc.waveform("Sawtooth");
filter.cutoff(2400.0);
delay.delay_time(0.375);
delay.feedback(0.35);
mix.master_gain(0.5);

// Fallback - string-based, resolves by name
osc.set("Frequency", 440.0);

Label Everything

Always pass a label to .add(). This makes scripts idempotent and self-documenting.

// Good - labeled, rerunnable
let filter = Biquad.add("main filter");

// Avoid - creates a new node every run
let filter = Biquad.add();

Use show() to Discover Names

When unsure of a property or port name:

let osc = Oscillator.add("osc");
osc.show();
// Prints: type, all ports, all properties with current values
// For ArrangerEditor/SequencerEditor: also prints tracks, regions, notes

osc.input("Frequency Mod").show();   // port details
mix.input("Input 0").show();          // port properties (gain, pan)

Name Resolution

String-based set()/get() and port names use fuzzy resolution:

Port Names

  1. Exact match - "Audio Out"
  2. Case-insensitive - "audio out"
  3. Underscores as spaces - "audio_out"
  4. Substring - "audio" (matches the first port containing that text)

Property Names (for set()/get())

  1. Exact property ID - "MasterGain"
  2. Case-insensitive property ID - "mastergain"
  3. Case-insensitive display name - "master gain"

Enum Properties

osc.waveform("Sawtooth");            // typed method
osc.set("Waveform", "Sawtooth");     // string-based
osc.set("Waveform", 2);              // by index

Function Reference

Arranger Region

FunctionDescription
extend_back(region, beats, fade_beats?, shape?)Extend the region's end later by N beats (resizing). Optional fade_beats adds a fade-out. Returns the region for chaining
extend_front(region, beats, fade_beats?, shape?)Move the region's start earlier by N beats (resizing). Optional fade_beats adds a fade-in. Returns the region for chaining
fade_in(region, beats, shape?)Apply a fade-in over N beats from the region's start (optional shape: linear/ease_in/ease_out/ease_in_out). Returns the region for chaining
fade_out(region, beats, shape?)Apply a fade-out over N beats to the region's end (optional shape). Returns the region for chaining
info(region)Get region info
remove(region)Remove region
set_color(region, color)Set region color
set_curve(region, curve)Set region amplitude curve shape
set_duration(region, dur)Set region duration
set_label(region, label)Set region label
set_level(region, level)Set region level
set_start(region, start)Set region start beat

Arranger Track

FunctionDescription
add_region(track, start, dur)Add region to track
gate_port(track)Return the output port name for this track's Gate output
gate_threshold(track, value?)Get/set per-track gate threshold (0..1). Track Gate output goes high when Level exceeds this value
level_port(track)Return the output port name for this track's Level (ControlNorm) output
regions(track)List regions in track

Connections

FunctionDescription
connect(target_port)port.connect(other_port)
connected()port.connected() - returns true if port has any connection
disconnect()port.disconnect()
source()input_port.source() - returns "Type(#id):PortName" of connected source, or () if disconnected
targets()output_port.targets() - returns "[Type(#id):Port, ...]" of connected targets

Curve

FunctionDescription
add_linear_point(time, value)Add a keyframe and patch the previous point so the segment is a true straight line
add_point(time, value)Add a keyframe with zero tangents (smoothstep S-curve into this point)
add_smooth_point(time, value, in_tangent, out_tangent)Add a keyframe with explicit in/out tangents
bipolar()Clamp output to -1..1
constant_curve(value, duration)Constant value for duration seconds
curve()Create an empty curve - add keyframes with add_point()
duration()Total duration of the curve
ease_in_curve(duration)Slow start, fast end from 0 to 1
ease_in_out_curve(duration)Slow start, slow end from 0 to 1
ease_out_curve(duration)Fast start, slow end from 0 to 1
eval(time)Evaluate the curve at a given time
fade_in_out_curve(duration)Fade in to midpoint then out over duration seconds
fade_out_curve(duration)Linear ramp from 1 to 0 over duration seconds
len()Number of keyframes
linear_curve(duration)Linear ramp from 0 to 1 over duration seconds
linearize()Rewrite all tangents so every segment is a straight line
normalized()Clamp output to 0..1
unbounded()No output clamping

Debugging

FunctionDescription
back_trace()Return the current call stack as an array of maps (fn_name, args, source, line, position)

Edit

FunctionDescription
clipboard(text)Copy text to system clipboard
export_graph()Export current graph as Rhai script
graph_clear()Remove all nodes except AudioSink
graph_new(name?)Create a new graph and switch to it
redo()Redo last undone action
undo()Undo last action

Envelope

FunctionDescription
adsr(attack, decay, sustain, release)Classic ADSR: attack, decay, sustain level, release (seconds)
decay_env(decay)Instant peak, decay to zero
gated_hold(attack, release)Attack to peak, hold until release
one_shot(attack, decay)Attack-decay, no sustain hold

Files

FunctionDescription
include(uri)Load and execute a script from the project (preprocessor directive)

Help

FunctionDescription
help(filter)Search functions by keyword
help()List all functions

Inspection

FunctionDescription
list_files()List script files
list_nodes()List all nodes in graph
list_types()List registered node types

Journal

FunctionDescription
journal(on_off)Enable/disable command journal
journal_status()Print journal status
replay(file)Replay a journal file

Nodes

FunctionDescription
add(label?)Type.add() or Type.add("label")
deselect()Clear selection
find()Type.find() - all existing nodes of type
first()Type.first() - first existing node of type
label(node, name)Set display label
node_color(r, g, b, a)Set node title tint color (RGBA, 0.0–1.0)
position(x, y)Set node canvas position in pixels
remove(node)Delete a node
select(node)Select a node on canvas
show(node)Print node info

Properties

FunctionDescription
get(prop)Get a property value: node.get(prop)
set(prop, value)Set a property value: node.set(prop, value)

Sequencer

FunctionDescription
get_bars(node)Get sequencer bar count
get_bpm(node)Get sequencer BPM
scroll_to_beat(node, beat)Scroll sequencer to beat
scroll_to_note(node, pitch)Scroll sequencer to pitch
zoom(node, x, y)Set sequencer zoom

Sequencer Note

FunctionDescription
info(note)Get note info
move_to(note, pitch, beat)Move note (pitch + beat)
remove(note)Remove note
set_duration(note, dur)Set note duration
set_pitch(note, pitch)Set note pitch
set_start(note, beat)Set note start beat
set_velocity(note, vel)Set note velocity

Sequencer Track

FunctionDescription
add_note(track, pitch, start, dur, velocity)Add note with explicit velocity
add_note(track, pitch, start, dur)Add note to track
add_notes(track, notes_array)Add many notes in one call
notes(track)List notes in track
set_channel(track, channel)Set track MIDI channel

Shared

FunctionDescription
add_track(node, name)Add named track (arranger or sequencer), idempotent by name
bars(node, bars)Set bar count (arranger or sequencer)
bpm(node, bpm)Set BPM (arranger or sequencer)
can_redo(node)Check redo available (arranger or sequencer)
can_undo(node)Check undo available (arranger or sequencer)
redo(node)Redo edit (arranger or sequencer)
set_loop(node, on_off)Toggle loop (arranger or sequencer)
timesig(node, num, den)Set time signature (arranger or sequencer)
tracks(node)List tracks (arranger or sequencer)
undo(node)Undo edit (arranger or sequencer)

Shared Track

FunctionDescription
clear(track)Clear track (arranger or sequencer)
enable(track, on_off)Enable/disable track (arranger or sequencer)
info(track)Get track info (arranger or sequencer)
mute(track, on_off)Mute track (arranger or sequencer)
remove(track)Remove track (arranger or sequencer)
set_name(track, name)Set track name (arranger or sequencer)
solo(track, on_off)Solo track (arranger or sequencer)
track_port(track)Get the output port name for this track (e.g. "Track 0") for connecting to a playback node

Timing

FunctionDescription
breakpoint(label)Pause with a label shown in the console (file scripts only)
breakpoint()Pause script execution until manually resumed (file scripts only)
sleep(ms)Pause script execution (ms)

Tour

FunctionDescription
tour(on_off)Start/stop camera tour

Transport

FunctionDescription
current_beat()Query current transport beat position
get_key()Query musical key. Returns () if no key is set
get_tempo()Query global transport BPM
is_playing()Query whether transport is playing
pause()Pause transport playback
play()Start transport playback
seek(beat)Seek transport to absolute beat position
set_key(key)Set musical key (e.g. "C", "Am", "F#m"). Empty string clears
set_tempo(bpm)Set global transport BPM (clamped 1–999)
set_time_signature(num, denom)Set global time signature. denom is power of 2 (2=quarter, 3=eighth). Example: set_time_signature(3, 2) for 3/4
stop()Stop transport and reset position

Values

FunctionDescription
channel(n)Shorthand for MidiChannel::create(n)
color(r, g, b, a)color(r, g, b, a) - RGBA color (0.0–1.0)
vec2(x, y)vec2(x, y) - 2D vector
vec3(x, y, z)vec3(x, y, z) - 3D vector

View

FunctionDescription
autolayout(on_off)Toggle auto-layout
autozoom(on_off)Toggle auto-zoom
toast(message, severity?, position?)Show a toast. severity: "info" (default), "error". position: "bottom_right" (default), "top", "center"
toggle(element, on_off)Toggle a UI element. elements: "grid", "palette", "properties", "menu", "status", "sequencer", "console", "auto_properties", "script_editor", "editor", "3d", "activity", "overlay"
zoom_to_fit()Fit graph in view
zoom_to_node(node)Center on a node

Node Reference

Analysis

Chromatic Tuner (ChromaticTuner)

Real-time pitch detection with note name and cents deviation display

let node = ChromaticTuner.add("my_chromatictuner");

Real-time pitch detection and tuning display. Reads spectral magnitudes from an upstream SpectralAnalyze node and identifies the fundamental frequency via harmonic product spectrum (HPS).

When detection confidence exceeds the Sensitivity threshold, the detected pitch is smoothed over time and output as V/Oct on the Pitch port; the Gate port goes high. When confidence drops below the threshold, the smoothed frequency resets to zero, V/Oct outputs 0.0, and the gate goes low. The optional Tuning input sets divisions-per-octave for note naming (defaults to 12-TET).

Properties:

PropertyMethodTypeDefaultRange
Sensitivitysensitivity()Float0.50..1
Smoothingsmoothing()Float0.10..1

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Linear spectral magnitudes from an upstream SpectralAnalyze node. Required -- the tuner has no internal FFT.
TuningData(Tuning)Tuning configuration for note naming. Defaults to 12-TET when disconnected.

Outputs:

PortTypeNotes
PitchVOctDetected pitch as V/Oct (0.0 = 440 Hz). Outputs 0.0 when no pitch is confidently detected.
GateGateHigh while a pitch is confidently detected (confidence >= Sensitivity and frequency > 0). Emits edge events only on state transitions.

Clip Detector (ClipDetector)

Detects audio clipping with control output

let node = ClipDetector.add("my_clipdetector");

Monitors audio for clipping by comparing per-sample amplitude against a configurable threshold. Passes audio through unchanged.

Both left and right channels are checked; if either exceeds the threshold the clip indicator fires. The Clip Signal output stays at 1.0 for the duration of the hold period after the last clipping sample, then drops to 0.0. Internally tracks total clip events, samples clipped, and peak amplitude for diagnostics. Returns early with no output if Audio In is disconnected.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold()Float10.1..2
Hold Timehold_time()Float100..1000

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to monitor for clipping.

Outputs:

PortTypeNotes
Audio OutAudioUnmodified pass-through of the input audio.
Clip SignalControlNormControl signal: 1.0 while clipping (including hold period), 0.0 otherwise.

Envelope Follower (EnvelopeFollower)

Tracks amplitude envelope of audio signal

let node = EnvelopeFollower.add("my_envelopefollower");

Extracts the amplitude envelope from an audio signal, producing a smooth control voltage that tracks the signal's loudness over time.

Stereo input is mono-downmixed and fed sample-by-sample into a peak detector with independent attack/release time constants. The resulting envelope level drives the Envelope Out control signal. A threshold comparator on the envelope generates gate events: the gate goes high on the sample where the envelope first exceeds the threshold and low on the sample where it drops below. Returns early with no output if Audio In is disconnected.

Properties:

PropertyMethodTypeDefaultRange
Attack Timeattack_time()Float0.0050.001..1
Release Timerelease_time()Float0.10.01..5
Thresholdthreshold()Float0.10..1

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio whose amplitude envelope is tracked. Mono-downmixed internally before peak detection.

Outputs:

PortTypeNotes
Envelope OutControlNormSmoothed amplitude envelope as a normalized control signal. Represents the last sample's envelope value in the current buffer.
Gate OutGateGate high when the envelope exceeds the threshold. Edge events carry sample-accurate offsets within the buffer.

Oscilloscope (Oscilloscope)

Real-time waveform visualization with trigger modes

let node = Oscilloscope.add("my_oscilloscope");

Real-time waveform display for inspecting audio signals. Supports dual-channel comparison and configurable trigger modes.

Each stereo input is mono-downmixed for display. In Auto mode the trigger level is continuously derived from the signal's running min/max midpoint (works for bipolar and rectified signals); in Rising/Falling modes it uses the user-set Trigger Level. FreeRun captures continuously with no trigger gating. Discontinuity mode triggers on sudden sample-to-sample jumps by comparing the current delta against a running average - useful for catching clicks, pops, retrigger boundaries, and envelope attacks. When a trigger fires, samples fill the capture buffer until it reaches the configured time-scale width, then a snapshot is staged for the UI. In Auto and Discontinuity modes, a periodic fallback flush fires every 4096 frames if no trigger occurs. Audio is always passed through on both channels regardless of freeze or trigger state. Freezing pauses capture but not pass-through. Returns early with no output if Channel 1 is disconnected.

Properties:

PropertyMethodTypeDefaultRange
Time Scaletime_scale()Float101..100
Trigger Modetrigger_mode()Enumenum(0)Auto, Rising, Falling, Free Run, Discontinuity
Trigger Leveltrigger_level()Float0-1..1
Freezefrozen()Boolfalse
Y Scaley_scale()Float10.1..20

Inputs:

PortTypePropertiesNotes
Channel 1Audiorequired; Primary stereo audio signal. Mono-downmixed for the Channel 1 waveform display and passed through to Channel 1 Out.
Channel 2AudioOptional second stereo audio signal for dual-channel comparison. Mono-downmixed for display and passed through to Channel 2 Out. Trigger always fires from Channel 1.
FreezeGateGate input to freeze the waveform display. While high, capture pauses and the display holds its last frame. Audio pass-through continues regardless. Overrides the Frozen property when connected.
ResetGateRising edge clears freeze and re-arms the trigger. Pairs with Discontinuity mode's auto-freeze: pulse Reset to hunt for the next artifact.

Outputs:

PortTypeNotes
Channel 1 OutAudioPass-through of Channel 1 audio.
Channel 2 OutAudioPass-through of Channel 2 audio.

Peak Meter (PeakMeter)

Peak level measurement with hold and decay

let node = PeakMeter.add("my_peakmeter");

Measures peak audio levels with hold and ballistic decay, outputting a control signal for driving level meters and VU displays.

Left and right channels are metered independently through separate PeakMeter DSP instances. The Peak Level control output is the maximum of L/R peaks each buffer. A poll response carries per-channel linear peaks, combined dB level, and a clipping flag (true when either channel >= 1.0). Audio is passed through unchanged. Returns early with no output if Audio In is disconnected. Meters are fully re-initialized on setup() when the sample rate changes.

Properties:

PropertyMethodTypeDefaultRange
Hold Timehold_time()Float10..5
Decay Timedecay_time()Float20.1..5

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to measure. Left and right samples are fed to independent peak meters and also copied to Audio Out.

Outputs:

PortTypeNotes
Audio OutAudioUnmodified pass-through of the input audio.
Peak LevelControlNormPeak level as a control signal (max of L/R after hold and decay). Can exceed 1.0 if the input clips.

Spectrum Analyzer (SpectrumAnalyzer)

FFT-based frequency spectrum visualization with configurable analysis

let node = SpectrumAnalyzer.add("my_spectrumanalyzer");

FFT-based frequency spectrum display. Shows the frequency content of an audio signal in real time with configurable resolution, windowing, and spectral averaging.

Accepts two input paths: a Spectral port and an Audio port. When Spectral is connected, magnitudes arrive pre-computed from an upstream SpectralAnalyze node and the internal FFT is bypassed. When only Audio is connected, stereo input is mono-downmixed and accumulated into an FFT buffer with 50% overlap, then processed on a dedicated analysis thread to keep the audio thread real-time safe. Audio is always passed through unchanged regardless of which analysis path is active. Freezing pauses spectral capture but does not interrupt audio pass-through. The optional Tuning input sets divisions-per-octave for the note overlay gridlines (defaults to 12-TET when disconnected).

Properties:

PropertyMethodTypeDefaultRange
FFT Sizefft_size()Int20..4
Windowwindow_type()Enumenum(0)Hann, Hamming, BlackmanHarris, Rectangular
Averagingaveraging_mode()Enumenum(2)None, PeakHold, Exponential
Averaging Timeaveraging_time()Float0.30.05..5
Min Frequencymin_frequency()Float2020..10000
Max Frequencymax_frequency()Float22050100..22050
Note Overlaynote_overlay()Boolfalse
Freezefrozen()Boolfalse

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Pre-computed spectral magnitudes from an upstream SpectralAnalyze node. When connected, the internal FFT and averaging are bypassed entirely.
Audio InAudiorequired; Stereo audio to analyze. Mono-downmixed and fed to the internal FFT when the Spectral port is disconnected. Also passed through to Audio Out regardless.
TuningData(Tuning)Tuning configuration for note overlay gridlines. Defaults to 12-TET when disconnected.

Outputs:

PortTypeNotes
Audio OutAudioUnmodified pass-through of the input audio.

Waterfall (Waterfall)

Scrolling spectrogram - frequency × time heatmap

let node = Waterfall.add("my_waterfall");

Scrolling spectrogram that plots frequency content over time as a color-mapped heatmap. Each row is one FFT slice; the display scrolls so the most recent spectrum appears at the top.

Accepts two input paths: a Spectral port and an Audio port. When Spectral is connected, magnitudes arrive pre-computed and the internal FFT is bypassed. When only Audio is connected, stereo input is mono-downmixed and accumulated with 75% overlap for smooth scrolling, then processed on a dedicated analysis thread. Averaging is always disabled (each row is a single un-smoothed FFT frame). Audio is passed through unchanged regardless of which analysis path is active. Freezing pauses spectrogram scrolling but does not interrupt audio pass-through.

Properties:

PropertyMethodTypeDefaultRange
FFT Sizefft_size()Int10..3
Min Freqmin_frequency()Float2020..10000
Max Freqmax_frequency()Float22050100..22050
Freezefrozen()Boolfalse

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Pre-computed spectral magnitudes from an upstream SpectralAnalyze node. When connected, the internal FFT is bypassed entirely.
Audio InAudiorequired; Stereo audio to analyze. Mono-downmixed and fed to the internal FFT when the Spectral port is disconnected. Also passed through to Audio Out regardless.

Outputs:

PortTypeNotes
Audio OutAudioUnmodified pass-through of the input audio.

Effect

Allpass Filter (AllpassFilter)

Phase rotation without amplitude change - building block for phasers and reverbs

let node = AllpassFilter.add("my_allpassfilter");

Second-order allpass filter (RBJ biquad). Passes all frequencies at unity gain but rotates phase around the center frequency.

True stereo with independent filter state per channel. Frequency and Q are smoothed over 128 samples to prevent clicks during modulation.

Freq Mod overrides the Frequency property when connected (ControlFreq, value in Hz, clamped to 20-20,000 Hz). The CV fully replaces the knob value.

Chain several allpass filters in series to build a phaser. Place one in a feedback delay loop for dispersive reverb tails.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float100020..20000
Qq()Float0.7070.1..20

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio signal to phase-rotate.
Freq ModControlFreqOverrides the Frequency property. Value is in Hz (ControlFreq), clamped to 20-20,000 Hz. Smoothed - safe for LFO-driven phaser sweeps.

Outputs:

PortTypeNotes
AudioAudioPhase-rotated stereo audio output.

Amp Envelope (AmpEnvelope)

Amplitude envelope - shapes audio volume with a gate-triggered envelope

let node = AmpEnvelope.add("my_ampenvelope");

Combined envelope generator and VCA. Multiplies an audio input by a gate-triggered envelope curve, replacing the Envelope-into-VCA two-node pattern.

The Depth knob scales the envelope level before it is applied to the audio. DepthMod multiplies with Depth (disconnected defaults to 1.0), so effective depth = Depth * DepthMod. The Env output carries the effective envelope value clamped to 0.0-1.0 for downstream modulation. With no audio input connected, Audio Out produces silence but the envelope still advances.

Properties:

PropertyMethodTypeDefaultRange
Shapeshape()Envelope[envelope]
Depthdepth()Float10..1

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Audio signal to shape. When disconnected, Audio Out is silent but the envelope still advances.
Gate InGaterequired; Rising edge triggers attack from curve start; falling edge triggers release from the hold point.
Depth ModControlNormMultiplied with the Depth knob. Disconnected defaults to 1.0 (no attenuation).

Outputs:

PortTypeNotes
Audio OutAudioInput audio multiplied by the depth-scaled envelope, per sample.
Env OutControlNormEffective envelope level (envelope * depth * depth_mod) clamped to 0.0-1.0.

Automation Curve (AutomationCurve)

Transport-synced drawn curve for parameter automation

let node = AutomationCurve.add("my_automationcurve");

Transport-synced modulation source driven by a user-drawn keyframe curve. Evaluates against the beat timeline to produce parameter automation across six output formats.

The curve position is derived from the transport beat, looping over the configured bar length. Position input overrides the transport playhead when connected (0.0 = curve start, 1.0 = curve end). Depth input scales all outputs (disconnected defaults to 1.0). Frequency outputs use log-scale mapping between FreqMin and FreqMax. VOct is derived from the same frequency mapping relative to middle C (261.63 Hz). Gate goes high when the depth-scaled curve value reaches 0.5.

Properties:

PropertyMethodTypeDefaultRange
Curvecurve_data()Curve[curve]
Lengthlength_bars()Int41..64
Looploop()Booltrue
Freq Minfreq_min()Float201..20000
Freq Maxfreq_max()Float200001..20000

Inputs:

PortTypePropertiesNotes
PositionControlNormOverrides the transport playhead. 0.0 = curve start, 1.0 = curve end. Clamped to 0.0-1.0, then scaled to the beat range to re-evaluate the curve.
DepthControlNormMultiplies all outputs by this value (clamped to 0.0-1.0). Disconnected defaults to 1.0.

Outputs:

PortTypeNotes
NormControlNormDepth-scaled curve value (0.0-1.0).
BipolarControlBipolarDepth-scaled curve value remapped via (scaled * 2 - 1) to -1.0 to 1.0.
FreqControlFreqDepth-scaled curve value mapped to Hz via log interpolation between FreqMin and FreqMax.
AudioAudioDepth-scaled curve value as constant mono-to-stereo audio (same value for every sample in the buffer).
VOctVOctV/Oct derived from the same frequency mapping as Freq, relative to middle C (261.63 Hz). Constant per buffer.
GateGateEdge-detected gate high when the depth-scaled curve value is >= 0.5.

Biquad Filter (Biquad)

Second-order IIR filter with multiple types

let node = Biquad.add("my_biquad");

Second-order IIR filter with seven modes: lowpass, highpass, bandpass, notch, peak, low shelf, and high shelf.

True stereo with independent filter state per channel - no crosstalk. All parameters are smoothed over 128 samples to avoid clicks during modulation.

Cutoff Mod overrides the Frequency property when connected (ControlFreq, value in Hz). Q Mod overrides the Q property (ControlNorm, 0.0-1.0 mapped linearly to Q 0.1-20.0). Both CV inputs fully replace the knob value - there is no additive modulation.

Gain only affects Peak, Low Shelf, and High Shelf modes. For LP/HP/BP/Notch it has no effect.

Properties:

PropertyMethodTypeDefaultRange
Typefilter_type()Enumenum(0)Lowpass, Highpass, Bandpass, Notch, Peak, Lowshelf, Highshelf
Frequencyfrequency()Float100020..20000
Qq()Float0.7070.1..20
Gaingain_db()Float0-24..24

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to filter.
Cutoff ModControlFreqOverrides the Frequency property. Value is in Hz (ControlFreq), clamped to 20 Hz through Nyquist. Smoothed - safe for LFO or envelope-driven filter sweeps.
Q ModControlNormOverrides the Q property. 0.0 maps to Q 0.1, 1.0 maps to Q 20.0 (linear scaling). Modulating Q with an envelope creates wah-like effects.

Outputs:

PortTypeNotes
Audio OutAudioFiltered stereo audio.

Chorus (Chorus)

Multi-voice chorus effect with LFO modulation

let node = Chorus.add("my_chorus");

Multi-voice chorus with LFO-modulated delay lines. Thickens and widens the input by mixing it with detuned, time-varying copies.

Each voice has its own sine LFO with a phase offset evenly distributed across the cycle and a rate that increases by 10% per voice (voice 0 = base rate, voice 1 = 1.1x, etc.). Base delay also staggers by 3 ms per voice. The output is the average of all voices mixed with the dry signal. No feedback path, so the effect stays clean. RateMod CV uses an exponential 0.1..10 Hz mapping; DepthMod maps linearly to 0..20 ms; both replace the property value when connected.

Properties:

PropertyMethodTypeDefaultRange
Voicesnum_voices()Int31..8
Delaybase_delay()Float255..100
Depthdepth()Float30..20
Raterate()Float0.50.1..10
Mixmix()Float0.40..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
InputAudioStereo audio to chorus. Outputs silence when disconnected.
Rate ModControlNormControlNorm 0..1 mapped exponentially to 0.1..10 Hz, replacing the Rate property value when connected.
Depth ModControlNormControlNorm 0..1 mapped linearly to 0..20 ms depth, replacing the Depth property value when connected.
Mix ModControlNormControlNorm 0..1 mapped directly to wet/dry mix, replacing the property value when connected.

Outputs:

PortTypeNotes
OutputAudioStereo output: dry * (1 - mix) + chorus_average * mix, scaled by OutputGain.

Comb Filter (CombFilter)

Short delay with feedback for metallic resonances, flanging, and bell tones

let node = CombFilter.add("my_combfilter");

Comb filter with feedback, feedforward, and combined modes. A short tuned delay line that reinforces harmonics of its fundamental frequency, producing metallic resonances, bell tones, and Karplus-Strong-style plucks.

True stereo with independent delay buffers per channel. The delay line uses linear interpolation for fractional sample lengths. Frequency, feedback, and mix are all smoothed to prevent clicks.

Frequency Mod accepts both ControlFreq (direct Hz) and V/Oct inputs. V/Oct is relative to the Frequency property (0 = unison, +1 = octave up). If both types are connected, V/Oct takes priority.

Feedback Mod overrides the Feedback property. ControlNorm 0.0-1.0 is scaled to 0.0-0.99.

Damping places a one-pole lowpass in the feedback path. Higher values darken the decay - simulates string damping for physical modeling. Only affects Feedback and Both modes.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..10000
Feedbackfeedback()Float0.70..0.99
Mixmix()Float0.50..1
Modemode()Enumenum(0)Feedback, Feedforward, Both
Dampingdamping()Float00..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio input to the comb filter.
Frequency ModControlFreq, VOctOverrides comb frequency. Accepts ControlFreq (direct Hz) or V/Oct (relative to Frequency property, +1 = octave up). V/Oct takes priority when both are connected.
Feedback ModControlNormOverrides the Feedback property. ControlNorm 0.0-1.0 is scaled to feedback 0.0-0.99.

Outputs:

PortTypeNotes
Audio OutAudioFiltered stereo audio output.

Compressor (Compressor)

Dynamic range compressor with optional sidechain

let node = Compressor.add("my_compressor");

Dynamic range compressor with stereo-linked detection. Reduces the volume of signals that exceed the threshold, taming peaks and adding punch.

When the Sidechain input is connected, compression is keyed from that signal (converted to mono) instead of the main audio. The Sidechain takes full priority - there is no blend between internal and external detection. Use this for ducking (kick→bass) and pumping effects.

Threshold Mod overrides the Threshold property when connected. The CV is scaled linearly: 0.0 maps to -60 dB, 1.0 maps to 0 dB. The override is smoothed to prevent clicks.

GR Out reports the maximum gain reduction across L/R channels, normalized so 60 dB of reduction reads as 1.0.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold_db()Float-20-60..0
Ratioratio()Float41..20
Attackattack_ms()Float100.1..100
Releaserelease_ms()Float10010..1000
Kneeknee_db()Float00..12
Makeup Gainmakeup_gain_db()Float00..24
Auto Makeupauto_makeup()Boolfalse0..1

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Audio signal to compress.
SidechainAudioExternal sidechain signal. When connected, the compressor detects level from this signal (summed to mono) instead of the main audio input. Typical use: feed a kick drum here to duck a bassline.
Threshold ModControlNormOverrides the Threshold property. 0.0 maps to -60 dB, 1.0 maps to 0 dB (linear scaling). Smoothed to prevent clicks.

Outputs:

PortTypeNotes
Audio OutAudioCompressed audio output.
GR OutControlNormMaximum gain reduction across L/R channels. 0.0 = no reduction, 1.0 = 60 dB of reduction. Useful for driving meters or modulating other parameters.

DeClicker (DeClicker)

Active click and pop removal via derivative detection and interpolation repair

let node = DeClicker.add("my_declicker");

Active click and pop removal via derivative-based detection and interpolation repair.

Incoming audio is delayed by Lookahead samples through a ring buffer. First- and second-order derivatives are computed per sample; spikes exceeding the Threshold are marked as damaged. If a consecutive damage run exceeds the Sensitivity duration cutoff (Gentle=2, Normal=4, Aggressive=8 samples), it is classified as a musical transient and left untouched. Damaged regions within the cutoff are repaired using Hermite or linear interpolation from the surrounding undamaged context. The Monitor output carries only the removed material (original minus repaired) for audible verification. The Gate output pulses high whenever clicks are detected in a buffer.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold()Float0.10.001..1
Sensitivitysensitivity()Enumenum(1)Gentle, Normal, Aggressive
Lookaheadlookahead()Int328..128
Max Windowmax_window()Int81..32
Moderepair_mode()Enumenum(0)Hermite, Linear

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to process. Required; produces silence when disconnected. Each channel has independent detection and repair state.

Outputs:

PortTypeNotes
AudioAudioRepaired stereo audio, delayed by Lookahead samples. Outputs silence during the initial priming period.
MonitorAudioDifference signal (original minus repaired): only the removed click material. Useful for monitoring what the algorithm is cutting.
GateGateGate high while clicks are detected in the current buffer, low otherwise. Fires edge events, not per-click pulses.

Delay (Delay)

Audio delay with optional time modulation

let node = Delay.add("my_delay");

Stereo delay line with feedback and wet/dry mix. Creates echoes and repeats of the input signal.

Feedback feeds the delayed output back into the delay buffer (input + delayed * feedback), producing decaying repeats. The range is capped at 99% to prevent runaway oscillation, but values above ~90% sustain almost indefinitely. Delay time changes are smoothed over 256 samples to avoid pitch glitches from read-head jumps; connect a slow CV source to the DelayTimeMod port for chorus and vibrato effects. When the DelayTimeMod CV is connected it replaces the property value directly (in seconds), while FeedbackMod and MixMod scale their respective ControlNorm 0..1 ranges into the parameter range.

Properties:

PropertyMethodTypeDefaultRange
Delay Timedelay_time()Float0.50.001..2
Feedbackfeedback()Float00..0.99
Mixmix()Float10..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to delay. Produces silence when disconnected.
Delay Time ModControlDelay time in seconds (Control, not ControlNorm). When connected, replaces the DelayTime property value directly.
FeedbackControlNormControlNorm 0..1 scaled to 0..99% feedback, replacing the property value when connected.
MixControlNormControlNorm 0..1 mapped directly to wet/dry mix, replacing the property value when connected.

Outputs:

PortTypeNotes
Audio OutAudioStereo output: dry * (1 - mix) + delayed * mix, scaled by OutputGain.

Distortion (Distortion)

Waveshaping and harmonic distortion with multiple types

let node = Distortion.add("my_distortion");

Waveshaping distortion with seven selectable algorithms. Drive pushes the signal into saturation; tone and mix shape the final character.

The signal is multiplied by Drive before entering the selected waveshaper. Algorithm differences: HardClip clips at +/-1.0 (harsh, buzzy); SoftClip and Tanh both use soft_clip (smooth saturation); Tube uses asymmetric tube simulation; Fuzz doubles the drive into soft_clip for aggressive saturation; Wavefold folds the signal back at +/-1.0 (adds dense upper harmonics); Bitcrush quantizes to the Bits setting (lo-fi, stepped). The Bits property only affects the Bitcrush algorithm. DriveMod CV maps 0..1 to 1..20x drive; MixMod maps 0..1 directly to wet/dry.

Properties:

PropertyMethodTypeDefaultRange
Typedistortion_type()Enumenum(2)HardClip, SoftClip, Tanh, Tube, Fuzz, Wavefold, Bitcrush
Drivedrive()Float21..20
Mixmix()Float10..1
Tonetone()Float50001000..10000
Output Gainoutput_gain()Float10..4
DC Blockingdc_blocking()Booltrue
Bitsbits()Int81..16

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to distort. Required; produces silence when disconnected.
Drive ModControlNormControlNorm 0..1 mapped linearly to 1..20x drive, replacing the property value when connected.
Mix ModControlNormControlNorm 0..1 mapped directly to wet/dry mix, replacing the property value when connected.

Outputs:

PortTypeNotes
Audio OutAudioStereo output: clean * (1 - mix) + distorted * mix, then scaled by OutputGain. Per-channel processing.

Envelope (Envelope)

ADSR envelope generator

let node = Envelope.add("my_envelope");

General-purpose gate-triggered envelope generator. Outputs the envelope level as a stereo audio signal for use as a VCA control or any parameter modulation source.

The envelope shape is drawn via keyframes and tangents, with an optional hold point that sustains the level while the gate is held. Gate rising edge triggers attack from the start of the curve; falling edge triggers release from the hold point onward. The envelope advances per sample for smooth output.

Properties:

PropertyMethodTypeDefaultRange
Shapeshape()Envelope[envelope]

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Rising edge triggers attack from curve start; falling edge triggers release from the hold point.

Outputs:

PortTypeNotes
Env OutAudioEnvelope level as mono-to-stereo audio. Multiply with an audio signal for VCA-style amplitude shaping.

Filter (Filter)

One-pole lowpass filter with cutoff modulation

let node = Filter.add("my_filter");

Simple one-pole lowpass filter. Smoothly attenuates frequencies above the cutoff with a gentle 6 dB/octave slope.

True stereo with independent filter state per channel. The cutoff is smoothed to prevent clicks during modulation.

Cutoff Mod overrides the Cutoff property when connected (ControlFreq, value in Hz). The CV fully replaces the knob value - there is no additive modulation. When disconnected, the property value is used.

For steeper filtering or resonance control, use the Biquad Filter.

Properties:

PropertyMethodTypeDefaultRange
Cutoffcutoff()Float100020..20000

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to filter.
Cutoff ModControlFreqOverrides the Cutoff property. Value is in Hz (ControlFreq). Smoothed - safe for LFO-driven sweeps. When disconnected, the Cutoff property value is used.

Outputs:

PortTypeNotes
Audio OutAudioLowpass-filtered stereo audio output.

Flanger (Flanger)

Short modulated delay with feedback - classic flanger effect

let node = Flanger.add("my_flanger");

Classic flanger effect. A short delay modulated by a sine LFO and fed back into itself, producing a sweeping comb-filter tone.

The modulated delay time equals base_delay * (1 + LFO * depth), clamped to the 10 ms hardware maximum. Feedback feeds the delayed output back into the delay buffer (input + delayed * feedback). Negative feedback values invert the signal before feeding back, shifting the comb peaks to produce a hollower, more nasal character. No CV modulation inputs; use the property controls. No parameter smoothing, so abrupt changes to delay or rate may click.

Properties:

PropertyMethodTypeDefaultRange
Raterate()Float0.30.01..10
Depthdepth()Float0.70..1
Delaydelay()Float30.1..10
Feedbackfeedback()Float0.5-0.95..0.95
Mixmix()Float0.50..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to flange. Required; produces silence when disconnected.

Outputs:

PortTypeNotes
AudioAudioStereo output: dry * (1 - mix) + delayed * mix, scaled by OutputGain.

Granular (GranularProcessor)

Live granular effects processor with freeze and pitch control

let node = GranularProcessor.add("my_granularprocessor");

Live granular effects processor. Records audio into a circular buffer and spawns overlapping grains that read back from configurable positions with pitch shifting and stereo spread.

Grains are scheduled at the Density rate (Hz). Each grain reads from Position (0 = most recent, 1 = oldest) in the circular buffer, with Jitter randomizing position, size, and pitch per grain. Grains use linear interpolation for fractional read positions and a morphable window envelope (Texture: 0 = rectangular, 0.5 = Hann, 1.0 = narrow Gaussian). The Freeze gate stops buffer recording so grains read from a frozen snapshot; unfreezing resumes recording from where the write head left off. Active grains are averaged (not summed) when more than one is playing. CV inputs are additive offsets to the property values, not replacements. PitchMod is ControlBipolar and scales by the full +/-24 semitone range.

Properties:

PropertyMethodTypeDefaultRange
Bufferbuffer_length()Float41..8
Densitydensity()Float100.5..100
Sizesize()Float505..500
Positionposition()Float00..1
Pitchpitch()Float0-24..24
Spreadspread()Float0.30..1
Jitterjitter()Float0.10..1
Max Grainsmax_grains()Int161..64
Texturetexture()Float0.50..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Live stereo audio, continuously recorded into the circular buffer (unless frozen). Required; produces silence when disconnected.
FreezeGaterequired; Rising edge freezes buffer recording; falling edge resumes. Grains continue reading from the frozen buffer while frozen.
Position ModControlNormrequired; ControlNorm 0..1 added to the Position property value. The sum is clamped to 0..1.
Density ModControlNormrequired; ControlNorm 0..1 scaled by the full density range (0.5..100 Hz) and added to the property value.
Size ModControlNormrequired; ControlNorm 0..1 scaled by the full size range (5..500 ms) and added to the property value.
Pitch ModControlBipolarrequired; ControlBipolar -1..1 scaled by the full pitch range (+/-24 semitones) and added to the property value.

Outputs:

PortTypeNotes
Audio OutAudioAveraged grain output, scaled by OutputGain. No dry signal is mixed in; use an external mixer for dry/wet blending.

LFO (LFO)

Low-frequency oscillator for modulation

let node = LFO.add("my_lfo");

Low-frequency oscillator for cyclic modulation of any parameter. Produces synchronized outputs in multiple formats: audio, normalized, bipolar, and gate.

FrequencyMod overrides the Frequency knob entirely when connected (it does not add to it). DepthMod overrides the Depth knob's smoother target when connected. All outputs are scaled by the effective depth. The Gate output goes high on the positive half of the waveform cycle.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float50.01..20
Depthdepth()Float0.50..1
Waveformwaveform()Enumenum(0)Sine, Square, Sawtooth, Triangle

Inputs:

PortTypePropertiesNotes
FrequencyControlFreqOverrides the Frequency knob with an external signal in Hz. Uses the raw control value directly.
ResetGateRising edge resets phase to zero for tempo sync or retriggering.
Depth ModControlNormOverrides the Depth knob's smoother target. Smoothing still applies to avoid clicks.

Outputs:

PortTypeNotes
Audio OutAudioBipolar waveform as stereo audio, scaled by depth. Per-sample generation.
NormControlNormLast sample of the buffer remapped to 0.0-1.0, scaled by depth.
BipolarControlBipolarLast sample of the buffer as bipolar control, scaled by depth.
GateGateEdge-detected gate high when the depth-scaled waveform is positive.

Low-Pass Gate (LowPassGate)

Combined VCA + lowpass with vactrol-style decay - Buchla LPG

let node = LowPassGate.add("my_lowpassgate");

Combined VCA and lowpass filter with vactrol-style decay. The Buchla signature sound: strike it with a gate and it opens briefly, then closes with an organic, woody decay.

A gate rising edge snaps the internal vactrol level to 1.0. It then decays exponentially, with a sqrt curve applied to model the fast-open, slow-close photoresistor response. The CV Level input can also drive the vactrol; it takes the maximum of the current vactrol level and the CV value, so holding CV high keeps the gate open. VCA Amount controls how much the vactrol affects amplitude (0 = unity gain, 1 = full gating). LPF Amount controls cutoff sweep depth; the cutoff tracks the vactrol level on a log scale from 20 Hz to just below Nyquist. With both VCA and LPF at 1.0 the sound starts bright and loud, then dims and quiets together.

Properties:

PropertyMethodTypeDefaultRange
Decaydecay()Float20010..2000
Resonanceresonance()Float00..0.95
VCAvca_amount()Float0.50..1
LPFlpf_amount()Float0.50..1

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to pass through the gate. Required; produces silence when disconnected.
GateGateGate signal. Each rising edge resets the vactrol level to 1.0, starting a fresh decay. Has no effect while the vactrol is already at 1.0.
CV LevelControlNormControlNorm 0..1 that holds the vactrol open. The vactrol level becomes max(decaying_level, cv), so holding CV high prevents the gate from closing.

Outputs:

PortTypeNotes
AudioAudioAudio shaped by the combined VCA gain and lowpass filter, both driven by the vactrol level.

Phaser (Phaser)

Multi-stage allpass sweep - classic phaser effect

let node = Phaser.add("my_phaser");

Multi-stage phaser effect. Chains allpass filters whose center frequency sweeps via an internal LFO, carving moving notches through the spectrum.

The LFO sweeps logarithmically between MinFreq and MaxFreq, scaled by Depth. The allpass chain output feeds back into its own input (input + chain_output * feedback) to deepen the notches. More stages produce more notches; the step size is 2 so the count is always even. RateMod CV scales the base rate multiplicatively: effective_rate = rate * (1 + cv * 4), so at CV=1.0 the rate is 5x faster.

Properties:

PropertyMethodTypeDefaultRange
Raterate()Float0.50.01..10
Depthdepth()Float0.80..1
Feedbackfeedback()Float0.50..0.95
Stagesstages()Int42..12
Mixmix()Float0.50..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to phase. Required; produces silence when disconnected.
Rate ModControlNormControlNorm 0..1 that multiplies the base rate: effective = rate * (1 + cv * 4). At cv=0 uses the base rate; at cv=1 the rate is 5x faster.

Outputs:

PortTypeNotes
AudioAudioStereo output: dry * (1 - mix) + allpass_chain * mix, scaled by OutputGain.

Pitch Envelope (PitchEnvelope)

Gate-triggered frequency sweep for percussive pitch control

let node = PitchEnvelope.add("my_pitchenvelope");

Gate-triggered frequency sweep for percussive pitch effects. Outputs ControlFreq directly, eliminating the need for an Envelope into a frequency mapper chain.

The drawn curve maps 0.0 to StartFreq and 1.0 to EndFreq using log-space interpolation for perceptually even pitch movement. The default curve fires a fast attack to EndFreq then decays back to StartFreq with no hold point (fire-and-forget). The envelope is sampled once per buffer, not per sample.

Properties:

PropertyMethodTypeDefaultRange
Start Freqstart_freq()Float5520..20000
End Freqend_freq()Float30020..20000
Shapeshape()Envelope[envelope]

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Rising edge fires the pitch sweep from curve start. Falling edge triggers release if a hold point is set.

Outputs:

PortTypeNotes
Freq OutControlFreqFrequency in Hz, log-interpolated between StartFreq and EndFreq based on the envelope curve value.

Reverb (Reverb)

Room simulation reverb with Schroeder algorithm

let node = Reverb.add("my_reverb");

Schroeder reverb with true stereo output. Simulates room reflections from tight rooms to vast halls.

The input is downmixed to mono before entering the reverb engine. Parallel damped comb filters produce late reflections, then series allpass filters add diffusion. Left and right channels use decorrelated delay lines for stereo imaging, controlled by the Width parameter. Pre-delay inserts a fixed gap between the dry sound and the onset of the reverb tail; changing pre-delay or room size rebuilds the internal filter network (may click during live adjustment). CV inputs for room size, damping, and mix all replace the property value directly via smoothers.

Properties:

PropertyMethodTypeDefaultRange
Room Sizeroom_size()Float0.50..1
Dampingdamping()Float0.50..1
Pre-Delaypre_delay_ms()Float00..100
Diffusiondiffusion()Float0.50..1
Widthwidth()Float10..1
Mixmix()Float0.30..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
InputAudioStereo audio input. Both channels are summed to mono before entering the reverb engine. Outputs silence when disconnected (the reverb tail still decays naturally).
Mix ModControlNormControlNorm 0..1 mapped directly to wet/dry mix, replacing the property value when connected.
Room Size ModControlNormControlNorm 0..1 mapped directly to room size, replacing the property value when connected. Smoothed, does not trigger filter rebuild.
Damping ModControlNormControlNorm 0..1 mapped directly to damping, replacing the property value when connected.

Outputs:

PortTypeNotes
OutputAudioStereo reverb output with decorrelated L/R channels, mixed with the dry input per the Mix setting.

Ring Modulator (RingModulator)

Carrier × modulator ring modulation with dry/wet mix

let node = RingModulator.add("my_ringmodulator");

Ring modulator -- multiplies a carrier and modulator signal together, producing sum and difference frequencies for inharmonic, bell-like, or robotic timbres.

Both Carrier and Modulator audio inputs are required; disconnecting either silences the output. The wet signal is carrier * modulator (per-channel); the Mix control crossfades between the dry carrier and the ring-modulated result. Unlike SignalMath's Multiply mode, this node provides explicit carrier/modulator labeling and a dedicated dry/wet mix.

Properties:

PropertyMethodTypeDefaultRange
Mixmix()Float10..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
CarrierAudiorequired; Primary audio signal. Used as the "dry" signal for the Mix crossfade. Required; silences output when disconnected.
ModulatorAudiorequired; Audio signal multiplied with the carrier per-channel. Required; silences output when disconnected.
Mix ModControlNormControlNorm 0..1 mapped directly to wet/dry mix, replacing the property value when connected. Clamped to 0..1.

Outputs:

PortTypeNotes
AudioAudioStereo output: carrier * (1 - mix) + (carrier * modulator) * mix, scaled by OutputGain.

Sample Rate Reducer (SampleRateReducer)

Lo-fi aliasing effect - reduces effective sample rate

let node = SampleRateReducer.add("my_sampleratereducer");

Lo-fi aliasing effect that reduces the effective sample rate by holding each input sample for multiple output cycles.

Uses a phase accumulator: the input is sampled only when the phase wraps past 1.0, then that value is held until the next wrap. This creates staircase artifacts and harsh aliasing distinct from bitcrushing. The RateMod CV scales linearly from 100 Hz (at cv=0) to the configured target rate (at cv=1), replacing the property value when connected.

Properties:

PropertyMethodTypeDefaultRange
Raterate()Float8000100..44100

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to decimate. Required; produces silence when disconnected.
Rate ModControlNormControlNorm 0..1 mapped linearly from 100 Hz (at 0) to the configured target rate (at 1). Replaces the property value when connected.

Outputs:

PortTypeNotes
AudioAudioStereo output with sample-and-hold decimation applied.

Transient Shaper (TransientShaper)

Independent attack and sustain gain reshaping

let node = TransientShaper.add("my_transientshaper");

Reshapes the attack and sustain portions of a signal independently. Boost the attack to add punch, or pull it back to soften transients.

Uses dual envelope followers per channel: a fast follower (~1 ms attack) that catches transients, and a slow follower (4x the Speed setting) that tracks the sustain level. The difference (fast - slow) isolates the transient component. Each sample's gain is a weighted blend of the Attack and Sustain gains based on the transient ratio. Both gain controls are in dB and converted to linear internally. No CV modulation inputs. Speed affects both the fast follower's release and the slow follower's time constant, so increasing it widens the transient detection window.

Properties:

PropertyMethodTypeDefaultRange
Attackattack()Float0-12..12
Sustainsustain()Float0-12..12
Speedspeed()Float205..100
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio to reshape. Required; produces silence when disconnected. Each channel is processed independently with its own envelope followers.

Outputs:

PortTypeNotes
AudioAudioStereo audio with reshaped transient and sustain gain, scaled by OutputGain.

Vocoder (Vocoder)

Channel vocoder - spectral envelope transfer from modulator to carrier

let node = Vocoder.add("my_vocoder");

Channel vocoder that transfers the spectral envelope of a modulator onto a carrier signal, producing the iconic robot-voice effect.

The modulator (voice, drums) is split into frequency bands; an envelope follower on each band extracts how loud that frequency region is. Those envelopes are applied to the same bands of the carrier (synth, noise), so the carrier "speaks" with the modulator's tonal shape.

Both inputs are required. Without a modulator the output is silence because the envelope followers produce zero. A carrier alone produces nothing - the modulator's envelope gates it.

Sibilance detection measures the energy ratio of the top quarter of bands to the total. When high-frequency energy dominates, unfiltered modulator audio is blended into the output, preserving consonant sounds like "s", "t", and "sh" that the band filters would otherwise smear.

The Freq Tilt curve applies per-band gain using a log-frequency axis (20 Hz to 20 kHz). Each band's center frequency is mapped onto this curve. A rising curve brightens the output; a falling curve warms it.

Properties:

PropertyMethodTypeDefaultRange
Bandsbands()Int164..32
Low Freqlow_freq()Float8020..500
High Freqhigh_freq()Float80002000..16000
Attackattack()Float50.1..50
Releaserelease()Float201..200
Qq()Float51..20
Noise Gatenoise_gate()Float00..1
Sibilancesibilance()Float00..1
Freq Tilttilt()Curve[curve]
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
CarrierAudiorequired; Harmonically rich signal (sawtooth, noise, chord) whose spectral content is shaped by the modulator. This is what you hear.
ModulatorAudiorequired; Signal whose spectral envelope controls the carrier (voice, drums). Without a modulator the output is silence.

Outputs:

PortTypeNotes
AudioAudioCarrier audio shaped by the modulator's spectral envelope, scaled by Freq Tilt and Output Gain.

fBm Noise (FbmNoise)

Fractal Brownian Motion noise - organic modulation source

let node = FbmNoise.add("my_fbmnoise");

Fractal Brownian Motion noise source for organic, evolving modulation. Sums multiple octaves of smooth value noise to produce natural-feeling movement.

Audio and control outputs are the raw fBm value scaled by Amplitude. RateMod maps 0.0-1.0 to a 1x-4x rate multiplier (exponential via 2^(mod*2)); disconnected defaults to 1x. Gate rising edge jumps to a new region of the noise field (each retrigger lands at a different position). The Gate output goes high on the positive half of the noise signal.

Properties:

PropertyMethodTypeDefaultRange
Raterate()Float10.01..100
Octavesoctaves()Int41..8
Persistencepersistence()Float0.50..1
Lacunaritylacunarity()Float21.5..3
Amplitudeamplitude()Float10..1
Seedseed()Int420..9999

Inputs:

PortTypePropertiesNotes
GateGateRising edge jumps to a new region of the noise field. Each retrigger lands at a different position, so rapid retriggering does not freeze the output.
Rate ModControlNormMultiplies the Rate knob via 2^(mod*2). At 0.0 = 1x, at 1.0 = 4x. Disconnected defaults to 1x.

Outputs:

PortTypeNotes
Audio OutAudioNoise as mono-to-stereo audio, bipolar and scaled by Amplitude. Per-sample generation.
NormControlNormLast sample of the buffer remapped from bipolar to 0.0-1.0.
BipolarControlBipolarLast sample of the buffer clamped to -1.0 to 1.0.
ControlControlRaw noise value without clamping, for custom downstream scaling.
GateGateEdge-detected gate high when the amplitude-scaled noise value is positive.

Interface

Bipolar Knob (BipolarKnob)

Constant ControlBipolar (-1..+1) source - dial a value and patch it

let node = BipolarKnob.add("my_bipolarknob");

Bipolar knob that outputs a constant value in the -1..+1 range.

The value is set via the on-node slider, a property change, or a ControlKnobCommand from the UI. The output is written every process() call as a ControlBipolar. A state snapshot is sent back to the UI each frame for the custom renderer.

Properties:

PropertyMethodTypeDefaultRange
Valuevalue()Float0-1..1

Outputs:

PortTypeNotes
OutputControlBipolarConstant bipolar control signal (-1.0–+1.0).

Control Knob (ControlKnob)

Constant ControlNorm (0..1) source - dial a value and patch it

let node = ControlKnob.add("my_controlknob");

Unipolar knob that outputs a constant value in the 0..1 range.

The value is set via the on-node slider, a property change, or a ControlKnobCommand from the UI. The output is written every process() call as a ControlNorm. A state snapshot is sent back to the UI each frame for the custom renderer.

Properties:

PropertyMethodTypeDefaultRange
Valuevalue()Float0.50..1

Outputs:

PortTypeNotes
OutputControlNormConstant unipolar control signal (0.0–1.0).

Control Panel (ControlPanel)

Configurable bank of labeled control and gate outputs with per-channel type selection

let node = ControlPanel.add("my_controlpanel");

Configurable bank of labeled control and gate outputs. Each channel independently selects its type via an inline dropdown on the node face.

Uses custom topology -- output port count and types are dynamic. Control-type channels produce one ControlNorm, ControlBipolar, or Control port. Gate-type channels produce a Gate + Velocity (ControlNorm) port pair. Changing a channel's kind or adjusting the channel count triggers a port remap that the editor uses to rewire existing connections. Gate edge events are emitted only on state transitions (toggled on/off via SetToggle or pad press/release via SetGate). Always processes so initial state reaches the UI even without downstream connections.

Properties:

PropertyMethodTypeDefaultRange
Channelschannels()Int41..16

Control Source (ControlSource)

Constant Control (unbounded) source - for tempo, delay time, or any raw value

let node = ControlSource.add("my_controlsource");

Unbounded control source that outputs a raw floating-point value.

Unlike the normalized knobs, this carries real-world units (BPM, milliseconds, semitones, etc.). The value is not clamped on set; ControlKnobCommand writes the raw float directly. The output is written every process() call as a Control value. Min and max config fields exist for UI display hints but do not constrain the output.

Properties:

PropertyMethodTypeDefaultRange
Valuevalue()Float0-10000..10000

Outputs:

PortTypeNotes
OutputControlUnbounded control signal carrying the raw value.

Gate Button (GateButton)

UI-controlled gate source with momentary and toggle modes. Outputs velocity on a separate control port.

let node = GateButton.add("my_gatebutton");

Manual gate source with momentary and toggle modes. Click or hold the button to fire a gate signal; velocity is output on a separate control port.

Two input paths: UI commands (SetGate) set the gate directly with velocity 1.0, while MIDI-style property writes (Gate property) follow a toggle state machine. On a rising edge, if the value >= ToggleThreshold the gate latches on; below threshold it acts as momentary (gate follows press/release). A second press while latched marks the gate for unlatch on release. The Velocity output holds the press value while the gate is high and resets to 0.0 on gate-off. Gate edge events are emitted only on state transitions.

Properties:

PropertyMethodTypeDefaultRange
Gategate()Float00..1
Toggle Veltoggle_threshold()Float0.50..1

Outputs:

PortTypeNotes
Gate OutGateGate on/off edge events. High while the button is held (momentary) or latched (toggle). Events are emitted only on state transitions, not every frame.
VelocityControlNormVelocity of the press that opened the gate, held at the trigger value while high. Resets to 0.0 on gate-off. UI commands (SetGate) always produce velocity 1.0.

Keyboard (Keyboard)

Interactive MIDI keyboard with monitoring and visualization

let node = Keyboard.add("my_keyboard");

Interactive 88-key MIDI keyboard that generates and monitors MIDI note events with optional visual effects.

Operates in three modes depending on connections: generator (no MIDI In -- UI clicks produce notes), monitor (MIDI In connected -- input events are visualized and passed through), or hybrid (both). In Hold mode, clicking a key latches it on; clicking again toggles it off. Latched keys persist across save/load via the held_notes config. When Hold is active and MIDI In is connected, incoming note-offs for UI-latched keys are suppressed in both the visualization and the MIDI output. Disabling Hold clears all latched notes immediately. Visual effects (particles, fire, etc.) are selected per-node and reported to the UI each frame alongside active key state.

Properties:

PropertyMethodTypeDefaultRange
Visual Effectvisual_effect()Enumenum(3)None, Firework, Bottle Rocket, Starburst, Note Spark, Fire, Laser, Laser Beam, Piano Beam
Holdhold()Boolfalse
Note Labelsshow_note_labels()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiIncoming MIDI to monitor. Notes are visualized on the keyboard and merged into the output alongside UI-generated events. When Hold is active, note-offs for UI-latched keys are filtered out.

Outputs:

PortTypeNotes
MIDI OutMidiMerged MIDI output: pass-through of input events (with Hold filtering applied) plus UI-generated note on/off events.

Patch Input (PatchInput)

Source node inside a patch - data injected by PatchInstance

let node = PatchInput.add("my_patchinput");

Entry point for signals coming into a patch. Lives inside the patch's inner graph and exposes one output per port defined on the patch interface.

Has no audio-thread inputs of its own. Before each inner-graph pull, PatchInstanceNode calls inject() to stage port data from the parent graph. process() then copies the staged data to outputs. Uses custom topology -- output count and types are derived from the ports config, which can be mutated at runtime via PatchInputCommand (add, remove, rename, reorder ports).

Patch Instance (PatchInstance)

Instantiated patch - contains a nested subgraph

let node = PatchInstance.add("my_patchinstance");

A single node in the parent graph that encapsulates an entire subgraph, making the patch behave like one composite node.

Each process() call runs a four-phase cycle: (1) collect parent input port data and inject it into the inner PatchInputNode, (2) advance the inner engine's time via process_subgraph, (3) pull the inner PatchOutputNode to drive inner-graph processing, (4) extract captured output data and copy it to this node's outputs. Uses custom topology -- input and output port counts and types mirror the PatchInterface definition. The inner engine's default AudioSink is removed on setup since PatchOutput serves as the pull target. If the inner engine, PatchInput ID, or PatchOutput ID is missing, process() returns immediately with no output.

Patch Output (PatchOutput)

Sink node inside a patch - data extracted by PatchInstance

let node = PatchOutput.add("my_patchoutput");

Exit point for signals leaving a patch. Lives inside the patch's inner graph and exposes one input per port defined on the patch interface.

process() captures all input port data into a staging buffer. After the inner-graph pull, PatchInstanceNode calls extract() to retrieve the captured data and copy it to the parent graph's outputs. The Sink output port serves as the pull target for the inner graph engine (same pattern as AudioSink). Uses custom topology -- input count and types are derived from the ports config, mutated at runtime via PatchOutputCommand.

Outputs:

PortTypeNotes
SinkSinkPull target for the inner graph engine. The inner engine pulls this node to drive processing of all upstream nodes in the patch.

MIDI

ABC File Loader (AbcFileLoader)

Loads ABC notation files and converts to sequencer configuration. Supports file paths or raw ABC text.

let node = AbcFileLoader.add("my_abcfileloader");

Loads ABC notation and produces a MidiSequencer on its output for downstream playback.

Accepts an AbcSource (file path or raw text), a ConstantValue file path, or a full AbcFileLoaderConfig via the Config input. When no Config input is connected, falls back to the embedded source property. Parsing only runs when the config changes (detected via a string key). The Sequencer Out streams the cached MidiSequencer every frame. Timing Out carries BPM and time signature extracted from the ABC notation.

Inputs:

PortTypePropertiesNotes
Config InData(Unknown)Accepts AbcSource, ConstantValue::FilePath, or full AbcFileLoaderConfig. Overrides the embedded source property when connected.

Outputs:

PortTypeNotes
Sequencer OutData(Sequence)Cached MidiSequencer data, streamed every frame. Connect to a Sequencer or Sequencer Editor.
TimingData(Timing)BPM and time signature extracted from the ABC notation. Defaults to 4/4 if not specified in the source.

Arpeggiator (Arpeggiator)

Converts held MIDI notes into arpeggiated patterns

let node = Arpeggiator.add("my_arpeggiator");

Turns held MIDI chords into rhythmic arpeggiated patterns using an internal sample-accurate clock.

Feed it notes and it cycles through them at a configurable rate with selectable direction (up, down, up-down, random), octave range, gate length, and swing. Uses NoteOn velocity=0 as NoteOff. The internal clock derives step timing from the Rate property; swing delays every other step by a fraction of the step duration. Gate length determines when each note-off fires within the step. The Reset input resets the arpeggiator to the first note and kills any currently sounding note. With Latch enabled, notes remain in the pattern even after key release -- new notes replace the latched set. All output MIDI is on channel 1.

Properties:

PropertyMethodTypeDefaultRange
Raterate()Float80.1..20
Patternpattern()Enumenum(0)Up, Down, Up-Down, Random, As Played, Chord
Octavesoctaves()Int11..4
Gate Lengthgate_length()Float0.750.1..0.95
Swingswing()Float00..0.75
Latchlatch()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Incoming MIDI notes to arpeggiate.
ResetGateRising edge resets the pattern to the first note, zeroes the accumulator, and kills any sounding note.

Outputs:

PortTypeNotes
MIDI OutMidiArpeggiated MIDI note-on/note-off events on channel 1. Velocity is the most recent input velocity.
Gate OutGateHigh for the gate-length fraction of each step, synchronized with MIDI note-on/off.

Arranger (Arranger)

Song arrangement with per-track ControlNorm outputs for enabling/controlling downstream nodes

let node = Arranger.add("my_arranger");

Song-level arrangement player that outputs per-track level controls synchronized to the graph transport.

Receives an Arrangement via Config In and advances a tick-based playhead. Each arrangement track maps to an unbounded ControlNorm output: the value is the region's level (0.0--1.0) when the playhead is inside a region, otherwise 0.0. Muted, disabled, or non-soloed (when any track is soloed) tracks output 0.0. The Timing input overrides BPM; tempo changes reset the sample accumulator. Enabled gate (disconnected = enabled) forces all outputs to 0.0 when low. Transport seek events resync the tick position. Loop wraps to the start when the arrangement ends. The End gate pulses on loop or completion. Hot-swapping the Config input preserves playhead position and state. Tracks property sets a floor on output count; it also grows to match the arrangement's track count.

Properties:

PropertyMethodTypeDefaultRange
Trackstracks()Int41..64
Looploop()Booltrue
Content BPMcontent_bpm()Float0

Inputs:

PortTypePropertiesNotes
RestartGateRising edge restarts the arrangement from tick 0. Processed even when disabled.
TimingData(Timing)Overrides BPM and time signature from the transport. Tempo changes reset the sample accumulator.
Config InData(Arrangement)Arrangement data from an Arranger Editor. Hot-swapped each frame: tracks and timing update but playhead is preserved.
EnabledGateGates playback. Disconnected = enabled. When low, all per-track outputs are forced to 0.0 and tick advancement stops.

Outputs:

PortTypeNotes
TempoControlEffective BPM after Timing port override or transport fallback. Output even when disabled.
BarControlCurrent bar number (0-based) as a raw control value. Derived from current_beat / beats_per_bar.
EndGateSingle-sample gate pulse on arrangement end or loop wrap.
TrackControlNormunbounded; Region level (0.0--1.0) when the playhead is inside a region, 0.0 otherwise. Muted/disabled/non-soloed tracks output 0.0.

Arranger Editor (ArrangerEditor)

Visual arrangement editor. Click to open arranger panel.

let node = ArrangerEditor.add("my_arrangereditor");

Visual editor for song-level arrangements.

Holds the authoritative Arrangement data (tracks, regions, tempo, time signature) and outputs it via Data port to an Arranger node each frame. The UI sends incremental ArrangerCommand edits (add/remove/move regions, track management, BPM, time signature, loop) through the message bus. In-flight regions (being dragged) are tracked but do not block region output. The Update gate pulses whenever an edit is applied. Timing output carries BPM and time signature. The Import input accepts an external Arrangement for future import support.

Properties:

PropertyMethodTypeDefaultRange
Tempotempo()Float12020..300
Lengthlength_bars()Int161..256

Inputs:

PortTypePropertiesNotes
ImportData(Arrangement)External Arrangement data for future import support.

Outputs:

PortTypeNotes
ArrangementData(Arrangement)Full Arrangement data, output every frame. Connect to an Arranger node's Config In.
UpdateGateSingle-sample gate pulse after each ArrangerCommand edit is applied.
TimingData(Timing)BPM and time signature from the editor's properties. Connect to an Arranger's Timing input.

Chord Generator (ChordGenerator)

Generates chords from single MIDI notes

let node = ChordGenerator.add("my_chordgenerator");

Harmonizer that turns single MIDI notes into full chords.

Each incoming note-on becomes the root of a chord built from the selected type (major, minor, seventh, etc.) with configurable voicing and inversions. On note-off, all chord tones for that root are released. Non-note MIDI messages pass through unchanged. Active chords are tracked per root note, so multiple simultaneous roots produce independent chords. Notes are clamped to 0--127 after transposition; inversions raise lower tones by an octave. Open voicing raises inner tones +12; Drop-2 lowers the second-from-top tone by 12. Third inversion only has an effect on seventh chords or larger.

Properties:

PropertyMethodTypeDefaultRange
Chord Typechord_type()Enumenum(0)Major, Minor, Diminished, Augmented, Sus2, Sus4, Major7, Minor7, Dominant7, Diminished7, HalfDiminished7, MinorMajor7, Augmented7, Major6, Minor6, Major9, Minor9, Dominant9
Voicingvoicing()Int00..2
Inversioninversion()Int00..3

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Single-note MIDI input - each note becomes the chord root.

Outputs:

PortTypeNotes
MIDI OutMidiMultiple simultaneous note-ons per input note. Non-note messages pass through unchanged.

Chord Progression (ChordProgressionGenerator)

Per-layer curve-driven chord progression generator with polymetric support

let node = ChordProgressionGenerator.add("my_chordprogressiongenerator");

Generates chord progressions with per-layer curves for tension, velocity, and style.

Each layer defines its own bar count and chords-per-bar, enabling polymetric progressions. Generation blends user-drawn curves with fBm noise (controlled by the Mix knob) to select chord degree, velocity, and voicing style per chord slot. Generation runs on a background thread -- property changes queue a request (when auto-regen is enabled) and only the latest request is processed. Connect Sequencer Out to a Sequencer Editor to import and edit the result. The Loaded gate pulses once after each completed generation triggered by the Regenerate command. The Timing input overrides BPM and time signature from the transport.

Properties:

PropertyMethodTypeDefaultRange
Keykey()Int600..127
Scalescale()Enumenum(1)Chromatic, Major, Minor, HarmonicMinor, MelodicMinor, Dorian, Phrygian, Lydian, Mixolydian, Aeolian, Locrian, MajorPentatonic, MinorPentatonic, Blues, WholeTone, Diminished
Extensionschord_extensions()Enumenum(0)Triads, Sevenths, Extended
Mixmix()Float00..1
Complexitycomplexity()Int41..8
Persistencepersistence()Float0.50..1
Raterate()Float10.1..10
Seedseed()Int00..9999

Inputs:

PortTypePropertiesNotes
TimingData(Timing)Overrides BPM and time signature from the transport. When disconnected, values come from the graph transport.

Outputs:

PortTypeNotes
Sequencer OutData(Sequence)Generated MidiSequencer data, streamed every frame. Connect to a Sequencer Editor's Import port to edit.
LoadedGateSingle-frame gate pulse emitted when a Regenerate command completes (not on auto-regen property changes).

Generative Melody (GenerativeMelody)

Marbles-style clocked random note/gate generator with scale quantization

let node = GenerativeMelody.add("my_generativemelody");

Clocked random note and gate generator with scale quantization, inspired by Mutable Instruments Marbles.

Each rising edge on the Clock input generates a new pitch from a bell-curve distribution shaped by Bias (center) and Spread (width), quantized to the selected scale. Gate density controls the probability that a clock step produces a note; gate length sets the duration as a fraction of the measured clock period. Jitter adds random timing offset to gate events. The Lock parameter controls sequence recall: at 0.0 every step is fully random; at 1.0 the cached sequence replays deterministically. Intermediate values probabilistically replace cached steps. The cache size equals the Steps property. Bias, Spread, and Density can be modulated via CV inputs that override the corresponding properties. VOct output is constant across the buffer (updated on each clock step). The Tuning port overrides 12-EDO divisions and applies a V/Oct offset.

Properties:

PropertyMethodTypeDefaultRange
Biasbias()Float0.50..1
Spreadspread()Float0.50..1
Stepssteps()Int82..32
Scalescale()Enumenum(1)Chromatic, Major, Minor, HarmonicMinor, MelodicMinor, Dorian, Phrygian, Lydian, Mixolydian, Aeolian, Locrian, MajorPentatonic, MinorPentatonic, Blues, WholeTone, Diminished
Rootroot()Int600..127
Octave Rangeoctave_range()Int21..5
Locklock()Float00..1
Gate Densitygate_density()Float0.50..1
Gate Lengthgate_length()Float0.50.1..1
Jitterjitter()Float00..1

Inputs:

PortTypePropertiesNotes
ClockGaterequired; Each rising edge advances the step index and generates a new pitch/gate/velocity decision. Clock period is measured between edges.
Bias CVControlNormrequired; Overrides the Bias property when connected. Clamped to 0.0--1.0.
Spread CVControlNormrequired; Overrides the Spread property when connected. Clamped to 0.0--1.0.
Density CVControlNormrequired; Overrides the Gate Density property when connected. Clamped to 0.0--1.0.
TuningData(Tuning)Overrides the default 12-EDO divisions-per-octave and applies a V/Oct offset to the pitch output.

Outputs:

PortTypeNotes
VOctVOctScale-quantized V/Oct pitch, constant across the buffer. Updated on each clock step that produces a gate.
GateGateHigh for the gate-length fraction of the clock period. Previous gate is closed before a new one opens.
VelocityControlNormRandom velocity shaped by Bias (higher bias shifts the distribution upward). Updated per clock step.

Lookahead Sequencer (LookAheadSequencer)

MIDI sequencer with lookahead for visualization and practice features

let node = LookAheadSequencer.add("my_lookaheadsequencer");

MIDI sequencer with a lookahead window for score visualization and practice features.

Plays back a MidiSequencer with sample-accurate timing while also computing upcoming notes (1--16 bars ahead) that the UI renders as a grand staff or scrolling notation. The Timing input overrides BPM from the transport. An optional count-in metronome plays before the sequence starts. The lookahead buffer is sent to the UI via poll_response each process cycle. Config In accepts a MidiSequencer from a file loader or sequencer editor; when first loaded the sequence auto-plays. The Restart gate restarts from the beginning; End of Sequence pulses when the sequence finishes.

Properties:

PropertyMethodTypeDefaultRange
Key Signaturekey_signature()Enumenum(0)CMajor, GMajor, DMajor, AMajor, EMajor, BMajor, FSharpMajor, CSharpMajor, FMajor, BFlatMajor, EFlatMajor, AFlatMajor, DFlatMajor, GFlatMajor, CFlatMajor
Look-Ahead Barslook_ahead_bars()Int41..16
Count-In Barscount_in_bars()Int00..16
Staff Offsetstaff_offset()Vec2(0, -140)
Staff Scalestaff_scale()Vec2(400, 120)

Inputs:

PortTypePropertiesNotes
RestartGateRising edge restarts the sequence from tick 0.
TimingData(Timing)Overrides BPM and time signature from the transport. When disconnected, values come from the graph transport.
Config InData(Sequence)MidiSequencer data from a file loader or sequencer editor. Auto-plays on first load.

Outputs:

PortTypeNotes
MIDI OutMidiSample-accurate MIDI events from the current playback position.
Look-Ahead OutData(Sequence)Lookahead buffer for grand staff / notation visualization. Also sent via poll_response for the UI.
End of SequenceGateGate pulse emitted when the sequence reaches its end.

MIDI Channel Splitter (MidiChannelSplitter)

Routes MIDI events by channel to separate outputs. Each output receives events from one MIDI channel.

let node = MidiChannelSplitter.add("my_midichannelsplitter");

Demultiplexes a multi-channel MIDI stream into separate per-channel outputs.

Each event is routed to the output matching its MIDI channel (channel 0 to output 0, channel 1 to output 1, etc.). Events on channels beyond the configured output count are silently dropped. The number of outputs is controlled by the Channels property and capped at 16.

Properties:

PropertyMethodTypeDefaultRange
Channelschannels()Int161..16

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Combined multi-channel MIDI stream to split.

Outputs:

PortTypeNotes
ChMidiunbounded; Unbounded per-channel MIDI output. Output index matches the MIDI channel number (wire format).

MIDI File Loader (MidiFileLoader)

Loads Standard MIDI Files and converts to sequencer configuration. Supports file paths or raw bytes with optional tempo override.

let node = MidiFileLoader.add("my_midifileloader");

Loads a Standard MIDI File (.mid) and produces a MidiSequencer on its output for downstream playback.

Accepts a MidiSource (file path or raw bytes), a ConstantValue file path, or a full MidiFileLoaderConfig via the Config input. When no Config input is connected, falls back to the embedded source and tempo properties. An optional tempo override rescales all event timestamps proportionally (original_tempo / new_tempo). Parsing only runs when the config changes (detected via a string key including tempo). The Loaded gate pulses once when a file is successfully parsed. Timing Out carries BPM and time signature from the loaded file.

Inputs:

PortTypePropertiesNotes
Config InData(Unknown)Accepts MidiSource, ConstantValue::FilePath, or full MidiFileLoaderConfig. Overrides the embedded source property when connected.

Outputs:

PortTypeNotes
Sequencer OutData(Sequence)Cached MidiSequencer data, streamed every frame. Connect to a Sequencer or Sequencer Editor.
LoadedGateSingle-frame gate pulse emitted when a file is successfully parsed (including on initial embedded load).
TimingData(Timing)BPM and time signature from the loaded MIDI file. Defaults to 4/4 if not specified in the file.

MIDI Input (MidiInput)

Receives MIDI events from a virtual MIDI device

let node = MidiInput.add("my_midiinput");

Receives live MIDI from a hardware controller or virtual port via the MIDI Device Manager pub/sub system.

Set the Device property to a VirtualDeviceId to subscribe; the audio thread establishes the subscription and injects a crossbeam receiver. Events are drained from the receiver each process cycle. System messages (clock, start, etc.) always pass through; channel messages are filtered by the Channel property (0 = all). When Device is 0 (none) the node produces no output. Changing the Device property clears stale subscriptions immediately.

Properties:

PropertyMethodTypeDefaultRange
Devicedevice()Int00..65535
Channelchannel()Int00..16

Outputs:

PortTypeNotes
MIDI OutMidiMIDI events drained from the subscription receiver each process cycle. Empty when no device is subscribed.

MIDI Mixer (MidiMixer)

Merges multiple MIDI input streams into a single output stream.

let node = MidiMixer.add("my_midimixer");

Merges multiple MIDI streams into a single time-ordered output.

All events from all connected inputs are collected, sorted by sample offset, and written to a single output buffer. The number of input ports is controlled by the Inputs property and also grows dynamically via topology overrides as cables are connected.

Properties:

PropertyMethodTypeDefaultRange
Inputsinputs()Int41..64

Inputs:

PortTypePropertiesNotes
MIDI InMidiunbounded; Unbounded MIDI input. Each connected port contributes events to the merged output.

Outputs:

PortTypeNotes
MIDI OutMidiAll input events merged and sorted by sample offset.

MIDI Remap (MidiRemap)

Remaps MIDI channel, transposes notes, scales velocity, and filters note range

let node = MidiRemap.add("my_midiremap");

MIDI transformer that remaps channels, transposes notes, scales velocity, and filters by note range.

Processing order: source channel filter, then transpose, then note range filter, then velocity scale, then target channel remap. Events that fail the source channel or note range filters are silently dropped (not passed through). Transpose is applied to NoteOn, NoteOff, and polyphonic Aftertouch messages. Velocity scaling clamps to 1--127 (never produces velocity 0). Non-note messages (CC, pitch bend, etc.) pass through with only channel remapping applied.

Properties:

PropertyMethodTypeDefaultRange
Source Chsource_channel()Int00..16
Target Chtarget_channel()Int00..16
Transposetranspose()Int0-48..48
Note Minnote_min()Int00..127
Note Maxnote_max()Int1270..127
Vel Scalevelocity_scale()Int1000..200

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Incoming MIDI events to remap.

Outputs:

PortTypeNotes
MIDI OutMidiRemapped MIDI events (transposed, channel-shifted, velocity-scaled).

MIDI Sample & Hold (MidiSampleHold)

Latch polyphonic MIDI note state on gate trigger

let node = MidiSampleHold.add("my_midisamplehold");

Latches polyphonic MIDI note state on each gate trigger.

In Trigger mode, incoming MIDI notes are tracked silently via MidiNoteTracker. On each Trigger rising edge, the tracker diffs the current input state against the held output state and emits the minimal note-off/note-on set to transition cleanly. Between triggers the output holds the captured snapshot -- stuck notes are impossible because the tracker manages all diffing. The Reset input flushes all held notes (all note-offs). In Pass mode, events pass through transparently (bypass). Disconnecting the MIDI input flushes the tracker silently. Max Notes limits the snapshot size; oldest notes are dropped when full.

Properties:

PropertyMethodTypeDefaultRange
Max Notesmax_notes()Int81..16
Modemode()Enumenum(0)Trigger, Pass

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Source MIDI stream. In Trigger mode notes are tracked silently until capture. In Pass mode events flow straight through.
TriggerGaterequired; Rising edge captures the current input note state and emits the diff to the output.
ResetGaterequired; Rising edge flushes all held notes (emits note-offs for everything in the snapshot).

Outputs:

PortTypeNotes
MIDI OutMidiIn Trigger mode: the minimal diff events (note-offs then note-ons) on each capture. In Pass mode: all input events.

MIDI Voice Splitter (MidiVoiceSplitter)

Splits polyphonic MIDI into monophonic voices. Voice count determined by connected outputs.

let node = MidiVoiceSplitter.add("my_midivoicesplitter");

Splits polyphonic MIDI into separate monophonic voice outputs with oldest-note voice stealing.

Each NoteOn is assigned to the first idle output; when all outputs are busy, the oldest voice is stolen (NoteOff sent before the new NoteOn). NoteOff is routed to whichever output holds that note. Non-note messages (CC, pitch bend, etc.) are broadcast to all outputs. All output events are on channel 1 regardless of the input channel. The Voices property controls the number of outputs.

Properties:

PropertyMethodTypeDefaultRange
Voicesvoices()Int41..64

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Polyphonic MIDI input to split across voices.

Outputs:

PortTypeNotes
Voice OutMidiunbounded; Each output carries one monophonic voice on channel 1. Non-note messages are broadcast to all outputs.

MIDI ➔ CV (MidiToCv)

Converts MIDI notes to VOct pitch CV and gate signals

let node = MidiToCv.add("my_miditocv");

Converts MIDI note events into modular-style CV signals for driving oscillators, envelopes, and modulation sources.

Outputs volt-per-octave pitch, a gate, normalized velocity, channel/poly aftertouch, and mod wheel (CC 1). In Last mode every note passes through (classic mono last-note priority with note stack -- releasing a note restores the previous pitch). In Exclusive mode the node claims one note at a time and strips it from the Thru output; chain several Exclusive nodes for manual polyphonic voice allocation. The Channel MIDI output always carries all channel-matched events regardless of voice mode. Non-note events (CC, aftertouch) are never claimed in Exclusive mode and always appear on Thru. When the Tuning port is connected it overrides divisions-per-octave and applies a V/Oct offset to the pitch output.

Properties:

PropertyMethodTypeDefaultRange
Voice Modevoice_mode()Enumenum(0)Last, Exclusive
Reference Notereference_note()Int600..127
Channelchannel()Int00..16

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; MIDI events to convert. Only note, aftertouch, and CC 1 messages are extracted; other events pass through.
TuningData(Tuning)Overrides the default 12-EDO divisions-per-octave and applies a V/Oct offset to the pitch output.

Outputs:

PortTypeNotes
VOctVOctVolt-per-octave pitch. Constant across the buffer, updated on each note-on. 0V at the reference note.
GateGateHigh while any note is held. In Last mode, stays high across note transitions; falls low only when the note stack empties.
VelocityControlNormMost recent note-on velocity, normalized 0.0--1.0. Resets to 0 when all notes release.
AftertouchControlNormChannel or polyphonic aftertouch pressure, normalized 0.0--1.0. Both aftertouch types write to this output.
Mod WheelControlNormMod wheel (CC 1) as normalized 0.0--1.0.
Channel MIDIMidiAll channel-matched MIDI events, forwarded regardless of voice mode or claim status.
Thru MIDIMidiIn Last mode: all channel-matched events. In Exclusive mode: only unclaimed events. Non-matching channels always pass through.

Polysynth (Polysynth)

Polyphonic MIDI synthesizer with configurable waveform and envelope

let node = Polysynth.add("my_polysynth");

Self-contained polyphonic synthesizer that receives MIDI and outputs stereo audio directly.

Up to 8 simultaneous voices, each with its own oscillator and ADSR envelope. Voice allocation prefers idle voices; when all are busy the oldest active voice is stolen with velocity smoothing and a cosine fade-in to prevent clicks. NoteOff is reference-counted: if the same note is triggered multiple times it only releases when all matching note-offs arrive. Output is the sum of all voices divided by max_voices, then scaled by Master Gain. Disconnecting the MIDI input releases all active voices. The Tuning port overrides 12-EDO divisions and applies a V/Oct offset.

Properties:

PropertyMethodTypeDefaultRange
Waveformwaveform()Enumenum(0)Sine, Square, Sawtooth, Triangle
Shapeshape()Envelope[envelope]

Inputs:

PortTypePropertiesNotes
MIDI InMidiNoteOn triggers a voice; NoteOn with velocity 0 acts as NoteOff. Disconnecting releases all voices.
TuningData(Tuning)Overrides the default 12-EDO divisions-per-octave and applies a frequency offset to all voices.

Outputs:

PortTypeNotes
Audio OutAudioSum of all voices divided by max_voices, scaled by Master Gain, as mono-to-stereo.

Polysynth V2 (PolysynthV2)

Polyphonic MIDI synthesizer with configurable waveform and envelope

let node = PolysynthV2.add("my_polysynthv2");

Polyphonic synthesizer with up to 16 voices and smooth frequency crossfades on voice steal.

Same voice allocation strategy as Polysynth (idle-first, then oldest-note steal) but adds a 16-sample linear crossfade when stealing to smooth frequency discontinuities. Voices are re-initialized at the audio thread's actual sample rate in setup(). NoteOff is reference-counted. Output is the sum of all voices divided by voice count, then scaled by Master Gain. Disconnecting the MIDI input releases all active voices. The Tuning port overrides 12-EDO divisions and applies a frequency offset at note-on time.

Properties:

PropertyMethodTypeDefaultRange
Waveformwaveform()Enumenum(0)Sine, Square, Sawtooth, Triangle
Shapeshape()Envelope[envelope]

Inputs:

PortTypePropertiesNotes
MIDI InMidiNoteOn triggers a voice; NoteOn with velocity 0 acts as NoteOff. Disconnecting releases all voices.
TuningData(Tuning)Overrides the default 12-EDO divisions-per-octave and applies a frequency offset at note-on time.

Outputs:

PortTypeNotes
Audio OutAudioSum of all voices divided by voice count, scaled by Master Gain, as mono-to-stereo.

Scale Quantizer (ScaleQuantizer)

Quantizes MIDI notes to a musical scale

let node = ScaleQuantizer.add("my_scalequantizer");

Snaps MIDI note pitches to the nearest degree in a selected musical scale.

NoteOn pitches are quantized and the original-to-quantized mapping is cached for the corresponding NoteOff, so note-offs always match their note-ons. Changing the Scale or Root Note property flushes all active notes (sends note-offs on channel 1 at sample offset 0) before clearing the mapping cache. Non-note messages pass through unchanged. Snap mode determines the quantization direction: Nearest picks the closest scale degree, Up always rounds up, Down always rounds down. The mapping cache avoids recomputing scale lookups for repeated pitches.

Properties:

PropertyMethodTypeDefaultRange
Scalescale_type()Enumenum(1)Chromatic, Major, Minor, HarmonicMinor, MelodicMinor, Dorian, Phrygian, Lydian, Mixolydian, Aeolian, Locrian, MajorPentatonic, MinorPentatonic, Blues, WholeTone, Diminished
Root Noteroot_note()Enumenum(60)C-1, C#-1, D-1, D#-1, E-1, F-1, F#-1, G-1, G#-1, A-1, A#-1, B-1, C0, C#0, D0, D#0, E0, F0, F#0, G0, G#0, A0, A#0, B0, C1, C#1, D1, D#1, E1, F1, F#1, G1, G#1, A1, A#1, B1, C2, C#2, D2, D#2, E2, F2, F#2, G2, G#2, A2, A#2, B2, C3, C#3, D3, D#3, E3, F3, F#3, G3, G#3, A3, A#3, B3, C4, C#4, D4, D#4, E4, F4, F#4, G4, G#4, A4, A#4, B4, C5, C#5, D5, D#5, E5, F5, F#5, G5, G#5, A5, A#5, B5, C6, C#6, D6, D#6, E6, F6, F#6, G6, G#6, A6, A#6, B6, C7, C#7, D7, D#7, E7, F7, F#7, G7, G#7, A7, A#7, B7, C8, C#8, D8, D#8, E8, F8, F#8, G8, G#8, A8, A#8, B8, C9, C#9, D9, D#9, E9, F9, F#9, G9
Snap Modesnap_mode()Int00..2

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Incoming MIDI. Only NoteOn/NoteOff pitches are altered; all other messages pass through.

Outputs:

PortTypeNotes
MIDI OutMidiMIDI events with note pitches snapped to the scale. NoteOff pitches match their corresponding quantized NoteOn.

Sequencer (Sequencer)

MIDI sequencer that outputs timed MIDI events. Uses graph transport for tempo and play state.

let node = Sequencer.add("my_sequencer");

MIDI playback engine synchronized to the graph transport.

Receives a MidiSequencer via Config In and plays back timed MIDI events. The merged MIDI Out carries events with their original channel assignments; per-track outputs (unbounded) carry the same events remapped to channel 1. Tempo comes from the Timing input when connected, otherwise from the graph transport; tempo changes flush stuck notes. The Enabled gate (disconnected = enabled) gates playback and flushes notes on transitions. Restart resets the playhead; Reload hot-swaps the config without resetting position. When Reload is not connected, Config In is polled continuously. Transport seek events cause an immediate seek-and-flush. Loop wraps playback to the loop region when enabled; if loop_end is at the default it auto-extends to cover the entire sequence. The Tracks property sets a floor on output count -- it also grows to match the loaded sequence's track count.

Properties:

PropertyMethodTypeDefaultRange
Trackstracks()Int41..64
Looploop()Boolfalse
Content BPMcontent_bpm()Float0
Gatinggating()Enumenum(0)None, OneShot, Loop

Inputs:

PortTypePropertiesNotes
RestartGateRising edge restarts the sequence from tick 0, flushing all active notes.
TimingData(Timing)Overrides BPM and time signature from the transport. Tempo changes flush stuck notes.
ReloadGateRising edge hot-swaps the Config In data without resetting the playhead. When disconnected, Config In is polled continuously.
Config InData(Sequence)MidiSequencer data from a file loader or sequencer editor. Loaded continuously unless Reload is connected.
EnabledGateGates playback. Disconnected = enabled. Transitions flush all active notes.
Gate InGateClip-launcher gate. In OneShot / Loop modes, a rising edge resets the local playhead to 0 and starts playback. Loop stops on falling edge; OneShot plays through. Ignored in None mode.
Speed ModControlMultiplier on playback rate. 1.0 = normal, 0.5 = half speed, 2.0 = double, 0.0 = freeze playhead (resumable from the same tick when the value comes back up). Negative values clamp to zero. Disconnected = 1.0 (no effect). Works in all gating modes.

Outputs:

PortTypeNotes
MIDI OutMidiMerged MIDI from all tracks with original channel assignments preserved.
TempoControlEffective BPM after Timing port override or transport fallback. Useful for downstream tempo-dependent effects.
TrackMidiunbounded; Per-track MIDI output with all events remapped to channel 1. One output per sequencer track.

Sequencer Editor (SequencerEditor)

Visual MIDI sequencer editor with piano roll interface. Click to open editor panel.

let node = SequencerEditor.add("my_sequencereditor");

Visual MIDI sequencer editor with a piano-roll interface.

Holds the authoritative MidiSequencer state and outputs it via Data port to a Sequencer node each frame. The UI sends incremental SequencerCommand edits (add, move, resize, delete notes; track mute/solo/channel changes; BPM and time signature updates). The node maintains a note_map as the single source of truth and rebuilds track MIDI events from it. In-flight notes (being dragged) are excluded from events until they land. The Import input accepts a MidiSequencer from an external source (file loader, chord progression); use the ImportFromInput command to merge it. Audition MIDI (note preview during editing) is output on the MIDI Out port on the configured audition channel. The Update Gate pulses whenever an edit is applied. Timing output carries BPM and time signature from the editor's properties.

Properties:

PropertyMethodTypeDefaultRange
Audition Channelaudition_channel()Int10..15

Inputs:

PortTypePropertiesNotes
ImportData(Sequence)External MidiSequencer to import. Connected data is cached; use the ImportFromInput command to merge it into the editor.

Outputs:

PortTypeNotes
Sequencer OutData(Sequence)Full MidiSequencer data, output every frame. Connect to a Sequencer node's Config In.
Update GateGateSingle-frame gate pulse after each SequencerCommand edit is applied.
MIDI OutMidiNote audition/preview events on the configured audition channel. Triggered by SequencerAudition commands.
TimingData(Timing)BPM, time signature, and key signature from the editor's properties. Connect to a Sequencer's Timing input.

Voice Mixer (VoiceMixer)

MIDI-controlled polyphonic mixer with per-voice ADSR envelopes and voice stealing

let node = VoiceMixer.add("my_voicemixer");

MIDI-controlled polyphonic voice mixer with per-voice ADSR envelopes and voice stealing.

Allocates MIDI notes to voice slots (idle-first, then oldest-note steal). Each slot gates one unbounded audio input with an independent ADSR envelope, velocity smoothing, and cosine fade-in. All gated voices are summed, divided by the connected voice count (fixed denominator -- not the number of active voices), then scaled by Master Gain. NoteOff is reference-counted. The slot pool resizes dynamically to match the number of connected audio inputs. Disconnecting the MIDI input releases all active slots.

Properties:

PropertyMethodTypeDefaultRange
Voicesvoices()Int41..64
Shapeshape()Envelope[envelope]
Master Gainmaster_gain()Float10..4

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; MIDI notes for voice allocation. Disconnecting releases all active slots.
Voice InAudiounbounded; Audio from a voice processing chain. Slot index maps directly to input index (after the MIDI port). Unconnected slots contribute silence.

Outputs:

PortTypeNotes
Audio OutAudioSum of all gated voices divided by voice count, scaled by Master Gain.

Sink

Audio Sink (AudioSink)

Audio output point with optional well-known label

let node = AudioSink.add("my_audiosink");

Final destination for audio in the graph. Connect any stereo audio source here to route it to the hardware output.

Every graph has exactly one AudioSink that the engine pulls from each buffer cycle. process() copies the stereo input buffer directly to the Sink output with no transformation. If Audio In is disconnected the output buffer is left silent. The Sink port type marks this node as the pull target for the graph engine's demand-driven processing.

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to send to the hardware output. Copied directly to the Sink output with no processing.

Outputs:

PortTypeNotes
Sink OutSinkSink port that the graph engine pulls to drive demand-driven processing of all upstream nodes.

Source

Audio Input (AudioInput)

Hardware audio capture (microphone, line in)

let node = AudioInput.add("my_audioinput");

Captures live audio from a hardware input device (microphone, line in, audio interface) and injects it into the graph.

Device names come from the OS audio subsystem. "Default" uses the system default input. Streams open at stereo regardless of the device's native channel count; multi-channel interfaces route through the OS stereo bus.

Gain uses exponential scaling above unity: 0.0 = silent, 0.5 = unity, 1.0 = +12 dB. Defaults to unity (0.5) when the Gain input is disconnected.

The internal ring buffer holds ~100 ms at 48 kHz. If the graph cannot keep up, the oldest input samples are dropped. This node does not record -- use Audio Looper or Sample Recorder downstream for capture.

Properties:

PropertyMethodTypeDefaultRange
Devicedevice()StringListDefault
Refresh Devicesrefresh_devices()Boolfalse
Channelschannels()Enumenum(1)Mono, Stereo

Inputs:

PortTypePropertiesNotes
GainControlNormInput gain control. Exponential above unity: 0.0 = silent, 0.5 = unity, 1.0 = +12 dB. Defaults to unity when disconnected.

Outputs:

PortTypeNotes
AudioAudioCaptured stereo audio from the selected hardware device. Outputs silence when no consumer is attached or the ring buffer is empty.
LevelControlNormRMS level of the captured signal as ControlNorm, suitable for metering without an Envelope Follower. Smoothed to avoid jitter (only updates when the change exceeds 0.001).

Audio Looper (AudioLooper)

Gate-triggered audio loop recorder with overdub

let node = AudioLooper.add("my_audiolooper");

Gate-triggered loop recorder with multi-layer overdub. Hold Record to capture; the first recording defines the loop length and all subsequent overdubs wrap within it.

Two recording inputs: Record (hold to record, release to stop) and Record Latch (rising edge toggles record on/off for hands-free or foot pedal use). When Record Latch is connected, it overrides the Record gate.

With Layers set to 1, overdubs mix directly into the base buffer. Feedback is applied during playback (not just overdub): at 1.0 the loop plays forever, below 1.0 the buffer decays each pass like a delay line. With Layers > 1, each overdub is stored on a separate layer; Clear removes the most recent layer (undo), and Feedback is ignored to preserve undo integrity.

Freeze holds the current position, sustaining audio as a crossfaded micro-loop around the freeze point. Freeze Scrub picks where in the loop you are frozen (ignored without Freeze). Freeze Width sets the size of the micro-loop window.

Speed uses exponential scaling (0.25x-4x). Reverse plays the loop backwards. Quantize defers record start/stop to the next beat boundary using transport position. Monitor passes input audio through to the output during recording to prevent latency surprise. Max Duration pre-allocates the buffer and cannot be changed while a loop is loaded.

Properties:

PropertyMethodTypeDefaultRange
Max Durationmax_duration()Float301..120
Monitormonitor()Booltrue
Quantizequantize()Boolfalse
Fadefade()Float50..50
Layerslayers()Int11..32

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to record into the loop. During playback without recording, this input is ignored unless Monitor is on.
RecordGateHold high to record/overdub, release to stop. The first recording pass defines the loop length; subsequent holds overdub within it. Ignored when Record Latch is connected.
Record LatchGateRising edge toggles record on/off (hands-free / foot pedal). Overrides the Record gate when connected.
ClearGateRising edge erases content. With Layers > 1, clears the most recent layer (undo). With 1 layer remaining, performs a full reset (erases buffer, stops playback, resets latch state).
RestartGateRising edge resets playback position to the loop start.
SpeedControlNormPlayback speed with exponential scaling: 0.0 = 0.25x, 0.5 = normal, 1.0 = 4x. Defaults to normal speed when disconnected.
ReverseGateGate high reverses the playback direction. Resets to forward when disconnected.
FeedbackControlNormLoop buffer decay amount (Layers = 1 only). Applied during playback, not just overdub: at 1.0 (default when disconnected) the loop plays forever; below 1.0, the buffer decays each pass like a delay line. Ignored in multi-layer mode to preserve undo integrity.
Freeze ScrubControlNormPicks where in the loop you are frozen (0.0 = start, 1.0 = end). Only active while Freeze is held; ignored otherwise. Smoothed to avoid clicks on abrupt CV changes.
Freeze WidthControlNormSize of the frozen micro-loop window as a fraction of the loop length. Defaults to ~1% (~20 ms at typical loop lengths) when disconnected. Smoothed to prevent clicks.
FreezeGateGate high freezes playback at the current position. Audio sustains as a crossfaded micro-loop around the freeze point. Resets to normal playback when disconnected.
MonitorGateGate to toggle input monitoring on/off. Overrides the Monitor property when connected. Falls back to the property value when disconnected.
VolumeControlNormOutput volume scaling. Defaults to 1.0 (full) when disconnected.

Outputs:

PortTypeNotes
AudioAudioStereo mix of all recorded layers (interpolated). Includes the monitored input signal during overdub if Monitor is on.
Gate OutGateHigh while the loop is playing back (after the first recording completes). Goes low when cleared.
PositionControlNormNormalized playback position within the loop (0.0-1.0).
LengthControlLoop length in beats (derived from sample count and transport BPM). Zero when no loop is loaded or BPM is zero.

Drone Oscillator (DroneOscillator)

Detuned beating sines for ambient drone textures

let node = DroneOscillator.add("my_droneoscillator");

Layers multiple tightly-detuned sine waves to produce slow beating and interference patterns - the foundation for ambient pads and drones.

Voices are spread symmetrically around the center frequency with sub-Hz offsets determined by the Beat Rate. For N voices, offsets range from -beat_rate/2 to +beat_rate/2 Hz. Warmth blends in a second harmonic (one octave up) at half amplitude per voice. Beat Rate CV maps 0.0-1.0 linearly to 0.01-5.0 Hz and overrides the property. The output is normalized by voice count.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..2000
Voicesvoice_count()Int42..8
Beat Ratebeat_rate()Float0.50.01..5
Warmthwarmth()Float00..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets center pitch, resets all voice phases on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets all voice phases. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Beat Rate ModControlNormOverrides the Beat Rate property. 0.0 maps to 0.01 Hz, 1.0 maps to 5.0 Hz (linear).
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
AudioAudioSummed drone voices, normalized by voice count.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Drum Voice (DrumVoice)

All-in-one percussion synthesizer with multiple drum modes

let node = DrumVoice.add("my_drumvoice");

All-in-one percussion synthesizer with selectable drum modes. Each mode uses a different internal topology of oscillators, noise, filters, and envelopes tuned for that drum sound.

Triggering: a rising edge on the Gate input or a MIDI NoteOn resets all envelopes, oscillator phases, and filter state. Both trigger sources are additive - either one fires the drum. The voice auto-deactivates when its amplitude envelope completes, zeroing the remaining output buffer for efficiency.

Pitch is the sum of the Pitch property, MIDI note offset (note - 60 in octaves), and the V/Oct input. The combined value maps to a frequency multiplier via 2^pitch, so +1 = one octave up, -1 = one octave down. Decay CV, Tone Mod, and Snap Mod each replace their respective property value when connected (not additive). Drive applies tanh soft clipping with gain ranging from 1x to 9x.

Mode-specific topologies: Kick uses a sine oscillator with pitch sweep plus noise click. Snare combines a sine body with bandpass-filtered noise. Hihat runs white noise through highpass and bandpass filters. Tom is similar to kick but higher pitch and less sweep. Clap fires three rapid bandpass-filtered noise bursts. Rimshot blends two detuned sine oscillators with a noise transient. Cowbell uses two detuned clipped-sine oscillators through a bandpass filter.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Kick, Snare, Hihat, Tom, Clap, Rimshot, Cowbell
Pitchpitch()Float0-1..1
Decaydecay()Float0.50..1
Tonetone()Float0.50..1
Snapsnap()Float0.30..1
Drivedrive()Float00..1

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note input. NoteOn triggers the drum and sets a pitch offset based on the note number (C4/note 60 = zero offset). Gate and velocity events are forwarded to the output ports.
Gate InGaterequired; Rising edge triggers the drum hit. Only rising edges trigger; falling edges are ignored. Can fire alongside MIDI - both sources are independent triggers.
V/OctVOctPitch offset in volts-per-octave, added to the Pitch property and any MIDI note offset. When disconnected, contributes zero offset.
Decay CVControlNormReplaces the Decay property value when connected. The CV value is used directly as the 0-1 decay parameter. When disconnected, the property value is used.
AccentControlNormScales the output amplitude before drive processing. Typically driven by a sequencer velocity output. Defaults to 1.0 when disconnected.
Tone ModControlNormReplaces the Tone property value when connected. The CV value is used directly. When disconnected, the property value is used.
Snap ModControlNormReplaces the Snap property value when connected. The CV value is used directly. When disconnected, the property value is used.
TuningData(Tuning)Tuning configuration for MIDI pitch quantization. Overrides the default 12-TET divisions per octave and V/Oct offset.

Outputs:

PortTypeNotes
Audio OutAudioMono drum audio (emitted as identical L/R). Includes accent scaling and drive processing. Silent when the voice is inactive.
GateGateGate events forwarded from the MIDI input. Not emitted when triggered by the Gate input port alone.
VelocityControlNormMIDI velocity forwarded as normalized CV. Only emitted when MIDI input is connected.

FM Operator (FmOperator)

Frequency modulation synthesis operator with external modulation and feedback

let node = FmOperator.add("my_fmoperator");

Single FM synthesis operator that works as both carrier and modulator. Chain operators by connecting one's Mod Out to another's Modulator In for classic DX-style patches.

Audio Out and Mod Out carry the same signal (both scaled by Output Level); use Audio Out for final output and Mod Out for chaining into other operators. Ratio multiplies the carrier frequency to set the operator's actual oscillation frequency. FM Index CV and Feedback CV each add to their respective property values via smoothers. The operator DSP is reconstructed each process call, so property changes take effect immediately. No dedicated Gate input - phase reset is triggered only via MIDI note-on.

Properties:

PropertyMethodTypeDefaultRange
Carrier Freqcarrier_frequency()Float44020..20000
Ratioratio()Float10.25..16
FM Indexfm_index()Float00..10
Feedbackfeedback()Float00..1
Waveformwaveform()Enumenum(0)Sine, Square, Sawtooth, Triangle
Output Leveloutput_level()Float10..1

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets carrier pitch and drives Gate/Velocity outputs. The only way to trigger this node - there is no Gate input.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or Carrier Freq exponentially; ControlFreq overrides in Hz.
Modulator InAudioAudio-rate modulator signal from another operator's Mod Out. Downmixed to mono, scaled by FM Index.
FM Index ModControlNormAdds to the FM Index property value via the smoother.
Feedback ModControlNormAdds to the Feedback property value via the smoother.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioFinal operator audio, scaled by Output Level. Identical signal to Mod Out.
Mod OutAudioSame signal as Audio Out, intended for chaining into another operator's Modulator In.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Formant Oscillator (Formant)

Vowel-like sounds via resonant formant filters with morph control

let node = Formant.add("my_formant");

Produces vowel-like vocal sounds by running a carrier waveform through resonant bandpass filters tuned to formant frequencies. Pick two vowel shapes and sweep between them with the Morph knob.

The carrier waveform (Saw, Pulse, or Noise) excites the formant filter bank; Resonance controls how sharp the vowel peaks are. Morph CV adds to the property value, clamped 0.0-1.0, and bypasses the smoother when connected. The Resonance property has no CV input and applies uniformly to all formant bands.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float22020..5000
Carriercarrier()Enumenum(0)Saw, Pulse, Noise
Vowel Avowel_a()Enumenum(0)A, E, I, O, U
Vowel Bvowel_b()Enumenum(3)A, E, I, O, U
Morphmorph()Float00..1
Resonanceresonance()Float0.50..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets carrier pitch, resets phase on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets the carrier phase and filter state. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Morph ModControlNormAdds to the Morph property value, clamped 0.0-1.0. Bypasses the smoother when connected.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioFormant-filtered audio.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Frequency Control (FrequencyControl)

Constant frequency control source in Hz

let node = FrequencyControl.add("my_frequencycontrol");

Outputs a constant frequency value in Hz as a ControlFreq signal. Use it to drive filter cutoffs, oscillator frequencies, or any parameter that accepts ControlFreq.

Pure source node with no inputs - the output is the Frequency property value written directly to the control port each frame.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float100020..20000

Outputs:

PortTypeNotes
FrequencyControlFreqEmits the Frequency property value as ControlFreq each frame.

Granular Voice (GranularVoice)

Micro-grain playback with textural, evolving sound

let node = GranularVoice.add("my_granularvoice");

Granular synthesis voice that continuously fills a circular buffer from an internal oscillator or external audio, then spawns overlapping micro-grains from that buffer to produce textural, evolving timbres.

The buffer is always being written to. Grains spawn at a rate set by Density and read from a position relative to the write head (Position = 0 reads the oldest sample, 1 reads the newest). Each grain gets independent randomized pitch offset, stereo pan, and optional reverse playback. The output is the normalized sum of all active grains, divided by the number currently sounding.

Gate (from the Gate port or MIDI NoteOn) resets the write head and spawn accumulator but does not start or stop grain generation - grains run continuously regardless of gate state. MIDI also sets oscillator frequency and emits gate/velocity on the output ports.

When Source is set to Input, the Audio In signal is written into the buffer instead of the internal oscillator. The oscillator frequency is ignored in this mode, but Frequency still affects MIDI-driven pitch tracking on the output.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..5000
Grain Sizegrain_size()Float301..100
Densitydensity()Float101..50
Positionposition()Float0.50..1
Position Scatterposition_scatter()Float0.10..1
Pitch Scatterpitch_scatter()Float00..100
Pan Scatterpan_scatter()Float00..1
Reverse Chancereverse_chance()Float00..1
Sourcesource()Enumenum(0)Sine, Saw, Noise, Input
Buffer Lengthbuffer_length()Float10050..2000
Grain Envelopeenvelope()Curve[curve]

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note input. NoteOn sets oscillator frequency and resets the write head; NoteOff clears the triggered flag. Gate and velocity events are forwarded to the output ports.
GateGateRising edge resets the write head and spawn accumulator. Does not start or stop grain generation. Falling edge clears the triggered flag so the next rising edge can re-trigger.
Audio InAudioExternal audio fed into the grain buffer. Only used when Source is set to Input; otherwise this port is ignored. The stereo signal is mono-summed before writing to the buffer.
Frequency ModControlFreq, VOctFrequency control via V/Oct or ControlFreq. Priority: if MIDI is active and V/Oct is connected, they combine additively. V/Oct alone offsets the property frequency exponentially. ControlFreq replaces the frequency directly. When disconnected, the property value is used.
Position ModControlNormOverrides the Position property when connected. Smoothed to avoid zipper noise. When disconnected, the property value is used.
Density ModControlNormOverrides the Density property when connected. CV 0.0 maps to 1 grain/s, 1.0 maps to 50 grains/s. Smoothed. When disconnected, the property value is used.
Grain Size ModControlNormOverrides the Grain Size property when connected. CV 0.0 maps to 1 ms, 1.0 maps to 100 ms. Smoothed. When disconnected, the property value is used.
Pitch Scatter ModControlNormOverrides the Pitch Scatter property when connected. CV 0.0 maps to 0 cents, 1.0 maps to 100 cents. Written directly (not smoothed). When disconnected, the property value is used.
Pan Scatter ModControlNormOverrides the Pan Scatter property when connected. Smoothed. When disconnected, the property value is used.
TuningData(Tuning)Tuning configuration for MIDI pitch quantization. Overrides the default 12-TET divisions per octave and V/Oct offset.

Outputs:

PortTypeNotes
AudioAudioStereo mix of all active grains, normalized by dividing by the number of currently sounding grains.
GateGateGate events forwarded from the MIDI input. Not emitted when triggered by the Gate input port alone.
VelocityControlNormMIDI velocity forwarded as normalized CV. Only emitted when MIDI input is connected.

Harmonic Oscillator (HarmonicOscillator)

16-partial additive synthesis with spectral tilt and inharmonicity

let node = HarmonicOscillator.add("my_harmonicoscillator");

Additive oscillator with 16 independently controllable sine partials. Sculpt timbres by drawing the harmonic spectrum directly - set each partial's amplitude and frequency ratio via node commands.

Tilt applies a dB-per-octave brightness slope across all partials: positive boosts upper partials, negative attenuates them. Tilt CV maps 0.0-1.0 to the full -1.0 to +1.0 range and overrides the property. Stretch shifts partial ratios toward inharmonic spacing using the formula ratio * (1 + stretch * (ratio - 1) * 0.01), so higher partials are displaced more. The output is normalized by the count of active (non-zero amplitude) partials.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..5000
Tilttilt()Float0-1..1
Stretchstretch()Float00..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets fundamental pitch, resets all 16 phases on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets all 16 partial phases. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Tilt ModControlNormOverrides the Tilt property. 0.0 maps to -1.0 (dark), 1.0 maps to +1.0 (bright).
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
AudioAudioSum of all active partials, normalized by the count of non-zero-amplitude partials.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Karplus-Strong (KarplusStrong)

Physical modeling of plucked strings using delay line synthesis

let node = KarplusStrong.add("my_karplusstrong");

Plucked-string physical model using delay line synthesis. A noise burst or impulse excites a tuned delay line that feeds back through a lowpass filter, producing realistic guitar, harp, and bell-like tones.

Trigger via Gate input or MIDI. MIDI NoteOn plucks at the given pitch and passes gate/velocity to the output ports. When both MIDI and V/Oct are connected, MIDI sets the base pitch and V/Oct adds an offset. V/Oct alone multiplies the Frequency property. ControlFreq directly sets frequency in Hz. Pitch is locked at trigger time in the delay line DSP.

Damping CV maps 0.0-1.0 to the 0.9-0.9999 feedback range. When disconnected, the Damping property is smoothed. Brightness CV is additive with the property value and clamped to 0.0-1.0. When disconnected, it is also smoothed.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..5000
Dampingdamping()Float0.9950.9..0.9999
Brightnessbrightness()Float0.50..1
Pick Positionpick_position()Float0.50..1
Excitationexcitation_type()Enumenum(0)Noise, Impulse, FilteredNoise

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note input. NoteOn plucks the string at the given pitch and velocity. Gate and velocity are forwarded to the output ports. When both MIDI and V/Oct are connected, MIDI sets the base pitch and V/Oct adds an offset.
TriggerGateRising edge excites the delay line (plucks the string). Uses the current frequency from property or CV inputs. Falling edge re-arms the trigger.
Frequency ModControlFreq, VOctPitch control. Accepts V/Oct (multiplied with base frequency or added to MIDI pitch) or ControlFreq (direct Hz). Priority: MIDI+V/Oct combined > V/Oct alone > ControlFreq > property.
Damping ModControlNormCV override for damping. Maps 0.0-1.0 to the 0.9-0.9999 feedback range. Overrides the smoothed property value when connected.
Brightness ModControlNormCV modulation added to the Brightness property value, clamped to 0.0-1.0. Overrides the smoothed property when connected.
TuningData(Tuning)Tuning configuration data. Overrides the MIDI driver's divisions-per-octave and V/Oct offset for microtonal tuning.

Outputs:

PortTypeNotes
Audio OutAudioSynthesized plucked-string audio (mono duplicated to stereo).
GateGateGate events forwarded from MIDI input. Only emits events when MIDI In is connected.
VelocityControlNormMIDI velocity as normalized CV. Only updates when a MIDI NoteOn is received.

Modal Body (ModalBody)

Struck body physical model - bells, marimbas, glass, metal, wood

let node = ModalBody.add("my_modalbody");

Physical model of struck objects using a bank of damped resonators. Simulates bells, marimbas, glass, metal plates, and wood blocks.

Trigger via Gate input or MIDI. MIDI NoteOn strikes the body at the given pitch and passes gate/velocity to the output ports. When both MIDI and V/Oct are connected, MIDI sets the base pitch and V/Oct adds an offset. V/Oct alone multiplies the Frequency property. ControlFreq directly sets frequency in Hz.

Material, Brightness, Decay, and Inharmonicity are sampled at trigger time to configure the resonator bank. Brightness and Decay CV inputs are evaluated at trigger time; changing them mid-ring does not alter the decay envelope.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..5000
Materialmaterial()Enumenum(0)0..4; Bell, Marimba, Glass, Metal, Wood
Brightnessbrightness()Float0.80..1
Decaydecay()Float0.50..1
Inharmonicityinharmonicity()Float00..1

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note input. NoteOn strikes the body at the given pitch and velocity. Gate and velocity are forwarded to the output ports. When both MIDI and V/Oct are connected, MIDI sets the base pitch and V/Oct adds an offset.
GateGateRising edge triggers a strike using the current frequency, material, brightness, decay, and inharmonicity. Falling edge re-arms the trigger.
Frequency ModControlFreq, VOctPitch control. Accepts V/Oct (multiplied with base frequency or added to MIDI pitch) or ControlFreq (direct Hz). Priority: MIDI+V/Oct combined > V/Oct alone > ControlFreq > property.
Brightness ModControlNormCV modulation added to the Brightness property value, clamped to 0.0-1.0. Evaluated at trigger time.
Decay ModControlNormCV override for decay time. Replaces the Decay property value when connected. Evaluated at trigger time.
TuningData(Tuning)Tuning configuration data. Overrides the MIDI driver's divisions-per-octave and V/Oct offset for microtonal tuning.

Outputs:

PortTypeNotes
Audio OutAudioSynthesized struck-body audio (mono duplicated to stereo).
GateGateGate events forwarded from MIDI input. Only emits events when MIDI In is connected.
VelocityControlNormMIDI velocity as normalized CV. Only updates when a MIDI NoteOn is received.

Noise Filter Bank (NoiseFilterBank)

Noise through parallel bandpass filters with per-band envelopes for percussion synthesis

let node = NoiseFilterBank.add("my_noisefilterbank");

Noise source routed through four parallel bandpass filters, each with its own gain and exponential decay envelope. Designed for metallic percussion: hihats, cymbals, snare noise layers.

On a gate rising edge, all four band envelopes reset to zero and filter state is cleared. Each band runs an independent exponential decay (exp(-5t)) whose duration comes from the preset's per-band decay time multiplied by the Decay Scale property. A band is considered finished when its envelope time exceeds 3.0 (approximately -65 dB). When all four bands have finished, the voice deactivates and zeros the remaining output buffer for efficiency.

The Tone property shifts all four band center frequencies together as a power-of-two multiplier (2^tone octaves). Brightness scales the filter Q values (0.5 + brightness * 2.0), so higher brightness produces tighter, more resonant bands. The output is the sum of all four filtered bands, scaled by the Accent input.

Properties:

PropertyMethodTypeDefaultRange
Presetpreset()Enumenum(0)Hihat, Snare, Cymbal, Custom
Noise Typenoise_type()Enumenum(0)White, Pink, Brown
Tonetone()Float0-1..1
Decaydecay_scale()Float10.1..4
Brightnessbrightness()Float0.50..1

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Rising edge resets all four band envelopes and clears filter state for a clean attack. Only rising edges trigger; falling edges are ignored.
Decay CVControlNormReplaces the Decay Scale property when connected. CV 0.0 maps to 0.1x, 1.0 maps to 4.0x. Sampled once per buffer. When disconnected, the property value is used.
Brightness CVControlNormReplaces the Brightness property when connected. Sampled once per buffer. When disconnected, the property value is used.
AccentControlNormScales the output amplitude of all bands. Typically driven by a sequencer velocity output. Defaults to 1.0 when disconnected.

Outputs:

PortTypeNotes
Audio OutAudioSum of all four filtered noise bands, each weighted by its preset gain and envelope, then scaled by Accent.

Noise Generator (Noise)

White, pink, and brown noise generator

let node = Noise.add("my_noise");

Continuous noise source with selectable color. White has equal energy at all frequencies; pink has equal energy per octave (1/f via Voss-McCartney); brown rolls off at 1/f-squared (leaky integrator of white noise).

No MIDI or pitch input - this is a free-running generator. Amplitude CV overrides the property entirely (sets the smoother target to the CV value, ignoring the knob). When disconnected, the smoothed property value is used.

Properties:

PropertyMethodTypeDefaultRange
Noise Typenoise_type()Enumenum(0)White, Pink, Brown
Amplitudeamplitude()Float10..1

Inputs:

PortTypePropertiesNotes
Amplitude ModControlNormOverrides the Amplitude property entirely - the CV value replaces the knob setting via the smoother.

Outputs:

PortTypeNotes
Audio OutAudioContinuous noise audio, amplitude-scaled.

Organ (Organ)

Hammond-style drawbar organ with 9 harmonics and key click

let node = Organ.add("my_organ");

Hammond-style tonewheel organ with nine drawbar harmonics and optional key click. Each drawbar controls the level of a sine partial at a specific footage ratio (16' through 1').

Gate and MIDI note-on both reset the internal oscillator phases and trigger the key click transient (edge-triggered). Key Click CV adds to the property value, clamped 0.0-1.0; it bypasses the smoother when connected. Drawbar levels are integers 0-8 mapping to the traditional Hammond registration scale.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..5000
16' Subdb_sub()Int80..8
8' Funddb_fund()Int80..8
5-1/3'db2nd()Int80..8
4'db4th()Int60..8
2-2/3'db5_1_3()Int00..8
2'db8th()Int40..8
1-3/5'db10_2_3()Int00..8
1-1/3'db12th()Int00..8
1'db16th()Int00..8
Key Clickkey_click()Float0.30..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets pitch, resets phases and triggers key click on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets oscillator phases and fires the key click. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Key Click ModControlNormAdds to the Key Click property value, clamped 0.0-1.0. Bypasses the smoother when connected.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioSum of all nine drawbar harmonics plus key click transient.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Oscillator (Oscillator)

Waveform generator with frequency modulation

let node = Oscillator.add("my_oscillator");

General-purpose waveform generator with sine, saw, square, triangle, and pulse shapes. Use as a sound source, LFO, or modulator.

Pitch priority: MIDI sets the base pitch and VOct offsets it; VOct alone scales the Frequency knob exponentially; ControlFreq overrides the knob with an absolute Hz value. Detune applies on top of all three as an exponential octave offset. Gate and MIDI note-on both reset phase on the rising edge (edge-triggered, not level-sensitive). Gate Out and Velocity Out only emit when MIDI is connected.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..20000
Waveformwaveform()Enumenum(0)Sine, Square, Sawtooth, Triangle
Pulse Widthpulse_width()Float0.50.01..0.99
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets base pitch, resets phase on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets phase for consistent attack. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
PW ModControlNormOverrides the PulseWidth property via the smoother. Only audible with Pulse waveform.
DetuneControlBipolarBipolar pitch offset applied after frequency resolution. -1.0 to +1.0 maps exponentially to -1 to +1 octaves.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioGenerated waveform audio.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Phase Distortion (PhaseDistortion)

CZ-style phase distortion oscillator - saw, square, resonant, pulse timbres

let node = PhaseDistortion.add("my_phasedistortion");

Casio CZ-style oscillator that warps a sine wave's phase to produce saw, square, resonant, and pulse timbres from a single core. Sweep the Depth knob from zero (pure sine) to full for dramatically changing harmonic content.

Depth CV adds to the property value and clamps to 0.0-1.0; when disconnected the smoothed property value is used. The Mode selector chooses the phase transfer function - each mode produces a different harmonic structure at the same depth setting.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..20000
Modemode()Enumenum(0)0..3; Saw, Square, Resonant, Pulse
Depthdepth()Float0.50..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets pitch, resets phase on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets phase for consistent attack. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Depth ModControlNormAdds to the Depth property value, clamped 0.0-1.0. Bypasses the smoother when connected.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioPhase-distorted audio.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Sample Player (SamplePlayer)

Gate-triggered sample playback with stereo output

let node = SamplePlayer.add("my_sampleplayer");

Gate-triggered sample playback from the project library. Supports one-shot and looping modes with adjustable start/end points and pitch control.

Samples are borrowed from the resource cache each process call, so hot-swapped samples are picked up automatically. Stereo samples produce true stereo output; mono samples are duplicated to both channels. Linear interpolation is used between sample frames.

The Sample data input overrides the Sample property when connected. The Pitch input controls playback speed as a multiplier (1.0 = normal, 2.0 = double speed/octave up); negative values play in reverse. Defaults to 1.0 when disconnected.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)OneShot, Loop
Startstart()Float00..1
Endend()Float10..1
Samplesample_key()String

Inputs:

PortTypePropertiesNotes
GateGaterequired; Rising edge resets the playback position to Start and begins playing. If the sample is not yet cached, the trigger is silently ignored (no crash, no playback).
PitchControlBipolarPlayback speed multiplier added to the position each sample. 1.0 = normal, 2.0 = double speed / octave up, negative = reverse. Defaults to 1.0 when disconnected.
SampleData(Sample)Data input to select a sample by resource key. Overrides the Sample property when connected.

Outputs:

PortTypeNotes
OutputAudioStereo audio output. Mono samples are duplicated to both channels. Outputs silence when stopped or when the sample is not cached.
PlayingGateHigh while the sample is actively playing. Goes low on OneShot completion or when the sample is cleared.

Sample Recorder (SampleRecorder)

Records audio input to the project sample library

let node = SampleRecorder.add("my_samplerecorder");

Records audio input into the project sample library. Gate-on starts recording, gate-off saves the result. Can be inserted inline without breaking the signal chain -- audio passes through unchanged to the Thru output.

Create mode adds a numbered sample each recording (e.g. "recording_001"). Overwrite mode replaces an existing sample by key. The Sample data input overrides both mode and target property: when connected, recordings always overwrite that key regardless of mode setting.

Audio is downmixed to mono internally before saving. Recording auto-stops when Max Length is reached.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Create, Overwrite
Namesample_name()Stringrecording
Max Lengthmax_length()Float600.1..300
Target Sampletarget_key()String

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to record. Downmixed to mono before saving. Passed through unchanged to the Thru output regardless of recording state.
GateGaterequired; Rising edge starts recording (clears any previous buffer). Falling edge finalizes and saves the recording to the project library.
SampleData(Sample)Data input to select a target sample key. When connected, recordings always overwrite the specified key regardless of the Mode or Target Sample property settings.

Outputs:

PortTypeNotes
ThruAudioAudio passthrough -- the input signal forwarded unchanged regardless of recording state. Outputs silence when Audio In is disconnected.

Shepard Tone (ShepardTone)

Continuously ascending/descending pitch illusion

let node = ShepardTone.add("my_shepardtone");

Creates the auditory illusion of a pitch that rises (or falls) forever. Multiple sine voices spaced one octave apart are faded with a Gaussian window centered on the mid-range, so entering and leaving voices are inaudible.

The sweep position advances continuously in octaves and wraps at 1.0 (one full octave cycle). Each voice's frequency is base_freq * 2^(voice_index + sweep_position). The Spread property controls the Gaussian window width in octaves - smaller values create a narrower audible band. Speed CV maps 0.0-1.0 linearly to 0.01-2.0 oct/s and overrides the property. Gate and MIDI note-on both reset sweep position and all phases.

Properties:

PropertyMethodTypeDefaultRange
Frequencybase_frequency()Float10020..500
Speedspeed()Float0.20.01..2
Directiondirection()Enumenum(0)Up, Down, Static
Spreadspread()Float20.5..4
Voicesvoice_count()Int64..8
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets base pitch, resets sweep position and phases on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets sweep position to zero and clears all phases. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the base frequency exponentially; ControlFreq overrides in Hz.
Speed ModControlNormOverrides the Speed property. 0.0 maps to 0.01 oct/s, 1.0 maps to 2.0 oct/s (linear).
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
AudioAudioSummed and Gaussian-windowed sine voices, normalized by voice count.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Spectral Painter (SpectralPainter)

Image-based drawable spectrogram - outputs spectral data

let node = SpectralPainter.add("my_spectralpainter");

Drawable spectrogram that converts painted pixel brightness into spectral magnitude data. Paint directly on the canvas in the UI to sculpt frequency content over time.

Each image column represents one spectral frame. The playhead advances with the transport, stepping one column per rows-per-beat subdivision, so timing is tempo-synced. Pixel Y maps to frequency on a logarithmic scale (bottom = 20 Hz, top = Nyquist). Pixel brightness (max of RGB channels) maps through a -90 dB to 0 dB range into linear magnitude.

When the Position CV is connected, it overrides the transport-driven playhead - the CV value selects the column directly as a normalized position across the canvas width. Depth CV scales all output magnitudes (defaults to 1.0 when disconnected).

The Reference input accepts spectral data from another source and renders it as an onion-skin overlay on the canvas, useful for tracing existing sounds. The onion skin can be shifted, captured, and cleared via commands. The canvas pixel buffer is persisted in the project file as an RGBA blob.

Properties:

PropertyMethodTypeDefaultRange
Lengthlength_bars()Int41..32
Resolutionrows_per_beat()Int164..64
Looploop()Booltrue

Inputs:

PortTypePropertiesNotes
ReferenceSpectralSpectral data rendered as an onion-skin overlay on the canvas for tracing. The reference's FFT size and sample rate are resampled to the painter's own bin grid, so any upstream FFT configuration works. Only captured while onion recording is active.
PositionControlNormOverrides the transport-driven playhead when connected. The CV value selects the column as a fraction of total canvas width (0.0 = first column, 1.0 = last column). Takes priority over transport position.
DepthControlNormScales all output spectral magnitudes. At 0.0 the output is silent regardless of canvas content; at 1.0 magnitudes pass through at full strength. Defaults to 1.0 when disconnected.

Outputs:

PortTypeNotes
Spectral OutSpectralSpectral frames derived from the painted canvas. One frame is emitted each time the playhead advances to a new column. Magnitudes are zero-phase; connect to an ISTFT or spectral processor downstream for audio output.

Speech Synth (SpeechSynth)

Text-to-speech formant synthesis with enhanced playback features

let node = SpeechSynth.add("my_speechsynth");

Formant speech synthesizer based on the SAM (Software Automatic Mouth) engine. Type text and trigger playback with a gate to produce per-sample speech audio.

Gate triggers playback from the beginning. The Loop property auto-retriggers on completion. Gate Out goes high on play start and low on finish; with Loop on, it emits off+on at each loop boundary.

CV modulation inputs (Speed/Pitch/Mouth/Throat Mod) compute effective values without mutating config properties -- property values restore automatically on disconnect. CV maps 0.0-1.0 across the full parameter range.

External oscillator inputs (F1/F2/F3 Osc) replace the built-in oscillator for that formant. SAM still controls amplitude, frequency tracking, and glottal timing.

Scrub overrides linear playback: CV directly sets frame position. An LFO on Scrub creates cyclic vowel scanning. Freeze holds the current frame while oscillator phases and glottal pulse continue running. Freeze Drift adds random formant frequency wobble while frozen, creating evolving pad textures.

V/Oct overrides glottal pitch while preserving formant shapes (vowel identity). Morph crossfades between Text A and Text B frame data (requires both text inputs connected).

Properties:

PropertyMethodTypeDefaultRange
Texttext()Stringhello world
Speedspeed()Int7220..200
Pitchpitch()Int640..255
Mouthmouth()Int1280..255
Throatthroat()Int1280..255
Looploop()Boolfalse
Interpolateinterpolate()Booltrue
Reversereverse()Boolfalse
Glottalglottal_envelope()Curve[curve]
Waveformwaveform()Enumenum(0)Classic, Saw, Triangle, Square, Pulse
Noisenoise()Float00..1
Subsub()Float00..1
Voicesvoices()Int11..8
Detunedetune()Float00..1
Spreadspread()Float00..1
Scatterscatter()Float00..1
Freeze Driftfreeze_drift()Float00..200
Morphmorph()Float00..1

Inputs:

PortTypePropertiesNotes
GateGateRising edge starts speech playback from the beginning (or from the end when Reverse is on). Unison voices are staggered with phase offsets to avoid cancellation.
Text AData(Speech)Text data for phrase A. Overrides the Text property when connected; reverts to the property when disconnected.
Text BData(Speech)Text data for phrase B, used as the morph target. Required for the Morph control to have any effect.
Speed ModControlNormCV modulation for phoneme playback speed. Maps 0.0-1.0 to the 20-200 range. Computes an effective value without mutating the property; disconnecting restores the property.
Pitch ModControlNormCV modulation for voice fundamental pitch. Maps 0.0-1.0 to the 0-255 range. Disconnecting restores the property value.
Mouth ModControlNormCV modulation for mouth cavity size. Maps 0.0-1.0 to the 0-255 range. Disconnecting restores the property value.
Throat ModControlNormCV modulation for throat cavity size. Maps 0.0-1.0 to the 0-255 range. Disconnecting restores the property value.
V/OctVOctOverrides glottal pitch using V/Oct standard (0V = middle C, ~261.6 Hz). Formant shapes (vowel identity) are preserved while the fundamental pitch follows the CV.
Formant ShiftControlNormShifts formant frequencies up/down independent of pitch. Maps 0.0-1.0 to -1.0..+1.0 shift range. At 0.5 (center), no shift. Defaults to no shift when disconnected.
RateControlNormPlayback rate with exponential scaling: 0.0 = 0.25x, 0.5 = normal, 1.0 = 4x. Defaults to normal speed when disconnected.
ScrubControlNormOverrides linear playback -- CV directly sets the frame position. An LFO on Scrub creates cyclic vowel scanning. Active even when the voice is not playing.
FreezeGateGate high freezes playback at the current phoneme frame. Oscillator phases and glottal pulse continue running, so the frozen vowel sustains with tonal variation. Resets to normal playback when disconnected.
Scatter ModControlNormCV override for scatter amount. Overrides the Scatter property when connected.
Morph ModControlNormCV override for A/B text morph position (0.0 = A, 1.0 = B). Overrides the Morph property when connected.
Drift ModControlNormCV override for freeze drift rate. Maps 0.0-1.0 to 0-200 Hz. Overrides the Freeze Drift property when connected.
Voices ModControlNormCV override for unison voice count (0.0 = 1 voice, 1.0 = 8 voices). Overrides the Voices property when connected.
F1 OscAudioExternal oscillator replacing the first formant carrier. SAM still controls amplitude, frequency tracking, and glottal timing for this formant.
F2 OscAudioExternal oscillator replacing the second formant carrier. SAM still controls amplitude, frequency tracking, and glottal timing for this formant.
F3 OscAudioExternal oscillator replacing the third formant carrier. SAM still controls amplitude, frequency tracking, and glottal timing for this formant.

Outputs:

PortTypeNotes
AudioAudioSynthesized speech audio. Stereo when unison voices are spread, mono-duplicated otherwise.
Gate OutGateHigh while speech is actively playing. With Loop on, emits off+on at each loop boundary for downstream envelope retriggering.
F1 FreqControlNormFirst formant frequency as normalized CV (0.0-1.0 maps to 0-3000 Hz). Useful for driving external filters or visualizations.
F2 FreqControlNormSecond formant frequency as normalized CV (0.0-1.0 maps to 0-3000 Hz).
F3 FreqControlNormThird formant frequency as normalized CV (0.0-1.0 maps to 0-3000 Hz).

Supersaw (Supersaw)

Multiple detuned sawtooth oscillators for unison lead and pad sounds

let node = Supersaw.add("my_supersaw");

Stack of up to seven detuned sawtooth oscillators for massive unison sounds. The signature trance/EDM lead and pad tone.

Spread sets the total detuning width in cents across all voices; mix crossfades between the center voice alone (0.0) and the full chorus (1.0). When Spread CV is connected it adds cv * 100 cents to the property value; Mix CV adds directly. Both are clamped to their property range. Pitch priority follows the standard chain: MIDI+VOct combined, VOct alone, ControlFreq, then the Frequency knob.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..20000
Voicesvoice_count()Int71..7
Spreadspread()Float250..100
Mixmix()Float10..1
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets pitch, resets all voice phases on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets all voice phases for consistent attack. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Spread ModControlNormAdds cv * 100 cents to the Spread property, clamped 0-100. Bypasses the smoother when connected.
Mix ModControlNormAdds directly to the Mix property, clamped 0.0-1.0. Bypasses the smoother when connected.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioSummed and mixed supersaw audio.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Sync Oscillator (SyncOsc)

Hard-sync oscillator - aggressive, harmonically rich lead sounds

let node = SyncOsc.add("my_syncosc");

Hard-sync oscillator with a master/slave pair. The slave resets its phase every time the master completes a cycle, producing aggressive, harmonically rich timbres. Sweep the ratio for the classic sync-lead sound.

Frequency sets the master pitch; the slave runs at frequency * ratio. Ratio CV adds cv * 15 to the property value, clamped 1.0-16.0, and bypasses the smoother when connected. Gate and MIDI note-on both reset master and slave phases together (edge-triggered).

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..20000
Ratioratio()Float21..16
Waveformwaveform()Enumenum(0)0..3; Saw, Square, Sine, Triangle
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets master pitch, resets both phases on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets both master and slave phases. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Ratio ModControlNormAdds cv * 15 to the Ratio property, clamped 1.0-16.0. Bypasses the smoother when connected.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioSlave oscillator audio, periodically reset by the master.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Wavetable Oscillator (Wavetable)

Morphable wavetable oscillator with multiple waveform frames

let node = Wavetable.add("my_wavetable");

Scans through a table of stored waveform frames, interpolating between them for smoothly evolving timbres. Sweep the Position knob to morph through the wavetable; connect an audio signal to FM Input for linear frequency modulation.

FM is linear: the FM Input audio value is multiplied by FM Amount (in Hz) and added directly to the current frequency each sample. Position CV adds to the property value and clamps to 0.0-1.0; when disconnected, the smoothed property value is used. Detune is a static cents offset converted via 2^(cents/1200) and applied as a final frequency multiplier.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float44020..20000
Wavetablewavetable_type()Enumenum(0)SawStack, PWM, Formant, Harmonic, Digital, Vocal
Positionposition()Float0.50..1
Detunedetune()Float0-100..100
FM Amountfm_amount()Float00..1000
Phase Resetphase_reset()Boolfalse

Inputs:

PortTypePropertiesNotes
MIDI InMidiMIDI note data. Sets pitch, resets phase on note-on, and drives Gate/Velocity outputs.
GateGateRising edge resets phase for consistent attack. Shares trigger state with MIDI gate.
Frequency ModControlFreq, VOctPitch input. VOct offsets MIDI or the Frequency knob exponentially; ControlFreq overrides the knob in Hz.
Position ModControlNormAdds to the Position property value, clamped 0.0-1.0. Bypasses the smoother when connected.
FM InputAudioAudio-rate modulator for linear FM. Downmixed to mono, scaled by FM Amount, and added to frequency in Hz.
TuningData(Tuning)Tuning configuration - overrides local divisions/octave.

Outputs:

PortTypeNotes
Audio OutAudioInterpolated wavetable audio.
GateGateForwards gate events from MIDI input. Silent when MIDI is disconnected.
VelocityControlNormLast MIDI note velocity as 0.0-1.0. Only emits when MIDI is connected.

Spectral

Phase Sculptor (PhaseScatter)

Per-bin phase manipulation - scatter, coherence, drift, freeze, transfer, smear

let node = PhaseScatter.add("my_phasescatter");

Per-bin phase manipulation with six modes for reshaping spectral phase relationships.

Scatter: replaces inst_freq with random offsets (regenerated on Gate rising edge). Destroys pitch, creates diffuse textures. Coherence: locks inst_freq to deterministic mathematical patterns (Zero, Linear, Alternating, Quadratic). Creates metallic, robotic, or glassy timbres. Drift: adds a slow random walk to inst_freq per bin, creating evolving detuned textures. Rate controls walk speed, Amount limits max offset. FreezeDrift: captures magnitudes on Gate rising edge (or Freeze toggle), then applies Drift to the frozen spectrum. Gate toggles freeze state. Transfer: crossfades inst_freq toward a Reference spectral input. Holds last received reference when disconnected. Smear: blurs inst_freq across neighboring bins using a triangular kernel of Width radius. Amount at 0 bypasses all modes (passthrough). The Amount Mod and Rate Mod CV inputs add to their respective knob values.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Scatter, Coherence, Drift, FreezeDrift, Transfer, Smear
Amountamount()Float00..1
Patternpattern()Enumenum(0)Zero, Linear, Alternating, Quadratic
Raterate()Float10.01..10
Widthwidth()Int41..32
Freezefreeze()Boolfalse

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Primary spectral data to manipulate. Required - produces no output without a connection.
ReferenceSpectralrequired; Phase source for Transfer mode. The last received frame's inst_freq is held when disconnected, so the transfer effect persists after unplugging.
GateGaterequired; Rising edge behavior depends on mode: Scatter regenerates random offsets, FreezeDrift toggles magnitude freeze state. Ignored in other modes.
Amount ModControlNormrequired; CV added to the Amount knob. Combined total is clamped 0-1.
Rate ModControlNormrequired; CV scaled to a 10x range and added to the Rate knob. Only affects Drift and FreezeDrift modes.

Outputs:

PortTypeNotes
SpectralSpectralSpectral data with manipulated instantaneous frequencies. Magnitudes are unmodified except in FreezeDrift mode where they are replaced by the frozen capture.

Pitch Correct (SpectralPitchCorrect)

Auto-tune - pitch detection + scale snapping + spectral correction

let node = SpectralPitchCorrect.add("my_spectralpitchcorrect");

Automatic pitch correction (auto-tune). Detects the fundamental pitch via Harmonic Product Spectrum, snaps it to the nearest note in the configured scale, and shifts the spectrum to correct.

Pitch detection runs on the first channel of the last spectral frame. The detected MIDI note is smoothed (0.7 EMA) to filter frame-to-frame jitter, then snapped to the nearest in-scale note. The correction amount is the difference between the snapped target and the smoothed detection. Speed controls convergence: at 0 the correction applies instantly (hard-tune effect), at 1 it glides very slowly (transparent correction). Notes further from the nearest scale tone than Range semitones are left uncorrected. The spectral shift uses the same bin interpolation as Spectral Shift. Detected pitch is output as V/Oct for free pitch tracking. Correction amount is output as bipolar CV (clamped to one semitone).

Properties:

PropertyMethodTypeDefaultRange
Speedspeed()Float00..1
Keykey()Enumenum(0)C, C#, D, D#, E, F, F#, G, G#, A, A#, B
Scalescale()Enumenum(0)Chromatic, Major, Minor, Pentatonic
Sensitivitysensitivity()Float0.10..1
Rangerange()Float20.5..12
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to pitch-correct. Required - produces no output without a connection. Needs valid sample_rate and fft_size for pitch detection.

Outputs:

PortTypeNotes
SpectralSpectralPitch-corrected spectral data with shifted bins and scaled instantaneous frequencies.
PitchVOctDetected fundamental pitch as V/Oct. Derived from the raw (unsmoothed) MIDI note: (note - 69) / 12. Useful for pitch tracking even if correction is disabled.
CorrectionControlBipolarSmoothed correction amount as bipolar CV, clamped to the -1..+1 range (one semitone each direction). Useful for visualizing or modulating other parameters based on how far the pitch is being adjusted.

Spectral Analyze (SpectralAnalyze)

Audio to spectral data (forward FFT with phase vocoder)

let node = SpectralAnalyze.add("my_spectralanalyze");

Converts stereo audio into spectral data using forward FFT with phase vocoder analysis. This is the entry point for the spectral processing chain.

Connect the output to any spectral effect, then into Spectral Synthesize to return to audio. FFT Size trades frequency resolution for latency: 512 = ~11 ms, 1024 = ~21 ms, 2048 = ~43 ms, 4096 = ~85 ms at 48 kHz. Higher overlap (4x vs 2x) produces smoother results at more CPU cost. Low Freq and High Freq set the analysis range and are baked into every downstream SpectralBuffer so nodes like Spectral Split and Spectral Rotate inherit them automatically. The analyzer rebuilds when FFT Size or Overlap change.

Properties:

PropertyMethodTypeDefaultRange
FFT Sizefft_size_prop()Enumenum(2)S512, S1024, S2048, S4096
Overlapoverlap_prop()Enumenum(1)2x, 4x
Low Freqlow_freq()Float2020..500
High Freqhigh_freq()Float200002000..22000

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to analyze. Each channel is processed independently through the phase vocoder.

Outputs:

PortTypeNotes
SpectralSpectralSpectral magnitude, phase, and instantaneous frequency data. Connect to any spectral effect or directly to Spectral Synthesize.

Spectral Cross (SpectralCross)

Morph or vocode between two spectral sources

let node = SpectralCross.add("my_spectralcross");

Morphs between two spectral sources. In Blend mode, crossfades magnitudes, phases, and frequencies for smooth timbral transitions. In Vocoder mode, crossfades magnitudes while locking phase and frequency to input B.

Requires both inputs for crossfading. If only one input is connected, that signal passes through unmodified. Both inputs must share the same bin count - a mismatch produces silence with a logged error. Mix at 0.0 gives pure A; at 1.0 gives pure B. The Mix Mod CV input adds to the Mix knob (clamped 0-1). Output Gain is applied to the crossfaded magnitudes. In Vocoder mode, A provides the spectral envelope (magnitude) and B provides the pitch structure (phase + inst_freq), enabling spectral vocoding at full FFT resolution without band quantization.

Properties:

PropertyMethodTypeDefaultRange
Mixmix()Float0.50..1
Modemode()Enumenum(0)Blend, Vocoder
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
Spectral ASpectralrequired; First spectral source. Provides the spectral envelope (magnitudes) in Vocoder mode. Passes through if B is disconnected.
Spectral BSpectralrequired; Second spectral source. Provides the pitch structure (phase + inst_freq) in Vocoder mode. Passes through if A is disconnected. Must match A's bin count.
Mix ModControlNormrequired; CV added to the Mix knob. Combined total is clamped 0-1.

Outputs:

PortTypeNotes
SpectralSpectralBlended or vocoded spectral data. Uses A's metadata (FFT size, sample rate, frequency range) for the output buffer.

Spectral Delay (SpectralDelay)

Per-bin frequency-dependent delay with feedback

let node = SpectralDelay.add("my_spectraldelay");

Delays individual frequency bins independently, creating "frequency waterfall" effects impossible with conventional delay.

Each bin has its own delay line sized from the hop rate. The Time property sets the base delay for all bins. Spread offsets delay time linearly across the spectrum: positive values delay low frequencies more (bin_frac < 0.5 gets added time), negative values delay high frequencies more. Feedback mixes the delayed magnitude back into the delay line tail, building resonant spectral echoes (capped at 0.95 to prevent runaway). Phases and instantaneous frequencies pass through undelayed. The Time Mod CV input scales 0-1 to 0-2 seconds and adds to the Time knob. Delay lines rebuild whenever the upstream bin count or channel count changes.

Properties:

PropertyMethodTypeDefaultRange
Timetime()Float0.50.01..2
Spreadspread()Float0-1..1
Feedbackfeedback()Float00..0.95
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to delay. Required - produces no output without a connection.
Time ModControlNormrequired; CV added to the Time knob. 0-1 maps to 0-2 seconds. Combined total is clamped to the valid delay range.

Outputs:

PortTypeNotes
SpectralSpectralSpectral data with per-bin delayed magnitudes. Phases and instantaneous frequencies are undelayed.

Spectral Denoise (SpectralDenoise)

Noise profile capture + spectral subtraction

let node = SpectralDenoise.add("my_spectraldenoise");

Removes steady-state noise via spectral subtraction. Capture a noise profile during a noise-only passage, then the node continuously subtracts that profile from the signal.

Workflow: connect Signal, optionally connect Reference, trigger Learn Gate (or toggle Learn) during noise-only audio, then release to apply. The noise profile is accumulated using EMA smoothing from the Reference input - or from Signal if Reference is disconnected. Subtraction always applies to Signal. Each bin's magnitude is reduced by (noise_profile * Reduction) and clamped to Floor to prevent musical noise artifacts. Before a profile is captured, Signal passes through unchanged. Phases and instantaneous frequencies are unmodified.

Properties:

PropertyMethodTypeDefaultRange
Reductionreduction()Float10..2
Smoothingsmoothing()Float0.80..1
Floorfloor()Float0.0010..0.1
Learnlearn()Boolfalse
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SignalSpectralrequired; Spectral signal to denoise. Subtraction is applied here. Required - produces no output without a connection. Passes through unchanged before a noise profile is learned.
ReferenceSpectralrequired; Noise reference source for learning. When disconnected, learning captures from Signal instead. Connect a separate noise-only source here for cleaner profiles.
Learn GateGaterequired; Rising edge starts learning, falling edge stops. Either the gate or the Learn toggle can activate learning independently.

Outputs:

PortTypeNotes
SpectralSpectralDenoised spectral data with noise profile subtracted from magnitudes. Phases and instantaneous frequencies are unmodified.

Spectral Freeze (SpectralFreeze)

Gate captures the current spectrum and holds it indefinitely

let node = SpectralFreeze.add("my_spectralfreeze");

Captures the current spectrum and holds it indefinitely, producing a sustained drone from any input.

On the rising edge of the Freeze toggle or Gate input, magnitudes from the first available frame are captured and held. While frozen, these captured magnitudes replace the live signal's magnitudes every frame. Phases and instantaneous frequencies pass through unmodified, so the downstream synthesizer's phase accumulator keeps evolving - producing a naturally shifting texture rather than a static buzz. Output Gain is applied to magnitudes during freeze; when not frozen, signal passes through unchanged. The Gate input overrides the Freeze toggle: a rising edge activates freeze regardless of the toggle state.

Properties:

PropertyMethodTypeDefaultRange
Freezefreeze()Boolfalse
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to freeze. Passes through unmodified when not frozen. Required - produces no output without a connection.
GateGaterequired; Rising edge captures the current spectrum and activates freeze. Overrides the Freeze toggle - freeze stays active as long as either the gate or toggle is high.

Outputs:

PortTypeNotes
SpectralSpectralFrozen spectral data: captured magnitudes with live phases and instantaneous frequencies from the input signal.

Spectral Granular (SpectralGranular)

Spectral-domain granular processor with frame buffer and pitch shifting

let node = SpectralGranular.add("my_spectralgranular");

Spectral-domain granular processor. Captures spectral frames into a circular buffer and replays them as overlapping grains with per-grain pitch shifting.

Sits in the standard Analyze -> Effect -> Synthesize chain. Grains are scheduled at the Density rate and last for Size spectral frames. Each grain reads from a jittered Position in the frame buffer with pitch shifting via bin interpolation (same technique as Spectral Shift). Multiple grains are mixed by summing magnitudes (divided by active grain count) with winner-take-all phase selection - the grain with the highest magnitude at each bin determines the output phase and instantaneous frequency. Grain envelopes use a raised cosine window controlled by Blend (0 = rectangular, 1 = maximum fade). The Freeze gate stops recording into the buffer, letting grains play from a fixed snapshot. When the buffer is empty, input passes through directly.

Properties:

PropertyMethodTypeDefaultRange
Bufferbuffer_frames()Int12832..512
Densitydensity()Float80.5..50
Sizesize()Int164..64
Positionposition()Float00..1
Pitchpitch()Float0-24..24
Jitterjitter()Float0.10..1
Max Grainsmax_grains()Int81..32
Blendblend()Float0.50..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Source spectral data, continuously recorded into the frame buffer. Required - passes through directly when the buffer is empty.
FreezeGaterequired; Rising edge freezes buffer recording; falling edge resumes. Grains continue playing from the frozen buffer contents.
Position ModControlNormrequired; CV added to the Position knob. Combined total is clamped 0-1.
Density ModControlNormrequired; CV scaled to the density range and added to the Density knob. Combined total is clamped to valid bounds.
Size ModControlNormrequired; CV scaled to a 60-frame range and added to the Size property. Combined total is clamped to valid bounds.

Outputs:

PortTypeNotes
Spectral OutSpectralMixed grain output: summed magnitudes (normalized by active grain count) with winner-take-all phase selection.

Spectral Join (SpectralJoin)

Recombines per-band spectral data from Spectral Split

let node = SpectralJoin.add("my_spectraljoin");

Recombines per-band spectral data into a single full spectrum. The dual of Spectral Split - connect processed band outputs here to merge them back into one spectral stream for Spectral Synthesize.

For each bin, the input with the highest magnitude wins (winner-take-all): phase and instantaneous frequency come from that same input. When bands from Spectral Split do not overlap, each bin comes from exactly one input with no ambiguity. The output uses metadata (FFT size, sample rate, frequency range) from the first connected input.

Properties:

PropertyMethodTypeDefaultRange
Bandsbands()Int41..64

Inputs:

PortTypePropertiesNotes
BandSpectralunbounded; required; Per-band spectral data from Spectral Split or per-band effects. Only connected inputs contribute; disconnected ports are skipped. When no inputs are connected, no output is produced.

Outputs:

PortTypeNotes
SpectralSpectralMerged full-spectrum spectral data ready for Spectral Synthesize or further spectral effects.

Spectral Mask (SpectralMask)

Drawable per-bin frequency filter with live spectrum overlay

let node = SpectralMask.add("my_spectralmask");

Drawable frequency filter that multiplies each bin's magnitude by a user-drawn curve. Sculpt the spectrum to boost, cut, or isolate any frequency region.

The mask curve is drawn on a logarithmic frequency axis (20 Hz - 20 kHz) in the Band Curve Editor. Each FFT bin is mapped to its LogFreqT position and the curve is evaluated there, so the resolution follows the FFT size. Values above 1.0 boost that frequency region; 0.0 silences it. The curve is recomputed whenever upstream FFT parameters change (bin count, sample rate, FFT size). A live spectrum overlay displays the first channel's magnitudes in real time. Output Gain is multiplied into each bin alongside the mask value.

Properties:

PropertyMethodTypeDefaultRange
Maskmask()Curve[curve]
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to filter. Required - produces no output without a connection. Provides FFT parameters used to map curve positions to frequency bins.

Outputs:

PortTypeNotes
SpectralSpectralSpectral data with per-bin magnitudes scaled by the mask curve and Output Gain. Phases and instantaneous frequencies are unmodified.

Spectral Rotate (SpectralRotate)

Circular bin rotation on the spectral bus

let node = SpectralRotate.add("my_spectralrotate");

Circular rotation of FFT bins by band-aligned offsets. Creates inharmonic, metallic textures or repositions the spectrum before Spectral Split.

Uses the same log-spaced band mapping as Spectral Split (derived from the upstream SpectralBuffer's frequency range and FFT size), so rotating by N shifts by exactly N Split bands worth of bins. Rotation wraps circularly - bins shifted past Nyquist reappear at DC. Magnitudes are scaled by Output Gain during rotation. Phases and instantaneous frequencies move with their bins unmodified. The Rotate Mod input is bipolar, scaled to the band count, and added to the Rotate property. Zero rotation passes through without processing.

Properties:

PropertyMethodTypeDefaultRange
Bandsbands()Int82..64
Rotaterotate()Int0-64..64
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to rotate. Required - produces no output without a connection.
Rotate ModControlBipolarrequired; Bipolar CV scaled to the band count and added to Rotate. -1 rotates by -N bands, +1 rotates by +N bands.

Outputs:

PortTypeNotes
SpectralSpectralSpectral data with circularly rotated bins, magnitudes, phases, and instantaneous frequencies.

Spectral Shift (SpectralShift)

Pitch shift via spectral bin shifting (±24 semitones)

let node = SpectralShift.add("my_spectralshift");

Pitch-shifts the spectrum by moving FFT bins up or down without changing playback speed.

Computes a frequency ratio from the semitone shift (2^(st/12)), then for each output bin, reads from a fractional source bin using linear interpolation on magnitudes. Instantaneous frequencies are taken from the nearest source bin and scaled by the ratio. Bins that would read beyond the spectrum stay zeroed. When shift is near zero and gain is unity, the signal passes through without processing. The Shift Mod input adds a bipolar offset scaled to the full range.

Properties:

PropertyMethodTypeDefaultRange
Shiftshift()Float0-24..24
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to pitch-shift. Required - produces no output without a connection.
Shift ModControlBipolarrequired; Bipolar CV added to the Shift value. -1 maps to -24 st, +1 maps to +24 st. Combined total is clamped to the full range.

Outputs:

PortTypeNotes
SpectralSpectralPitch-shifted spectral data with interpolated magnitudes and scaled instantaneous frequencies.

Spectral Smear (SpectralSmear)

Temporal magnitude smoothing for ambient textures

let node = SpectralSmear.add("my_spectralsmear");

Applies temporal smoothing to per-bin magnitudes, blurring the spectrum over time. Low values add subtle sustain; high values create evolving ambient washes.

Uses an exponential moving average per bin: each frame blends the stored average with the incoming magnitude using the Smear factor as the EMA coefficient. At maximum, approaches infinite hold similar to Spectral Freeze but with gradual accumulation rather than a hard capture. When Smear is near zero, averages are reset and signal passes through. Phases and instantaneous frequencies are unmodified. The Smear Mod CV input adds to the Smear knob value (clamped 0-1).

Properties:

PropertyMethodTypeDefaultRange
Smearsmear()Float00..1
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Spectral data to smooth. Required - produces no output without a connection.
Smear ModControlNormrequired; CV added to the Smear knob value. Combined total is clamped 0-1.

Outputs:

PortTypeNotes
SpectralSpectralTemporally smoothed spectral data with EMA-blended magnitudes and original phases.

Spectral Split (SpectralSplit)

Partitions spectral data into N frequency bands

let node = SpectralSplit.add("my_spectralsplit");

Partitions spectral data into N logarithmically-spaced frequency bands. Patch any effect between Split and Join to make it spectral - delay becomes spectral delay, distortion becomes spectral distortion.

Each output carries a SpectralBuffer with only that band's bins populated (all others zeroed). Pure spectral routing - no FFT/IFFT happens here. The typical chain is Spectral Analyze -> Split -> per-band effects -> Join -> Spectral Synthesize. Band boundaries use log-frequency spacing derived from the upstream Analyze node's Low Freq, High Freq, and FFT Size. Inherent latency equals the upstream FFT size in samples (~21 ms at 1024/48 kHz).

Properties:

PropertyMethodTypeDefaultRange
Bandsbands()Int82..64

Inputs:

PortTypePropertiesNotes
SpectralSpectralrequired; Full-spectrum spectral data from Spectral Analyze or another spectral effect. Provides bin count, frequency range, and sample rate used to compute band boundaries.

Outputs:

PortTypeNotes
BandSpectralunbounded; One output per band, each containing only the bins for that frequency region. Connect to per-band effects, then into Spectral Join to recombine.

Spectral Synthesize (SpectralSynthesize)

Spectral data to audio (inverse FFT with phase vocoder)

let node = SpectralSynthesize.add("my_spectralsynthesize");

Converts spectral data back into stereo audio using inverse FFT with overlap-add reconstruction. This is the exit point of the spectral processing chain.

Accepts one or many spectral inputs and produces a matching number of stereo audio outputs. Each input/output pair runs its own synthesizer, but all share FFT plans for efficiency. Synthesizers are lazily created on first data - FFT parameters (size, overlap) come from the upstream SpectralBuffer. Set the Channels property to match the number of spectral inputs you intend to connect.

Properties:

PropertyMethodTypeDefaultRange
Channelschannels()Int41..64
Output Gainoutput_gain()Float10..4

Inputs:

PortTypePropertiesNotes
SpectralSpectralunbounded; required; Spectral data from Spectral Analyze, spectral effects, or Spectral Split bands. Each connected input creates a dedicated synthesizer.

Outputs:

PortTypeNotes
AudioAudiounbounded; Reconstructed stereo audio. Output index matches the corresponding spectral input index.

Utility

Audio ➔ Control (AudioToControl)

Converts audio-rate signals to control-rate by sampling first sample of buffer

let node = AudioToControl.add("my_audiotocontrol");

Samples the first stereo frame of each audio buffer, downmixes to mono ((L+R)/2), and outputs the result as a control-rate value.

Only the first sample of each buffer is used -- subsequent samples are ignored. The output updates once per buffer at whatever the graph's block size is. Useful for driving parameters from audio-rate signals like envelopes or LFOs running through the audio bus.

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to sample.

Outputs:

PortTypeNotes
Control OutControlNormMono-downmixed amplitude as a normalized control value.

Burst Generator (BurstGenerator)

Single trigger → N evenly-spaced trigger pulses with acceleration

let node = BurstGenerator.add("my_burstgenerator");

Fires a rapid burst of gate pulses from a single trigger.

Each rising edge on Trigger starts a burst of Count pulses at the configured Rate. Pulses have a 50% duty cycle. Acceleration divides each successive interval: >1.0 speeds up (accelerando), <1.0 slows down (ritardando), 1.0 is even spacing. A retrigger during an active burst restarts from the beginning. The minimum interval is clamped at 5 ms to prevent degenerate pulse widths.

Properties:

PropertyMethodTypeDefaultRange
Countcount()Int41..32
Raterate()Float101..100
Accelacceleration()Float10.25..4

Inputs:

PortTypePropertiesNotes
TriggerGaterequired; Rising edge starts a new burst.

Outputs:

PortTypeNotes
GateGateBurst pulse train output.

Clipper (Clipper)

Audio clipping and saturation with hard and soft modes

let node = Clipper.add("my_clipper");

Clips or saturates a stereo audio signal. Each stereo channel is processed independently per sample.

In Hard mode the signal hits a symmetric brick wall at +/- threshold. In Soft mode tanh saturation provides a warmer overdrive character that smoothly approaches the ceiling. The threshold is per-sample smoothed to prevent clicks when adjusted. Lower threshold values clip harder.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold()Float0.950.1..1
Modemode()Enumenum(1)Hard, Soft

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to clip.

Outputs:

PortTypeNotes
Audio OutAudioClipped stereo audio.

Clock (Clock)

Generates precise timing gate signals

let node = Clock.add("my_clock");

Free-running clock source that emits gate pulses at a configurable frequency.

Each cycle begins with the gate going high for the pulse width duration, then low for the remainder of the period. The pulse width is capped at 90% of the period to guarantee a falling edge even at high frequencies. A Rate Mod CV replaces the Frequency property with an exponential mapping from 0--1 across 0.01--1000 Hz. A Reset rising edge zeros the phase for sync.

Properties:

PropertyMethodTypeDefaultRange
Frequencyfrequency()Float10.01..1000
Pulse Widthpulse_width()Float101..100

Inputs:

PortTypePropertiesNotes
Rate ModControlNormReplaces the Frequency property with an exponential mapping: 0.0 = 0.01 Hz, 1.0 = 1000 Hz.
ResetGateRising edge resets the clock phase to zero.

Outputs:

PortTypeNotes
Gate OutGateClock pulse output.

Clock Div/Mult (ClockDivider)

Divide or multiply incoming clock triggers by an integer ratio

let node = ClockDivider.add("my_clockdivider");

Divides or multiplies an incoming clock by an integer ratio.

In Divide mode, a rising edge passes through every N-th input trigger; falling edges only pass when the counter is at zero. In Multiply mode, the node measures the period between incoming triggers and emits N evenly-spaced subdivisions within that period, each with a 50% duty cycle. The first incoming trigger establishes the period -- no subdivisions are emitted until the second trigger arrives. A Reset rising edge zeros the counter.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Divide, Multiply
Ratioratio()Int21..32

Inputs:

PortTypePropertiesNotes
ClockGaterequired; Incoming clock trigger to divide or multiply.
ResetGateRising edge resets the internal counter.

Outputs:

PortTypeNotes
GateGateDivided or multiplied clock output.

Comparator (Comparator)

Threshold comparison on continuous signals, outputs gate

let node = Comparator.add("my_comparator");

Compares a continuous control signal against a threshold and outputs a gate. Schmitt trigger hysteresis prevents chattering.

The hysteresis creates a dead band: for > and >= modes, the gate turns on when the input exceeds threshold + hysteresis/2 and stays on until it drops below threshold - hysteresis/2 (and vice versa for < and <=). A Threshold Mod CV replaces the property value when connected. The input defaults to 0.0 when disconnected.

Properties:

PropertyMethodTypeDefaultRange
Compareop()Enumenum(0)>, <, >=, <=
Thresholdthreshold()Float0.5-1..1
Hysteresishysteresis()Float0.010..0.2

Inputs:

PortTypePropertiesNotes
InputControlBipolarrequired; Signal to compare against the threshold.
ThresholdControlBipolarReplaces the Threshold property value when connected.

Outputs:

PortTypeNotes
GateGateHigh when the comparison is true, low otherwise.

Constant (Constant)

Outputs a constant value as configuration data

let node = Constant.add("my_constant");

Outputs a fixed value as structured data on every buffer.

Set the type (Number, String, Bool, FilePath, or Resource) and the corresponding value, then wire the Data output to any node that expects configuration. Changing the type resets the value to a default for that type. The output is a boxed ConstantValue enum on a Data port.

Properties:

PropertyMethodTypeDefaultRange
Typevalue_type()Enumenum(0)Number, String, Bool, FilePath, Resource
Numbernumber_value()Float0-1000000..1000000
Stringstring_value()String
Boolbool_value()Boolfalse
File Pathfile_path_value()String
Resourceresource_value()String

Outputs:

PortTypeNotes
Data OutData(Unknown)The constant value as structured data.

Control Converter (ControlConverter)

Converts between control signal types with proper range mapping

let node = ControlConverter.add("my_controlconverter");

Accepts any control-family signal and produces correctly converted outputs for every signal type simultaneously.

The node detects the source port type at process time and applies proper conversion math. Norm uses linear 0--1 mapping; Bipolar maps -1..1 to 0..1 linearly; ControlFreq uses log-scale normalization across 20--20000 Hz. Generic Control is treated as already 0--1 for Norm and clamped to -1..1 for Bipolar.

Audio output is dual-mono stereo from the normalized value. V/Oct is derived by converting through frequency first (relative to middle C at 261.63 Hz). Gate goes high when the normalized value reaches 0.5 and low when it drops below, with edge detection. The raw Control output passes through unchanged.

Inputs:

PortTypePropertiesNotes
InputControl, ControlNorm, ControlBipolar, ControlFreqrequired; Any control-family signal (Control, Norm, Bipolar, Freq).

Outputs:

PortTypeNotes
ControlControlRaw input value passed through with no conversion.
NormControlNormNormalized 0.0--1.0 output.
BipolarControlBipolarBipolar -1.0--1.0 output.
FreqControlFreqFrequency in Hz. Norm/Bipolar sources are exponentially mapped across the audible range; ControlFreq is clamped; generic Control is treated as Hz and clamped.
AudioAudioDual-mono stereo audio from the normalized value.
VOctVOctV/Oct pitch CV derived from frequency conversion.
GateGateGate high when normalized value >= 0.5.

Control Mapper (ControlMapper)

Maps control signals from one range to another

let node = ControlMapper.add("my_controlmapper");

Linearly rescales a control signal from one range to another.

The input value is normalized against the Input Min/Max range, then mapped to the Output Min/Max range. If the input range has zero width the output defaults to Output Min. With Clamp enabled, the output is constrained to the output bounds. With Clamp off, values outside the input range extrapolate beyond the output range. Inverted ranges (min > max) are supported for reverse mapping.

Properties:

PropertyMethodTypeDefaultRange
Input Mininput_min()Float0-1000..1000
Input Maxinput_max()Float1-1000..1000
Output Minoutput_min()Float0-10000..10000
Output Maxoutput_max()Float1-10000..10000
Clampclamp()Booltrue

Inputs:

PortTypePropertiesNotes
Control InControlrequired; Control signal to remap.

Outputs:

PortTypeNotes
Control OutControlRescaled control signal.

Control Math (ControlMath)

Two-input control math: add, subtract, multiply, min, max, crossfade

let node = ControlMath.add("my_controlmath");

Two-input math on control-rate signals. Combine, compare, or crossfade a pair of normalized control values.

Disconnected inputs default to 0.0. Add and Subtract results are clamped to 0.0--1.0. Multiply, Min, and Max are unclamped. Crossfade uses the Mix property: 0.0 = all A, 1.0 = all B. Unlike SignalMathNode this operates at control rate (one value per buffer, no per-sample smoothing on Mix).

Properties:

PropertyMethodTypeDefaultRange
Operationop()Enumenum(0)Add, Subtract, Multiply, Min, Max, Crossfade
Mixmix()Float0.50..1

Inputs:

PortTypePropertiesNotes
AControlNormFirst control operand (0.0--1.0).
BControlNormSecond control operand (0.0--1.0).

Outputs:

PortTypeNotes
OutControlNormResult of the selected operation (0.0--1.0).

Control Scale (ControlScale)

Scales normalized control (0-1) to frequency range in Hz

let node = ControlScale.add("my_controlscale");

Scales a normalized 0--1 control value to a frequency range in Hz using linear interpolation between Min Hz and Max Hz.

The input is clamped to 0--1 before scaling. Min Hz must be less than Max Hz. Useful for converting LFO or knob output into a frequency modulation signal for oscillators and filters.

Properties:

PropertyMethodTypeDefaultRange
Min Hzmin_hz()Float2020..20000
Max Hzmax_hz()Float2000020..20000

Inputs:

PortTypePropertiesNotes
Control InControlNormrequired; Normalized control input (0.0--1.0).

Outputs:

PortTypeNotes
Frequency OutControlFreqScaled frequency in Hz.

Control Slew (ControlSlew)

Smooth control signal transitions with independent rise and fall rates

let node = ControlSlew.add("my_controlslew");

Rate-limiter for control signals with independent rise and fall times.

Smooths abrupt parameter changes into gradual transitions. The slew operates at control rate (once per buffer): the maximum change per buffer is buffer_duration / slew_time. Rise time governs upward movement, fall time governs downward. At 0 seconds the output tracks the input instantly. Output is clamped to 0--1. On the first buffer, the output jumps to the input value with no slew. Useful for lag processing, portamento on control values, or envelope-like shaping of knob movements.

Properties:

PropertyMethodTypeDefaultRange
Rise Timerise_time()Float0.10..10
Fall Timefall_time()Float0.10..10

Inputs:

PortTypePropertiesNotes
Control InControlNormrequired; Control signal to smooth.

Outputs:

PortTypeNotes
Control OutControlNormSmoothed control output (0.0--1.0).

Crossfade (Crossfade)

Smooth blend between two audio inputs

let node = Crossfade.add("my_crossfade");

Smooth blend between two audio inputs with per-sample smoothing on the position parameter.

Linear mode: gain_A = 1-pos, gain_B = pos. Equal-power mode uses sin/cos curves for constant loudness across the crossfade range. A Position Mod CV replaces the property value when connected; when disconnected the smoother tracks the property. Disconnected audio inputs contribute silence, so a single connected input acts as a fade in/out. Both inputs disconnected reports Silent.

Properties:

PropertyMethodTypeDefaultRange
Positionposition()Float00..1
Curvecurve()Enumenum(0)Linear, EqualPower

Inputs:

PortTypePropertiesNotes
Input AAudioAudio input A (heard at Position 0.0).
Input BAudioAudio input B (heard at Position 1.0).
PositionControlNormCV control over crossfade position (0.0 = A, 1.0 = B).

Outputs:

PortTypeNotes
OutputAudioBlended audio output.

Curve Function (CurveFunctionGenerator)

Drawable signal→signal transfer function for waveshaping and CV remapping

let node = CurveFunctionGenerator.add("my_curvefunctiongenerator");

Drawable signal-to-signal transfer function. Maps audio or control input through a user-drawn spline curve.

For audio, each sample is driven by InputGain, clamped to -1..1, normalized to 0..1 for the curve lookup, then denormalized back to -1..1 and scaled by OutputGain. The Mix knob blends the shaped (wet) signal with the original (dry) per-sample with smoothing.

For control, the input is evaluated through the curve once per buffer without smoothing. InputGain and OutputGain only affect the audio path. Both audio and control paths can operate simultaneously through the same curve. A Mix CV overrides the property value when connected.

Properties:

PropertyMethodTypeDefaultRange
Curvecurve_data()Curve[curve]
Input Gaininput_gain()Float10.1..4
Output Gainoutput_gain()Float10.1..4
Mixmix()Float10..1

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Audio signal for per-sample waveshaping.
ControlControlNormrequired; Control signal for CV remapping (evaluated once per buffer).
Mix CVControlNormrequired; Modulates dry/wet mix.

Outputs:

PortTypeNotes
AudioAudioShaped audio output.
ControlControlNormShaped control output.

Debug (Debug)

Comprehensive debug node for testing all proc macro features

let node = Debug.add("my_debug");

Diagnostic probe for inspecting signals in the graph. Accepts any signal type on unbounded inputs.

In Passthrough mode, the first connected input is forwarded to the output unchanged; remaining inputs are ignored. In Monitor and Analyze modes, all inputs are consumed (force-pulled to keep upstream nodes processing) but the output is silence. When Enabled is on, the node periodically emits a debug_tick custom event and increments the read-only EmitCount property at the configured interval. The output port type locks to the first connected input type.

Properties:

PropertyMethodTypeDefaultRange
Inputsinputs()Int41..64
Emit Intervalemit_interval()Float10..10
Emit Countemit_count()Int00..1000000
Enabledenabled()Booltrue0..1
Modemode()Enumenum(0)Passthrough, Monitor, Analyze

Inputs:

PortTypePropertiesNotes
InputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), Imagegain()unbounded; Any signal type -- connect as many sources as needed.

Outputs:

PortTypeNotes
OutputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), ImageFirst input forwarded (Passthrough mode) or silence (Monitor/Analyze).

Discontinuity Detector (DiscontinuityDetector)

Detects and logs sudden jumps in audio signal (clicks/pops)

let node = DiscontinuityDetector.add("my_discontinuitydetector");

Monitors an audio stream for sudden sample-to-sample jumps that indicate clicks, pops, or buffer-boundary artifacts.

Computes the absolute difference between consecutive samples on each stereo channel independently and reports when the larger of the two exceeds the threshold. When Log to Console is enabled, each detection emits a tracing warning with the sample offset and per-channel deltas. Pass Through controls whether audio reaches the output or is replaced with silence, allowing silent monitoring. Internal counters track total detections and maximum discontinuity magnitude.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold()Float0.10.001..1
Log to Consolelog_to_console()Booltrue
Pass Throughpass_through()Booltrue

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Audio signal to monitor for discontinuities.

Outputs:

PortTypeNotes
Audio OutAudioPass-through audio (or silence if pass-through is off).

Euclidean Rhythm (EuclideanRhythm)

Evenly distributed rhythmic patterns via the Bjorklund algorithm

let node = EuclideanRhythm.add("my_euclideanrhythm");

Distributes N hits as evenly as possible across M steps using the Bjorklund algorithm.

On each clock rising edge the pattern advances one step. If the current step is a hit and the gate is low, a rising edge is emitted. On a clock falling edge the gate always goes low. This means the output gate width matches the input clock pulse width. A Reset rising edge returns the step counter to zero. Rotation shifts the pattern start position. The pattern recomputes whenever Hits, Steps, or Rotation changes.

Properties:

PropertyMethodTypeDefaultRange
Hitshits()Int30..32
Stepssteps()Int81..32
Rotationrotation()Int00..31

Inputs:

PortTypePropertiesNotes
ClockGaterequired; Clock input -- each rising edge advances the pattern one step.
ResetGateRising edge resets the step counter to zero.

Outputs:

PortTypeNotes
GateGateGate high on hit steps, low on rests.

Fade (Fade)

Gate-triggered audio fade in/out

let node = Fade.add("my_fade");

Smoothly fades audio in and out with independent fade times.

Two trigger modes: the Level input (ControlNorm) takes priority when connected -- values at or above the Gate Threshold trigger fade in, below triggers fade out. This lets Arranger track outputs wire directly without a converter. When Level is not connected, the Gate input drives the fade via edge detection.

The fade is linear per-sample: each sample advances the internal gain by 1/(fade_time * sample_rate). When fully faded out with the gate low, the node reports Silent for optimization.

Properties:

PropertyMethodTypeDefaultRange
Fade Infade_in()Float1000.5..5000
Fade Outfade_out()Float1000.5..5000
Gate Thresholdgate_threshold()Float0.50..1

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Audio signal to fade.
GateGateGate input - rising edge triggers fade in, falling edge triggers fade out. Ignored when the Level input is connected.
LevelControlNormControlNorm level input. When connected, overrides the Gate input. Values at or above the Gate Threshold trigger fade in; below triggers fade out. Wire Arranger track outputs here directly.

Outputs:

PortTypeNotes
Audio OutAudioFaded audio output.

Flip-Flop (FlipFlop)

Toggles between two audio inputs on gate trigger with smooth crossfading

let node = FlipFlop.add("my_flipflop");

Routes one of two audio inputs to the output, toggling on each gate trigger with smooth crossfading.

Gate priority: Set forces A (active_b = false), Reset forces B (active_b = true), Toggle flips the state. All three are evaluated per buffer in that order. A Crossfade CV overrides the toggle state entirely when connected: 0.0 = A, 1.0 = B, with intermediate values blending. The State gate output tracks the toggle state (high = B active). Disconnected audio inputs contribute silence.

Properties:

PropertyMethodTypeDefaultRange
Crossfadecrossfade_time()Float50..1000

Inputs:

PortTypePropertiesNotes
AAudioFirst audio source (selected when toggle is off).
BAudioSecond audio source (selected when toggle is on).
ToggleGateRising edge flips between A and B.
SetGateRising edge forces output to A (clears active_b).
ResetGateRising edge forces output to B (sets active_b).
CrossfadeControlNormCV mix override (0.0 = A, 1.0 = B). Overrides toggle state.

Outputs:

PortTypeNotes
AudioAudioCrossfaded audio from A and B.
StateGateGate high when B is active, low when A is active.

Gain (Gain)

Amplify or attenuate audio signal

let node = Gain.add("my_gain");

Simple volume control for a stereo audio signal with per-sample smoothing to avoid clicks.

The Gain Mod CV input, when connected, replaces the property value: ControlNorm 0.0--1.0 maps to gain 0.0--2.0. When disconnected the smoother tracks the property value. Both paths go through the same smoother so transitions are always clean.

Properties:

PropertyMethodTypeDefaultRange
Gainamount()Float10..4

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to amplify or attenuate.
Gain ModControlNormReplaces the property value. 0.0 = silence, 0.5 = unity, 1.0 = 2x.

Outputs:

PortTypeNotes
Audio OutAudioGained stereo audio.

Gate Converter (GateConverter)

Converts gate events to Audio or Control signals based on output connection.

let node = GateConverter.add("my_gateconverter");

Converts gate events into Audio, Control, or Gate output depending on what the output port is connected to.

The conversion target is set automatically when the output is wired. Audio mode produces stereo dual-mono 0.0/1.0 steps with instant transitions on gate edges. Control mode applies one-pole attack/release smoothing from 0.0 to 1.0 -- the envelope advances by one sample per buffer, so attack/release times interact with buffer size at very short settings. Gate mode passes events through unchanged. When disconnected, the output reverts to accepting any of the three types.

Properties:

PropertyMethodTypeDefaultRange
Attackattack()Float50.1..1000
Releaserelease()Float1001..5000

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Gate events to convert.

Outputs:

PortTypeNotes
OutputAudio, Control, GateConverted signal (Audio, Control, or Gate based on connection).

Gate Curve (GateCurve)

Transport-synced gate pattern from a drawn curve

let node = GateCurve.add("my_gatecurve");

Transport-synced gate pattern from a drawn curve. Outputs gate edges at threshold crossings and the raw curve value as a control signal.

The curve is evaluated once per buffer via advance_time against the transport beat position, looping over the configured bar length. The Gate output goes high when the curve value is >= Threshold. The default curve is flat at 1.0 (constant gate high). No inputs; position comes entirely from the transport.

Properties:

PropertyMethodTypeDefaultRange
Curvecurve_data()Curve[curve]
Lengthlength_bars()Int41..64
Looploop()Booltrue
Thresholdthreshold()Float0.50..1

Outputs:

PortTypeNotes
GateGateEdge-detected gate high when the curve value is >= Threshold.
LevelControlNormRaw curve value clamped to 0.0-1.0, independent of the Threshold setting.

Gate Logic (GateLogic)

Boolean logic on two gate inputs (AND, OR, XOR, NOT)

let node = GateLogic.add("my_gatelogic");

Boolean logic on two gate inputs. All five outputs (AND, OR, XOR, NOT A, NOT B) are computed simultaneously every buffer.

Unconnected inputs default to low (false). Gate edges are emitted only on state transitions, so outputs stay silent when the logic result does not change. The node tracks the last event on each input -- if multiple events arrive in one buffer, only the final state matters for the logic evaluation.

Inputs:

PortTypePropertiesNotes
AGateFirst gate operand.
BGateSecond gate operand.

Outputs:

PortTypeNotes
ANDGateHigh only when both A and B are high.
ORGateHigh when either A or B is high.
XORGateHigh when exactly one of A or B is high.
NOT AGateInverted A -- high when A is low.
NOT BGateInverted B -- high when B is low.

Gate Router (ProbabilisticGateRouter)

Routes each gate to one of N outputs by probability, round-robin, or random

let node = ProbabilisticGateRouter.add("my_probabilisticgaterouter");

Routes each incoming gate to exactly one of N outputs based on probability weights, round-robin order, or uniform random selection.

Each gate-on selects a target output; the corresponding gate-off is always sent to the same output. In Weighted mode, per-output Weight properties control relative probability; a CV input shifts probability toward the last output. In RoundRobin mode, outputs are cycled in order regardless of weights. In Random mode, each output has equal probability regardless of weights.

Properties:

PropertyMethodTypeDefaultRange
Outputsoutputs()Int22..16
Modemode()Enumenum(0)Weighted, RoundRobin, Random

Inputs:

PortTypePropertiesNotes
ClockGaterequired; Incoming gate events to distribute.
CVControlNormrequired; Modulates weight distribution in Weighted mode. At 1.0, all probability shifts to the last output. Ignored in other modes.

Outputs:

PortTypeNotes
GateGateunbounded

Grain Scheduler (GrainScheduler)

Stochastic MIDI grain triggers for modular granular synthesis

let node = GrainScheduler.add("my_grainscheduler");

Stochastic MIDI grain trigger generator. Emits overlapping note-on / note-off pairs at a configurable density.

When MIDI In is disconnected, note numbers cycle round-robin through base_note..base_note+Voices-1, mapping to Voice Mixer slots. When MIDI In is connected, held notes form a note pool and the scheduler cycles through those instead -- if the pool is empty no grains fire.

Clock input overrides density: one grain per rising edge. Density and Size Mod CVs are additive to the property values. Jitter randomizes spawn timing; Size Jitter randomizes grain duration; Velocity Jitter randomizes note velocity. In Chord mode all voice slots fire simultaneously per grain with optional stagger spread. If a new grain targets a note that is already active, the old grain is released first to prevent double note-ons.

Properties:

PropertyMethodTypeDefaultRange
Densitydensity()Float100.5..100
Sizesize()Float2005..500
Voicesvoices()Int81..64
Base Notebase_note()Int600..127
Modemode()Enumenum(0)Single, Chord
Staggerstagger()Float50..10
Jitterjitter()Float0.10..1
Size Jittersize_jitter()Float0.10..1
Velocityvelocity()Float10..1
Vel Jittervelocity_jitter()Float00..1

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; Held notes define which notes the scheduler cycles through. When disconnected, notes are generated from BaseNote + Voices.
ClockGaterequired; External clock for synced grain density. One grain per rising edge.
Density ModControlNormrequired; Modulates grain spawn rate.
Size ModControlNormrequired; Modulates grain duration.

Outputs:

PortTypeNotes
MIDI OutMidiGrain triggers as MIDI note-on/note-off events.

Logger (Logger)

Logs port data and passes it through unchanged. Useful for debugging.

let node = Logger.add("my_logger");

Logs signal information to the console and passes data through unchanged. Accepts any port type.

Insert inline to inspect audio levels, control values, MIDI events, gate counts, V/Oct ranges, or data payloads without altering the signal chain. The output port type locks to match the connected input. Audio logs show stereo min/max range; MIDI logs show individual events; empty MIDI buffers are skipped. The node label (if set) prefixes every log line.

Properties:

PropertyMethodTypeDefaultRange
Log Levellog_level()Enumenum(2)Trace, Debug, Info, Warn, Error

Inputs:

PortTypePropertiesNotes
InputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), Imagerequired; Any signal type to log and forward.

Outputs:

PortTypeNotes
OutputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), ImageInput data passed through unchanged.

Micro Tuning (MicroTuning)

Microtonal tuning - divisions/octave and V/Oct offset with CV modulation

let node = MicroTuning.add("my_microtuning");

Microtonal tuning configuration source. Outputs a TuningConfig on a Data port for downstream pitch calculations.

CV inputs are additive: the Divisions CV value is added to the property value, and the Offset CV value is added to the property value, both clamped to their respective ranges after summing. Standard 12-TET is the default (12 divisions, 0 offset).

Properties:

PropertyMethodTypeDefaultRange
Divisions/Octdivisions_per_octave()Float121..128
V/Oct Offsetv_oct_offset()Float0-10..10

Inputs:

PortTypePropertiesNotes
Divisions CVControlFreqModulates divisions/octave (added to property value).
Offset CVControlBipolarModulates V/Oct offset (added to property value).

Outputs:

PortTypeNotes
TuningData(Tuning)TuningConfig for downstream pitch calculations.

Mid/Side (MidSide)

Stereo ↔ mid/side conversion for independent channel processing

let node = MidSide.add("my_midside");

Converts between stereo L/R and mid/side representation.

Encode: M = (L+R)/2, S = (L-R)/2. The left channel of the output carries mid, the right carries side. Decode: L = M+S, R = M-S. The left channel of the input is treated as mid, right as side. Use an Encode→processing→Decode chain for mastering-style EQ, compression, or stereo widening on the mid and side independently.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Encode, Decode

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Stereo audio: L/R for encoding, M/S for decoding.

Outputs:

PortTypeNotes
AudioAudioConverted stereo audio: M/S from encoding, L/R from decoding.

Mixer (Mixer)

Sums multiple audio inputs with per-input gain and pan control

let node = Mixer.add("my_mixer");

Sums multiple stereo audio inputs into a single output with per-input gain and constant-power pan controls, plus a master gain stage.

Each input is gained and then panned using a constant-power (sin/cos) law before summing. Pan at -1.0 routes all energy to the left; at 1.0 to the right; at 0.0 the input is centered with equal power in both channels. The per-input gain multiplies the signal before the pan stage, so gain and pan interact: a gained signal is panned, not the other way around. Master gain is applied after all inputs are summed. All gain and pan values are per-sample smoothed to prevent clicks.

Properties:

PropertyMethodTypeDefaultRange
Inputsinputs()Int41..64
Master Gainmaster_gain()Float10..4

Inputs:

PortTypePropertiesNotes
InputAudiogain(), pan()unbounded; Audio source to mix. Per-input gain and pan are available.

Outputs:

PortTypeNotes
OutputAudioSummed and gained stereo mix.

Multiplexer (Multiplexer)

Selects from multiple audio inputs with smooth crossfading

let node = Multiplexer.add("my_multiplexer");

Selects one of N audio inputs and routes it to a single output with smooth crossfading between adjacent channels.

Selection by CV (0.0 = first input, 1.0 = last) or gate stepping. The Select CV overrides the step index when connected. Step gate advances by one on each rising edge; with Wrap enabled, stepping past the last input returns to the first, otherwise it clamps. Crossfade time controls how quickly the smoothed position tracks the target -- at 0 ms transitions are instant. Only connected inputs participate; disconnected slots contribute silence.

Properties:

PropertyMethodTypeDefaultRange
Inputsinputs()Int41..64
Crossfadecrossfade_time()Float50..1000
Selectionselection()Int00..63
Wrapwrap()Booltrue

Inputs:

PortTypePropertiesNotes
SelectControlNormContinuous position selector. Fractional values crossfade between adjacent inputs. Overrides the step index when connected.
StepGateRising edge advances to the next input.
InputAudiounbounded; Audio source to select from.

Outputs:

PortTypeNotes
AudioAudioSelected and crossfaded audio output.

Null Sink (NullSink)

Discards all inputs and outputs silence

let node = NullSink.add("my_nullsink");

Pulls and discards all connected inputs, then outputs silence.

Forces upstream nodes to process in a pull-based graph without routing their output anywhere audible. Accepts any signal type on unbounded inputs. The audio output is always silent zeros. Useful for side-chain triggers, analysis nodes, or any upstream processing chain that needs to run but not be heard.

Properties:

PropertyMethodTypeDefaultRange
Inputsinputs()Int41..64

Inputs:

PortTypePropertiesNotes
InputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), Imageunbounded; Any signal type -- pulled and discarded each buffer.

Outputs:

PortTypeNotes
Audio OutAudioSilent stereo audio (all zeros).

Offset (Offset)

Adds DC bias to audio signal

let node = Offset.add("my_offset");

Adds a constant DC offset to both channels of a stereo audio signal, with per-sample smoothing to prevent clicks.

The same offset value is added to both left and right channels. Useful for shifting bipolar signals to unipolar, biasing control signals routed through the audio bus, or centering waveforms.

Properties:

PropertyMethodTypeDefaultRange
Offsetamount()Float0-2..2

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to offset.

Outputs:

PortTypeNotes
Audio OutAudioOffset stereo audio.

Passthrough (Passthrough)

Passes data through unchanged. Accepts any port type.

let node = Passthrough.add("my_passthrough");

Copies input data to the output unchanged. Accepts any signal type.

When connected, the port type locks to the first connection's type. If the input is disconnected and the output is audio, the output fills with silence. Useful for testing, as a routing placeholder, or as a type-locking bridge between polymorphic ports.

Inputs:

PortTypePropertiesNotes
InputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), ImageAny signal type to pass through.

Outputs:

PortTypeNotes
OutputAudio, Control, ControlNorm, ControlBipolar, ControlFreq, Midi, Gate, VOct, Data(Unknown), ImageUnmodified copy of the input signal.

Probability Gate (ProbabilityGate)

Randomly passes or blocks gate events with configurable probability

let node = ProbabilityGate.add("my_probabilitygate");

Randomly passes or blocks incoming gate events based on a probability percentage.

Each gate-on event is evaluated independently: at 100% everything passes, at 0% nothing does. Gate-off events pass through only if their corresponding gate-on was allowed, so downstream nodes always see matched on/off pairs.

When PatternLength is >0, random decisions are cached per step position within the pattern cycle. The same step always gets the same pass/block result until the pattern length changes, giving repeatable variation. A Probability Mod CV input overrides the property (0.0--1.0 maps to 0--100%).

Properties:

PropertyMethodTypeDefaultRange
Probabilityprobability()Float1000..100
Pattern Lengthpattern_length()Int00..64

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Incoming gate events to filter.
Probability ModControlNormCV override for probability (0.0--1.0 maps to 0--100%). Replaces the property value when connected.

Outputs:

PortTypeNotes
Gate OutGateFiltered gate events that passed the probability check.

Quantizer (Quantizer)

Quantizes CV to musical scales with optional slew limiting

let node = Quantizer.add("my_quantizer");

Snaps V/Oct pitch CV to the nearest note in a musical scale.

Choose a scale type and root note, and the quantizer constrains incoming pitch to valid scale degrees. When the optional Trigger input is connected, quantization only updates on rising edges -- between triggers the output holds the last quantized value. Without Trigger, every sample is quantized continuously.

The Slew property adds portamento between quantized notes. The Gate output fires a rising edge each time the quantized pitch changes to a different note.

Properties:

PropertyMethodTypeDefaultRange
Scalescale()Enumenum(1)Chromatic, Major, Minor, HarmonicMinor, MelodicMinor, Dorian, Phrygian, Lydian, Mixolydian, Aeolian, Locrian, MajorPentatonic, MinorPentatonic, Blues, WholeTone, Diminished
Root Noteroot_note()Enumenum(0)C, C#, D, D#, E, F, F#, G, G#, A, A#, B
Rangerange_octaves()Float31..5
Slewslew_ms()Float00..100

Inputs:

PortTypePropertiesNotes
CV InVOctrequired; V/Oct pitch CV to quantize.
TriggerGateOptional trigger -- when connected, quantization only updates on rising edges.

Outputs:

PortTypeNotes
CV OutVOctQuantized V/Oct pitch CV snapped to the selected scale.
Gate OutGateTrigger pulse on each pitch change.

Rectifier (Rectifier)

Half-wave or full-wave rectification for audio and control signals

let node = Rectifier.add("my_rectifier");

Rectifies audio or control signals. Both paths operate independently and simultaneously when both inputs are connected.

Full-wave mode applies abs() to each sample, folding the negative half upward and doubling the perceived frequency (octave-up effect on audio). Half-wave mode applies max(0, x), clipping negative values to zero and adding odd harmonics. The control output type is ControlNorm (>= 0) regardless of mode, effectively converting bipolar to unipolar.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)Full, Half

Inputs:

PortTypePropertiesNotes
AudioAudioStereo audio to rectify.
ControlControlBipolarBipolar control signal to rectify.

Outputs:

PortTypeNotes
AudioAudioRectified stereo audio.
ControlControlNormRectified control value (always >= 0).

Sample & Hold (SampleHold)

Gate-triggered sample and hold with glide

let node = SampleHold.add("my_samplehold");

Captures the input signal on each gate rising edge and holds that value until the next trigger.

The input audio is mono-downmixed at the sample where the rising edge occurs. The held value is linearly mapped through the OutputMin/OutputMax range (value * (max - min) + min). When glide is non-zero, transitions between held values use an ease-out curve over the glide duration. Gate state is tracked per sample for sample-accurate triggering.

Properties:

PropertyMethodTypeDefaultRange
Glide Timeglide_time()Float00..1000
Output Minoutput_min()Float0-1..1
Output Maxoutput_max()Float1-1..1

Inputs:

PortTypePropertiesNotes
SignalAudiorequired; Audio to sample from. Mono-downmixed at the exact sample where the gate rising edge occurs.
Gate InGaterequired; Each rising edge captures a new value from Signal. Gate state is tracked per sample for sample-accurate triggering.

Outputs:

PortTypeNotes
OutputAudioHeld value as mono-to-stereo audio, mapped through the output range, with glide applied if non-zero.

Signal Follower (SignalFollower)

Envelope follower with gate output - trigger events from audio amplitude

let node = SignalFollower.add("my_signalfollower");

Tracks the amplitude envelope of an audio signal and emits gate events when the level crosses a threshold.

The envelope follower uses asymmetric one-pole smoothing: attack coefficient tracks rising amplitude, release coefficient tracks falling amplitude. The mono-downmixed absolute value is fed into the follower per sample. A Schmitt trigger with configurable hysteresis converts the envelope to a gate: the gate turns on when the envelope exceeds threshold + hysteresis/2, and off when it drops below threshold - hysteresis/2. Gate edges are emitted at sample-accurate offsets. The Envelope output provides the smoothed amplitude as a normalized 0--1 control value.

Properties:

PropertyMethodTypeDefaultRange
Thresholdthreshold()Float0.10.001..1
Hysteresishysteresis()Float0.050..0.3
Attackattack()Float10.1..50
Releaserelease()Float501..500

Inputs:

PortTypePropertiesNotes
AudioAudiorequired; Audio signal to track.

Outputs:

PortTypeNotes
GateGateHigh when envelope exceeds threshold, low when it drops below.
EnvelopeControlNormSmoothed amplitude envelope as normalized CV (0.0--1.0).

Signal Math (SignalMath)

Two-input audio math: add, subtract, multiply (ring mod), min, max, crossfade

let node = SignalMath.add("my_signalmath");

Two-input math on stereo audio signals. Add layers together, subtract for sidechain ducking, multiply for ring modulation, or crossfade between A and B with a mix knob.

Disconnected inputs contribute silence (zero). In Crossfade mode, 0.0 = all A, 1.0 = all B, with per-sample smoothing on the mix. A Mix Mod CV overrides the property value and is fed into the smoother. The smoother advances even when not in Crossfade mode to stay in sync, so switching modes mid-stream is seamless.

Properties:

PropertyMethodTypeDefaultRange
Operationop()Enumenum(0)Add, Subtract, Multiply, Min, Max, Crossfade
Mixmix()Float0.50..1

Inputs:

PortTypePropertiesNotes
Input AAudiorequired; First audio operand.
Input BAudioSecond audio operand. Defaults to silence when disconnected.
Mix ModControlNormCV modulation of the crossfade mix (0.0--1.0).

Outputs:

PortTypeNotes
Audio OutAudioResult of the selected math operation.

Splitter (Splitter)

Duplicates audio signal to multiple outputs with per-output gain control

let node = Splitter.add("my_splitter");

Duplicates a single stereo audio input to multiple outputs with independent per-output gain control.

At unity gain with a settled smoother, outputs share the input buffer via Arc clone (zero-copy). When gain differs from unity or the smoother is still transitioning, a per-sample copy with gain is performed. Use for parallel processing chains, dry/wet mixing, or multi-destination routing.

Properties:

PropertyMethodTypeDefaultRange
Outputsoutputs()Int41..64

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio signal to duplicate.

Outputs:

PortTypeNotes
OutputAudiounbounded; Copy of the input audio, with per-output gain.

Stereo Panner (StereoPanner)

Pan and mix up to two audio inputs with independent stereo placement

let node = StereoPanner.add("my_stereopanner");

Pans and mixes up to two stereo audio inputs with independent pan and width controls per channel into a single stereo output.

Pan uses constant-power (sin/cos) placement. Width crossfades between full stereo (1.0) and collapsed mono (0.0) by blending opposite channels. Both channels are summed into the output, so with two sources you get a stereo mix. CV modulation on all four parameters overrides the property values when connected. All parameters are per-sample smoothed. Unconnected inputs contribute nothing, but their smoothers still advance to stay in sync.

Properties:

PropertyMethodTypeDefaultRange
Pan Apan_a()Float0-1..1
Width Awidth_a()Float10..1
Pan Bpan_b()Float0-1..1
Width Bwidth_b()Float10..1

Inputs:

PortTypePropertiesNotes
Audio AAudioFirst stereo audio source.
Pan A ModControlBipolarCV modulation for Pan A (-1.0--1.0).
Width A ModControlNormCV modulation for Width A (0.0--1.0).
Audio BAudioSecond stereo audio source.
Pan B ModControlBipolarCV modulation for Pan B (-1.0--1.0).
Width B ModControlNormCV modulation for Width B (0.0--1.0).

Outputs:

PortTypeNotes
Audio OutAudioCombined stereo mix of A and B with panning applied.

Stereo ➔ Mono (StereoToMono)

Downmix stereo audio to mono (L+R average, output as dual-mono stereo)

let node = StereoToMono.add("my_stereotomono");

Downmixes stereo audio to mono by averaging L and R. The output is still a stereo frame (both channels identical) since the audio bus is always stereo. Useful before processing that expects a centered mono signal.

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Stereo audio to downmix.

Outputs:

PortTypeNotes
Audio OutAudioDual-mono stereo audio (L = R = average).

Timed Gate (TimedGate)

Fixed-duration gate with transport or wall-clock trigger

let node = TimedGate.add("my_timedgate");

Fixed-duration gate generator with two independent timing modes.

In WallClock mode, a rising edge on Gate In starts the cycle: optional delay, then the gate opens for the configured duration. A retrigger during the active phase restarts the cycle. The Reset input forces the gate closed and returns to idle.

In Transport mode, the gate auto-fires when the transport reaches the Offset bar. Stopping the transport closes the gate and re-arms the trigger; starting again re-evaluates the offset. Duration, delay, and gap are specified in bars and scale with tempo.

Both modes support repeat (Off, Infinite, or a fixed Count) with an optional gap between cycles. Three outputs: the gate itself, an inverted copy, and a one-sample end-trigger pulse when the active phase closes.

Properties:

PropertyMethodTypeDefaultRange
Modemode()Enumenum(0)WallClock, Transport
Offsetoffset()Int00..9999
Barsbars()Int11..9999
Delaydelay_bars()Int00..9999
Gapgap_bars()Int00..9999
Durationmilliseconds()Int5001..65535
Delaydelay_ms()Int00..65535
Gapgap_ms()Int00..65535
Repeatrepeat()Enumenum(0)Off, Infinite, Count
Countrepeat_count()Int11..9999

Inputs:

PortTypePropertiesNotes
Gate InGaterequired; Trigger source (WallClock mode only). Rising edge starts or retriggers the cycle. Ignored in Transport mode.
ResetGaterequired; Forces the gate closed and resets all state to idle (WallClock mode only). Ignored in Transport mode.

Outputs:

PortTypeNotes
Gate OutGateFixed-duration gate signal.
InverseGateInverted gate -- HIGH when Gate Out is LOW.
End TriggerGateOne-sample pulse when the active phase ends. Fires before the gap or next cycle begins -- useful for chaining.

Timing (Timing)

Timing source - BPM, time signature, and key signature

let node = Timing.add("my_timing");

Outputs structured timing metadata (BPM, time signature, key signature) as a TimingData value on a Data port.

When the Tempo input is connected, its value replaces the BPM property (clamped 1--999). Time signature and key signature always come from the properties. The Beat Unit property is an encoded power-of-two exponent (0=1, 1=2, 2=4, 3=8, 4=16, 5=32).

Properties:

PropertyMethodTypeDefaultRange
BPMbpm()Float1201..999
Beats/Bartime_sig_num()Int41..32
Beat Unittime_sig_denom()Int20..5
Key (sharps/flats)key_sharps()Int0-7..7
Minorkey_minor()Boolfalse

Inputs:

PortTypePropertiesNotes
TempoControlReplaces the BPM property with the signal value (clamped 1--999).

Outputs:

PortTypeNotes
TimingData(Timing)Structured timing metadata.

Transport (Transport)

Outputs transport state: playing gate, beat position, and tempo

let node = Transport.add("my_transport");

Exposes the global transport state as patchable signals and optionally accepts MIDI input for external transport control.

Three outputs: Playing (gate high while transport plays, with edge events on transitions), Beat (unbounded Control with the current beat position), and BPM (unbounded Control with the current tempo). The node always processes even when no outputs are connected, to ensure MIDI transport commands are captured.

When a MIDI input is connected, system real-time Start/Continue messages trigger Play, Stop messages trigger Stop, and configurable CC numbers map to play, stop, and master volume. CC values >0 trigger the action; volume maps 0--127 to 0.0--1.0.

Properties:

PropertyMethodTypeDefaultRange
Play CCplay_c_c()Int115-1..127
Stop CCstop_c_c()Int116-1..127
Volume CCvolume_c_c()Int79-1..127

Inputs:

PortTypePropertiesNotes
MIDI InMidirequired; MIDI input for external transport control. System RT messages and configured CCs are translated to transport commands.

Outputs:

PortTypeNotes
PlayingGateGate high while transport is playing, low when paused.
BeatControlCurrent beat position as an unbounded control value.
BPMControlCurrent tempo in beats per minute as an unbounded control value.

Turing Machine (TuringMachine)

Shift register sequencer with mutation probability for evolving patterns

let node = TuringMachine.add("my_turingmachine");

Shift register sequencer that generates looping CV and gate patterns which evolve over time via a mutation probability knob.

On each clock rising edge the register shifts right by one bit. The LSB wraps to the MSB position, with a configurable chance of being flipped. At 0% mutation the sequence repeats perfectly; at 100% the output is fully random. The CV output is the full register value normalized to 0.0--1.0. The Gate output reflects the MSB. The Pulse output fires a one-sample trigger on every clock step regardless of register content. The register initializes with random bits on the first clock edge.

Properties:

PropertyMethodTypeDefaultRange
Lengthlength()Int82..32
Mutationmutation()Float00..100

Inputs:

PortTypePropertiesNotes
ClockGaterequired; Clock input - each rising edge advances the register.
Mutation CVControlNormrequired; CV control over mutation probability (0.0--1.0 maps to 0--100%). Overrides the Mutation property when connected.

Outputs:

PortTypeNotes
CVControlNormFull register value normalized to 0.0--1.0. Updates once per clock step and holds between clocks.
GateGateHigh when MSB of register is 1.
PulseGateTrigger pulse on every clock step.

VCA (VCA)

Voltage controlled amplifier for audio-rate modulation

let node = VCA.add("my_vca");

Voltage-controlled amplifier -- multiplies two stereo audio signals sample-by-sample, channel-by-channel.

Both inputs are Audio type (not Control), enabling true stereo audio-rate modulation. Wire an envelope, LFO, or any audio source into the Control input for amplitude shaping, tremolo, or ring modulation. Both inputs are required -- the node produces nothing if either is disconnected.

Inputs:

PortTypePropertiesNotes
Audio InAudiorequired; Audio signal to modulate.
ControlAudiorequired; Audio-rate modulator (envelope, LFO, or other audio). Multiplied channel-by-channel with Audio In.

Outputs:

PortTypeNotes
Audio OutAudioAudio multiplied by the control signal.

VOct Converter (VoctConverter)

Converts VOct pitch CV to multiple output types simultaneously

let node = VoctConverter.add("my_voctconverter");

Converts V/Oct pitch CV to multiple output formats simultaneously.

Freq output: reference_freq * 2^voct. Audio output: dual-mono stereo from the V/Oct buffer values (not frequency). Control output: raw V/Oct value. VOct output: pass-through of the input buffer. MIDI output: converts the first sample's V/Oct to a note number (voct * 12 + reference_note, rounded) and emits note-on / note-off events driven by the Gate input. Without a Gate input, no MIDI events are generated. Note changes without a gate re-trigger do not emit new note-on events.

Properties:

PropertyMethodTypeDefaultRange
Reference Notereference_note()Int600..127

Inputs:

PortTypePropertiesNotes
VOct InVOctrequired; V/Oct pitch CV to convert.
Gate InGateDrives MIDI note-on/note-off generation. Without this input connected, the MIDI output stays empty.

Outputs:

PortTypeNotes
FreqControlFreqPitch as frequency in Hz.
AudioAudioDual-mono stereo audio from V/Oct values.
ControlControlRaw V/Oct value as a control signal.
MIDIMidiMIDI note events generated from V/Oct + gate.
VOctVOctV/Oct pass-through.

VOct Scale/Offset (VoctScaleOffset)

Scale and offset VOct pitch CV. Useful for creating intervals, harmonies, and creative pitch effects.

let node = VoctScaleOffset.add("my_voctscaleoffset");

Multiplies and offsets V/Oct pitch CV per sample: output = input * Scale + Offset.

Negative Scale inverts pitch intervals. Scale of 2.0 doubles intervals (octave becomes two octaves). Offset shifts the entire pitch up or down in V/Oct units (1.0 = one octave). Useful for creating harmonies, inversions, and creative pitch effects.

Properties:

PropertyMethodTypeDefaultRange
Scalescale()Float1-4..4
Offsetoffset()Float0-4..4

Inputs:

PortTypePropertiesNotes
VOct InVOctrequired; V/Oct pitch CV to transform.

Outputs:

PortTypeNotes
VOct OutVOctScaled and offset V/Oct pitch CV.

VOct Slew (VoctSlew)

Smooth VOct pitch transitions with configurable slew rate. Creates portamento/glide effects between notes.

let node = VoctSlew.add("my_voctslew");

Rate-limits V/Oct pitch transitions for portamento and glide effects. Operates at audio rate (per sample).

Rise and Fall times override SlewTime when set above zero. If both are zero, SlewTime is used for both directions. A Slew Mod CV (0.0--1.0) scales the effective slew time: at 0.0 transitions are instant, at 1.0 the full time is used. The maximum change per sample is 1/(slew_time * sample_rate) V/Oct. On the first sample the output jumps to the input with no slew.

Properties:

PropertyMethodTypeDefaultRange
Slew Timeslew_time()Float0.10..10
Rise Timerise_time()Float00..10
Fall Timefall_time()Float00..10

Inputs:

PortTypePropertiesNotes
VOct InVOctrequired; V/Oct pitch CV to smooth.
Slew ModControlNormCV scaling of slew time (0.0 = instant, 1.0 = full slew time).

Outputs:

PortTypeNotes
VOct OutVOctSlew-limited V/Oct output.

VOct Transpose (VoctTranspose)

Transpose VOct pitch CV by semitones, octaves, and cents.

let node = VoctTranspose.add("my_vocttranspose");

Shifts V/Oct pitch CV by semitones, octaves, and cents.

All three offsets are summed into a single V/Oct shift: semitones/12 + octaves + cents/1200. The combined offset is added to every sample in the input buffer. Use for fixed transpositions, octave layering, or fine-tuning.

Properties:

PropertyMethodTypeDefaultRange
Semitonessemitones()Int0-48..48
Octavesoctaves()Int0-4..4
Centscents()Int0-100..100

Inputs:

PortTypePropertiesNotes
VOct InVOctrequired; V/Oct pitch CV to transpose.

Outputs:

PortTypeNotes
VOct OutVOctTransposed V/Oct pitch CV.

Idempotency

Scripts are designed to be safely rerunnable. Running the same script twice produces the same graph, not duplicates.

OperationBehavior on rerun
Type.add("label")Returns existing node with that label and type
AudioSink.first()Always returns the singleton sink
out.port().connect(in.port())No-op if connection already exists
node.frequency(440.0)Naturally idempotent
node.add_track("name")Returns existing track if name matches

Hot Reload

The script editor (Cmd+E) supports Cmd+R to hot-reload: clear the graph and re-execute from scratch. With idempotent operations, scripts can also be rerun without clearing.

Tips

Inspecting State

osc.show();                          // print node details
osc.input("Audio In").show();        // print port details
track.show();                        // print track details
region.show();                       // print region details
note.show();                         // print note details
list_nodes();                        // list all nodes in the graph
list_types();                        // list all available node types
help();                              // list all functions
help("sequencer");                   // filter help by keyword

Connecting Nodes

Use typed port handles with .port() for connecting:

let osc = Oscillator.add("osc");
let mix = Mixer.add("mix");
let sink = AudioSink.first();

osc.output("Audio Out").port().connect(mix.input("Input 0").port());
mix.output("Output").port().connect(sink.input("Audio In").port());

Port Properties

Some ports have per-connection properties with typed methods:

let mix = Mixer.add("mix");
mix.input("Input 0").gain(0.5);    // typed method
mix.input("Input 0").pan(0.3);     // typed method

Sequencer Programming

let edit = SequencerEditor.add("seq_edit");
let seq = Sequencer.add("seq");
edit.output("Sequencer Out").port().connect(seq.input("Config In").port());

edit.bpm(120.0);
edit.bars(4);
edit.timesig(4, 4);
edit.set_loop(true);

let mel = edit.add_track("Melody");
mel.add_notes([
    ["C4",  0.0, 1.0, 100],
    ["E4",  1.0, 1.0, 90],
    ["G4",  2.0, 1.0, 85],
]);

Arranger Programming

let edit = ArrangerEditor.add("arr");
let arr = Arranger.add("arr_play");
edit.output("Arrangement").port().connect(arr.input("Config In").port());

edit.bpm(140.0);
edit.bars(32);

let verse = edit.add_track("Verse");
let r = verse.add_region(0.0, 16.0);
r.set_label("Intro");
r.set_level(0.8);

Envelopes

let synth = PolysynthV2.add("synth");
synth.shape(adsr(0.01, 0.1, 0.7, 0.2));   // attack, decay, sustain, release
synth.shape(one_shot(0.005, 0.3));          // attack, decay (no sustain)
synth.shape(decay_env(0.1));                // instant peak, decay
synth.shape(gated_hold(0.01, 0.5));         // attack to peak, hold until release

Curves

Build automation curves for AutomationCurve, CurveFunctionGenerator, and other curve-property nodes:

// Factory functions
let c = linear_curve(4.0);                  // 0→1 over 4 seconds
let c = ease_in_out_curve(8.0);             // smooth S-curve over 8 seconds

// Build from scratch
let c = curve();
c.add_point(0.0, 0.0);                     // time, value (zero tangents)
c.add_smooth_point(2.0, 0.8, 0.0, 1.5);   // time, value, in_tangent, out_tangent
c.add_point(4.0, 1.0);
c.bipolar();                                // set range to -1..1

// Apply to a node
let auto = AutomationCurve.add("sweep");
set(auto, "CurveData", c);

// Query
print(c.eval(1.0));                         // evaluate at time
print(c.duration());                        // total duration
print(c.len());                             // keyframe count

Timing

sleep(1000);         // pause for 1 second
breakpoint();        // pause until resumed (script editor only)

Batch Notes

Individual add_note() calls cost one round-trip each. For many notes, use add_notes() which sends the entire batch in one call:

track.add_notes([
    ["C4", 0.0, 1.0, 100],   // [pitch, beat, duration, velocity]
    ["E4", 1.0, 0.5, 90],
    ["G4", 1.5, 0.5, 85],
]);

View Control

autolayout(true);    // auto-arrange nodes on topology changes
zoom_to_fit();       // fit all nodes in view
toggle("3d");        // toggle 3D mode
toggle("activity");  // toggle activity monitor

Graph Management

graph_clear();       // remove all nodes except AudioSink
graph_new("name");   // create a new graph (requires open project)
undo();              // undo last operation
redo();              // redo

Generated by dump-scripting-docs. Regenerate with: cargo run -p editor-logic --bin dump-scripting-docs