Sections & Songs
A timeline arranges one lane. A section
arranges a slice of the whole piece: every track’s clips, every automation
curve, and the picture on screen, all under one length. Sequence a few sections
back to back with arrange() and you have a song — one value you can play,
render, and keep editing while it runs.
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.instrument(Sampler(Kit("CR-78")));
let verse = section(8);verse[drums] << [bd bd sd bd];
let chorus = verse.clone();chorus[drums] << [bd sd bd sd];
let song = arrange(#[verse, chorus]); // verse [0,8), chorus [8,16)song.play();Let’s take that apart.
Lanes, Keyed by Track
Section titled “Lanes, Keyed by Track”section(length) makes an empty section length cycles long. Index it with a
track to get that track’s lane, and assign with << exactly as you would
send a pattern to the track directly:
use "std/instruments" { Sampler, Kit };
let drums = AudioTrack("drums");drums.instrument(Sampler(Kit("CR-78")));let bass = AudioTrack("bass");bass.instrument(Sampler(Kit("CR-78")));
let verse = section(8);verse[drums] << [bd bd sd bd];verse[bass] << [c2 _ g1 _];One section, two lanes, both eight cycles long. Because the length is the section’s and not the lane’s, the tracks can never drift out of alignment — the problem that one-timeline-per-track leaves you to solve by hand.
A lane also takes a positioned write, .at(start, duration) << clip, which
places a clip inside the lane instead of covering the whole section. That is the
same layer machinery a timeline has, and
the rest of this page leans on it.
Reprises
Section titled “Reprises”.clone() gives you a deep, independent copy — every lane, every curve. Edit
the copy and the original is untouched, which is how you write a variation
without retyping the parts that stay:
let chorus = verse.clone();chorus[drums] << [bd sd bd sd]; // busier drums
// verse[drums] is still [bd bd sd bd]Sequencing Sections
Section titled “Sequencing Sections”arrange(#[...]) plays its elements back to back and returns one arrangement
whose length is the sum:
let song = arrange(#[verse, chorus]); // 16 cycles: verse [0,8), chorus [8,16)Repeat an element with elem * n — arrange(#[verse * 2, chorus]) is a
24-cycle song. Arrangements nest, so a chorus-plus-bridge group can itself be an
element of a larger arrange().
What arrange() lays down goes into each lane’s base layer. That matters:
anything you punch on top of the song afterwards sits above the structure and
survives a later rewrite of it.
Playing a Song
Section titled “Playing a Song”song.play() binds every lane — notes, automation, visuals — and starts the
transport from the top. It plays once through and then goes silent; call it
again to restart.
song.play();Masking Across a Seam
Section titled “Masking Across a Seam”Punch a fill over the song and it masks whatever is underneath, including across a section boundary:
song[drums].at(6, 4) << [cp cp]; // starts in the verse, reaches into the chorusshow(song);section — 16 cycles, 2 lanes
drums layers: base, main 0..6 [bd bd sd bd] base 6..10 [cp cp] main 10..16 [bd sd bd sd] +2c base
bass layers: base 0..8 [C2 ~ G1 ~] 8..16 [C2 ~ G1 ~]The claps run through the seam at cycle 8, and when they stop the chorus resumes
at its own cycle 2 — the +2c. It was masked, not cut, so it kept its
place. There is no need to split the write into two .at calls to cross a
boundary.
Rewriting the structure underneath leaves the punch alone, because a bare
song[drums] << clip replaces the base layer only:
song[drums] << [bd _ sd _]; // new groove everywhere; the claps at 6–10 stayAnd .clear() lifts a mask to bring back exactly what it was hiding:
song[drums].at(6, 4).clear(); // the chorus's opening is intact againNamed Layers on a Song
Section titled “Named Layers on a Song”Every lane on a section carries the full layer surface — .layer(name),
.mute(), .unmute(), .layers(#[..]), .clear(), .entries() — described
on the Arrangements page. Grouping
punches onto a named layer means you can lift the whole group at once:
song[drums].layer("fills").at(7, 1) << [hh hh hh hh];song[drums].layer("fills").at(15, 1) << [hh hh hh hh];
song[drums].layer("fills").mute(); // both gonesong[drums].layer("fills").unmute(); // both backAutomation Lanes
Section titled “Automation Lanes”A track’s parameters are lanes too. Address one with .volume, .pan, or
.get_effect("name").param("cutoff"), and assign a value or an
automation curve:
use "std/instruments" { Sampler, Kit };use "std/signals" { automation };
let drums = AudioTrack("drums");drums.instrument(Sampler(Kit("CR-78")));
let verse = section(8);verse[drums] << [bd bd sd bd];let chorus = verse.clone();chorus[drums] << [bd sd bd sd];let song = arrange(#[verse, chorus]);
song[drums].volume << 0; // whole song, 0 dBsong[drums].volume.at(8, 8) << automation().at(0, -24).at(8, 0); // chorus swells inA positioned curve masks the one underneath just like a clip does — and because a curve is continuous, “masks” needs to be precise about the edges. The base holds its level right up to the mask edge and steps there; it does not slide into the mask across the preceding cycles:
show(song);section — 16 cycles, 1 lane
drums layers: base 0..8 [bd bd sd bd] 8..16 [bd sd bd sd]
drums .volume layers: base, main 0..8 0.00 flat base 8..16 -24.00 → 0.00 mainCycles 0–7 sit flat at 0 dB, then cycle 8 drops to −24 dB and swells back. Clear the mask and the base curve comes back exactly as authored.
The Screen Lane
Section titled “The Screen Lane”section[screen] is the visual lane. A bare write puts a visual up for the
section’s whole span, so sequencing sections cuts the picture on section
boundaries — a section without a screen write renders black.
use "std/visuals" as gfx;
let verse = section(8);verse[screen] << gfx.Noise();
let chorus = verse.clone();chorus[screen] << (gfx.Noise() >> gfx.Blur());
let song = arrange(#[verse, chorus]);song[screen].layer("hits").at(14, 2) << gfx.Edge();
show(song);section — 16 cycles
screen layers: base, hits 0..8 Noise base 8..14 Blur base 14..16 Edge hitsOpen the window to watch it, exactly as for a static
v >> screen route:
screen.show_window();song.play();Seeing the Whole Song
Section titled “Seeing the Whole Song”show(song) renders the resolution of every lane — notes first, then
automation, then screen — one row per audible interval, tagged with the layer
that won it. It is the answer to “what will this actually sound like”, which the
list of writes you made cannot give you once masks are involved.
Two things it deliberately does not show: a muted layer contributes no
rows, so it stays findable in the layers: list instead; and an entry that is
completely hidden by another is not an interval at all.
.entries() is where those
show up, flagged masked — it works on any lane, so
song[drums].entries() and song[drums].volume.entries() both answer “what did
I actually write here”.
Editing While It Plays
Section titled “Editing While It Plays”Every lane edit lands live. Change a clip, punch a fill, write an automation
curve, mute a layer, swap the visual — it is heard with no second play() and
no rewind:
song.play();
// ...somewhere in the middle of the verse, execute just this line:song[drums].volume.at(8, 8) << automation().at(0, -24).at(8, 0);The transport keeps running and the swell is there when the playhead reaches cycle 8. Automation is positioned in absolute cycles, so it is bound the same way whether the song is playing or stopped.
When exactly it lands
Section titled “When exactly it lands”“Live” does not mean the same thing on all three lanes, which matters when you are punching things in on the beat:
| Lane | Takes effect | Why |
|---|---|---|
Notes (song[drums]) | next cycle boundary | the lane swaps its pattern once per cycle, so notes already sounding are never cut off mid-cycle |
Automation (.volume) | next audio block | the merged curve re-binds and the engine picks it up on its next callback |
Screen (song[screen]) | next frame | the renderer re-selects the covering span every frame |
So a note edit — including .mute() and .clear() on a note layer — is
quantized to the cycle, while automation and visuals are effectively immediate.
If a mute seems not to have taken, wait out the current cycle before assuming
something is wrong.
Next Steps
Section titled “Next Steps”- Rendering — bounce a song, its stems, or its visuals to disk
- Signals & Automation — the curves that go in an automation lane
- Arrangements — the layer surface in full, on a single lane