Skip to content

Script Patterns

A class that implements the Pattern interface is a pattern. Send an instance to a track with << and resonon calls query() once per cycle. For worked examples, see Write a Pattern as a Class.

class Arp implements Pattern {
fn query(cycle) -> Note | Number | Rest | Array | Pattern? { … }
}
  • The class defines query with one parameter named cycle, and declares its return type as the interface does. A class that does not conform is refused where it is defined.
  • A class with a query method that does not say implements Pattern is not a pattern: << refuses it and names the fix.
  • The class has every combinator of Pattern (.fast(), .transpose(), .stack(), …), and every parameter typed Pattern takes its instances.

A combinator, << and a stdlib parameter typed Pattern each capture the instance as it is at that moment, fields and methods. A later write to the instance changes nothing already captured:

let walk = Arp(#[C4, E4]);
let fast = walk.fast(2); // captures walk now
walk.notes = #[D4]; // fast still plays C4 and E4

A function of your own that takes p: Pattern gets the instance itself, not a capture.

For each cycle, the track:

  1. Rebuilds the instance’s fields by replaying query() for every earlier cycle, starting from the field values the instance had when it was sent to the track.
  2. Calls query(cycle) with the cycle number (0, 1, 2, …).
  3. Converts the return value into the events of that cycle.
RuleConsequence
Fields assigned in query() carry to the next cycle.this.idx = this.idx + 1; advances once per cycle.
State is replayed from cycle 0.The same cycle always returns the same result, in any order and after any seek.
Fields are captured when the instance is sent to a track, or passed to a combinator.Changing the original instance afterwards does not change the playing pattern.
cps is in scope inside query().The current tempo, in cycles per second.
Return valueResult
Number (60)A MIDI note filling the cycle
Note (C4)A note filling the cycle
Array (#[C4, E4, G4])A chord — all notes sound together for the cycle
Pattern ([C4 E4 G4], or an instance of a class implementing Pattern)A sub-pattern, laid out across the cycle
[_]A rest — silence for the cycle

query() runs in a restricted evaluator, so that it is deterministic and safe to run away from the main thread.

SupportedNot supported
let, if/else, match, return, for, loopprint(), put()
Arithmetic, field and array accessAudio and MIDI operations
Calls to your own functions, methods and classesNative functions
Seeded rand() and choose() from std/random