Skip to content
Urs Liska edited this page Mar 14, 2019 · 3 revisions

The openLilyLib edition-engraver

What is it?

In a nutshell, the edition-engraver provides a convenient way of storing tweaks, overrides and other objects separately from the musical content that can later be selectively applied to some musical content.

The edition-engraver is part of openLilyLib, an extension infrastructure for the GNU LilyPond notation software.

Why use it?

To keep the "musical source" of a project free from tweaks, temporary overrides, and tagged material that needs to be filtered later. This serves to generate code that is clean, reusable and has clarity of purpose, meaning it's fast to read and understand.

Through the concept of "editions" (see below) it is possible to conditionally apply tweaks for specific rendering targets (e.g. different tweaks for score/parts, manuscript/original edition, or A4/tablet).

How is it used?

In summary, by following these four logical steps:

  1. Load the Edition Engraver into the project.
  2. Create an edition (a rendering target to which edits are assigned)
  3. Assign edits to an edition.
  4. Consist the contents of the edition to the musical contexts to which they apply.

Each step explained:

1 Loading the Edition Engraver

The edition-engraver is loaded as an openLilyLib package, so this has to be already installed in the working environment (see oll-core's Wiki for instructions).

openLilyLib's infrastructure has to be loaded first:

\include "oll-core/package.ily"  

Then, load the edition-engraver itself:

\loadPackage edition-engraver  

2 Creating an "edition"

An "edition" in the context of the edition-engraver is basically a rendering target (there actually have been multiple and lengthy discussions about the best naming. However, lacking a better name, "edition" was kept).

The edition-engraver stores tweaks as "mods" (see next section) that are assigned to "editions". This way tweaks are only applied for specific rendering targets.

The basic way to create an edition is the \addEdition command like this:

\addEdition edition-name  

This means that when "mods" with various targets are present only those with the target edition-name are applied. For example, when mods with the targets global, score, parts, and part-violin are present, then the following might be included in the main file for the violin part:

\addEdition global
\addEdition parts
\addEdition part-violin

This will ensure that the global mods (e.g. inserting \mark elements), mods that should be applied to all parts (as opposed to the score), and mods that are specific to the violin part (e.g. a specific slur shape that is not needed in the score), are applied, but not those assigned to the score target.

Note:
editions are the way to control which mods are applied, so they are part of the concept of the rendering target. This means that the \addEdition commands have to be inserted in the file(s) controlling the engraving of the given targets. If the musical content is stored in some .ily files and there are entry files like score.ly, part-violin.ly etc. then the \addEdition commands should be placed in these latter files to control which mods are actually applied.

3 Creating edits and assigning them to targets/editions

As said in the very first section of this page the edition-engraver allows to store tweaks etc. as separate entities from the musical content. These entities are called mods, and there are several commands to create them.

Typically the mods can be stored in separate include files. These include files may be used to control which mods are applied (selectively include one or more such files), but the idea is to have the editions be responsible for this purpose. So usually one will want to store all mods in one file and group them by the target editions.

The most basic way to do store a mod is by using the \editionMod command. It is used as follows:

\editionMod edition measure position context content  

Breaking it apart:

  • edition specifies in what edition the content is stored.
  • measure specifies in what measure of the music the content is to be placed.
  • position specifies where where exactly in that measure the content is to be placed.
  • context specifies in what context the content belongs.
  • content specifies, finally, what should be placed there. This is one musical expression.

So, this means that

\editionMod my-edition 5 0/4 Score \break  

will store a \break element that will be placed in the Score context, in measure 5, specifically at 0/4, which is its first beat. This will only have an effect if the my-edition edition is active (see previous section).

\break is one atomic musical expression, but it is also possible to use expressions like this:

\editionMod my-edition 5 0/4 Score {
  \once \override TextScript.extra-offset = #'(-1 . 0.2)
  \shape #'((0 . 1)(1 . 2)(0 . -1)(1 . 1)) Slur
  \mark \default
}

To inject multiple elements at a single position

TODO: Clarify what can go into an \editionMod and what can't.

3.1 About the position value

The position in the measure may be confusing because it is not interpreted in terms of "beats" (as would seem more natural to humans) but in terms of musical time that has passed from the start of the given measure. A few useful examples:

  • 0/4 will not add anything, so it references the first beat of the measure.
  • 2/4 will count 2 4th notes / crotches from the start of the measure. In 4/4 time this references the third beat, i.e. the middle of the measure.
  • 3/8 will count three 8th notes / quavers from the start of the measure. In 4/4 time this would reference the second half of the second beat.
  • 1/24 will count one 16th note / semiquaver of a 16th note triplet. If the measure starts with 16th note triplets, this will point to the second note of the measure. The fraction is expressed like this because there are 24 "tripleted 16th notes" in a whole note.

Instead of fractions also rational numbers may be used that are implicitly converted to fractions (if that is possible). So the following positions are equivalent:

  • 1/8 = 0.125
  • 1/1 = 1
  • 0/4 = 0

Sometimes it may be necessary to pass the position as a ly:moment? value. 2/4 is equivalent to #(ly:make-moment 2/4); however, this approach is necessary to address grace moments, which are addressed as negative values from the following regular moment. Consider a measure starting with

\grace { c16 [ d e d ] } c4

then #(ly:make-moment 0 4 -2 16) will address the second semiquaver before the c4.

Note:
If there is no musical event at the time assigned to the mod (e.g. a measure starts with c4. d8 and a mod is assigned to 1/4) the mod will silently have no effect.

3.2 About referencing contexts

Precise control can be achieved by giving ID's to contexts. This is done with the \editionID command:

\new Staff \with { \editionID my-staff } {  
  \new Voice { c4 d e f }  
}  

This ID can be used like this:

\editionMod test 1 2/4 my-staff.Staff \accidentalStyle dodecaphonic  
\editionMod test 1 3/4 my-staff.Voice.A \override NoteHead.color = #red  

Notice that even though the ID my-staff points to a specific Staff, \editionMod still needs to know specifically where you need to inject the content. So, my-staff.Staff puts it in the Staff context, while my-staff.Voice.A puts it in the first Voice inside the Staff.

Voices are listed in the order they are created, starting with the symbol A, and each Staff keeps a separate count. The Edition Engraver produces a ".edition.log" file listing all the contexts it finds along with their names. This is useful to work with music that requires spontaneous creation of Voices, such as piano music, where naming them provides a straightforward way of finding how to reference them.

Say you have an "example.ly" file with the following music:

\new Staff \with { \editionID my-staff } {  
  \new Voice = "main-voice" \relative c'' {  
    c4 d e f  
    << 
      { \voiceOne e d c2 }  
      \new Voice = "spontaneous-voice" { \voiceTwo g2 e }
    >>
  }  
}  

This will produce an "example.edition.log" file that, among other things, will have the following:

(my-staff Voice A) "main-voice"  
(my-staff Voice B) "spontaneous-voice"  

While the Score context can't be instantiated, an ID can be given to a \score block in it 's \layout block, like this:

\score {  
  ...  music goes here ...  
  \layout {  
    \context {  
      \Score  
      \editionID my-score  
    }  
  }  
}  

This very useful when you need specific edits for parts that you want to keep out of the full score. While references can grow long pretty quickly, fortunately they can be stored in variables:

referenceOne = my-score.my-staff.Voice.A  
referenceTwo = my-other-score.my-staff.Voice.B  

And then used like this:

\editionMod test 1 3/4 \referenceOne ->
3.2.1 A warning

Keep bottom level content to bottom level contexts. See this example:

\version "2.19.82"  

\include "oll-core/package.ily"  
\loadPackage edition-engraver  

\addEdition example  
\editionMod example 1 0/4 good-staff.Voice.A \once \override NoteHead.color = #red  
\editionMod example 1 0/4 bad-staff.Voice.A \once \override NoteHead.color = #red  
\consistToContexts #edition-engraver Staff.Voice  

\score {  
  \new StaffGroup <<  
    \new Staff \with { \editionID good-staff } {  
      \new Voice { \clef C c' d' e' f' }  
    }  
    \new Staff \with { \editionID bad-staff } {  
      \clef C \new Voice { c' d' e' f' }
    }  
  >>  
}

Running this shows that good-staff has a red first note, while bad-staff doesn't. This is because on the second Staff the \clef command is tacitly in a Voice that has no length. This kind of tacit Voice creation produces strange results. This is easily avoided by moving the \clef command inside the Voice that has actual music, like good-staff shows.

3.3 Applying mods to multiple moments

In many cases it is necessary to apply the same mod to multiple moments, for example mods like \break or \mark \default. For this there is the command \editionModList that applies one mod to a list of musical positions (but only in a single context). It is used like this:

\editionModList target context mod list-of-moments

This is very similar to \editionMod, and the rules for target, context and mod are identical. However, note the different order or arguments, and instead of measure and position (after target) there is list-of-moments after the mod expression. This is a list of moments at which the mod will be applied.

Each element of the list may be either an integer or a pair of an integer and a position. Simple integers reference the start of a given measure while pairs reference a moment within a measure. A "position" may be expressed in all the ways described above in section 3.1.

For example:

\editionMod my-edition my-score.my-staff.Staff \mark \default #'(5 23 (29 2/4))

will apply the mod \mark \default at the start of measures 5 and 23, and 2/4 into measure 29.

4 Consisting to contexts

As the name suggests, the edition-engraver is an engraver (see the LilyPond documentation about engravers). Engravers are only active for contexts where they are explicitly enabled. While the built-in engravers are enabled for suitable default contexts the edition-engraver has to be enabled specifically for all contexts it should listen. This can be done like with all other engravers, in a \layout block:

\layout {
  \context {
    \Voice
    \consists edition-engraver
  }
}

However, openLilyLib provides \consistToContexts, a shorthand to install an engraver into multiple contexts at once:

\consistToContexts #edition-engraver contexts.separated.by.dots  

The contexts absent from the dot-separated list will not be modified. So, for instance:

\editionMod test 1 0/4 my-score.Score \tempo "Adagio."  
\editionMod test 1 0/4 my-other-score.my-staff.Staff \tempo "Adagio."  
\consistToContexts #edition-engraver Staff.Voice  

will create a TempoChangeEvent in my-other-score, since the instruction is to create it in the Staff context, but leave my-score untouched.

Hopefully this will be enough to get anyone started. There is more functionality than this. For a start, examine the usage-examples folder in the Openlilylib Edition Engraver repository.