The language

Patterns are questions about time.

Mora follows the span-query approach associated with TidalCycles: a pattern describes the events that appear in a requested interval. What Mora emphasizes is the representation left behind. Selected evaluated constructs remain as inspectable objects, interpreted through an open protocol, so the notation can stay terse while the implementation stays available.

Time as exact ratios

A pattern answers a question about an interval instead of stepping through a list that is consumed once. Mora calls that operation events-in. A span is half-open: it includes its beginning and excludes its end. Time is expressed in cycles, and fractions such as 1/3 and 7/8 can remain exact Common Lisp ratios.

A cycle is a musical coordinate, not intrinsically a second or a bar. The transport maps it to physical time using tempo and beats per cycle. With four beats per cycle, 140 BPM corresponds to 7/12 cycles per second, so these two forms express the same rate:

Common Lisp
(bpm 140)
(set-cps 7/12)

(events-in *first-pattern* (span 5/8 9/8) )

Drag the window or its endpoints, or tap the track to move the nearer endpoint. With an endpoint focused, use the arrow keys.

Events visible in the span [5/8, 9/8)
Event Whole Visible part Attack in this span
sn [1/2, 3/4) [5/8, 3/4) No, it began earlier
hh [3/4, 1) [3/4, 1) Yes
bd [1, 5/4) [1, 9/8) Yes

A span query over *first-pattern*, bound to (s "bd [hh hh] sn hh") as in the getting-started guide. The window is half-open: it includes its start (filled endpoint) and excludes its end (open endpoint). An event cut by the window keeps its whole span, and only an event whose onset falls inside the window starts a new attack. This figure is drawn by the website to explain the idea; it does not run Mora.

Visible spans and whole events. A scheduler may query only a fragment of a note or loop. That query should not turn the fragment into a new full event, change a recording's pitch, or create another attack by accident. An onset belongs to the event's temporal identity, which is why score-time looping, audio-file looping, and changing a sample's playback speed are separate operations.

Patterns and time

Notation inside Lisp

Mini notation is compact temporal notation inside strings. It is embedded in Common Lisp rather than replacing it. The literal forms s, n, notes, p, and e are macros with context-sensitive coercion: inside s, bare symbols can mean sample names.

Selected mini notation
NotationMeaningExample
Spaces Sequence within the current cycle or group. "bd hh sn hh"
~ Rest. "bd ~ sn ~"
[ ... ] Subdivide the containing slot. "bd [hh hh] sn hh"
Comma inside a group Parallel voices. "[bd ~ sn ~, hh*8]"
< ... > Alternate across cycles. "<bd sn sn>"
* Repetition, a faster local occurrence. "hh*8"
@ Relative temporal weighting. "bd@3 hh sn@2 hh"
_ Extend the preceding event's whole rather than make a new attack. "f3 _ ab3 c4"
Euclidean suffix A Euclidean attack structure. "bd(3,8)"

Use sub to subdivide a slot directly in s-expressions:

Common Lisp
(d1! (s bd sn hh cp))

(d1! (s bd (sub hh hh) sn (sub hh cp)))

Use ($ expression) when a literal should evaluate ordinary Lisp. Functions, variables, and control structures remain available; a list is ordinary Lisp data unless it is explicitly turned into a pattern.

Common Lisp
(defparameter *kit* '("bd" "hh" "sn" "hh"))

(d1! (s ($ (apply #'cat *kit*))))

Composition, left to right

>> threads a pattern through transformations and clauses from left to right. Use stack for simultaneous voices. Parallel voices are not parameter merging: annotations such as gain use merge-left, so each existing event keeps its multiplicity while receiving its parameter. The open pattern-merge-style protocol selects that behavior.

Common Lisp
(d1! (stack
       (>> (s "bd ~ bd ~")
           (cut 1))
       (>> (s "~ sn ~ sn")
           (cut 2))
       (>> (s "hh*8")
           (cut 3))))
Temporal composition operations
OperationPurpose
stack, overlay Parallel patterns.
cat, fast-cat Subdivided succession.
slow-cat Succession across cycles.
time-cat Fit phrases into proportional weighted spans.
arrange Allocate actual cycle durations to sections.
align Combine temporal value layers according to their spans.
merge-left Annotate existing events without turning sibling voices into one event.

time-cat weights are proportions; arrange allocates actual cycle durations. A Mora channel owns a source pattern, while a SuperDirt orbit is an output bus, so one stack can route its lanes to separate orbits.

Pipelines and composition

Transformation and groove

Temporal transformations act on score time. Audio-file parameters act on the resulting sound: rev reverses a score, while sample-rev reverses sample playback. The supplied chance operators are temporally reproducible, rather than consulting global random state on every scheduler fragment.

Rate and phrase shape
fast, slow, rev, palindrome, hurry, rot, iter, iter-prime
Placement and extraction
early, late, compress, zoom, trunc, linger, within, inside, outside
Repetition and copies
ply, jux, jux-by, off, superimpose, spin
Groove
swing-by, press-by
Conditional application
every, sometimes, and related conditional and chunk operations
Echoes
echo-with, echo-spaced, echo-indexed
Common Lisp
(d1! (>> (s "bd hh sn cp")
         (every 3 #'rev)))

(d1! (>> (s "hh*8")
         (swing-by 1/3 4)))

(d1! (within 1/2 1 #'rev (s "bd hh sn cp")))

(d1! (>> (s "bd hh sn cp")
         (jux #'rev)))

(d1! (echo-spaced 4 1/8 0.7 (s "bd ~ sn ~")))

Musical structure, explicitly authored

Named pitches, scale degrees, chords and voicings, arpeggiation, tuning beyond twelve equal divisions, and authored meter are part of the language. Chord identity and its realization as voices are separate, and arpeggiate selects actual voices from those chords.

Common Lisp
(defparameter *changes* (chords "<Fm7 Dbmaj7 Eb7 Cm7>"))

(d1! (>> (voicing *changes*
                  :anchor "c4")
         (arpeggiate "0 ~ 2 [1 3]")
         (s "psin")
         (legato 0.6)))

Authored positions are not the same as emitted attacks: rests count as positions. pace retimes a phrase according to authored units, separately from global BPM. Here the three-unit and five-unit phrases occupy 3/4 and 5/4 cycles at four units per cycle, with consistent unit spacing instead of squeezing each phrase into an equal duration.

Common Lisp
(defparameter *phrases*
  (slow-cat (s "bd ~ sn")
            (s "bd hh ~ sn hh")))

(d1! (pace 4 *phrases*
           :period 2))

The pitched examples need an available instrument named psin; an arbitrary SuperDirt installation is not assumed to contain it.

What remains after evaluation

Consider a composition made from a sample sequence and a speed change, like the one below. The source is a convenient way to construct it, but the result is not limited to source text. Named pattern instances, their children, metadata, and applicable methods remain available for inspection and interpretation.

  1. 1 Source expression
    (defparameter *example-pattern*
      (>> (s "bd sn")
          (fast 2)))
  2. 2 Retained pattern objects speed-pattern instance (s "bd sn") pattern Inspectable now: pattern-summary, pattern-children
  3. 3 A query over a span (here, cycle 0)
    (query-cycle *example-pattern* 0)
    Arbitrary spans use the lower-level events-in protocol, whose methods can be extended
  4. 4 Events with values, spans, and provenance bd [0, 1/4) sn [1/4, 1/2) bd [1/2, 3/4) sn [3/4, 1)
  5. 5 Interpretation by an output backend For sample and synthesis output: timestamped OSC to SuperDirt in SuperCollider.
What evaluation leaves behind. The source is a convenient way to construct the composition, not the whole result. Retained objects remain available for inspection and answer later queries, so a changed method changes future answers. Already-dispatched sound is not rewritten. The forms are from the public framework example file.

Introspection

Inspect the retained objects, their structure, parameters, and event answers. These forms are not audible.

Intercession

Add or redefine applicable protocol methods, changing the behavior obtained through those objects on subsequent queries. Output already dispatched is not rewritten.

Common Lisp
(defparameter *pattern* (>> (s "bd ~ sn hh") (fast 2)))

(class-of *pattern*)
(pattern-summary *pattern*)
(pattern-children *pattern*)
(pattern-metadata *pattern*)
(events-in *pattern* (span 13/4 7/2))

Common Lisp and CLOS

Common Lisp is not only a notation host for Mora; it supplies the working environment in which the language is developed and performed. In CLOS, a generic function can have methods specialized for different classes. Mora uses this to separate temporal interpretation, structural observation, construction, composition policy, and shader emission, so an extension can implement the operation it actually needs.

Mora chooses named classes and generic operations so representation, strategy, and state can be inspected and specialized in the running image.

  1. Authored pattern program (>> (s "bd sn") (fast 2)) Constructs a temporal program.
  2. Mora's retained implementation objects A speed-pattern instance, events-in, applicable methods Interpret and expose that temporal program.
  3. CLOS implementation facilities Classes, generic functions, methods Supply the metalanguage in which Mora is built.
“Metaobject” is relative to a language level. Mora's pattern objects participate in implementing the pattern language; CLOS implements those objects. Mora opens selected parts of its implementation through a protocol written in CLOS, which does not require extending the CLOS metaobject protocol itself.
The deliberately bounded protocol
SurfaceRepresentative operationsScope
Retained temporal interpretation events-in Answers event queries.
Structural observation pattern-children, pattern-summary, pattern-metadata Supports inspection and tools.
Tooling estimate pattern-period Estimates visible repetition; it is not an exact metrical clock.
Open construction and composition apply-transform, normalize-clause, apply-clause, pattern-merge-style Builds and combines behavior; some construction objects are transient.
Adjacent visual interpretation emit-glsl Applies to the visual-operator subset, not every arbitrary pattern class.

The openness is bounded. Not every intermediate construction object is retained, not every custom extension automatically gains every editor affordance, and a new interpretation may apply only to a particular class family.

Common Lisp and CLOS

Extending the language from inside

defpattern defines a named pattern class, constructor, and observation and query methods. The class generated here is pulse-pattern, with a pulse-factor reader.

Common Lisp
(defpattern pulse (&key (factor 1))
  "An inspectable backbeat. Example: (pulse :factor 2)."
  (fast factor (s "bd ~ sn ~")))

(defparameter *live-pulse* (pulse :factor 1))

(d1! *live-pulse*)

An applicable method can change the behavior of the same object on subsequent queries:

Common Lisp
(defmethod events-in ((self pulse-pattern) query-span)
  (declare (ignore self))
  (events-in (s "bd hh sn [hh cp]") query-span))

The defpattern body is evaluated by its query method, not once as a universal compile step, so keep it suitable for repeated arbitrary-span interpretation. deftransform defines a reusable, inspectable transformation, and musical vocabularies such as scales can be extended as well:

Common Lisp
(deftransform doubles (factor)
  "Double or otherwise scale source rate."
  (:apply (pattern)
    (fast factor pattern)))

(d1! (>> (s "bd sn")
         (doubles 2)))
Common Lisp
(define-scale :my-pentatonic '(0 3 5 7 10))

(d1! (>> (degrees "0 1 2 3 4 5 6 7")
         (in-scale :my-pentatonic
                   :root "f3")
         (s "psin")))

The shape of the system

Mora is SBCL-first Common Lisp. Its scheduler and backends are separate from the notation layer, and Studio's editor and evaluation model is separate from its native GL renderer. Visual operators are pattern objects with an adjacent GLSL interpretation for that subset.

The language

  1. mora/core Temporal values, events, retained pattern protocol
  2. mora/runtime Transport, channels, scheduling, backend protocol
  3. mora/mini Terse livecoding language
  4. mora User facade

Optional clients and adapters

  • mora/superdirt Timestamped sound output
  • mora/audio Prepared audio and control descriptions
  • mora/samples* Discovery, cache, control, import, audition, Studio glue
  • mora/visual Visual operators and native GL renderers
  • mora/analysis cl-mltk integration
  • mora/link Link integration
  • mora/studio-core Editor, evaluation, assistance, inspection; no GL
  • mora/studio Native window, GL rendering, application lifecycle
Deliberately layered. mora/runtime builds on mora/core; the mini language and the mora facade sit above the runtime, and every client is optional. Studio's editor model is separate from its GL renderer, which allows substantial work from a plain Lisp REPL. Entries with a solid blue outline include native OpenGL rendering.

Search the documentation

Results update as you type. Use the up and down arrow keys to choose a result and Enter to open it.