Lanes are Tracks in a derive; one sequence plays them on the runner's clock, with
no action per step. Each loops at its own length (polymeter). MIDI and the rest: "Sound, MIDI and media".
sound "assets/kits/808/kick.wav"
sound "assets/kits/808/hat.wav"
sound "assets/kits/909/kick.wav"
sound "assets/kits/909/hat.wav"
shape Step
beat: number
src: string
gain: number
group: string
note: number
velocity: number
channel: number
duration: number
haptic: string
shape Track
beats: number
loops: number
offset: number
output: string
steps: Step[]
shape Transport
bpm: number
anchorAt: number
anchorBeat: number
// `n` steps of `every` beats, sounding at `hits`.
fn lane(kit: string, slot: string, n: number, every: number, hits: number[]): Track = Track(beats=n * every, loops=0, offset=0, output="", steps=hits.map(i => Step(beat=i * every, src=`assets/kits/${kit}/${slot}.wav`, gain=1, group=slot, note=-1, velocity=100, channel=9, duration=every, haptic="")))
component Drums
state playing = false
state at = 0
state kit = "808"
resource transport = exactTransport() as shape Transport
derive tracks = [lane(kit, "kick", 16, 0.25, [0, 4, 8, 12]), lane(kit, "hat", 12, 0.25, [0, 3, 6, 9])]
sequence groove when playing
play(tracks, bpm=120, from=at)
action start
playing = true
action pause
at = transport.anchorBeat + (performanceNow() - transport.anchorAt) * transport.bpm / 60000
playing = false
action setKit(name: string)
kit = name
view
row gap=8
if playing
button "Pause" press=pause testId="pause"
else
button "Play" press=start testId="play"
button "909" press=setKit("909") aria-pressed=(kit == "909") testId="kit-909"
test "lanes loop at their own lengths; an edit plays at once"
tap "play"
clock +2000
expect sound has "assets/kits/808/hat.wav" at 1500
tap "kit-909"
clock +1000
expect sound has "assets/kits/909/kick.wav" at 2500
- Declare every file a built path can name, a
soundline each: a step whosesrcnone declares is silent (logs:… is not a declared sound). - The shapes are positional: keep their fields in this order.
- Resolution is beats a step:
0.25is a sixteenth,1/3a triplet eighth. - Edits are live: a changed step, lane, kit or
bpmplays from its commit, in phase.pausekeeps the beat inatfor the next start. A newkey=starts again atfrom: one sequence plays at a time, so a mode is a key, not a secondsequence. - A playhead is an animation: the guide's "Following the transport".
- MIDI: a track's
outputis an output'sid, itsoffseta delay in ms;clock=an input'sidfollows that device (waitinguntil Start). - iOS stops it when hidden unless the app plays in the background (LLP 1125 D4); a
task on
transport.reason == "background"(addreason: stringtoTransport) setsplayingfalse.