| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The Guile interpreter is part of LilyPond, which means that Scheme can be included in LilyPond input files. There are several methods for including Scheme in LilyPond.
The simplest way is to use a hash mark # before a Scheme
expression.
Now LilyPond’s input is structured into tokens and expressions, much like human language is structured into words and sentences. LilyPond has a lexer that recognizes tokens (literal numbers, strings, Scheme elements, pitches and so on), and a parser that understands the syntax, (contributor)LilyPond grammar section ‘LilyPond grammar’ in Contributor’s Guide. Once it knows that a particular syntax rule applies, it executes actions associated with it.
The hash mark # method of embedding Scheme is a natural fit
for this system. Once the lexer sees a hash mark, it calls the Scheme
reader to read one full Scheme expression (this can be an identifier, an
expression enclosed in parentheses, or several other things). After the
Scheme expression is read, it is stored away as the value for an
SCM_TOKEN in the grammar. Once the parser knows how to make use
of this token, it calls Guile for evaluating the Scheme expression.
Since the parser usually requires a bit of lookahead from the lexer to
make its parsing decisions, this separation of reading and evaluation
between lexer and parser is exactly what is needed to keep the execution
of LilyPond and Scheme expressions in sync. For this reason, you should
use the hash mark # for calling Scheme whenever this is
feasible.
Another way to call the Scheme interpreter from LilyPond is the use of
dollar $ instead of a hash mark for introducing Scheme
expressions. In this case, LilyPond evaluates the code right after the
lexer has read it. It checks the resulting type of the Scheme
expression and then picks a token type (one of several
xxx_IDENTIFIER in the syntax) for it. It creates a copy
of the value and uses that for the value of the token. If the value of
the expression is void (Guile’s value of *unspecified*), nothing
at all is passed to the parser.
This is, in fact, exactly the same mechanism that LilyPond employs when
you call any variable or music function by name, as \name, with
the only difference that the name is determined by the LilyPond lexer
without consulting the Scheme reader, and thus only variable names
consistent with the current LilyPond mode are accepted.
The immediate action of $ can lead to surprises, see
Importing Scheme in LilyPond. Using # where the
parser supports it is usually preferable. Inside of music expressions,
expressions created using # are interpreted as
music. However, they are not copied before use. If they are
part of some structure that might still get used, you may need to use
ly:music-deep-copy explicitly.
There are also ‘list splicing’ operators $@ and #@
that insert all elements of a list in the surrounding context.
Now let’s take a look at some actual Scheme code. Scheme procedures can be defined in LilyPond input files:
#(define (average a b c) (/ (+ a b c) 3)) |
Note that LilyPond comments (% and %{ %}) cannot
be used within Scheme code, even in a LilyPond input file, because
the Guile interpreter, not the LilyPond lexer, is reading
the Scheme expression. Comments in Guile Scheme are entered
as follows:
; this is a single-line comment #! This a (non-nestable) Guile-style block comment But these are rarely used by Schemers and never in LilyPond source code !# |
For the rest of this section, we will assume that the data is entered
in a music file, so we add a # at the beginning of each Scheme
expression.
All of the top-level Scheme expressions in a LilyPond input file can
be combined into a single Scheme expression by use of the
begin statement:
#(begin (define foo 0) (define bar 1)) |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
LilyPond variables are stored internally in the form of Scheme variables. Thus,
twelve = 12 |
is equivalent to
#(define twelve 12) |
This means that LilyPond variables are available for use in Scheme expressions. For example, we could use
twentyFour = #(* 2 twelve) |
which would result in the number 24 being stored in the LilyPond
(and Scheme) variable twentyFour.
Scheme allows modifying complex expressions in-place and LilyPond makes
use of this ‘in-place modification’ when using music functions. But
when music expressions are stored in variables rather than entered
directly the usual expectation, when passing them to music functions,
would be that the original value is unmodified. So when referencing a
music variable with leading backslash (such as \twentyFour),
LilyPond creates a copy of that variable’s music value for use in the
surrounding music expression rather than using the variable’s value
directly.
Therefore, Scheme music expressions written with the # syntax
should be used for material that is created ‘from scratch’ (or that is
explicitly copied) rather than being used, instead, to directly
reference material.
Extending: LilyPond Scheme syntax.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The input format supports the notion of variables: in the following
example, a music expression is assigned to a variable with the name
traLaLa.
traLaLa = { c'4 d'4 }
|
There is also a form of scoping: in the following example, the
\layout block also contains a traLaLa variable, which is
independent of the outer \traLaLa.
traLaLa = { c'4 d'4 }
\layout { traLaLa = 1.0 }
|
In effect, each input file is a scope, and all \header,
\midi, and \layout blocks are scopes nested inside that
toplevel scope.
Both variables and scoping are implemented in the GUILE module system. An anonymous Scheme module is attached to each scope. An assignment of the form:
traLaLa = { c'4 d'4 }
|
is internally converted to a Scheme definition:
(define traLaLa Scheme value of ` |
This means that LilyPond variables and Scheme variables may be freely
mixed. In the following example, a music fragment is stored in the
variable traLaLa, and duplicated using Scheme. The result is
imported in a \score block by means of a second variable
twice:
traLaLa = { c'4 d'4 }
#(define newLa (map ly:music-deep-copy
(list traLaLa traLaLa)))
#(define twice
(make-sequential-music newLa))
\twice
|
This is actually a rather interesting example. The assignment will only
take place after the parser has ascertained that nothing akin to
\addlyrics follows, so it needs to check what comes next. It
reads # and the following Scheme expression without
evaluating it, so it can go ahead with the assignment, and
afterwards execute the Scheme code without problem.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The above example shows how to ‘export’ music expressions from the
input to the Scheme interpreter. The opposite is also possible. By
placing it after $, a Scheme
value is interpreted as if it were entered in LilyPond syntax.
Instead of defining \twice, the example above could also have
been written as
… $(make-sequential-music newLa) |
You can use $ with a Scheme expression anywhere you could use
\name after having assigned the Scheme expression to a
variable name. This replacement happens in the ‘lexer’, so
LilyPond is not even aware of the difference.
One drawback, however, is that of timing. If we had been using $
instead of # for defining newLa in the above example, the
following Scheme definition would have failed because traLaLa
would not yet have been defined. For an explanation of this timing
problem, LilyPond Scheme syntax.
A further convenience can be the ‘list splicing’ operators $@
and #@ for inserting the elements of a list in the surrounding
context. Using those, the last part of the example could have been
written as
…
{ #@newLa }
|
Here, every element of the list stored in newLa is taken in
sequence and inserted into the list, as if we had written
{ #(first newLa) #(second newLa) }
|
Now in all of these forms, the Scheme code is evaluated while the input is still being consumed, either in the lexer or in the parser. If you need it to be executed at a later point of time, check out Void scheme functions, or store it in a procedure:
#(define (nopc)
(ly:set-option 'point-and-click #f))
…
#(nopc)
{ c'4 }
|
Mixing Scheme and LilyPond variables is not possible with the ‘--safe’ option.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Object properties are stored in LilyPond in the form of alist-chains, which are lists of alists. Properties are set by adding values at the beginning of the property list. Properties are read by retrieving values from the alists.
Setting a new value for a property requires assigning a value to the alist with both a key and a value. The LilyPond syntax for doing this is:
\override Stem.thickness = #2.6 |
This instruction adjusts the appearance of stems. An alist entry
'(thickness . 2.6) is added to the property list of the
Stem
object. thickness is measured relative to the thickness of
staff lines, so these stem lines will be 2.6 times the
width of staff lines. This makes stems almost twice as thick as their
normal size. To distinguish between variables defined in input files (like
twentyFour in the example above) and variables of internal
objects, we will call the latter ‘properties’ and the former
‘variables.’ So, the stem object has a thickness property,
while twentyFour is a variable.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| Offsets | ||
| Fractions | ||
| Extents | ||
| Property alists | ||
| Alist chains |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Two-dimensional offsets (X and Y coordinates) are stored as pairs.
The car of the offset is the X coordinate, and the cdr is
the Y coordinate.
\override TextScript.extra-offset = #'(1 . 2) |
This assigns the pair (1 . 2) to the extra-offset
property of the
TextScript object. These numbers are measured in staff-spaces, so
this command moves the object 1 staff space to the right, and 2 spaces up.
Procedures for working with offsets are found in ‘scm/lily-library.scm’.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Fractions as used by LilyPond are again stored as pairs, this
time of unsigned integers. While Scheme can represent rational numbers
as a native type, musically ‘2/4’ and ‘1/2’ are not the same,
and we need to be able to distinguish between them. Similarly there are
no negative ‘fractions’ in LilyPond’s mind. So 2/4 in LilyPond
means (2 . 4) in Scheme, and #2/4 in LilyPond means
1/2 in Scheme.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Pairs are also used to store intervals, which represent a range of numbers
from the minimum (the car) to the maximum (the cdr).
Intervals are used to store the X- and Y- extents of printable objects.
For X extents, the car is the left hand X coordinate, and the
cdr is the right hand X coordinate. For Y extents, the car
is the bottom coordinate, and the cdr is the top coordinate.
Procedures for working with intervals are found in ‘scm/lily-library.scm’. These procedures should be used when possible to ensure consistency of code.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A property alist is a LilyPond data structure that is an alist whose keys are properties and whose values are Scheme expressions that give the desired value for the property.
LilyPond properties are Scheme symbols, such as 'thickness.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
An alist chain is a list containing property alists.
The set of all properties that will apply to a grob is typically stored as an alist chain. In order to find the value for a particular property that a grob should have, each alist in the chain is searched in order, looking for an entry containing the property key. The first alist entry found is returned, and the value is the property value.
The Scheme procedure chain-assoc-get is normally used to get
grob property values.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Internally, music is represented as a Scheme list. The list contains various elements that affect the printed output. Parsing is the process of converting music from the LilyPond input representation to the internal Scheme representation.
When a music expression is parsed, it is converted into a set of Scheme music objects. The defining property of a music object is that it takes up time. The time it takes up is called its duration. Durations are expressed as a rational number that measures the length of the music object in whole notes.
A music object has three kinds of types:
\simultaneous leads to
a
(internals)SimultaneousMusic section ‘SimultaneousMusic’ in Internals Reference. A list of all expressions
available is in the Internals Reference manual, under
(internals)Music expressions section ‘Music expressions’ in Internals Reference.
event, but it is also a
note-event, a rhythmic-event, and a
melodic-event. All classes of music are listed in the
Internals Reference, under
(internals)Music classes section ‘Music classes’ in Internals Reference.
Music.
The actual information of a music expression is stored in properties.
For example, a
(internals)NoteEvent section ‘NoteEvent’ in Internals Reference has pitch and
duration properties that store the pitch and duration of that
note. A list of all properties available can be found in the
Internals Reference, under
(internals)Music properties section ‘Music properties’ in Internals Reference.
A compound music expression is a music object that contains other
music objects in its properties. A list of objects can be stored in
the elements property of a music object, or a single ‘child’
music object in the element property. For example,
(internals)SequentialMusic section ‘SequentialMusic’ in Internals Reference has its children in elements,
and
(internals)GraceMusic section ‘GraceMusic’ in Internals Reference has its single argument in
element. The body of a repeat is stored in the element
property of
(internals)RepeatedMusic section ‘RepeatedMusic’ in Internals Reference, and the alternatives in
elements.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] |
This document was generated by gub on July 13, 2020 using texi2html 1.82.
Andere talen: deutsch, español, français.
Gebruik van automatische taalkeuze.