The events to humanize.
Humanization options.
Humanized copies of events, in input order.
import { humanize } from '@libraz/libcantus';
const events = [{ pitch: 60, startBeat: 0, durationBeat: 1, velocity: 80 }];
humanize(events, { ctx: 1, timing: 0.03 }); // copies with jittered timing and accented velocity
humanize(events, { ctx: { seed: 42 }, part: 'lead' }); // under a project context
Notes with a zero or negative duration never sound and are dropped, so the result can be shorter than the input.
Humanize a sequence of note events by nudging their timing and velocity with small, deterministic (seeded) randomness plus a metric-accent shape: events on strong beats (see metricWeight) come out louder on average than events on weak ones.
Each returned event is a copy;
startBeatis jittered within[-timing, +timing]beats — not floored at 0, because a pickup sounds before the downbeat and flooring it there would play two upbeats as one — andvelocityis the event's own velocity (orbaseVelocityif it has none) plus an accent term scaled by the event's metric weight plus a jitter within[-velocity, +velocity], clamped to[1, 127]and rounded. The metric weight is computed from each event's original (pre-jitter)startBeat.pitchanddurationBeatpass through unchanged, and the output keeps the input order.The jitter is drawn from the generation context, addressed by the event's own onset and pitch rather than by its position in the array: an event added or removed leaves every other event's jitter exactly where it was, and a part humanized under its own name is independent of the others sharing the seed.