Technical documentation
EES Tools is a collection of scripts that are required for engraving scores for the Edition Esser-Skala. In addition, this repository includes instructions to build a Docker container ees-tools with these tools and all dependencies.
TL;DR: Engraving scores
… using the Docker image
We recommend to engrave scores via the ees-tools Docker image. This image is based on python, with all dependencies installed by docker/setup.sh. GitHub Actions uses this image to automatically engrave and release scores of the Edition Esser-Skala whenever a tag is pushed.
From the root directory of an edition, run
docker run --rm -it -u engraver -v $PWD:/ees ees-tools
to engrave all final scores (i.e., make final/scores
). To list all available build targets, run
docker run --rm -it -u engraver -v $PWD:/ees ees-tools make info
(Note: These commands ensure that there is a user engraver in the container whose uid and gid match the user who runs the container. Thereby, all files created by the container will have the correct permissions.)
… using a manual installation
Install the following dependencies:
- Python v3.11 with packages GitPython, numpy, pandas, segno, strictyaml, termcolor, and texoutparse.
- Source Sans v3.046 and Fredericka the Great v1.001
- TinyTex v2023.10 with LaTeX packages in docker/tinytex_packages.txt
- LilyPond v2.24.2
Clone the repository and make sure that the files can be found by the respective programs:
- Define the shell variable
EES_TOOLS_PATH
to point to this directory. - Run
tlmgr conf auxtrees add $EES_TOOLS_PATH
. - Always run LilyPond with the flag
--include=$EES_TOOLS_PATH
.
From the root directory of an edition, invoke make
to engrave scores:
make final/scores
generates all publication-ready scores in folder final.make info
lists all available build targets.
Alternatively, configure your text editor to invoke LilyPond. For instance, use this task for VS Code:
{
"label": "Run LilyPond with EES Tools",
"type": "shell",
"command": "lilypond",
"args": [
"--include=<path to EES tools>",
"--output=main",
"-dno-point-and-click",
"scores/full_score.ly"
],
"options": {
"env": {
"LANG": "en"
}
},
"group": "build",
"problemMatcher": {
"owner": "ly",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": {
"regexp": "^(.*):(\\d+):(\\d+):\\s+(\\w*):\\s+(.*)$",
"file": 1,
"line": 2,
"column": 3,
"severity": 4,
"message": 5
}
}
}
Structure of a score repository
In order to create a new edition, clone the ees-template repository:
gh repo create edition-esser-skala/<repository> \
--public \
-p edition-esser-skala/ees-template \
-d "<composer>: <title>"
The new repository will contain the following folders and files:
- notes/*.ly – LilyPond files containing individual voices; add new variables with add_variables.py
- scores/*.ly – LilyPond files containing score definitions
- .gitignore – excludes irrelevant files from the repository
- CHANGELOG.md – the changelog
- definitions.ly – general definitions; include ees.ly
- LICENSE – the license (CC BY-SA 4.0 or CC BY-NC-SA 4.0)
- Makefile – configuration file for
make
; imports ees.mk - metadata.yaml – metadata whose format is described below; can be processed with read_metadata.py
- .github/workflows/engrave-and-release.yaml – GitHub Actions workflow that reuses the workflow of the same name from EES Tools
- front_matter/critical_report.tex – prefatory material based upon ees.cls
ees.ly
General LilyPond settings and macros. This file is included by definitions.ly
in the repository of each work.
Options
Set these Scheme variables before including the file, like
#(define option-movement-title-markup "number-title")
#(define option-print-all-bar-numbers #f)
\include "ees.ly"
option-movement-title-markup
: Select the format of the movement title and the number of arguments for\section
. Choices:"genre-number-title"
,"number-title"
, and"title"
(default).option-print-all-bar-numbers
: If true, print all bar numbers (useful when preparing a score; default: false).
Score settings
Include one of the following files in subfolder score_settings
at the beginning of a score definition:
one-staff.ly
: Format parts with a single staff (e.g., vl 1).option-instrument-name
sets the instrument name of this staff.two-staves.ly
: Format parts with two bracketed staves (e.g., cor 1, 2).option-instrument-name
sets the instrument name of the bracket.three-staves.ly
: Format parts with three staves, of which the upper two are bracketed (e.g., ottoni).option-instrument-name-upper
andoption-instrument-name-lower
set the instrument name of the bracket and lower staff, respectively.four-staves.ly
: Format parts with four staves, of which the upper three are bracketed (e.g., ottoni with three trumpets).option-instrument-name-upper
andoption-instrument-name-lower
set the instrument name of the bracket and lower staff, respectively.five-staves.ly
: Format parts with five staves, of which the upper four are bracketed (e.g., ottoni with four trumpets).option-instrument-name-upper
andoption-instrument-name-lower
set the instrument name of the bracket and lower staff, respectively.full-score.ly
: Format the full score.coro.ly
: Format the vocal score.option-instrument-name
sets the instrument name of the lowermost staff.org-realized.ly
: Format the realized organ part.option-instrument-name
sets the instrument name of the bracket.
System configuration
\setGroupDistance <staff-staff> <after-group>
\setStaffDistance <after-staff>
These commands modify the vertical spacing of staff groups and single staves. <staff-staff>
will be the spacing between staves in the group, while <after-group>
and <after-staff>
will be the distance after the group and staff, respectively.
\new Staff \with { \setStaffDistance #10 } { … }
\new StaffGroup <<
\new GrandStaff \with { \setGroupDistance #12 #15 } <<
\new Staff { … }
\new Staff { … }
>>
\new Staff { … }
>>
\smallGroupDistance
\normalGroupDistance
\smallStaffDistance
For convenience, these three commands for changing distances are predefined.
\incipit "<name>" "<clef>" #<space1> #<space2>
\incipitSoprano
\incipitAlto
\incipitTenore
\incipit
prints an incipit in front of a staff with the given instrument name
and clef
. space1
and space2
determine the horizontal space between the instrument name and the staff, or the staff and the system, respectively. For convenience, predefined incipit commands for soprano, alto, and tenor are provided.
\new Staff {
\incipitSoprano
\new Voice = "Soprano" { \dynamicUp \SopranoNotes }
}
\transposedName "<name>" "<pitch>" "<accidental>"
\transposedNameShort "<name>" "<pitch>" "<accidental>"
\transposedTimp "<pitch-high>" "<acc-high>" "<pitch-low>" "<acc-low>"
\transposedTimpShort "<pitch-high>" "<acc-high>" "<pitch-low>" "<acc-low>"
make-one-pitch
make-timp-pitches
These commands print an instrument name including pitches. \transposedName
and \transposedTimp
should be used for the first movement, commands ending in …Short
should be used for subsequent movements. For special cases, the Scheme functions make-one-pitch
and make-timp-pitches
are available.
\new Staff {
\set Staff.instrumentName = \transposedName "Clarino" "B" "flat"
\Clarino
}
\new Staff {
\set Staff.instrumentName = \transposedTimp "B" "flat" "F" ""
\Timpani
}
Sectioning and TOC
Sectioning commands:
\insertEmptyPage
: Inserts an empty page (useful if parts should start on the right page).\part "<label>" "<number>" "<title>"
: Adds a part page, followed by an empty page. Must be used inside a\book
. For technical reasons, a<label>
has to be supplied even if the command is used for a default TOC.\section "<title>"
,\section "<number>" "<title>"
, or\section "<number>" "<genre>" "<title>"
: Adds a section heading. The number of arguments is determined by the optionoption-movement-title-format
. Must be used inside a\bookpart
.\subsection "<title>"
: Adds an unnumbered subsection heading. Must be used inside a\bookpart
.\tacet "<level>" [<distance> = #4] "<title>"
: Adds<title>
centered and the italic word “tacet” below. The optional argument<distance>
allows to change the vertical distance to the preceding staff.<level>
(eithersection
orsubsection
) ensures that the font size matches the respective heading.
TOC commands:
\addTocEntry
: Adds a TOC entry; should be used immediately after a heading command.\addTocLabel "<label>"
: Adds a labeled TOC entry. The<label>
must be unique throughout the score.
% normal TOC entries
\book {
\part "" "1" "First part"
\bookpart {
\section "1" "Kyrie"
\addTocEntry
\score { … }
}
\bookpart {
\subsection "Christe"
\addTocEntry
\score { … }
}
}
% labeled TOC entries
\book {
\part "firstpart" "1" "First part"
\bookpart {
\section "2" "Recitativo" "Title"
\addTocLabel "label2"
\score { … }
}
}
Markup
-
\remark <markup>
and\remarkE <markup>
: Format source directives (upright) and editorial directives (italic), respectively. In addition, several directives are predefined with source and editorial variants (e.g.,\solo
and\soloE
):Command Printed text \arco
arco \bassi
Bassi \colOrg
col’Org. \conSord
con sordino \dolce
dolce \org
Org. \pizz
pizz. \senzaOrg
senza Org. \senzaSord
senza sordino \solo
Solo \tasto
tasto solo \tenuto
ten. \tutti
Tutti \unisono
unisono \vlc
Vlc. \critnote
: print asterisk denoting an editorial emendation\mvTr
: move text 2 staff spaces to the right\mvTrh
: move text 2.5 staff spaces to the right\mvTrr
: move text 3 staff spaces to the right\tempoMarkup "<tempo>"
: format the tempo indication
Inside the staff
\twofourtime
and\twotwotime
adjust automatic beaming in 2/4 and 2/2 time, respectively.- The following dynamics commands are redefined and supplemented by an editorial variant:
\fff
(plus\fffE
etc),\ff
,\f
,\mf
,\mp
,\p
,\pp
,\ppp
,\sf
,\sfp
,\sfz
,\fp
,\fz
,\rf
,\rfz
,\passai
,\piuF
,\piuP
,\pocoF
,\pocoP
,\cresc
, and\decresc
. \bp
: override beam positions\extraNat
: force accidental\hairpinDashed
and\hairpinSolid
: turn on/off dashed hairpins\hideTn
: hide a single tuplet number\kneeBeam
and\noKneeBeam
: force/suppress kneed beams\markDaCapo
: print “da capo” right aligned above a bar line\markTimeSig #'(n d)
: add a parenthesized time signature markn/d
above a bar line to indicate a different bar length\mvDl
: move dynamic mark 2 staff spaces to the left\mvDll
: move dynamic mark 3 staff spaces to the left\parOn
and\parOff
: only print the left/right parenthesis in\parenthesize
\sbOn
and\sbOff
: turn on/off subdivided beams\scriptOut
: force script (like-|
) to be printed outside of slur\trillE
: editorial (parenthesized) trill\whOn
and\whOff
: switch on/off white (void) notation\xE
and\x
: turn on/off editorial (italic) lyrics
Polyphony
\pa
: short for\partCombineApart
\pao
: short for\once \partCombineApart
\pd
: short for\partCombineAutomatic
\rh
and\lh
: change staff in keyboard music
Bass figures
\bo
and\bc
: only print the left/right bass figure bracket\l
: empty space instead of figure; works like_
introduced in LilyPond 2.24.0, but yields centered extenders\t
: horizontal dash instead of figure\tllur
: dash from lower left to upper right instead of figure\fivehat
: the figure 5 with a hat, indicating a diminished fifth
ees.mk
Makefile that defines rules for engraving scores. This file is included by the Makefile
in the repository of each work. Available targets:
full_score
,b
,vl1
etc: individual scores (LilyPond output only)scores
: all scoresfinal/full_score
,final/b
,final/vl1
etc: individual final scores (LilyPond output + front matter)final/midi
: MIDI archivefinal/scores
: all final scores and the MIDI archiveinfo
: usage details
parse_logs.py
Each run of LilyPond and LuaLaTeX generates a log file, which is stored in tmp/<score>.ly.log
and tmp/<score>.tex.log
, respectively. This script collects all errors, warnings, and full boxes from these logs, prints them on the terminal, and stores them in tmp/_logs.txt
. Its single optional argument allows to change the directory where log files are searched (default: tmp).
ees_articulate.ly
A variant of LilyPond’s articulate.ly
with longer staccatissimo and slower trills.
instrument_data.csv
This table describes instruments (rows) via the following variables (columns):
- abbreviation – abbreviation used in the scoring, the list of abbreviations, and score file names
- long – full English name given in the list of abbreviations
- variable – name used in LilyPond variables
- score_type – name used for the score type on the title page
- relative – start pitch for relative octave entry
- clef – default clef
- autobeam – should notes be beamed automatically? (false for vocal parts)
- default_key – overrides key for transposing instruments; ‘none’ indicates no override
- second_template – second variable template to add (for vocal parts and figured bass)
read_metadata.py
This script creates various outputs from information in metadata.yaml
, depending on the subcommand given as first argument.
Subcommand edition
Generate a set of LaTeX macros that can be imported by front_matter/critical_report.tex
. Each of these LaTeX macros starts with \Metadata...
. The mapping between YAML keys and macros is described below.
-h
,--help
: show this help message and exit-i
,--input FILE
: read metadata fromFILE
(default:metadata.yaml
)-o
,--output FILE
: write the macros toFILE
(default:front_matter/critical_report.macros
)-t
,--type TYPE
: select scoreTYPE
for front matter:draft
(default):- set
\MetadataScoretype
toDraft
- include critical report, changelog and TOC
- do not print any scores
- set
full_score
:- set
\MetadataScoretype
toFull Score
- include critical report, changelog and TOC
- print the full score
- set
- any other value is interpreted as scoring abbreviation:
- set
\MetadataScoretype
to the long form of the abbreviation - do not print critical report, changelog and TOC
- print the respective score
- set
-c
,--checksum-from {head,tag}
: obtain version, date, and checksum from HEAD or the most recent tag (default:head
)-k
,--additional-keys [KEYS ...]
: process additional KEYS-s
,--score_directory DIR
: read included scores from this directory (default:../tmp
)-l
,--license-directory DIR
: check the LICENSE in this directory (default: current dir)-q
,--qr-base-url URL
: download score PDFs from this base URL (default: current GitHub release)
The long form of a scoring abbreviation is looked up instrument_data.csv. The abbreviation may end in an Arabic number, which is converted to a Roman numeral (e.g., vl2
-> “Violino II”). Abbreviations can also be defined in metadata.yaml
via the parts
key (e.g., clno12: Clarino I, II in C
).
The subcommand also obtains the following information from the git metadata:
- name of the remote repository
origin
(->\MetadataRepository
) - version … (->
\MetadataVersion
) - … date … (->
\MetadataDate
) - … and checksum of HEAD or the most recent tag (->
\MetadataChecksum
) - a link to the score PDF in the current release, represented as a QR code made by PGF macros (->
\MetadataQRCode
)
Furthermore, the subcommand reads the LilyPond version from the output of lilypond --version
(-> \MetadataLilypondVersion
) and the EES Tools version from the most recent tag of the repository in $EES_TOOLS_PATH
(-> \MetadataEESToolsVersion
).
Subcommand table
Collect metadata from several repositories and save it as a table. The subcommand requires a folder structure like root -> composer -> work.
-h
,--help
: show this help message and exit-d
,--root-directory ROOT
: read metadata from all repositories inROOT
, assuming the folder structure root -> composer -> repository (default: current folder)-o
,--output FILE
: write the table toFILE
(default:works.csv
)
metadata.yaml
This file describes metadata for each work and comprises the following keys:
composer
(optional): The composer’s name, specified by the following subkeys:last
(required): last name (->\MetadataLastname
)first
(optional): first name (->\MetadataFirstname
)suffix
(optional): name suffix (->\MetadataNamesuffix
)
Note that this key is optional mainly to facilitate collections of works by the same composer (such as the Proprium Missæ project). If the key is missing, first and last name are set to “(unknown)”.
title
(required): Work title (->\MetadataTitle
).subtitle
(optional): Work subtitle. The subtitle is combined with the work identifier and stored in\MetadataSubtitle
. If this key is missing, the work identifier is used alone.id
(optional): Work identifier (typically, the catalogue of works number). If this key is missing, the RISM library siglum and shelfmark of the principal source are used.genre
(required): Work genre (only used on the webpage).scoring
(required): Scoring of the work (->\MetadataScoring
). See the editorial guidelines for the scoring syntax. The list of abbreviations in the critical report is also assembled from the scoring information (->\MetadataAbbreviations
)editor
(optional): Editor of the work (default: Wolfgang Esser-Skala; ->\MetadataEditor
).license
(required): License of the edition (->\MetadataLicense
). Currently, the following values are supported:cc-by-sa-4.0
andcc-by-nc-sa-4.0
.sources
(required): Manuscript and print sources used for the edition (->\MetadataSources
). The name of each subkey will be used as source identifier (e.g., A1, B2). Each source is described by the following keys:siglum
(required): RISM library siglumshelfmark
(required): shelfmarkdate
(optional): daterism
(optional): RISM identifierurl
(optional): link to digital versionlicense
(required): license of the sourcenotes
(optional): miscellaneous notesprincipal
(optional/required): Boolean that denotes whether this source is the principal source. Exactly one source must contain this key with a true value.
imslp
(optional): IMSLP identifier (only used on the webpage).notes
(optional): Miscellaneous notes (only used on the webpage).parts
(optional): For each file in thescores/
subdirectory, this key may contain a subkey-value pair. The subkey corresponds to the file name (without extension), and the value will be used as score type on the title page (->\MetadataScoretype
). File names that correspond to default scoring abbreviations (such asorg
andvl1
) will be converted even in the absence of a respective subkey.extra_abbreviations
(optional): Additional abbreviations and their long forms (subkeys and values, respectively) to be included in the critical report. If the subkey corresponds to a known abbreviation, its value may be empty.- By default, all other keys are silently ignored. However, any
<key>
specified in the--additional-keys
option of read_metadata.py will be available in LaTeX via a\\Metadata<Key>
macro.
tex/latex/ees.cls
LaTeX class for printing scores with prefatory material.
Class options
Type and default value in parentheses.
abbrwidth
(length, 3em): width of the first column in the list of abbreviationschangelog
(Boolean, true): print the changelog (i.e., include CHANGELOG.md)shortnamesize
(number, 80): font size for the composer name in the title page headshorttitlesize
(number, 60): font size for the work title in the title page headtocdir
(string,../tmp
): directory where LilyPond saves the TOC filetocstyle
(string,default
): selects a style for the table of contentsnone
: do not print a TOCdefault
: print a normal TOCref
: print a manual TOC using labelsref-genre
: print a manual TOC using labels; include a genre
Note that even if a TOC is not printed, the pdf will contain bookmarks with entries for movements as well as sections in the prefatory material
toe
(Boolean, true): indicates whether the commentary contains a table of emendations
Formatting
\textlt{<text>}
and\ltseries
: Select light text weight.\textsb{<text>}
and\sbseries
: Select semibold text weight.\A{<number>}
to\E{<number>}
: Typeset a source identifier (uppercase letter plus index<number>
).\doublesharp{<pitch>}
,\sharp{<pitch>}
,\natural{<pitch>}
,\flat{<pitch>}
, and\flatflat{<pitch>}
: Add an accidental to<pitch>
and ensure correct kerning.\wholeNoteRest
and\halfNoteRest
: Print respective rest with improved kerning.\demisemiquaverRest
and\demisemiquaverRestDotted
: Print (dotted) thirty-second rest.\hemidemisemiquaverRest
and\hemidemisemiquaverRestDotted
: Print (dotted) sixty-fourth rest.
Metadata
By default, these macros use the respective values in metadata.yaml
.
\firstname{}
: first name of the composer (default:\MetadataFirstname
)\lastname{}
: last name of the composer (default:\MetadataLastname
)\namesuffix{}
: name suffix of the composer (default:\MetadataNamesuffix
)\shortname{}
: composer name for the title page head (default:\MetadataLastname
)\title{}
: work title (default:\MetadataTitle
)\shorttitle{}
: work title for the title page head (default:\MetadataTitle
)\subtitle{}
: work subtitle (default:\MetadataSubtitle
)\scoring{}
: scoring information (default:\MetadataScoring
)\editor{}
: editor (default:\MetadataEditor
)\license{}
: license of the edition (default:\MetadataLicense
)\scoretype{}
: score type printed on the title page (default:\MetadataScoretype
)\repository{}
: name with owner of the GitHub repository (default:\MetadataRepository
)\version{}
: version of the most recent git tag (default:\MetadataVersion
)\date{}
: date of the most recent git tag (default:\MetadataDate
)\checksum{}
: checksum of the most recent git tag (default:\MetadataChecksum
)
The value of any additional metadata <key>
can be retrieved via \Metadata<Key>
. Note the uppercase key name in the macro: For instance, the key genre
will provide a macro \MetadataGenre
.
Document structure
\eesTitlePage
: Print the default title and copyright page.\eesCriticalReport{<table rows>}
: Print the critical report (abbreviations, sources, and commentary) and the changelog. The single argument may contain rows for the table of emendations, which comprises three columns iftocstyle=none
, and four columns otherwise. Iftoe
is false, the argument is ignored.\eesCommentaryIntro
: Print the default introduction of the commentary section (automatically invoked by\eesCriticalReport
).\eesCommentaryAfterToe
: Text that should be printed after the table of emendations (by default empty).\eesToc{<contents>}
: Setup pdf bookmarks; print the table of contents unlesstocstyle=none
. Iftocstyle=ref
orref-genre
, the value of the argument is printed under the headline Contents and allows to format the TOC manually (see below).\eesScore
: Print the included score.\ifPrintFrontMatter
…\fi
: Additional content in the prefatory material should be surrounded by this conditional, which ensures that it is only printed in the full score and draft.
Manual TOC
\part{<label>}
: Print a TOC entry for the part with<label>
as defined in the LY file via\addTocLabel
.\section{<label>}
: Print a TOC entry for the section with<label>
.\begin{movement}{<label>} <lyrics> \end{movement}
: Print the TOC entry (section level) for the movement with<label>
. The<lyrics>
may comprise- continuous text, which represents all lyrics of the respective movement (as seen, for instance, in Michael Haydn’s Litaniæ MH 532); or
- text blocks labeled with the associated voice (as seen, for instance, in Stölzel’s Jeſu, Deine Paßion).
\voice[<label>]
sets the<label>
of each text block.
.github/workflows/engrave-and-release.yaml
This GitHub Actions workflow engraves scores using the ees-tools Docker container and creates a GitHub release that includes
- all generated PDFs, and
- a zip archive
midi_collection.zip
will all (manually curated) midi files in foldermidi
(only if the latter folder exists).
It is triggered whenever a SemVer tag is pushed to GitHub.
documents/*
This folder contains various documents:
editorial_guidelines.md
: the current editorial guidelinesimslp_instructions.md
: instructions for publishing scores at IMSLP
utils/*
This folder contains miscellaneous scripts:
add_variables.py
: extends LY files in subfoldernotes/
with variables for a new movement:-h
,--help
: show this help message and exit-m
,--movement MOVEMENT
: add this movement-n
,--notes [NOTES ...]
: add the movement to these instruments (default: all instruments in notes subfolder)-k
,--key KEY
: key signature (default: C major). Examples:C
is C majord
is D minord_dorian
is D dorian
-t
,--time TIME
: time signature (default: 4/4)-p
,--partial PARTIAL
: duration of upbeat (default: no upbeat)-b
,--current-bar CURRENT_BAR
: start movement with this bar number (default: 1)-f
,--force-file-creation
: create missing files (default: false)
download_from_manuscriptorium.sh
: obtains high-resolution images from Manuscriptorium. Usage:download_from_manuscriptorium.sh <ID> <last page>
where
<ID>
is the Manuscriptorium ID and<last page>
is the last page of the document. Images are saved in the current folder as a series of JPEG files0001r.jpg
,0001v.jpg
,0002r.jpg
etc.download_from_slub.sh
: obtains high-resolution images from SLUB. Usage:download_from_slub.sh <ID> <last page>
where
<ID>
is the SLUB ID and<last page>
is the last page of the document. Images are saved in the current folder as a series of JPEG files0000001.jpg
,00000002.jpg
etc.download_from_spitz.sh
: obtains high-resolution images from Musikarchiv Spitz. Usage:download_from_spitz.sh <ID> <last page>
where
<ID>
is the mirador ID (as evident from the IIIF manifest) and<last page>
is the last page of the document. Images are saved in the current folder as a series of JPEG files001.jpg
,002.jpg
etc.-
make_collection.py
: creates a collection of works for a printed edition. The semi-automatical workflow comprises the following steps:- Run
make_collection.py
. This script requires the name of the collection as first argument, followed by the included works as further arguments. It combines relevant data from the specified works (i.e., frommetadata.yaml
,definitions.ly
, andfull_score.ly
) and creates a subfolder incollections/
named after the collection. This folder contains three files:critical_report.tex
– the overall front matter. Abbreviations are merged into a single section at the beginning, followed by a section for each work, which contains general information, the table of emendations, and the lyrics.definitions.ly
– overall definitions. They include required files with note variables, tempo indications, macros etc.full_score.ly
– the full score with all works. For each work, top-level paper variables are moved into the paper blocks of its bookparts.
- Optionally, make minor (!) manual adjustments in
critical_report.tex
, such as line or page breaks. - Engrave the full score with LilyPond.
- Render the front matter with latexmk.
- Replace the first page in the generated PDF by a custom title page (e.g.,
collections/extra_title.pdf
).
The following commands execute this workflow:
NAME=B1 WORKS="44 47 50 53 54 56 61 78 85 86_43 93 107 132" python $EES_TOOLS_PATH/utils/make_collection.py $NAME $WORKS lilypond --include=$EES_TOOLS_PATH -dno-point-and-click -o tmp/$NAME/full_score collections/$NAME/full_score.ly latexmk -cd -lualatex -jobname=full_score collections/$NAME/critical_report.tex latexmk -cd -c -jobname=full_score collections/$NAME/critical_report.tex
- Run
split_image.sh
: splits double-sided PDFs. Usage:split_image.sh <file> <size>
where
<file>
is a PDF file and<size>
is the size of the half page in pixels, given as[width]x[height]
Appendix
Useful LilyPond snippets
Increase length of multi measure rest.
\override MultiMeasureRest.minimum-length = #40
R\breve.*123 \bar "||"
Adjust overall horizontal spacing.
\layout { \override Score.SpacingSpanner.common-shortest-duration = #(ly:make-moment 1/8) }
tightNotes = \override Score.SpacingSpanner.common-shortest-duration = #(ly:make-moment 1/8)
looseNotes = \revert Score.SpacingSpanner.common-shortest-duration
Define a right-aligned mark.
markOsannaDaCapo = {
\once \override Score.RehearsalMark.self-alignment-X = #RIGHT
\mark \markup \remark "Osanna da capo"
}
Change displayed time signature fraction.
\set Staff.timeSignatureFraction = 3/8
Show only numerator of time signature.
\once \override Staff.TimeSignature.style = #'single-digit
Add name to choir staff group.
\set ChoirStaff.instrumentName = \markup { \rotate #90 "C O R O 1" \hspace #10 }
Add a tie to the last note of a movement.
extendLV = #(define-music-function
(parser location further)
(number?)
#{
\once \override LaissezVibrerTie.X-extent = #'(0 . 0)
\once \override LaissezVibrerTie.details.note-head-gap = #(/ further -2)
\once \override LaissezVibrerTie.extra-offset = #(cons (/ further 2) 0)
#})
Mark deleted parts of a score by gaps across the staves.
startDeleted = {
\once \override Staff.BarLine.color = #white
\once \override Staff.BarLine.layer = #10000
\once \override Staff.BarLine.thick-thickness = #10
\noBreak \mark \markup { \fontsize #-2 \musicglyph #'"pedal.*" } \bar "." \noBreak
}
stopDeleted = {
\once \override Staff.BarLine.color = #white
\once \override Staff.BarLine.layer = #10000
\once \override Staff.BarLine.thick-thickness = #10
\noBreak \bar "." \noBreak
}
Make a multirow short instrument name.
#(define option-instrument-name (markup #:center-column ("vla 1" "trb 1")))
Incipits for …
- two sopranos:
\incipit "Soprano I" "soprano" #-19.5 #-1.8 \incipit "Soprano II" "soprano" #-20 #-1.8
</pre></div> </div>
- mixed chorus with or without continuo:
\incipit "Soprano" "soprano" #-20.5 #-0.3 \incipit "Alto" "alto" #-18.3 #-0.3 \incipit "Tenore" "tenor" #-19.7 #-0.3
</pre></div> </div>
- solo voice and strings:
\incipit "Soprano" "soprano" #-18.0 #-2.8 \incipit "Alto" "alto" #-15.8 #-2.8 \incipit "Tenore" "tenor" #-17.2 #-2.8
</pre></div> </div>
- alto and tenor with trombones:
\incipit \markup \center-column { "Alto" "Trombone I" } "alto" #-20.5 #-1.8 \incipit \markup \center-column { "Tenore" "Trombone II" } "tenor" #-20.9 #-1.8
</pre></div> </div>
- voices with accompanying strings:
\incipit \markup \center-column { "Soprano" "[Violino I]" } "soprano" #-21.3 #-0.3 \incipit \markup \center-column { "Alto" "[Violino II]" } "alto" #-21.8 #-0.3 \incipit \markup \center-column { "Tenore" "[Viola]" } "tenor" #-19.6 #-0.3
</pre></div> </div>
- two violins in a grand staff colla parte with S and A:
\incipit "I" "soprano" #-16.1 #-0.8 \incipit "II" "alto" #-16.4 #-0.8
</pre></div> </div>
- right hand of organ solo
\incipit " " "soprano" #0 #-1.8
</pre></div> </div>
Add a tacet followed by a repeated movement.
\tacet "section" "Benedictus"
\markup { \vspace #3 \fontsize #3 \fill-line { "" "Osanna ut supra" "" } }
Unmetered notation (see MH 98 and 628 for complete examples).
Basso = {
\relative c {
\clef bass
\key c \major \time 2/2 \tempoXXX
\omit Staff.TimeSignature
\time 10/1 \[ e1 d f \] \[ e f g f d f \] f \noBreak
\time 7/1 \[ f d \] f \[ e f g \] d \noBreak
\time 5/1 \[ f a \] \[ g f \] e\fermata \bar "||"
\undo \omit Staff.TimeSignature
e1 \noBreak
Spacing recommendations
Vertical spacing is changed by modifying
- the top margin via
top-system-spacing
(default: 20 staff spaces),top-markup-spacing
(5), andmarkup-system-spacing
(15); - the distance between systems via
system-system-spacing
(20); and - distances within a system via
\smallGroupDistance
,\smallStaffDistance
, and user-defined similar commands.
Note that both the .basic-distance
and .minimum-distance
must be changed.
For full scores with eight staves (e.g., horns, Vienna church trio and four-part choir), the following settings might allow to print two systems per page:
\paper {
top-system-spacing.basic-distance = #10
top-system-spacing.minimum-distance = #10
top-markup-spacing.basic-distance = #0
top-markup-spacing.minimum-distance = #0
markup-system-spacing.basic-distance = #10
markup-system-spacing.minimum-distance = #10
system-system-spacing.basic-distance = #17
system-system-spacing.minimum-distance = #17
systems-per-page = #2
}
\layout {
\context {
\StaffGroup
\setGroupDistance #11 #11
}
\context {
\GrandStaff
\setGroupDistance #11 #11
}
\context {
\ChoirStaff
\setGroupDistance #12 #13
}
}
For full scores with seven staves (e.g., Vienna church trio and four-part choir), the following settings usually allow to print two systems per page:
\paper {
top-system-spacing.basic-distance = #10
top-system-spacing.minimum-distance = #10
top-markup-spacing.basic-distance = #0
top-markup-spacing.minimum-distance = #0
markup-system-spacing.basic-distance = #10
markup-system-spacing.minimum-distance = #10
system-system-spacing.basic-distance = #19.5
system-system-spacing.minimum-distance = #19.5
systems-per-page = #2
}
Alternatively, decrease system-system spacing to 20 and use \smallGroupDistance
; this allows to preserve the top margin.
For scores with six or less staves, change (a) the distance between systems and (b) the number of systems per page (written as “a/b” in the table below; brackets indicate default values):
\paper {
system-system-spacing.basic-distance = <a>
system-system-spacing.minimum-distance = <a>
systems-per-page = <b>
}
Staves | Full score | Vocal score |
---|---|---|
6 | [20]/2 | 25/2 |
5 | 30/2 | [17]/[3] |
4 | 22/3 | 25/[3] |
3 | 20/4 (or 30/3) | 22/4 |
2 | 21/5 (or 18/6 with \smallGroupDistance ) |
20/6 |
If a work contains chorals with two stanzas, define
twoStanzaDistance = \setGroupDistance #15 #20
twoStanzaDistanceCoro = \setGroupDistance #13 #13
and apply these to the choir staff in the full and vocal score, respectively. In the vocal score, also decrease system-system spacing to 15 or 14 if there are three systems on the page.
If a work contains chorals with three stanzas, define
threeStanzaDistance = \setGroupDistance #18 #22
threeStanzaDistanceCoro = \setGroupDistance #18 #18
and apply these to the choir staff in the full and vocal score, respectively. In the vocal score, only show two systems per page.
In accompagnatos, parts comprise up to 5 staves per page by default. The number of staves may be increased to six per page if system-system spacing is 16 and the choir staff uses \smallGroupDistance
.
Useful bash snippets
Extract individual images from a PDF. (The origin lies in the top left corner.)
mkdir cropped
pdfimages -j score.pdf img
mogrify +repage -crop 1000x1300+120+120 -path cropped *.jpg
Crop a PDF (here: remove 1 pt from the left, 80 pt from the top, 2 pt from the right, and 60 pt from the bottom).
pdfcrop --margins '-1 -80 -2 -60' input.pdf output.pdf
Name files with sequential numbers.
ls -v | cat -n | while read n f; do mv -n "$f" "$n.jpg"; done
Resize all images in the current folder to the same width.
mogrify -resize $(identify -ping -format "%w\n" *.jpg | sort -n | tail -1)x -path resized *.jpg
Merge two images with sequential names horizontally, for all files in the current folder.
montage -tile 2x1 -geometry +0+0 *.jpg img.jpg
Reset image orientation (portrait).
mogrify -orient TopLeft -rotate 90 +repage *.jpg
Reset image orientation (landscape).
mogrify -orient TopLeft -rotate 180 +repage *.jpg
Extract even pages of a PDF.
gs -sDEVICE=pdfwrite -sPageList=even -sOutputFile=even.pdf -dBATCH -dNOPAUSE file-pdf
How to create a new EES Tools release
- update the changelog, clean up the TODO
- update version information manually in the following files:
.github/workflows/engrave-and-release.yaml
documents/editorial-guidelines.md
tex/latex/ees.cls
- build the Docker image via
docker build --build-arg user_id=$(id -u) --build-arg group_id=$(id -g) --tag ees-tools .