ScoreScript Language wiki

Music objects: scales that fit the player

A music object is a passage defined once and applied by name. The definition claims no bars; every application prints the object's bars in the part that applied it, moved to a tonic and — under fit — slid into that player's range. One definition of a one-octave scale becomes fifteen keys on twelve instruments, each in the register that instrument reads.

In a work with movements, an object before the movements collection belongs to the whole book and is available inside every movement. Define a movement-local object only for a chapter that genuinely needs a different body; the local definition shadows the book default with that name. The movement still owns its roster, bars, headings and layout.

Define, then apply

Independent rhythms and compact traversal

pulse = rhythm {q1 e6}
phrase = {
  @scale-major C4a {@pulse} | b {sim.}
}

C4a ascends from C4. The seven attacks here reach B4; b reattacks that actual last pitch and descends to C4. C4 without a suffix uses the rhythm once in each direction. C4b on its own begins at the upper tonic C5. | remains a measure boundary with meter none; sim. belongs only to this application. A new application starts fresh.

Rhythms count attacks (q1, e6), accept native tuplets (3{e3}) and native mark groups. name = rhythm {…} is pitch-free and can reference other named rhythms. 3{e3} {e3} repeats the triplet count within that rhythm body. Write q8 (,) for eight quarter attacks and a breath after the eighth; q7 (,) q1 puts the breath after the seventh. Initial marks attach to the first attack. Music objects can combine literal bars with other @ applications and the range rules below. An unmarked monophonic object can also supply an ordered pitch collection for retiming; its native notes remain the authoritative pitch definition.

Expansion refuses cycles, unknown references, empty rhythm measures and a rhythm longer than the selected traversal. Built-in compact traversals cover one octave; longer or differently shaped music uses authored objects. Marked music, rests and chords remain ordinary music objects, not silently stripped collections. Counted rests, ties, dotted counts and arbitrary repeats are not part of this first compact-rhythm cut.

The same source is accepted by the shared native parser used by every host; hosts must update their engine to use the new syntax.

Literal music

Edit this exampleDownload source
scorescript 0.3
score "Two scales, one definition" {
  meter 4/4
  key open

  allstate = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  parts {
    tpt F#3-C6
    tbn E2-Bb4
  }

  all written fit {
    @allstate F
    @allstate Bb
  }
}
Notation for the Music objects: scales that fit the player exampleNotation for the Music objects: scales that fit the player example
Original canonical spelling
scorescript 0.3
score "Two scales, one definition" {
  meter 4/4
  key open

  allstate = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  parts {
    tpt F#3-C6
    tbn E2-Bb4
  }

  all written fit {
    @allstate F
    @allstate Bb
  }
}

allstate = { … } defines the object in C, with its own bar lines and its closing double bar. @allstate F applies it at the tonic F: the object's C becomes F and every other note moves with it. all names every part on the roster; written says the head works on the player's page — the tonic, the range and the printed notes are all what the player reads, and the bars carry the instrument's transposition so the engine never derives them again; fit slides each application by whole octaves to the lowest position on or above the player's floor and refuses one whose top passes the ceiling. The trumpet, held to written F#3–C6, reads F major from F4; the trombone, held to E2–B♭4, reads it from F2. Each application opens with the key it was moved to and a label — F Allstate - 1 octave — derived from the object's name and its compass.

title "Major" on the body's first line is the word the label prints — Bb Major - 2 octaves — where a bare object prints its name (allstate2 → "Allstate2"). A \n or \p line between two applications opens the next object on a new system or page, exactly as the same mark before a measure group does; an All-State sheet is one \n between every scale.

A name is a word: letters, digits, hyphens. A name shaped like a chord symbol (am7, F7) is refused where it is defined, because @am7 would otherwise be ambiguous with the harmony label.

An object may also be moved by an interval (@allstate +P4) or an octave (@allstate F', @allstate F,), and applied inside a single part's body without a head — in which case the part's own range and concert pitch apply.

Choose by what fits

Edit this exampleDownload source
scorescript 0.3
score "What fits" {
  meter 4/4
  key open

  one = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  two = {
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    first { @two C, @one C }
    fits { @two G, @one G }
    if range contains @two D {
      @two D
      @one D
    } else {
      @one D
    }
  }
}
Notation for the Music objects: scales that fit the player exampleNotation for the Music objects: scales that fit the player example
Original canonical spelling
scorescript 0.3
score "What fits" {
  meter 4/4
  key open

  one = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  two = {
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    first { @two C, @one C }
    fits { @two G, @one G }
    if range contains @two D {
      @two D
      @one D
    } else {
      @one D
    }
  }
}

Three doors, one rule. first { @two C, @one C } prints the FIRST object that fits — the flute gets two octaves of C, the trombone (whose written E2–B♭4 holds one octave of C but not two) gets one. fits { @two G, @one G } prints EVERY object that fits, in order: the flute prints both, the trombone the one. if range contains @two D { … } else { … } is the same question asked as logic, for a packet whose branches print different things.

The failure rule is strict. An object that does not fit is not cut short and not swapped for a smaller one: it is omitted and named in an error (object.no-fit) with the range in force, so the packet is never quietly wrong. A first or fits with nothing that fits is the same error.

Book-level range maps are inherited by movements and exercise containers. State the editable instrument ranges once; a local roster or part declaration can override a particular chapter. fit checks the complete object, including neighbor tones above and below its tonic span. It never replaces those notes.

For method-book parts with different exercise lengths, use book { cover, contents, folios, running-heads, independent-parts }. Extracted parts omit only generated exercise-alignment tails, retaining real rests and source identities. The combined score remains aligned; it is not a new synchronized arrangement of the differing variants. Put systems N and local layout { \p1 } inside exercise containers so placement follows each exercise rather than fixed global bar numbers.

An independent part's contents list omits an exercise when none of its bars remain for that player. A partly retained exercise points to its first retained bar; an intentionally written rest remains an exercise. Page references follow that part's actual pagination, including pickups and gaps in source bar numbers. This does not renumber score-global exercise ordinals.

Composed copies of named notes retain their source provenance and receive distinct instance names. The first keeps its authored name; later copies use the existing name-mN return-instance spelling. Truly duplicate authored names remain errors.

The range in force is the declared contract (the roster line, a range statement, or bounds on the head — ob written C4-C6 { … }), else the catalog's practical band for the instrument, else nothing constrains the application at all. See declared ranges.

Write the rule once, in a definition

Edit this exampleDownload source
scorescript 0.3
score "Rules written once" {
  meter 4/4
  key open

  one = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  two = {
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  scale-for-range = {
    title "Major"
    if range contains @two {
      @two
      @one
    } else {
      @one
    }
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    @scale-for-range C
    @scale-for-range G
  }
}
Notation for the Music objects: scales that fit the player exampleNotation for the Music objects: scales that fit the player example
Original canonical spelling
scorescript 0.3
score "Rules written once" {
  meter 4/4
  key open

  one = {
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  two = {
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  scale-for-range = {
    title "Major"
    if range contains @two {
      @two
      @one
    } else {
      @one
    }
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    @scale-for-range C
    @scale-for-range G
  }
}

A definition can hold the same three rules a reader head holds: first { }, fits { } and if range contains … { } else { }. The rule is asked where the definition is applied, once for each reader. @scale-for-range G asks each player whether their range holds @two G, and prints what if range contains @two G { @two G @one G } else { @one G } would print at the head. Here the flute plays both scales in C and in G. The trombone plays one octave of C, because C3–C5 passes its B♭4, and both scales in G.

The objects named inside keep their usual meaning: each one moves with the application around it. @two inside @scale-for-range G is two octaves of G, and @scale-for-range G +P4 asks and answers in C. A written head asks in written pitch and a concert head in concert pitch. The range is the one in force where the definition is applied, so a chapter's own range map still decides. Rules nest: a definition that chooses can itself be a choice in another rule, or be applied inside another definition.

A definition is still one passage. Whatever it chooses moves with it, is slid into range as one piece under fit, and prints one label: the definition's own title (G Major - 2 octaves) or its name. Each object inside is in its own key, as it would be when applied directly. A signature prints only where the key changes, so pieces in the same key read as one line. Two choices that start in different octaves stay together, where the same rule at the head would place each on its own.

If a first { } or fits { } inside a definition finds nothing that fits, the reader gets nothing and an error names the rule (object.no-fit), the same as at the head. A layout cut (\n, \p) cannot go inside a definition. Every reader shares the definition, but a page break belongs to one reader's page, so write the cut at the reader head before the application.

Edit this exampleDownload source
scorescript 0.3
score "One family" {
  meter 4/4
  key open

  two-octave = {
    title "Major"
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  one-octave = {
    title "Major"
    range-variant-of two-octave
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    @two-octave C
  }
}
Notation for the Music objects: scales that fit the player exampleNotation for the Music objects: scales that fit the player example
Original canonical spelling
scorescript 0.3
score "One family" {
  meter 4/4
  key open

  two-octave = {
    title "Major"
    4C4 8D E F G A B | 4C 8D E F G A B | 4C 8B A G F E D | 4C 8B A G F E D | 1C ||
  }

  one-octave = {
    title "Major"
    range-variant-of two-octave
    4C4 8D E F G A B | 4C 8B A G F E D | 1C ||
  }

  parts {
    fl C4-C7
    tbn E2-Bb4
  }

  all written fit {
    @two-octave C
  }
}

range-variant-of two-octave says that one-octave is the same teaching object at a smaller compass. Under fit, @two-octave is then not one object but a FAMILY, and the widest member the reader's range holds is the one that prints: the flute gets two octaves, the trombone one, from a single application written once. It is first { @two-octave C, @one-octave C } stated at the definition instead of by hand in every chapter of every part book, and it lowers to exactly that — the failure is the same object.no-fit, naming every member it tried.

Without fit the author named the object they wanted, and the family is never consulted. fit is the word that means choose by what this player holds.

variant-of thirds records the other kind of relation — another treatment of the same teaching object, simple beside complex — for the index. It moves no note and selects nothing.

The relation sits on the body's head beside title, because both are facts about the object rather than music in it. An object stands in at most one relation: a second would be a second answer to "what is this a version of". A relation that names nothing defined here, either end of which is a rhythm, or a chain that returns to where it started, is refused where it is written — object.relation-unknown, object.relation-on-rhythm, object.relation-cycle, object.relation-repeated.

Relations that can be read off the score are never written down: an object whose body applies another is derived from it, and an object applied inside an exercise appears in it. Only what the notes cannot show is authored.

Definitions from another file

scorescript 0.3
score "Scales with Character — C major" {
  use "../definitions.scorescript"

  meter none
  key C

  parts {
    tpt F#3-C6
  }

  all written fit {
    @two-octave C
  }
}

use "…" reads every music object and rhythm that file defines at book level. A chapter then writes applications and no notes, and the notes have exactly one home: edit definitions.scorescript and every chapter that uses it changes on its next compile, with nothing to touch in between.

The path is relative to the file that wrote it, never the working directory. This file's own definitions shadow what it reads, the same way a movement-local object shadows its book's. Two used files offering one name is refused (link.ambiguous-definition) rather than guessed at, and so are a cycle (link.cycle) and a path that does not open (link.file-not-found); a file with no book-level definitions says so (link.nothing-used). A door handed source text with no directory of its own — the MCP compile_score endpoint, the wasm build — refuses with link.no-filesystem.

The formatter prints the use line and never the music it names. Writing the pulled definitions into this file would turn a source of truth into a stale copy, which is the one thing the statement exists to prevent.

Built-in scales

Edit this exampleDownload source
scorescript 0.3
score "Built in" {
  meter 4/4
  key open

  parts {
    cl E3-G6
  }

  cl written fit {
    @scale-major G
    @scale-harmonic-minor A
    @scale-dorian D
    @scale-chromatic
  }
}
Notation for the Music objects: scales that fit the player exampleNotation for the Music objects: scales that fit the player example
Original canonical spelling
scorescript 0.3
score "Built in" {
  meter 4/4
  key open

  parts {
    cl E3-G6
  }

  cl written fit {
    @scale-major G
    @scale-harmonic-minor A
    @scale-dorian D
    @scale-chromatic
  }
}

The compiler builds in the scales and modes: @scale-major, @scale-minor, @scale-harmonic-minor, @scale-melodic-minor, @scale-dorian, @scale-phrygian, @scale-lydian, @scale-mixolydian, @scale-aeolian, @scale-locrian, @scale-whole-tone, @scale-pentatonic, @scale-minor-pentatonic, @scale-blues, and @scale-chromatic. Each seven-note scale is one octave in the audition pattern — a quarter on the tonic, six eighths, the top tonic, and back — and prints the signature its tonic asks for (a mode prints its parent major's). @scale-chromatic runs from the bottom to the top of the reader's range and back, sharps up and flats down, the last note filling its bar, so it needs a range. scorescript scales prints the whole list with each scale's octave in C; hosts read the same list as the scorescript://catalog/scales resource.

A built-in name cannot be redefined; an authored object of the same name is refused. An unknown @name is object.unknown.

What the expanded score shows

Objects are a desugaring: the analyzer turns every application into ordinary bars before anything downstream sees the score, so a part that applied three scales is a part with three scales' bars, numbered after its last written bar. scorescript format --normalize expand writes that expanded score out, which is how to see — or hand to a tool that knows nothing of objects — exactly what each player was given.