Node: Typography and program architecture, Next: Music representation, Previous: Engraving in LilyPond, Up: Introduction
Producing good engraving requires skill and knowledge. As the previous examples show, there is a lot of subtlety involved in music engraving, and unfortunately, only a small fraction of these details are documented. Master engravers must learn all these details from experience or from other engravers, which is why it takes so long to become a master. As an engraver gets older and wiser, he will be able to produce better and more complex pieces. A similar situation is present when putting typographical knowledge into a computer program. It is not possible to come up with a definitive solution for a problem at the first try. Instead, we start out with simple solution that might cover 75% of the cases, and gradually refine that solution over the course of months or years, so 90 or 95 % of the cases are handled.
This has an important implication for the design of the program: at any time, almost every piece of formatting code must be considered as temporary. When the need arises, it is to be replaced a solution that will cover even more cases. A "plug-in" architecture is a clean way to accomplish this. This is an architecture where new pieces of code can be inserted in the program dynamically. In such a program, a new solution can be developed along-side the existing code. For testing, it is plugged in, but for production use, the old solution is used. The new module can be perfected separately until it is better than the existing solution, at which point it replaces the old one.
Until that time, users must have a way to deal with imperfections: these 25%, 10% or 5% of the cases that are not handled automatically. In these cases, a user must be able to override formatting decisions. To accomplish this we store decisions in generic variables, and let the user manipulate thosed. For example, consider the following fragment of notation:
The position of the forte symbol is slightly awkward, because it is next to the low note, whereas dynamics should be below notes in general. This may be remedied by inserting extra space between the high note and the `f', as shown in this example:
This was achieved with the following input statement:
\once \property Voice. DynamicLineSpanner \override #'padding = #4.0It increases the amount of space (
padding
) between the note and
the dynamic symbol to 4.0 (which is measured in staff space, so 4.0
equals the height of a staff). The keyword \once
indicates that
this is a tweak: it is only done one time.
Both design aspects, a plug-in architecture, and formatting variables, are built on top of GUILE, an interpreter for the programming language Scheme, which is a member of the LISP family. Variables are stored as Scheme objects, and attached to graphical objects such as note heads and stems. The variables are a means to adjust formatting details in individual cases, but they are used in a more general manner.
Consider the case of a publisher that is not satisfied with the in the
default layout, and wants heavier stems. Normally, they are 1.3
times the thickness of staff lines, but suppose that their editions
require them to be twice the thickness of the staff lines. The same
mechanism can be used to adjust a setting globally. By issuing the
following command, the entire piece is now formatted with thicker stems:
\property Score.Stem \override #'thickness = #2.0
In effect, by setting these variables, users can define their own layout styles.
"Plug-ins" are also implemented using Scheme. A formatting
"plug-in" takes the form of a function written in Scheme (or a C++
function made available as a Scheme function), and it is also stored
in a variable. For example, the placement of the forte symbol in the
example above is calculated by the function
Side_position_interface::aligned_side
. If we want to replace
this function by a more advanced one, we could issue
\property Voice.DynamicLineSpanner \override #'Y-offset-callbacks = #`(,gee-whiz-gadget)
Now, the formatting process will trigger a call to our new
gee-whiz-gadget
function when the position of the f symbol has
to be determined.
The full scope of this functionality certainly is intimidating, but there is no need to fear: normally, it is not necessary to define style-sheets or rewrite formatting functions. In fact, LilyPond gets a lot of formatting right automatically, so adjusting individual layout situations is not needed often at all.
This page is for LilyPond-2.0.1 (stable-branch).