01
How to read this
This is a reference to the .lys language as Lily# 0.8.0 accepts it.
Every example here is run through lysc check when the page is built — the
build fails if one does not compile. Where a claim is about something subtle, the page
says how it was measured.
Three ideas run through the whole language, and most surprises dissolve once you have them:
- Music lives inside a part. A file is a set of declarations. A bare note at
the top level is an error, and that is what lets a top-level
keyortimealways mean “the file's default” with no ambiguity. - Order carries meaning; clauses do not. A
scoreis a vertical stack of bands. A lyric row under a staff is that staff's verse because it is under it — not because a clause says so. - Anything that changes the playing order lives in the
form. Repeats and endings are written there, never among the notes.
There is one canonical way to write each idea. Where the language could have been clever it is usually explicit instead.
02
A file at a glance
The smallest complete document is four lines:
part melody { clef treble }
section Main { melody { c4 d e f | g2 g | } }
form main { Main }
score main { staff melody }
Everything else is optional, and top-level settings come first:
// comments are // to end of line, or /* … */
title "Song"
composer "Composer"
tempo 120 // also: tempo "Allegro" 4 = 96, tempo 120 swing
time 4/4 // default 4/4; engraves as C, and 2/2 as cut-C
key c major // default c major; all church modes work
octave absolute // optional; relative is the default — see Pitches
pitch written // optional; concert = the letters are what SOUNDS — see Transposing instruments
fonts { serif "Georgia" } // optional, a face per kind of text
paper { size a4 } // optional, page geometry
part rightHand { clef treble }
part leftHand { clef bass octave 3 }
phrase motif { c4 d e f | } // optional reusable music
section Main {
rightHand { motif g2 g | } // a section binds music to each part by name
leftHand { c2 c | g2 g | }
}
form main { Main } // the playing order
score main "out" { // one or more render blocks
grandStaff { staff rightHand staff leftHand }
}
The declaration order above is the conventional one. Parts must be declared before the
sections that use them, and a score names a form.
03
Lexical rules
| Thing | Rule |
|---|---|
| Comments | // to end of line and /* block */ |
| Case | Everything is case-sensitive. Treble is not treble; it is an unknown symbol and an error, never a silent fallback. |
| Identifiers | Any Unicode letters. phrase 動機 { … } is fine. |
| Strings | Double quotes: "Für Elise" |
| Numbers | Integers, and decimals as values (3.5). A decimal is never a duration — c4.5 is an error, c4. is a dotted quarter. |
| Units | Glued to the number: 210mm, 8.5in. A space (210 mm) is an error that names the glued spelling. |
| Annotation prefix | @. The backslash is used for one thing only: a string number (c'\3). |
Whitespace and newlines are not significant. You can put a whole part on one line or one bar per line; the samples on the showcase page do both.
04
Pitches and octaves
Note names are Dutch: c d e f g a b, sharp is, flat
es.
| Written | Means |
|---|---|
cis fis | C♯, F♯ |
ees bes | E♭, B♭ |
cisis deses | C𝄪, D𝄫 |
' , | octave up / down, repeatable (c'', c,,) |
Two octave modes
Relative (the default). Each bare pitch takes the octave nearest the previous
note — an interval of a fourth or less — and '/, shift from
there. Compact, but one wrong mark moves everything after it.
Absolute. Write octave absolute at the top level, in a part header,
or mid-music. Bare c is then C4 (or CN in a part that says
octave N) and the marks are absolute offsets from it: c' is C5,
c, is C3, resolved independently per note. A wrong octave stays one wrong
note instead of cascading.
Write relative. It is the default, it is shorter, and it is how a
person reads music anyway — each note against the one before it. Reach for absolute when
something other than a person is doing the writing: a generator, an importer, or an AI
producing a score it cannot hear back. There the guarantee that a mistake stays local is
worth the extra marks; at the keyboard it usually is not.
part bass { octave 3 } re-anchors a low part so its commas do not pile up.
Sections restore the file-level mode, so a mid-music switch does not leak.
Show the whole file
// Relative is the DEFAULT: each bare pitch takes the octave nearest the note before
// it. `octave absolute` switches that off and anchors a bare c to C4 (or to the part's
// `octave N`), so a wrong octave never cascades — worth it when a generator is writing,
// not by hand.
octave absolute
time 4/4
part melody { clef treble }
section A { melody { c4 c' c'' c, | e g e' g, | } }
form main { ~A }
score main { staff melody }05
Durations
| Written | Means |
|---|---|
1 2 4 8 16 32 64 128 | whole, half, quarter, … |
4. 4.. | dotted, double-dotted |
| (omitted) | reuse the previous note's duration |
c4:8 | tremolo — repeat the note in eighths for its length |
A duration is glued to what it lengthens: c4,
<c e g>4. It never sits on a chord member —
<c e g2> is an error.
The bare duration
A duration standing alone repeats the previous note, chord or slash at the new length, and sets the running default:
bes8 8 8 8 // four B♭ eighths, written once <c e g>4 4 // the chord again /4 4 4 4 // four beats of slash comping
Rests are transparent to it. With nothing before it to repeat, it is an error. Reaching
back across a barline only warns — because that shape is also what a dropped pitch
letter looks like (4 g f e meant as a4 g f e), so open a measure
with the event itself.
06
Notes, rests, chords
| Written | Means |
|---|---|
fis8 | F♯ eighth |
r4 | quarter rest |
s4 | invisible spacer rest |
R1 | full-measure rest |
a,4@rest | a rest printed where the note a, would sit |
<c e g>4 | chord |
<c 3 5>4 | the same triad by scale degree |
<1 3 5>2 | degrees only — anchored on the key's tonic |
/4 | slash note — pitchless rhythm, silent, on the middle line |
q | the previous chord again |
q' | …an octave up (q,, two down) |
Repeating a chord — and why there are two ways
A bare duration and a q both repeat what came before, and for the
plain case they are the same music — <c e g>4 4 and
<c e g>4 q4 engrave and play identically. They differ in what they
are, and that is what decides which one you can modify:
- A bare duration is a LENGTH. “The previous event again, this long.” It
cannot be displaced, because a length has nothing to move —
4'is not a spelling. qis an EVENT. “This chord again.” It takes its own duration, its own post-events (q@staccato— the original's are never copied), and octave marks.
The displacement accumulates along the chain: q' q plays the
chord an octave up both times, q' q' climbs by one and then two, and a bare
duration in the run repeats the chord where the last q left it. A
q with no chord before it warns and occupies its time silently; notes and
rests are transparent to it, and the run does not leak across a part, section or phrase
body.
Octave marks on q are Lily#'s own — LilyPond's q
takes none.
Show the whole file
// A duration standing alone repeats the previous event at the new length, and `q`
// repeats the previous CHORD. Only `q` can be displaced: q' is an octave up.
time 4/4
part melody { clef treble }
section A {
melody { c8 8 8 8 c4 4 | <c e g>4 q q' q | }
}
form main { ~A }
score main { staff melody }Show the whole file
// Rests, spacers, a full-measure rest, a pitched rest, chords by letter and by
// scale degree, and the pitchless slash note.
octave absolute
time 4/4
key c major
part melody { clef treble }
section A {
melody {
c4 r4 s4 g4 | R1 | c4 a,4@rest d4 r4 |
<c e g>4 <c 3 5>4 <1 3 5>2 | /4 4 8 8 4 |
}
}
form main { ~A }
score main { staff melody }A rest normally places itself: middle line, voiced position inside a
voice span, clear of what sounds with it. @rest on a
note overrides that — the rest sits where that pitch would and nothing moves it
again, which is how two voices' colliding rests get pulled apart. The pitch never sounds
and prints no accidental. On anything but a note it is an error.
Chord octaves — the anchor model
One rule: a mark moves only what it is attached to. The anchor is the first
member's bare letter (or the key tonic for a degrees-only chord), resolved nearest the
running frame; members sit at or above it, so order is free except the first slot. The
chord never moves the frame itself — only a mark after the > does.
| Written | Sounds | Next bare c |
|---|---|---|
<c e g> = <c g e> | C4 E4 G4 | C4 |
<c' e g> | C5 E4 G4 — the mark moved that note only | C4 |
<c e g>'4 | C5 E5 G5 — after the >, it moves the chord and the frame | C5 |
Arpeggios — written-out broken chords
<< … >> plays its members in sequence, equally subdividing the
group's total. Members take no durations of their own — a bare number inside is always a
scale degree.
<< c e g >> // c, then e and g stacked above it — a triplet of eighths after c4
<< 8 5 3 1 >> // degrees only: descending from the octave
<< c r e >> // a rest is a gap — an equal share
<< c e g >>2 // a duration after >> is the group's TOTAL
<< c e g >>' // marks after >> shift the group and propagate
<< c . d >>4 // a SPACED dot holds the member before it one more share: 2:1, the swing figure
<< c . . d >>4 // 3:1 — c8. d16 (never glued: c. would be a duration dot, 3. a decimal)
<< c@accent e\3 g( a) >> // a member carries scripts, string numbers, fingering, dynamics, slur marks
<< c e g >>4\2 // on the group: a dynamic, a chord name, a string number (every member's);
// a ~ or ( written after >> hangs on the last member
The tuplet is spelled the way engraving convention spells it — the member count against the power of two below it (3:2, 5:4, 7:4), a dotted total against 3 (2:3, 4:3) — from the total number of shares.
This is not LilyPond's << >>. Parallel
voices are voice { } { } in Lily#, and a \\ inside is an error.
Show the whole file
// `<< … >>` writes a broken chord out: the members play in sequence and divide the
// group's total. A bare number inside is a scale degree, never a duration.
octave absolute
time 4/4
key c major
part melody { clef treble }
section A {
melody { << c e g >>4 << c 3 5 >>4 << 8 5 3 1 >>2 | << c e g >>2 << c r e >>2 | }
}
form main { ~A }
score main { staff melody }07
Ties, slurs, beams
c4~ | c4 d e f // tie — same pitch, with ~ c4( d e f) // slur — different pitches, with ( ) <c e>4( <d f>) // a slur may bind chords too c8[ d e f] // manual beam; beaming is automatic otherwise c4@phrasingSlur d( e) f g@!phrasingSlur // a phrasing slur over a whole phrase; ordinary slurs may sit inside
A tie whose next note is a different pitch warns and tells you to use a slur instead. Beaming follows the meter unless you bracket it yourself. A phrasing slur is a spanner: its end is required, and one may be open per voice.
Show the whole file
// A tie joins the SAME pitch, a slur joins different ones, and square brackets
// beam by hand where the meter's own beaming is not what you want.
octave absolute
time 4/4
part melody { clef treble }
section A {
melody { c4~ c4 d4( e4) | <c e>4( <d f>4) c8[ d e f] | }
}
form main { ~A }
score main { staff melody }08
Annotations
Attach with @; one note may take several
(c4@staccato@p). Two suffixes force a side: .up and
.down (c4@staccato.up, @f.up). An annotation that
takes a value puts it in parentheses: @finger(3), @fig(6 4),
@text("dolce").
| Family | Names |
|---|---|
| Articulations | @staccato @staccatissimo @accent @tenuto @marcato @fermata @portato |
| String technique | @upbow @downbow @flageolet — always above |
| Ornaments | @trill @mordent @prall @turn @reverseturn |
| Dynamics | @ppp @pp @p @mp @mf @f @ff @fff, and @sfz @sf @fp @rfz @fz |
| Hairpins | @cresc @decresc @dim — placed on the starting note, running to the next dynamic. No .up/.down: a hairpin is always below. |
| Stems | @stemUp @stemDown — on a beamed note the beam's shared direction wins |
| Accidental style | @courtesy (parenthesised), @editorial |
| Effects | @arpeggio @glissando @cross @dead @fall @doit @breath @caesura |
| Half ties | @laissezVibrer, @repeatTie |
| With a value | @finger(3) @fig(6 4) @bend(half) @notehead(triangle) @feather(right) @text("dolce") @mark("A") @chord(Dm) @frame(032010) @pluck(i) @ottava(bassa) |
Spanners — the end is required
These open on one note and must be closed on another. A spanner nobody closes draws nothing at all, its word included, and says so:
| Opens | Closes |
|---|---|
@textSpan("poco rit."), or the sugar @rit @accel @rall | @!textSpan / @!rit … |
@ottava, @ottava(bassa), @quindicesima | @!ottava closes any of them |
@startTrillSpan | @stopTrillSpan |
@sustain, @sostenuto, @unaCorda | @!sustain, @!sostenuto, @!unaCorda (@treCorde is the last one's release, spelled as the printed word) |
These take no argument. @ped, @ped(off),
@una(corda) do not exist. A pedal change — release and press again on
the same note — is the pedal's name again while it is down: in
c4@sustain d e f | g4@sustain a b c@!sustain the second @sustain
re-pedals, and the bracket draws its notch there (@!sustain@sustain on one
note means the same).
The dot after a name is placement, not an argument
@fermata.up is a fermata forced above. It follows that
@notehead.x does not work — an argument always goes in parentheses:
@notehead(cross).
Show the whole file
// Articulations, ornaments and dynamics attach with '@'. A hairpin goes on the
// note it starts from and runs to the next dynamic. '.up' forces the side.
octave absolute
time 4/4
part melody { clef treble }
section A {
melody {
c4@staccato d4@accent e4@tenuto f4@marcato |
g4@trill a4@mordent b4@fermata c'4@staccato.up |
c'4@p@cresc b4 a4 g4@f | f4@f@decresc e4 d4 c4@p |
}
}
form main { ~A }
score main { staff melody }Show the whole file
// A spanner opens on one note and MUST be closed on another: one that is never
// closed draws nothing at all and says so.
octave absolute
time 4/4
part rh { clef treble }
part lh { clef bass octave 3 }
section A {
rh {
c'4@ottava d' e' f' | g'4 a' b' c''@!ottava |
c'4@rit b a g@!rit | c'1 |
}
lh {
c4@sustain e g e | c4@sustain e g e | // a second @sustain while down re-pedals
c4@sustain e g e | c1@!sustain |
}
}
form main { ~A }
score main { grandStaff { staff rh staff lh } }09
Tuplets, grace notes, voices, cues
tuplet 3/2 { c8 d e } // 3 in the time of 2
tuplet 3/2 { c8 d tuplet 3/2 { e16 f g } } // nesting is allowed
grace { d16 e } f4 // grace notes before f
acciaccatura { a16 } b4 // slashed
appoggiatura { c8 } d4 // unslashed
voice { c'2 d } { e2 f } // `voice` opens the span ONCE; each further { } is another voice
repeat unfold 8 { ground } // write the body out 8 times
repeat percent 2 { c4 d e f | } // repeat the previous measure
repeat tremolo 8 { c16 e } | // N x the pair: 8 x two 16ths fills a 4/4 bar
repeat is only for unfold / percent /
tremolo — things that abbreviate notes. It is not how a repeat sign is
written; see Forms.
Cue notes
A cue is a region, not an annotation, so there is no @cue:
c4 cue { e4 f } g4 | // small notes, a voice of their own
c4 cue bass { e4 f } g4 | // drawn in another instrument's clef; the staff's clef returns
A slur or tie may not cross the region's edge — close it inside the cue, or keep both
ends outside. Two adjacent cue blocks are two voices, so a span cannot run
from one into the next either.
Show the whole file
// Tuplets nest, grace notes come in three flavours, and `voice { } { }` opens a
// span of simultaneous voices on ONE staff.
octave absolute
time 4/4
part melody { clef treble }
section A {
melody {
tuplet 3/2 { c8 d e } tuplet 3/2 { f8 g a } c'2 |
grace { d16 e } f4 acciaccatura { a16 } b4 appoggiatura { c'8 } d'4 r4 |
voice { g'2 a'2 } { c'2 c'2 } |
}
}
form main { ~A }
score main { staff melody }10
Barlines and breaks
| In the music | Draws |
|---|---|
| | single |
|| | double |
|. | final |
! | dashed |
A written | closes exactly one measure, and a measure with nothing in
it is an empty one. So { | | | | } is four empty bars and
{ | c1 } is an empty bar then c1. An empty bar fills itself with
a full-measure spacer, on the page and in playback, so it is never diagnosed — which is
what lets a rhythm staff say nothing for pages at a time.
Typed barlines close nothing: || and |. decorate the bar
behind them, and a | landing where the meter just auto-filled a bar merely
confirms it. That is why a trailing c1 | is one bar, not two.
The repeat barlines |: :| :|: are
not music items. Writing one among the notes is refused, with a message naming the
form to write instead.
Forcing where a line or page turns
Four bare words, written in the music (or in the form). At a bar line they end the
system there; inside a bar, break splits that bar across two systems. They
are spelled in camelCase and, like everything else, are case-sensitive —
nobreak is not a word.
| Word | Means |
|---|---|
break | end the system here |
noBreak | do not end the system here |
pageBreak | end the page here |
noPageBreak | do not end the page here |
Line and page breaking are otherwise automatic — Lily# uses LilyPond's Knuth-Plass line breaking and its page-breaking search — so these are for the places where you disagree with the result, not for laying a score out by hand.
Show the whole file
// Every written '|' closes exactly one measure, so a bar with nothing in it is an
// empty bar. '||' and '|.' decorate the bar behind them; '!' is dashed.
octave absolute
time 4/4
part melody { clef treble }
section A {
melody { c1 | | d1 || e1 ! f1 |. }
}
form main { ~A }
score main { staff melody }11
Parts
A part is declared once and carries what stays true for it. Attributes are written
bare, with no =.
part melody { clef treble }
part bass { clef bass octave 3 }
part gtr { clef treble_8 tuning guitar }
part fl { clef treble instrument flute }
part cl { instrument clarinet "Clarinet in Bb" }
part sing { clef treble transpose d }
| Attribute | Takes |
|---|---|
clef | treble bass alto tenor treble_8 treble^8 bass_8 soprano mezzosoprano baritone percussion. A clef only draws the staff — it never changes which octave a bare letter means; that is octave's job, or the instrument preset's. |
octave | absolute, or a number that re-anchors the base (octave 3 for a low part) |
key | this part's own key signature (time and tempo are shared by every part, so they are written at the top level or in a section header) |
instrument | a preset name, a quoted display label, or both — see below |
transpose | a pitch, not a number of steps: it renames c to that pitch and moves every written note with it. This moves the PAGE — for a transposing instrument, name the preset instead. Writing a number is an error that says so. |
transposition | an octave marker — 8va 8vb 15ma 15mb. A different thing from transpose, and it does not take a pitch. |
pitch | concert or written — this part's convention for a transposing instrument, overriding the top-level pitch. Without a transposing instrument it changes nothing. See Transposing instruments. |
tuning | a tuning name; makes the part tablature-capable |
midiInstrument | a quoted General MIDI sound, midiInstrument "acoustic bass" — what playback sounds like, overriding the preset's |
pedal | text ("Ped. … *"), bracket (the default) or mixed — how this part's pedal marks are drawn |
Part names are ordinary identifiers and may not be reserved words — except the four
clef words treble bass alto tenor, which are allowed, so a part called
bass is fine.
instrument — one word, several answers
Naming an instrument is not just a label. The preset settles everything a part needs to know about itself, and each of those can still be overridden by writing it explicitly:
| It sets | Which shows up as |
|---|---|
| the clef | viola reads alto, cello and bass read bass, guitar reads treble_8 |
| the octave anchor | where a relative part's bare letters land |
| the tuning | which strings a tab row has — hence the fret numbers |
| the MIDI program | what playback sounds like |
| the sounding octave | the bass family sounds an octave below its notation, a piccolo an octave above |
| the printed name | the label beside the staff |
part gt { instrument guitar } // preset: clef, tuning, sound, label
part bs { instrument bass "Bass" } // preset, with the label overridden
part v1 { clef treble instrument "1st Violin" } // label only — no preset behaviour
A bare word is the preset; a quoted string is the display label; both together set the preset and rename it. A quoted string alone is a free-text name and carries no preset behaviour — the clef and the rest come from whatever else the header says.
Transposing instruments
Write what the player reads, and the preset makes it sound right. Naming a transposing instrument is enough — the part prints exactly the notes you typed, and playback (and a tab's frets, which read the same one value) shifts to where the instrument really is. A part cannot print at one pitch and play at an unrelated one.
| Preset | Written C sounds |
|---|---|
clarinet trumpet soprano-sax | B♭ — a major 2nd down |
clarinet-a | A — a minor 3rd down |
horn | F — a perfect 5th down |
alto-sax | E♭ — a major 6th down |
tenor-sax | B♭ — a major 9th down |
baritone-sax | E♭ — an octave and a major 6th down |
bass and its family | an octave down |
piccolo | an octave up |
trumpet-c flute oboe trombone … | as written |
A bare name takes the common member of its family — clarinet and
trumpet are the B♭ ones, horn is in F — because that is the
instrument someone means when they say no more. The others have their own spellings.
Every saxophone needs one (alto-sax, not alto): the plain
voice-range words are already the choral presets. Guitar and vocal tenor carry their
octave on the treble_8 clef instead of here, which is why their parts print
the little 8 under the clef and this table does not list them.
Or write what sounds, and let the part be transposed for you. A top-level
pitch concert says the letters are concert pitch: every chromatically
transposing part is then printed the way its player reads it, pitches and key signature
together — an alto-sax part of a piece in C major prints its c'
as a', in A major, and still plays C. The default, pitch written,
is the first convention above. Octave-only instruments (bass,
piccolo, a transposition 8vb) keep their notation under both, as
a printed concert score keeps them. To print one score at concert pitch whichever way the
file is written — the conductor's score — put the same words on that score:
score main "full" pitch concert { … }.
An explicit transpose is a different thing: it moves the
written notes by hand. Its argument is a PITCH, not a number of steps — it renames
c to that pitch and shifts every note by the same interval, so
part cl { clef treble transpose bes } prints c d e f as
B♭ C D E♭ — and it composes with the instrument's own shift. Do not confuse it with
transposition, which takes an octave marker
(8va / 8vb / 15ma / 15mb) and overrides
the preset's written-to-sounding octave.
Show the whole file
// One word sets several things at once: each part's clef, the octave its bare letters
// anchor to, its tuning (so its frets), what it sounds, and its printed name. Neither
// part below says `clef`, `octave` or `tuning` — the preset already did, which is why the
// same letters land at C4 on the guitar and at C3 on the bass.
time 4/4
part gt { instrument guitar }
part bs { instrument bass "Bass" }
section A {
gt { c4 e g e | }
bs { c4 e g e | }
}
form main { ~A }
score main {
staff gt tab gt
staff bs tab bs
}12
Phrases
Named music, declared with phrase and used by its bare name:
phrase motif { c4 d e f | }
section Main { melody { motif g2 g | } }
Each phrase body evaluates in a fresh frame — default octave, pitch and duration are reset — so a phrase means the same notes at every call. A reference is one item to the relative chain, exactly like a chord: the next note is relative to the phrase's anchor (its first note's bare letter, shifted by the reference's marks), never to how the body happens to end.
A trailing ' or , on a reference shifts that play's octave.
There is no per-reference transposition: a motif quoted at another interval is written
out, because transpose is a property of a part, not of a quotation.
13
Sections
A section binds music to each part by name, and is the unit the form
orders. Section boundaries reset the relative frame.
section Verse {
partial 8 // optional pickup, for every part at once
melody { a'8 | c4 d8 e8. f16 e8 | }
bass { r8 | a4 e8 a4. | }
chords prog { | Am | } // a chord row lives here too (the pickup holds none)
lyrics words sings melody { A- | las my love you do | }
}
A section prints a rehearsal label by default. ~ on a form reference hides
it for that play (form main { ~Verse Chorus }). The tilde belongs to the
reference only — section ~A { … } is an error.
14
Lyrics
sings binds a lyric track to the part it sings. It is a property of the
track, not of one place in the file, so it may be spelled at the definition, on the
score row, or both — the same one property, written wherever it reads best.
// on the definition
lyrics words sings melody { Hap- py birth- day | to you | }
score main { staff melody lyrics words }
// or on the score row, leaving the definition bare
lyrics words { Hap- py birth- day | to you | }
score main { staff melody lyrics words sings melody }
Spelling it on the row is what lets ONE track serve several staves. Place the
same lyrics row under each staff and bind it there — the words are written
once and appear under every voice that sings them, which is what a homophonic chorale
wants:
score main {
staff sop "Soprano"
lyrics verse sings sop
staff alt "Alto"
lyrics verse sings alt
}
Show the whole file
// `sings` is a property of the lyric TRACK, and it can be spelled at either site:
// on the definition, on the score row, or both. Spelling it on the ROW is what lets
// ONE set of words serve several staves — here the same track is placed twice.
octave absolute
time 4/4
key c major
part sop { clef treble }
part alt { clef treble }
section A {
sop { c'4 c' b a | g1 | }
alt { e4 e g f | e1 | }
lyrics verse { Sing- ing a song | now | }
}
form main { ~A }
score main {
staff sop "Soprano"
lyrics verse sings sop
staff alt "Alto"
lyrics verse sings alt
}| Written | Means |
|---|---|
| space | next syllable |
- | joins syllables of one word |
~ or _ | hold the previous syllable over one more note (a ~ glued on both sides, va~ga, puts two syllables on one note) |
__ | draw the extender line; takes no note |
| | mirrors the music's barlines |
A slur or a tie holds its syllable, as in LilyPond. The notes inside a slur
(after its first) and a note a tie arrives at take no syllable of their own, so
c4( d e) f sung to la __ lu puts lu on
f. A slur written only to mark phrasing over a lyric line would swallow its
syllables — write that one as @phrasingSlur … @!phrasingSlur, which holds
none; the warning says so when it happens.
Barlines follow the same rule as music: every written | closes one bar,
the one that opens the run included. That leading | is how a verse
skips the rest bar its melody opens with.
The score places the row by order. A bound lyrics NAME row directly
below the staff engraving its part is that staff's verse, and a run of rows stacks as
verses. Elsewhere it shows only the words, at the melody's rhythm, without engraving the
melody. Several tracks may sing one part — two languages, two names. Inside a staff group
a row must sing the staff directly above it; write the binding at the row to say which.
Show the whole file
// A lyric track sings a part. '-' joins syllables of one word, '~' holds the previous
// syllable over one more note, and '|' mirrors the music's barlines.
octave absolute
time 4/4
key f major
part melody { clef treble }
section A {
melody { f4 g a bes | c'2 a4 f4 | g4 a bes a | f1 | }
lyrics words sings melody {
Sing- ing all the | day ~ long, |
ev- ery word a | song |
}
}
form main { ~A }
score main { staff melody lyrics words }15
Chords and chord rows
A chords NAME { … } row holds chord symbols as they print. Placed
directly above a staff, they align over it by timing; placed on their own, they draw a
staff-less grid of barlines.
chords prog { Cmaj7 | Am7 | Dm7 | G7 | F#m7-5 B7-9 | }
| Written | Means |
|---|---|
| one entry in a bar | takes the bar |
| two entries in 4/4 | halves; four, beats — entries divide the bar on the meter's beat grid |
. | hold the previous chord one more beat (never across a barline) |
r R | print “N.C.” in that slot |
s | print nothing |
How a symbol is spelled
You type the symbol, not an encoding: Cmaj7, Am7,
G7sus4, C/G, Bb7/D, F#7. One rule is
worth knowing before it surprises you:
an altered tension takes + or −, never # or b
So a half-diminished chord is F#m7-5, a flat ninth is C7-9,
a sharp five is A7+5. The reason is that # and b
belong to the root and the bass — without that split, Bb9 could not
say whether it means B♭ with a ninth or B with a flat ninth. Written the other way
(F#m7b5) the suffix is not a quality Lily# knows: it prints as typed, but
carries no chord.
The registered qualities: m min dim aug 7 maj7 maj m7 min7 mmaj7 dim7 m7-5 +
6 m6 min6 9 maj9 m9 min9 sus2 sus4 sus 7sus4 7-5 7+5 7-9 7+9 7+11 add9 11 13 m11 min11
m13 min13 maj13. A quality outside that list still prints in a chord row —
the row keeps whatever suffix you wrote — but it has no interval set, so playback sounds
only its root and @chord on a note refuses it.
Entries carry no durations — the grid does the arithmetic. Barlines in the source are
drawn and follow the same bare-barline rule as music and lyrics. A |: in a
chord row is a repeat like any other and belongs in the form; the repeat barlines the form
composes still reach the row and draw there.
The same named row can be used twice — above a staff in one score, and as a standalone chart in another — so a progression is written once.
A row the score places also sounds. In the MIDI (and in the editor's playback)
it plays on a track of its own, NAME (chords), softer than the melody, each
symbol over exactly the span it prints over: . holds it, r is
silence. A symbol names a chord but voices none, so Lily# uses one voicing everywhere —
every tone between G3 and G4, a slash bass an octave below (G7/B sounds B2 G3
B3 D4 F4). A row no score places is silent.
What you write and what it prints are two different choices
A chord has three representations in Lily# — a symbol (Cmaj7), a
degree of the key (Imaj7), and the notes
(<c e g b>) — and the language keeps the one you type separate
from the one that prints. Both spellings resolve to the same structure, so
everything downstream — the printed name, the degree, playback, transposition — is one
road.
| You write | Score item | It prints |
|---|---|---|
chords p { Cmaj7 } | chords p | Cmaj7 |
chords p { Cmaj7 } | chords p as roman | Imaj7 |
chords p { Imaj7 } | chords p | Cmaj7 |
chords p { Imaj7 } | chords p as roman | Imaj7 |
<c e g>4@chord | staff … | C — derived from the notes |
c4@chord(Dm) | staff … | Dm — stated on the note |
So a chart written in degrees prints absolute names by default, and one written in
names prints degrees under as roman. A degree is read against the key in
force at that bar, which is why a modulation re-reads them rather than freezing them.
Rows one and two above are the same chords part,
placed twice in one score with different display. Row three is written in degrees. The
staff underneath carries no chord symbols of its own — each is derived from the notes by
a bare @chord.
The name a bare @chord derives
A bare @chord reads the symbol off the notes. The root comes from the
pitches, not from whichever member you typed first — the members are tried as the
root from the bass upward, and the first that names a registered quality wins. If that
root is not the lowest
sounding note, the chord is an inversion and the lowest note prints as the slash bass.
| Written | Sounds | Prints |
|---|---|---|
<c e g> | C4 E4 G4 | C |
<e g c> (absolute) | E4 G4 C4 | C — c is still the lowest |
<e g c> (relative) | E4 G4 C5 | C/E |
<e, g, c> (relative) | E3 G3 C5 | C/E |
The bass is tried first, and that is what keeps this safe. Some
sets read as more than one chord: <c e g a> is C6 from C and Am7 from A.
Preferring the bass settles it the way the voicing already suggests — C6 when c is at the
bottom, Am7 when a is — and it is why <c e g b> is Cmaj7 rather than
something rooted higher up. Another root is only ever consulted when the bass names
nothing at all.
Where the notes are genuinely ambiguous, say which you mean:
<e g, b d>@chord prints G6 (g is the bass), and
<e g, b d>@chord(Em7/G) prints Em7/G. Watch the octaves rather than the
written order — under octave absolute, <e g b d> puts d
below e and so reads Em7/D.
What completion offers
Inside a chords { } block, and inside a @chord(…) argument,
completion offers the current key's diatonic chords — each degree's triad and seventh (and,
among the names, the suspended forms) — read against the key in force at that point.
Hovering a chord symbol, or a chord or << >> in the music, shows
its name, its degree and its pitches (Dm (IIm) D4 F4 A4).
- In a
chords { }block you get both vocabularies: all seven degrees as names first (C D E F G A B …), then all seven as degrees (I II III …), so each list can be scanned on its own. - In a
@chord(…)argument you get the names only. The annotation reads the absolute-symbol grammar alone, so@chord(V7)is refused — the completion offers nothing it would then reject. - What it inserts is the symbol —
Dm7,Imaj7— not the notes. The entry format is the printed form, for a row and an annotation alike.
16
Forms — the playing order
A form lists sections in the order they are played and printed. This is
where repeats live, because a repeat is a change to the order.
form main { Intro Main Main "Main (reprise)" Coda }
form main { |: Body [1. ~First] :| [2. ~Second] }
form main { |: A :|*3 }
form practice { Verse } // a second form = a second output
| Written | Means |
|---|---|
|: … :| | repeat; count defaults to the number of endings, or 2 |
:|*N | an explicit play count |
[1. Name] | a volta ending. The opening [ is required; the closing ] is optional and draws the right-hand cap |
~Name | hide that play's rehearsal label |
Name' Name, | shift that play's octave — one section quoted at two octaves is ~B ~B' |
"Label" | a custom printed label for that play |
An ending needs a repeat to be an ending of: written without one, no bracket is
drawn and a warning says the 1. prints nothing.
Navigation marks
Signs (segno, coda) engrave at the start of the following
section; text directives (fine, to coda, dc,
ds, and dc al fine, ds al coda) engrave at the end
of the section just played.
form main { A segno B to coda C ds al coda coda D }
The same bare words may also be written in a section's music at a barline boundary.
They are landmarks, never note modifiers, so c4@segno is an error and putting
one mid-measure warns.
The reserved form name main writes to the input file's name; any other
form name becomes the output file name unless a "basename" overrides it.
Show the whole file
// A repeat changes the playing ORDER, so it lives in the form, never in the music.
// The endings name sections; the bracket and the repeat dots are drawn from this.
octave absolute
time 3/4
key g major
part melody { clef treble }
section Body { melody { d'4 g' fis' | g'2. | } }
section First { melody { a'2. | } }
section Second { melody { g'2.@fermata | } }
form main { |: ~Body [1. ~First] :| [2. ~Second] }
score main { staff melody }17
Scores
A score binds a form to a set of rows. It is a vertical stack of
bands: what a row means comes from where it sits.
score main "out" {
chords prog // a chord row above ...
staff melody "Melody" // ... the staff it belongs to
lyrics words // ... and that staff's verse below it
}
| Item | Row it draws |
|---|---|
staff NAME | a notation staff for that part |
staff NAME "Label" | …with a printed name |
staff NAME as lines N | …with N staff lines (1–5). as lines 1 is a rhythm staff |
staff NAME as removeEmpty true | …hidden in systems where it only rests (all: in the first system too) |
tab NAME | tablature — see below |
chords NAME | a chord row |
lyrics NAME | a lyric row |
ossia NAME | a small alternative staff |
NAME (bare) | played to MIDI only, never engraved — a click track, a cue part |
title / composer | restate the file's metadata for this score alone |
paper NAME / fonts NAME / layout NAME | use a named block for this score |
A staff's display name is always a quoted string, so a bare word after
staff NAME is always another score item — staff flute click is
flute's staff plus the MIDI-only click part. Position never changes what a
word means.
Grouping staves
| Group | Left edge | Barlines between staves | For |
|---|---|---|---|
grandStaff | brace | drawn through | one instrument on two staves |
staffGroup | bracket | drawn through | one family |
choirStaff | bracket | not drawn through | independent voices |
staffGroup reverses the word order on purpose — it is not a slip for
groupStaff: the other …Staff items each produce a staff, while a
staff group produces a group of staves.
Two more put several parts on one staff, and take bare part names:
condensedStaff { fl1 fl2 } gives each part its own voice of a single staff;
combinedStaff { fl1 fl2 } merges them the way an orchestral score condenses
two players — unisons become one notehead marked a2, different notes in the
same rhythm within a ninth become one voice of chords, a lone part is marked
Solo. The chord case is the usual outcome, not a corner; use
condensedStaff when the lines must stay visibly separate.
Because these are score items, one source prints both the condensed score and the separate parts:
score main "full" { condensedStaff { fl1 fl2 } }
score main "parts" { staff fl1 staff fl2 }
18
Tablature
Give a part a tuning and render it with tab:
part gt { clef treble_8 tuning guitar }
score main {
staff gt // the notation
tab gt // the tablature under it
}
A tab standing beside a staff prints fret numbers only — the staff above it
already carries the meter, stems, beams, rests and ties. A tab on its own carries the
meter, stems, rests and ties itself (beams are not drawn yet). That is the default;
say which you want with
tab gt as numbers or tab gt as full.
\N pins a note to string N when the automatic choice is not the one your
fingers want: c'\2. Technique letters (@tap @hammeron @pulloff
@pluck(i)) print on the tab, because they are ink a guitarist reads there.
19
Paper and fonts
Both are optional blocks whose defaults equal LilyPond's, so an absent block changes nothing. Both can also be named at the top level and referenced (or partly overridden) per score.
paper {
size b5 // width, height AND scaled margins, by name
paperWidth 210mm // bare numbers are staff spaces; units are GLUED
paperHeight 0 // 0 = one content-driven page
leftMargin 15mm rightMargin 15mm topMargin 10mm bottomMargin 10mm
indent 15mm shortIndent 0
raggedRight // a bare flag: do not justify
spacingIncrement 1.2
systemSystemSpacing { basicDistance 12 minimumDistance 8 padding 1 stretchability 60 }
}
The staff-spacing family lives here, not in override. Unknown keys are an
error; a key set twice warns and the last wins.
fonts {
serif "Georgia" // the two generic families together are
sans "Verdana" // "the whole document's text"
lyricText "Charis SIL" "Noto Serif CJK JP" // several names = a fallback chain
tempo "Playfair Display" // one role beats the group it belongs to
embedded // subset the named faces into the PDF
}
Keys are a generic family, a group, or a single role, and the narrower spelling
wins in either source order. Groups map to roles as: header → title, composer,
instrument · lyrics → lyricText, stanza · chords → chordName,
fretFrame, figuredBass · marks → tempo, mark, pedal, navigation, text,
dynamics, partCombine · numbers → barNumber, fingering, tuplet, volta, ottava,
bend, tabTechnique · notation → clefOctave, meter, tabFret.
The keyword is fonts, plural, and it takes a block — there is
no font keyword and no one-line form. A named face is measured as well
as drawn, so naming one that a machine lacks makes the page machine-dependent; a missing
face warns rather than passing quietly.
20
Override / revert
override NoteHead.color = red c4 d e f | revert NoteHead.color once override Stem.transparent = true // 'once' applies to the next note only c4 d e f |
The syntax accepts any Grob.property, but the vocabulary is deliberately
four properties: NoteHead.transparent, Stem.transparent,
NoteHead.color, Stem.color. Anything outside that list is
refused with a message listing what is supported, rather than silently doing nothing. The
list grows, and each addition removes one error.
Grob names are PascalCase and properties are lisp-case; both are case-sensitive.
Show the whole file
// The override vocabulary is four properties. `once` applies to the next note only,
// and `revert` puts the default back.
octave absolute
time 4/4
part melody { clef treble }
section A {
melody {
override NoteHead.color = red
c4 d e f |
revert NoteHead.color
once override Stem.transparent = true
g4 a b c' |
}
}
form main { ~A }
score main { staff melody }21
Reserved words
section form using tab ossia transpose octave pitch instrument percussion drummap score part staff grandStaff staffGroup choirStaff condensedStaff combinedStaff voice phrase repeat break noBreak pageBreak noPageBreak partial cue embedded fonts paper layout title composer tempo time key clef major minor ionian dorian phrygian lydian mixolydian aeolian locrian treble bass alto tenor treble_8 bass_8 soprano mezzosoprano baritone tuplet grace acciaccatura appoggiatura lyrics chords tuning override revert once segno fine coda dc ds al to ppp pp p mp mf ff fff
The four clef words treble bass alto tenor are the exception: they may
still be used as part, section and phrase names. Single letters a–g
are pitches and r/R/s are rests — note that
f is a pitch, while @f still works because dynamics resolve from
the annotation's text. Articulation, ornament and mark names are not reserved at
all; they resolve from the @name text, so they stay free for your own
identifiers.
22
Diagnostics
Lily# would rather refuse than quietly do the wrong thing, and its messages are written to be acted on. A few worth knowing, quoted as the compiler prints them:
| You wrote | It says |
|---|---|
c4 g. a4 | This '.' belongs to nothing. A duration dot needs a number in front of it - write g4., not g. … |
c4.5 | '4.5' is not a duration - a duration is a whole number (c4, c8), lengthened by dots… |
<c e g2> | A chord member can't carry a duration - members share one, written after the closing '>': <c e g>2. … |
4 g f e opening a part's music | A bare duration repeats the previous note, chord or slash - and nothing repeatable comes before this one… |
c4 d e f :| | ':|' is a repeat, so it belongs in the form, not in the music… |
repeat volta 2 { … } | 'repeat volta' is LilyPond's spelling. In Lily# a repeat is written in the form… |
\relative { … } | Lily# is relative by default — drop '\relative …'; switch modes with 'octave absolute'. |
clef Treble | Unknown clef 'Treble'. clef names are case-sensitive; known: alto, baritone, bass, … |
fonts "Georgia" | fonts binds a face per text role, so it takes a block… |
paperWidth 210 mm | mm is a unit, and a unit is spelled glued to its number: 210mm, one word. |
override Beam.thickness = 2 | 'Beam.thickness' is not supported in this version of Lily# — this 'override' would change nothing. Supported: NoteHead.color, NoteHead.transparent, Stem.color, Stem.transparent. … |
c4@rit d e f (never closed) | a text spanner is never closed, so neither its word nor its line is drawn; write '@!rit' (or '@!textSpan') on the note it should reach… |
c4~ d4 | the note after a tie '~' does not repeat the tied pitch; a tie joins two notes of the same pitch - use a slur '( )' to connect different pitches |
| a slur crossing a cue edge | a slur cannot cross a cue boundary… |
Warnings are for things that are legal but probably not what you meant; errors are for things with no defensible reading.
23
Coming from LilyPond
Lily#'s engraving engine is a port of LilyPond's, but the language is deliberately not LilyPond's. LilyPond's backslash commands are rejected outright, with a message naming the Lily# spelling.
| LilyPond | Lily# |
|---|---|
\relative c' { … } | relative is the default; or octave absolute |
\new Staff, \new Voice | part declarations and score rows |
<< … \\ … >> | voice { … } { … } |
<< … >> (parallel) | in Lily# this spelling is a written-out arpeggio |
\repeat volta 2 { … } | form main { |: A :| } |
\alternative | [1. B] :| [2. C] in the form |
c4\staccato, c4-. | c4@staccato |
c:maj7, fis:m7.5- | Cmaj7, F#m7-5 — the printed symbol, with +/- for an altered tension |
q (no marks) | q, and q' to repeat the chord an octave up |
\version | nothing; there is no version pragma |
\include | using "other.lys" |
Chord entry is the sharpest difference and the one most worth knowing: LilyPond asks you to encode a chord, Lily# asks you to type it as it prints.
24
Rough edges
Measured against Lily# 0.8.0 while this page was built. These are real and current; they are listed here rather than smoothed over.
One typo can still produce three diagnostics. c4@bend.half
reports the stray dot, then @bend missing its argument, then an undefined
variable half. The middle line now names the fix —
@bend(half) — but the other two remain.
Collapsing them means letting the parser eat the .half, and the obvious
rule for that (an argument-taking name followed by a dot) is wrong:
@ottava.bassa is a legitimate dotted name, and ottava
is in the same vocabulary.
The correct test is whether the whole dotted name is known, and that lives downstream.
lysc ly cannot express a displaced q. LilyPond's
q takes no octave marks, and wrapping it in \transpose does
not work either: LilyPond expands chord repetitions after transposition, so the
wrapper moves an empty placeholder and the expansion then fills in the untransposed
pitches (measured against 2.26.0 — it compiles and changes nothing). The twin writes a
plain q and warns; write the chord out by hand if the twin must match.
A chart that is nothing but a rhythm staff opens with a small gap. A one-line staff draws no clef, but the room for one is reserved per score rather than per staff, so a score with no other staff to fill it leaves the space empty. In a multi-staff score the reservation is right and nothing shows.
Documented gaps that are known and tracked: cross-staff beam layout and a LilyPond-to-Lily# converter. The long tail of specialist notation — early music, microtonal, clusters, ambitus — is deliberately out of scope.