K

Add controls

Knobs, switches, and menus.

Declare controls in describe. Msh draws them, styled like the built-in devices, with automation and modulation for free. Full options in the parameters reference.

A knob

// id, name, short name, min, max, default, modulatable
m.addParam(new ParamDef("cutoff", "Cutoff", "Cut", 20, 20000, 1000, true));

A different shape

A control is a knob by default. Add a helper to change it:

m.addSetting(
  new ParamDef("type", "Type", "Type", 0, 2, 0, false).asToggleGroup([
    "LP",
    "BP",
    "HP",
  ]),
);
  • .asToggle() for on/off (range 0 to 1)
  • .asToggleGroup([...]) for a row of buttons
  • .asSelect([...]) for a dropdown
  • .asDragNumber() for a draggable number

Knob or setting

addParam for something you'd sweep or modulate. addSetting for a fixed choice (a mode, a count). Same thing, except a setting gets no modulation wheel.

Read it

In process, by the order you declared them:

const cutoff = ctx.modulatedParam(0, i); // with modulation
const mode = ctx.param(1); // plain value, good for settings

Don't want to count indices? Resolve one by name: ctx.paramIndex("cutoff").

Feel

Chain .unit(UNIT_HZ) for a suffix, and .logarithmic() (frequency) or .skew(...) (time) so the sweep feels right. Chain .precision(2) to fix the readout to a set number of decimal places.

Shortcuts

For the common shapes there's a factory that fills in the unit and skew for you:

m.addParam(ParamDef.freq("cutoff", "Cutoff", "Cut", 20, 20000, 1000)); // Hz, log
m.addParam(ParamDef.time("attack", "Attack", "Atk", 0.001, 2, 0.01)); // seconds, skewed
m.addSetting(ParamDef.scaleSelect("scale", "Scale", "Scl")); // a scale dropdown

ParamDef.scaleSelect / rootSelect / chordSelect build dropdowns wired to the scale, key, and chord catalogs, so the value reads straight back as a catalog index. Full options in the parameters reference.