K

Harmony and sequencing

Scales, chords, arps, and Euclidean rhythms, all allocation-free.

The harmony toolkit ships in @msh/device-sdk/device/assembly. Everything here is real-time safe with no allocation, so it runs in process.

Scales

60+ scales in the ScaleType catalog (the first 21 match the host's mesh scales). SCALE_NAMES and ROOT_NAMES give labels for selects.

FunctionDoes
foldToScale(note, root, scaleId)Snap a note to the nearest scale member (ties up).
foldToMask(note, mask)Same, against a raw 12-bit mask.
transposeInScale(note, steps, root, scaleId)Move by scale degrees, wrapping octaves.
degreeOf(note, root, scaleId)Scale-degree index of a note.
scaleDegreeToNote(degree, octave, root, scaleId)MIDI note for a degree.
scaleMask(scaleId, root)12-bit in-scale mask.

Or hold a Scale and re-root it to the project key per block (allocation-free):

let scale: Scale;
prepare(): void { scale = new Scale(ScaleType.Dorian, 0); }
// per block:
scale.setMask(ctx.meshScaleMask(), ctx.meshKey());
const snapped = scale.fold(note);

Scale methods: setScale, setRoot, setMask, mask, fold, transpose, degree, contains, note, intervalAt, degreeCount. Build one from the project scale with ctx.meshScale() / ctx.globalScale().

Chords

60+ qualities in ChordQuality (CHORD_QUALITY_NAMES for labels). Chords write into a StaticArray<i32> you own (size 8 covers the largest).

FunctionDoes
buildChord(rootNote, quality, out)Write a chord's notes into out; returns the count.
invert(out, count, n)Raise the lowest n voices an octave, in place.
dropVoicing(out, count, n)Drop the n-th voice from the top an octave, in place.
diatonicTriad(degree, octave, root, scaleId, out)3-note stack of thirds within a scale.
diatonicSeventh(...)4-note version.

Interval constants (MAJOR_THIRD, PERFECT_FIFTH, MINOR_SEVENTH, ...) read better than raw semitones.

Rhythm and sequencing

ToolDoes
euclid(pulses, steps, rotation, out)Fill a StaticArray<bool> with a Euclidean pattern. Re-bake only on a param change.
Clock(beatsPerStep)Tempo-synced step clock. update(ctx.ppqPosition()) is true on each new step; step(), phase().
Arpeggiator(maxNotes)noteOn/noteOff to collect held notes, setPattern(ArpPattern.UpDown), setOctaves, next() per step.
MonoNoteStack(maxNotes)Mono voice priority: current(NotePriority.Highest | Lowest | Last).

ArpPattern: Up, Down, UpDown, DownUp, Converge, Diverge, Random, AsPlayed.

Tempo sync

FunctionReturns
noteToFreq(note) / freqToNote(hz)Pitch conversion.
syncToHz(beats, bpm)A note division as a rate in Hz (tempo-synced LFO).
syncToSamples(beats, bpm, sampleRate)The same in samples.
beatsToSeconds(beats, bpm)Quarter notes to seconds.

Beat constants: BEATS_WHOLE, BEATS_HALF, BEATS_QUARTER, BEATS_EIGHTH, BEATS_SIXTEENTH, BEATS_THIRTYSECOND, times DOTTED or TRIPLET.

Param factories

ParamDef.scaleSelect(id, name, short), ParamDef.rootSelect(...), ParamDef.chordSelect(...) build selects wired to these catalogs. The value is the catalog index, so read it straight into ScaleType / ChordQuality. Pair with m.addSetting(...).

How-to: Play in key, Build chords, Sequence and arp.