Function Reference

Patterns and Playback

Starting and stopping sound, and the pattern combinators that arrange it in time.

accel(from, to, bars)

number → rate

Accelerates a play’s rate from to to over bars bars. Holds at to upon completion.

Use in the rate parameter of play — play(riff, lead, accel(1, 2, 4)).

A to less than from from slows down — play(riff, lead, accel(2, 1, 4)) Both rates must be above zero: at zero the pattern would stop rather than slow.

Channel pressure — how hard the keys are being leant on — as a signal, 0 to 1.

Give a range to map it. Smoothed like cc. Zero on a keyboard that does not send it.

at(bar, section)

number → play

Place a section at an absolute bar, counted from the origin: at(8, chorus). Bars are counted from 0, so at(8, …) is the ninth bar

The pitch wheel as a signal, -1 to 1 with the wheel at rest reading 0 — so note + bend("keys", 1, -2, 2) bends two semitones either way.

Give a range to change that. Smoothed like cc.

One controller — a knob, a wheel, a pedal — as a signal: cc("push", 74) is 0 to 1. channel is 1-16 and defaults to 1.

Give a range to map it straight onto something: cc("push", 74, 1, 200, 5000) is a filter cutoff.

Smoothed over a few milliseconds, because seven bits wired to a cutoff zippers. Zero until the controller first moves, and silent when the port is not connected.

channels(buffer)

buffer → number

How many channels a buffer has — 1 for mono, 2 for a stereo file.

The current note’s length in seconds. Passed to a function used in a play scoped to the function.

load(path)

text → buffer

Read an audio file into a buffer: let amen = load("breaks/amen.wav"). The path is relative to the file it is written in.

Any format symphonia reads: wav, mp3, flac, ogg.

loop(play, times)

play → play

Loops the entire chain prior to its call n times. playn(groove, kit, 3).then_fill(roll).loop(4) is four bars of groove-and-fill.

Play a section with probability chance (0 to 1). Maybe decides each iteration:

playn(groove, drums, 4).maybe(0.25, fill).

midiclock(device)

number → number

Send the transport’s clock to a port, so a synth’s arps and delays line up with the part written for it: midiclock("deluge").

Twenty-four ticks to the quarter note, plus start and stop with the transport. The device is a port’s name — matched on any part of it, ignoring case — or its number.

Following somebody else’s clock is the other way round and is not this: it is in the settings panel under MIDI, because whether you are the slave tonight is about the rig rather than the piece.

midiin(device, channel?)

number → source

A keyboard to play, in place of a pattern: play(midiin("keystation"), lead), or midiin("keystation").play(lead).

The device is a port’s name — matched on any part of it, ignoring case — or its number in the settings panel’s list. channel is 1-16 and defaults to every channel, which is what a keyboard on its own means.

A note arrives as its MIDI note number, the same thing a pattern step carries. An instrument that declares a vel parameter is given the velocity, 0 to 1.

A keyboard has no length, so it takes neither a rate nor play_once/playn.

midiout(device, channel?)

number → destination

Gear to send a pattern to, in place of an instrument: play(bass, midiout("deluge"), vel: [1, .6]).

The device is a port’s name — matched on any part of it, ignoring case — or its number in the settings panel’s list. channel is 1-16 and defaults to 1.

A pattern’s values are MIDI note numbers, which is what c4, semi and scale already count in.

Lanes: vel is 0 to 1, chan overrides the channel per note, and legato sets how long the note is held.

A port that is not connected is a warning rather than an error, so a piece written for a rack still runs on the laptop it is edited on.

then, but the section starts bars before the first one ends. Two functions will sound together over the join: playn(verse, lead, 8).overlap(2, chorus). The chain carries on from whichever of the two ends later.

Schedule a pattern on an instrument: pat >> play(kick). The instrument must name a user fn.

rate defaults to 1.

Any further function parameter is added as a lane — play(bass, cut: [400, 2000]) lane’s values are sampled at each note’s onset.

Two names are reserved and reach the note rather than the instrument: legato: scales its length, and pan: places it across the stereo field from -1 (left) through 0 (centre) to 1 (right).

All children of play follow the same conventions.

play_all(section, ...)

section → play

Executes all plays simultaneously. play_all(verse, bassline).then(chorus).

Round where a chain of plays has reached up to a multiple of grid bars, without touching what is already playing: playn(pat, inst, 3, 2).quantize().then(chorus).

grid defaults to 1.

Useful when a section’s length is not a whole number of bars.

The quarter note in hertz — 1 / qvs. Use in oscillators: sin(qvh * 2)

The quarter note in seconds. Use with lengths: perc(0, qvs / 2) or delay(qvs * 0.75)

Random choice without weighting: playn(intro, lead, 2).rthen([verse, chorus, bridge]). Rerolls each iteration.

Read a buffer at a position: 0 is the start, 1 is the end. Anything outside that is silence.

position is a signal: sample(b, ramp(1 / b.secs)) — plays forwards, 1 - ramp(...) backwards.

channel defaults to 0 and wraps if the buffer has fewer.

secs(buffer)

buffer → number

Attribute on a buffer. How long a buffer is, in seconds.

seq(section, ...)

section → play

Plays plays one after another without the nesting: seq(intro, verse, chorus, verse). Only plays the next when the previous pattern completes.

Plays every section in a randomized order: play_once(intro, lead).shuffle_then([verse, chorus, bridge]). It is evaluated like scramble.

Read a portion of a buffer, once: slice(amen, 0, 0.25).

start and end are between 0 and 1.

start past end plays that portion backwards.

rate defaults to 1.

A control in the panel, named where it is used:

lowpass(saw(110), slider("cutoff", 200, 5000), 1)

That draws a slider called cutoff in the controls panel and reads it at audio rate, so dragging it is heard immediately with nothing recompiled. The range defaults to 0 to 1, and a fourth number says where it starts — otherwise it starts at the bottom.

The name is what labels the control and what makes it the same control after an edit, so writing one name in two places is one slider moving both.

Those two places need not agree on a range. What a slider holds is a position along its travel, and each place maps it into the range written there — so at halfway slider("cutoff", 200, 5000) reads 2600 while slider("cutoff", 0, 1) reads 0.5, one hand moving both across their own ends. The panel draws the range the program declares first.

A slider keeps its position across an evaluation and forgets it when the app quits, which is why the number written here is a starting point rather than a value: you dial a filter in, edit the line above it, play again, and the filter is where you left it.

Smoothed over a few milliseconds, because a drag wired straight to a cutoff zippers.

Written where the language wants a compile-time number — a ; length, a pattern step, a delay time — it is the position it stood at when the program compiled. The panel marks those, and letting go of one runs the program again.

take(play, bars)

play → play

Interrupts a play after n number of bars, play(riff, lead).take(8).then(chorus).

then(play, section)

play → play

Sequence one section after another: playn(verse, lead, 4).then(chorus).

then, with bars of silence in between the previous play: playn(verse, lead, 4).then_after(1, chorus) leaves a bar’s rest before the chorus. The gap cannot be negative.

One pass of the section per element of the list, in sequence, with the element from the list passed in: play_once(intro, lead).then_each([1, 2, 4], faster) calls faster(1), then faster(2), then faster(4).

A fill is played by the play it chains from: playn(groove, drums, 4).then_fill([1, 1, 1, 1]). The instrument and every lane are inherited and only the pattern is new.

A switch in the panel, off or on, named where it is used:

sin(220) * toggle("mute")

That draws a toggle called mute in the controls panel and reads it at audio rate, so flipping it is heard immediately with nothing recompiled.

It is 0 or 1, which is what makes multiplying by it the ordinary use: a part that is in or out, with no number to choose. A second argument says which end it starts at — toggle("lead", 1) starts on — and it has no range to give it, since its ends are its two states.

Everything else about it is a slider. One name is one control wherever it is written, so writing the same name in two places is one switch moving both. It keeps its state across an evaluation and forgets it when the app quits, which is why the number written here is a starting state rather than a value. And its ends are smoothed over a few milliseconds, so switching something in does not click.

trigger(name, section)

text → number

A button in the panel that starts a section when it is pressed:

fn fill() = play_once([38, 38, 40], snare)

trigger("fill", fill)

That draws a button called fill, and hits of it play fill.

The section is a fn named rather than called — the same thing then takes — so how long it lasts is what it says. A play_once or playn inside it is a one-shot; a plain play keeps going until something stops it.

It is lowered when the program runs, not when the button is pressed. So a press compiles nothing, can fail at nothing, and costs the performance nothing: what the button does is arm a section that was written out in full a moment after you hit play.

A press starts the section on the next beat, and pressing again restarts it from the top. Nothing else stops — a fired section plays over what is already going, and the only notes it decides are its own.

with(play, section)

play → play

Run a section alongside the previous play in the chain: playn(verse, lead, 4).with(drums).then(chorus). The pair finishes when the later of them does.

Weighted choice between sections each iteration: playn(intro, lead, 2).wthen([verse, chorus], [0.7, 0.3]). Weights are relative and need not sum to 1.

39names in Patterns and Playback. All categories.