Skip to content

Reference

Exhaustive documentation for the expression language, note properties, and file formats. If you are looking for how to do something, start with the User Guide. This section tells you what is true.

Expression language

  • Syntax — the complete grammar: tokens, literals, references, functions, operators, precedence, error behaviour
  • Operators — per-operator semantics and result types
  • Module API — note references and built-in functions
  • Fraction API — exact numbers, and the legacy new Fraction() compatibility surface

Note properties

The sixth property, measureLength, has no page of its own: it is derived from tempo and beatsPerMeasure and has no UI. It is covered under tempo.

Formats

Quick reference

The exhaustive tables live on the pages that own them. These are the ones you look up most.

  • Just-intonation ratios — the interval-to-expression table is on frequency. For the musical reasoning, see Pure Ratios.

Equal-temperament steps

SystemOne stepValue
12-TET2^(1/12)≈ 1.059463
19-TET2^(1/19)≈ 1.037155
31-TET2^(1/31)≈ 1.022611
Bohlen-Pierce (13 divisions of the tritave)3^(1/13)≈ 1.088182

n steps is 2^(n/12), 2^(n/19), and so on. All of these are irrational, so a note using one is flagged corrupted and drawn crosshatched. See Operators.

Note lengths

NoteBeatsExpression
Whole4beat(base) * 4
Half2beat(base) * 2
Quarter1beat(base)
Eighth1/2beat(base) * (1/2)
Sixteenth1/4beat(base) * (1/4)
Dotted quarter3/2beat(base) * (3/2)

beat(x) is one beat of x in seconds — that is, 60 / tempo(x). It is what the note-length buttons in the note widget write for you. The full table, including dotted values, is on duration.

Property shortnames

PropertyAccepted spellingsSaved as
frequencyf, freq, frequencyf
startTimet, s, start, startTimet
durationd, dur, durationd
tempotempotempo
beatsPerMeasurebpm, beatsPerMeasurebpm
measureLengthml, measureLengthml

Keyboard shortcuts

ActionWindows/LinuxMac
UndoCtrl+ZCmd+Z
RedoCtrl+YCmd+Y

Both are ignored while the focus is in a text field, so they never fight with editing an expression.

Pointer gestures

ActionGesture
Marquee-select notesShift + drag on empty background
Add or remove one note from the selectionShift + click the note
Loop playbackShift + click Play

See Keyboard Shortcuts for the full list.

Internals

These are implementation details. You do not need them to use the app, but they are stable and they are what the file format and the evaluator agree on.

Variable indices

IndexProperty
0startTime
1duration
2frequency
3tempo
4beatsPerMeasure
5measureLength

Corruption flags

A bitmask, one bit per property, recording which of a note's values came out irrational.

FlagProperty
0x01startTime
0x02duration
0x04frequency
0x08tempo
0x10beatsPerMeasure
0x20measureLength

Bytecode opcodes

OpcodeByteEffect
LOAD_CONST0x01Push a constant fraction (two 32-bit integers)
LOAD_REF0x02Push a property of note N (16-bit id, 8-bit variable index)
LOAD_BASE0x03Push a property of the BaseNote (8-bit variable index)
LOAD_CONST_BIG0x04Push a constant fraction with arbitrary-precision parts
ADD0x10Pop 2, push sum
SUB0x11Pop 2, push difference
MUL0x12Pop 2, push product
DIV0x13Pop 2, push quotient
NEG0x14Pop 1, push negation
POW0x15Pop base and exponent, push the power; may set a corruption flag
FIND_TEMPO0x20Defined, never emitted
FIND_MEASURE0x21Defined, never emitted
FIND_INSTRUMENT0x22Defined, never emitted, not implemented in the evaluator
DUP0x30Defined, never emitted
SWAP0x31Defined, never emitted

tempo(x) and measure(x) compile to a plain property load, not to FIND_TEMPO / FIND_MEASURE. beat(x) compiles to LOAD_CONST 60, a tempo load, then DIV.

Fallbacks and limits

ThingValue
Value used when a reference cannot be resolvedstartTime 0, duration 1, frequency 440, tempo 60, beatsPerMeasure 4, measureLength 4
Division by zero at evaluation timeResult 1, plus a console warning; the property is flagged corrupted (crosshatch)
An expression neither compiler can parseCompile error — console.error plus a thrown message naming both parser failures; validators return valid: false; on a file load the note's property is left unset
Decimal → fractionExact as written — the digits over the matching power of ten, reduced (0.333333 is 333333/1000000)
Constant fits LOAD_CONST when both parts are within−2 147 483 648 to 2 147 483 647 (bigger constants use LOAD_CONST_BIG, exact at any size)
Note id in a reference0 – 65 535, enforced when the expression compiles
Exact ^ capsInteger exponent ≤ 65 536 and result ≤ ~1 Mbit per component; past either, the value is approximated and flagged corrupted
Maximum expression length accepted on import10 000 characters
Compiled-expression cache4 000 entries, least-recently-used eviction

See also

Released under the MIT License