and more

mScore.js content language technical specification

This document contains the formal specifications of mScore.js’s content description languages — for describing voice content and rhythm patterns. It uses the Extended Backus-Naur Form (EBNF) notation which is in use in the W3C’s XML specification. If you wish to learn to use mScore.js to write musical scores this technical document is very likely the wrong place for you — we recommend the interactive manual for that.

General definitions

Common syntactic constructs

These are general syntax elements which appear in various places in the languages described below.

Char          ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF](As defined in XML)
S             ::= (#x20 | #x9 | #xD | #xA)+(White space, as defined in XML)
unsignedInt   ::= [0-9]+
signedInt     ::= ('+' | '-') unsignedInt
signedDecimal ::= ('+' | '-') (unsignedInt | [0-9]+ '.' [0-9]* | '.' [0-9]+)

Note that signed numbers must have a sign even when they are nonnegative, and that we don't allow numbers in exponential notation.

XMLTag        ::= An XML start-tag, end-tag, or empty-element-tag as defined in the XML specification

Source code comments

XMLComment    ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'(As defined in XML)

Note that in an XML comment the expression “--” can only appear as part of the comment-terminating “-->”.

In addition to XML comments mScore.js defines its own, more convenient comment syntax. An mScore.js comment consists of nested pairs of round brackets () and can contain any text, other mScore.js comments, complete XML tags and XML comments. As the grammar below specifies, closing comment brackets “)” that occur inside XML tags (in attributes) or inside XML comments do not terminate the mScore.js comment.

mScoreComment ::= '(' ([^()<] | XMLComment | XMLTag | mScoreComment)* ')'

The grammar allows comments which contain only one of a start-tag/end-tag pair, although the resulting content object may be invalid as a result. You can however enclose an XML element’s start-tag in one comment and its end-tag in another.

As part of the parsing process all XML comments and mScore.js comments are stripped from the source code, and only put back in for syntax highlighting in an editor or when returning an error message to give the correct line/column number. The language grammars below refers to the content after stripping comments. This implies that comments can occur anywhere including within mScore.js language items.

Rhythm pattern language

Because the rhythm pattern language is quite simple, it can be described with a single EBNF pattern:

rhythmPattern ::= (S? (tupletPattern S?)* (noteValue | beamedGroupPattern))+ S?
noteValue     ::= ('1' | '2' | '4' | '8' | '16' | '32' | '64') dots?
dots          ::= '.'+

Note values

In mScore.js note values are described by the reciprocal n of the base value and the number of dots d. Their length (as multiples of a full note) is thus provided by the formula v(n,d)=2d+112d·n. For example, a quarter note with two dots (noteValue4..”) has the length v(4,2)=7/16. Since the shortest note available has a length of 1/64, the following validity constraint applies to a dotted note:


Beamed groups

beamedGroupPattern ::= noteValueB dots? (beamConnector noteValueB dots)* beamConnector noteValueB
noteValueB         ::= ('8' | '16' | '32' | '64')
beamConnector      ::= S? ('_' | '_' '^'+ '_') S?

A beamed group is a sequence of notes with values n8 visually connected by beam(s). Note that in a beamed group all notes except the last are allowed to have dots, subject to the constraint described above.

Tuplet patterns

tupletPattern ::= 'tp' unsignedInt '/' unsignedInt ('/' unsignedInt)? ':'

A tuplet pattern is governed by three unsigned integer numbers, tp⟨baseBeat⟩/⟨split⟩/⟨nBeats⟩:. The meaning is that notes with a total length of splitbaseBeat go into the tuplet, but its actual duration will be nBeatsbaseBeat. If ⟨nBeats⟩ is omitted, the default value is used:

Tuplet patterns are subject to the following validity constraints:

2.3baseBeat must be a valid note base value, i.e. {1,2,4,8,16,32,64}.
2.4A number of single notes and complete beamed groups must follow the tuplet pattern which exactly sum up to the tuplet’s splitbaseBeat, i.e. the tuplet cannot be over- or underfilled.
2.5The tuplet’s content must contain more than one note.

Voice and multi-voice language

These two languages describe musical scores which consist of the content of a single voice separated into bars. The only difference between them is that multi-voices allow voice switches in addition to bar lines. When a voice switch is encountered the bar is restarted and the following material pertains to the next voice. A regular barline resets the current voice to the first voice in the multi-voice environment’s list of voices.

voice       ::= S? (bar      | ((bar      barLine)+ bar?)      | <tacet> (barLine <tacet>)* barLine?)+ S?
multiVoice  ::= S? (multiBar | ((multiBar barLine)+ multiBar?) | <tacet> (barLine <tacet>)* barLine?)+ S?
multiBar    ::= bar (voiceSwitch* bar)*
barLine     ::= S? ('|' | '||' | '||:' | ':||' | ':||:' | '|||' | <twoEndings> | (</twoEndings> S? barLine)) S?
voiceSwitch ::= S? '\' S?

Note: By this grammar bar-lines between <tacet> elements and bar/multi-bar content may be omitted. In that case they are assumed to be single bar-lines, i.e. '|'

3.1A multi-bar may contain at most v1 voice switches, where v is the number of voices of the multi-voice.
3.2Between <twoEndings> and </twoEndings> there has to come at least one bar-line of the form ':||' or ':||:'.
3.3Bar-lines which appear in a bar/multi-bar, but in another are skipped due to a <tacet> must be of the form '|'.

Obviously the usage and syntax of <twoEndings> must conform to XML rules. It is allowed to have more than one repeating bar-line in a <twoEndings> section, which will give it more than two endings.


bar         ::= (S? switch)* S? ('..' | '**' | (switch S? (chord | rest | beamedGroup))+) (S? switch)* S?
beamedGroup ::= chord (beamConnector switch* chord)+

'..'/'**' are invisible resp. visible full-bar rests, which differ from full-note rests insofar as they always fill the whole bar regardless of its length.


chord ::= note+ '.'* stemDirection? horizontalShift* signedDecimal? mergeGroup? accent? 
note ::= ('+'+ | '-' '='*)? [A-F] accidental?
accidental :: = '#'+ | 'b'+ | '0'
stemDirection ::= [uda]
horizontalShift ::= [rs]
mergeGroup ::= 'm' unsignedInt?
accent ::= [o^'>-]

Switches: Note value, tuplet, rhythm pattern, color


tuplet ::= ('t' | 'ts') unsignedInt ('/' unsignedInt)? ':'
CodeTypeStart character(s)
spwhitespacea sequence of XML whitespace characters
ctmScore.js commentStarted by (, ended by ); comments may be nested
ndXML nodestarted by <, subject to correct XML syntax
nvnote value switchNonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with a digit
rprhythm pattern switchNonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with p
cscolor switchNonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with c
tptuplet switchNonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with t
csbar line|, ||, |||, :||, ||:, or :||:
vsvoice switch in multivoice\\
rvvisible rest (regular & full-bar)* or **, possibly followed by a signed integer
riinvisible rest (regular & full-bar). or ..
b_beam connector_ or with beam cut _^_, _^^_ etc.
titie/slur between two chords> possibly followed by an (unsigned) voice index, followed by any number of characters from {u, d, .}
chchordanything else starting with AH, +, -, or = and ended by whitespace or the first occurance of {:, |, _, (, ), <, >}
euunknown tokenanything else

Note that the various chord modifiers (semantic and visual) are included in their respective chord tokens. To treat them seperately (e.g. for syntax highlighting) you must split them off yourself when you receive the token.