Automation
Automation is a pure curve over beat-time. You attach one to a track parameter
with track.automate(param, curve) inside a section body; the runtime samples
the curve and compiles it to parameter ramps (filter sweeps, gain fades, stereo
drift) at schedule time.
import { value, ramp, sweep, sine, bars } from "@barline/core";The automatable parameters are cutoff, resonance, gain, pan, and
pitch (the set is extensible by packages via declaration merging). cutoff
and resonance lazily create a dedicated filter on the track the first time
they’re automated, so they’re audible.
Generated devices also expose stable parameter and macro paths:
bass.automate("instrument.filterA", sine(900, 300, bars(4)));bass.automate("instrument.macro.color", sweep(0.2, 0.9, bars(8)));drums.automate("effect.1.drive", ramp(0.1, 0.7, bars(2)));drums.automate("effect.1.macro.dirt", sine(0.5, 0.2, bars(1)));Macro curves use normalized 0..1 positions and honor the macro’s published
polarity and response curve, including logarithmic frequency controls. Direct
parameter paths use their published units (Hz, dB, seconds, and so on). The
runtime clamps both forms to the generated safe range.
Effect indices are source-order positions in the track’s static chain. The runtime resolves paths against the generated device manifest, applies log ramps to log-scaled controls, and warns without changing the graph when a target is unknown, hidden, or not automatable.
value(v) — a constant
Section titled “value(v) — a constant”kick.automate("gain", value(0.8)); // hold a fixed valueramp(from, to, over) — a linear fade
Section titled “ramp(from, to, over) — a linear fade”Interpolates linearly from from to to across over beats, then holds.
kick.automate("gain", ramp(0.7, 1, bars(16))); // fade the kick up over the sectionhats.automate("gain", ramp(0.4, 1, bars(16))); // bring the hats inrumble.automate("gain", ramp(0.8, 0.15, bars(16))); // wind the bass down in the outrosweep(from, to, over, curve = "exp") — a filter sweep
Section titled “sweep(from, to, over, curve = "exp") — a filter sweep”Like ramp, but exponential by default — the natural shape for a frequency
sweep, where the ear hears ratios, not differences. Pass "lin" for linear, or
let it fall back to linear automatically across a zero or sign change.
rumble.automate("cutoff", sweep(250, 2500, bars(16), "exp")); // the classic opening filterrumble.automate("cutoff", sweep(400, 6000, bars(16))); // exp is the defaultsine(center, amp, period) — an LFO
Section titled “sine(center, amp, period) — an LFO”Oscillates around center by ±amp, one full cycle every period beats.
Great for stereo drift and slow filter wobble.
ride.automate("pan", sine(0, 0.5, bars(4))); // slow stereo driftacid.automate("cutoff", sine(1400, 900, bars(8))); // a wandering filterEditing curves from the studio
Section titled “Editing curves from the studio”A curve built from one of these four constructors with plain numeric literals
(or bars(n) / beats(n) wrappers) is editable from the Clip detail
panel — each argument shows as a scrub/select control that writes back into
the literal in your code. A computed curve, or two constructor calls on one
line, locks the row with a reason instead. Custom curve objects (any object with
an at(pos): number method) work too, but carry no call-site metadata, so they
always render read-only.