Skip to content

Algorithmic composition

“I can’t think of a melody, but I can write rules” — skulpton is well suited to that style. By combining primitives like scales, Euclidean rhythms, probability distributions, and LFOs, you can build a workflow where music is generated from code.

Core idea — “seeds” and “variations”

Section titled “Core idea — “seeds” and “variations””

Algorithmic composition is most efficient when you derive many variations from a single seed clip.

  1. Write a seed code block in a clip (e.g. scale + Euclidean rhythm + a touch of randomness)
  2. Duplicate the clip with Cmd/Ctrl + D
  3. In the duplicate, change just one line — usually the seed string or a coefficient
  4. Arrange them on the timeline to form the song structure

Because duplication is non-destructive, you never have to hand-edit notes between variations.

Example 1 — Variations through seed strings

Section titled “Example 1 — Variations through seed strings”

seed() fixes the random source so the same seed always produces the same result. Change just the seed string to get different variations.

seed("verse-1"); // <- change to "verse-2" or "chorus"
const sc = scale("dorian", 60);
onBeat((b) => {
if (chance(0.5) && Math.abs((b * 2) % 1) < 1e-6) {
setNote({ pitch: pick(sc), startBeat: b, lengthBeats: 0.5 });
}
});

Duplicate one clip and rewrite it as "verse-1" / "verse-2" / "chorus" and you have three coherent but distinct phrases.

Example 2 — Euclidean rhythms across parts

Section titled “Example 2 — Euclidean rhythms across parts”

Three tracks with different Euclidean ratios produce a conversational rhythm.

// Track 1 (percussion)
const pat = euclid(5, 16);
onBeat((b) => {
const i = Math.floor(b * 4);
if (pat[i % pat.length]) noteOn(60, 0.25, 90, b);
});
// Track 2 (bass) -> change to euclid(3, 16)
// Track 3 (lead) -> change to euclid(7, 16)

Different ratios (5/16, 3/16, 7/16) drift slightly against each other as they loop, producing a layered groove.

Example 3 — Time-varying density (build-up)

Section titled “Example 3 — Time-varying density (build-up)”

Using probability that increases over the clip you can create “gradually busier” phrases. This already appears in recipes and is great for live build-ups and outros.

const sc = scale("pentaMinor", 60);
onBeat((b) => {
const density = b / CLIP_LENGTH; // 0..1
if (chance(density)) {
setNote({ pitch: pick(sc), startBeat: b, lengthBeats: 0.25 });
}
});

Example 4 — Use input notes as raw material

Section titled “Example 4 — Use input notes as raw material”

Use a short hand-played riff as source material that code transforms.

// Input: a simple 4-note melody
// Output: each note expanded to a min7 chord + a 5th-up harmony layer
onNote((n) => {
chord("min7", n.pitch).forEach((p) => {
setNote({
pitch: p,
velocity: n.velocity,
startBeat: n.startBeat,
lengthBeats: n.lengthBeats,
});
});
setNote({ ...n, pitch: n.pitch + 7, velocity: Math.round(n.velocity * 0.6) });
});

This pattern combines “human musicality” with “code-driven amplification”.

Drop a .js file into {appData}/libs/codes/ to make recurring patterns (four-on-the-floor drums, custom scale handling) callable from every project.

  1. In the file browser, click + on App libs/codes, name it myhelpers.js
  2. Write function houseDrums(b) { ... } and save
  3. Toggle App libs ON
  4. Call houseDrums(b) directly from any clip’s code

See File browser and Coding Note Effect overview.

Treating a project as “a small set of role-specific generators” scales well.

TrackRolePatterns to use
DrumsBase rhythmeuclid + noteOn
BassRoot motionchord + transpose
PadHarmonic backdrophold chord("maj9", root)
LeadMelodic motiondrunk or urn(scale.length)
ModTimbre changessetCc + lfo

Each track runs its own small program; the song emerges from the combination.

  • Keep seed strings in comments so you can reproduce later
  • Keep one “sandbox clip” in each project for trying ideas without affecting the main timeline
  • Name clips by role + variant (“Bass A”, “Bass B variant”, etc.)
  • Use the Render tab to inspect generated notes — write in Code, switch to Render to verify, repeat