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+1−12d·n. For example, a quarter note with two dots (noteValue “4..”) 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 n≥8 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:
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. '|'
<twoEndings>
and </twoEndings>
there has to come at least one
bar-line of the form ':||'
or ':||:'
.<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.
Bars
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
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
Tuplets
tuplet ::= ('t' | 'ts') unsignedInt ('/' unsignedInt)? ':'
Code | Type | Start character(s) |
---|---|---|
sp | whitespace | a sequence of XML whitespace characters |
ct | mScore.js comment | Started by (, ended by ); comments may be nested |
nd | XML node | started by <, subject to correct XML syntax |
nv | note value switch | Nonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with a digit |
rp | rhythm pattern switch | Nonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with p |
cs | color switch | Nonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with c |
tp | tuplet switch | Nonzero number of characters from {c, p, t, s, /, 0,…,9} followed by :, starting with t |
cs | bar line | |, ||, |||, :||, ||:, or :||: |
vs | voice switch in multivoice | \\ |
rv | visible rest (regular & full-bar) | * or **, possibly followed by a signed integer |
ri | invisible rest (regular & full-bar) | . or .. |
b_ | beam connector | _ or with beam cut _^_, _^^_ etc. |
ti | tie/slur between two chords | > possibly followed by an (unsigned) voice index, followed by any number of characters from {u, d, .} |
ch | chord | anything else starting with A–H, +, -, or = and ended by whitespace or the first occurance of {:, |, _, (, ), <, >} |
eu | unknown token | anything 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.