Music objects¶
Defining music functions¶
Music functions are the fundamental tool to create and modify music objects. The template to write one is:
myFunction =
#(define-music-function (arg1 arg2 ...) (type1? type2? ...)
body...)
This defines a function that can be called as \myFunction
.
The arguments arg1
, arg2
, …, must satisfy the type predicates
type1?
, type2?
, …, respectively. The body is a sequence of
Scheme expressions; as with any Scheme function, they are evaluated in
order and the value of the last expression is returned. Here is a
simple music function:
withNoteNames =
#(define-music-function (music) (ly:music?)
#{
<<
\new Voice $music
\new NoteNames $music
>>
#})
\withNoteNames \relative c' { c d e c e f g e }
Argument type checking¶
All arguments to a music function are checked for being of the expected
type. Because Scheme has only latent typing, where you cannot retrieve
the type of an object but only know whether an object belongs to a
certain type, type1?
, type2?
, etc. are type predicates.
nrepeats =
#(define-music-function (n music) (index? ly:music?)
#{ \repeat unfold #n { #music } #})
\nrepeats 4 aes
The above (somewhat boring) music function is a shortcut for
\repeat unfold ...
. It takes two arguments, called n and music.
They must be an integer and a music object, respectively. When the
function is called, the checks (index? n)
and (ly:music? music)
are performed.
This becomes particularly interesting when you consider this example:
keyDuring =
#(define-music-function (duration pitch) (ly:duration? ly:pitch?)
#{ \key #pitch \major s $duration \key c \major #})
\new Staff <<
{ c'4 c' c' c' }
{ s2 \keyDuring 4 aes s4 }
>>
We define another function called \keyDuring
, with two arguments.
It returns a music expression with spacer rests so that the specified
key (in major scale) lasts a certain duration, after which C major
is used again.
We made the calls:
\nrepeats 4 aes
\keyDuring 4 aes
Even though the arguments are exactly the same, they were obtained
with different types. The \nrepeats
function got an integer
and a music expression. The \keyDuring
function, in constrast,
got a duration and a pitch! This is thanks to the capabilities
of the parser, coupled to the type predicates. When 4
and aes
are encountered, different rules are tried, until one is found that
allows for a successful match against the type predicate.
Predefined type predicates are listed in the Notation Reference.
A table containing the most common ones is found in the Music function primer
.
Optional arguments¶
An argument is made optional by enclosing its predicate in parentheses. When the function is called without this argument, the value of the parameter is the boolean false. Here is a function that prints a tempo mark with one of the most frequently used values, entered under the form of a term (“Allegro”, “Andante”, etc.). The printed text is optional; the term itself is used when it is not provided.
tempi =
#'(("Largo" . 50)
("Lento" . 60)
("Adagio" . 70)
("Andante" . 90)
("Moderato" . 100)
("Allegro" . 140)
("Presto" . 170))
commonTempo =
#(define-music-function (printed-term duration term) ((markup?) ly:duration? string?)
(ly:message "~s ~s ~s"
printed-term
duration
(assoc-ref tempi term))
#{
\tempo $(or printed-term term) $duration = $(assoc-ref tempi term)
#})
\relative c' {
\commonTempo 4 Adagio
c8 d e4 d c
\commonTempo "Allegro con brio" 4 Allegro
g'4 e'2 g,4
}
The order of arguments to this function is not arbitrary. Some
different signatures would lead to errors, because music function
arguments are parsed greedily: if the arguments had been specified
in the order (duration printed-term term) (ly:duration? (markup?) string?)
for instance, the word “Adagio”, which passes the predicate markup?
,
would have been interpreted as the printed-term
argument in the call
\commonTempo 4 Adagio
, leaving the following music to be parsed as
a string.
A default value for an optional parameter may be provided in the parentheses.
backgroundCluster =
#(define-music-function (transparency music) ((number? 0.5) ly:music?)
#{
<<
$music
{
\once \override ClusterSpanner.color = #(rgb-color 0 0 0 transparency)
\makeClusters $music
}
>>
#})
\new Voice \backgroundCluster { <g' b''>2 <c''' g'''> }
(This example requires a version in the development 2.23 series. This might be a good occasion for you to try these releases as we need more testers.)
Other function types¶
A music function must return music. There exist other kinds of functions, each constrained to a specific return type. The advantage is that they can be used in more syntactic contexts, because the parser knows the type of the return value in advance. (TODO: check this)
Function type |
Definition macro |
Return type |
---|---|---|
Music function |
|
Music ( |
Event function |
|
Post-event ( |
Scheme function |
|
Any ( |
Void function |
|
Unspecified ( |
TODO: example.
The \etc
shortcut¶
There is special syntax, \etc
, to write music functions
conveniently. The principle is that \etc
can be used
as a placeholder for one or several arguments at the very
end of a sequence of function applications. This is best
understood through example:
makeClarinetPart = \compressMMRests \transpose bes c \etc
\makeClarinetPart { bes }
\etc
also works in a some other contexts:
padText = \once \override TextScript.padding = \etc
{ \padText #1.8 c'4^"piu mosso" }
\markup reddish = \markup \with-color "LightCoral" \etc
\markup \reddish "Hello"
Music expressions¶
The examples above were just using the parameters passed to our
music functions to build expressions in LilyPond syntax. This
is useful for syntactic sugar. However, music functions are
much more powerful – just think of \transpose
. They allow
for analyzing and building music objects.
To understand how some particular music expression is constructed,
the most straightforward way is the \displayMusic
music function,
or, equivalently, the display-scheme-music
Scheme function.
It attempts to print out a loadable Scheme code that would
create an equal music expression. Let us take a first example:
\displayMusic { c' d'-> }
On the console, this prints:
(make-music
'SequentialMusic
'elements
(list (make-music
'NoteEvent
'pitch
(ly:make-pitch 0 0)
'duration
(ly:make-duration 2))
(make-music
'NoteEvent
'articulations
(list (make-music
'ArticulationEvent
'midi-extra-velocity
20
'articulation-type
"accent"))
'duration
(ly:make-duration 2)
'pitch
(ly:make-pitch 0 1))))
Every music object has a type. Possible types are listed
in the Internals Reference at Music expressions. Moreover,
it holds properties that describe it. NoteEvent
objects,
for instance, have a pitch and a duration. Optionally, they
may contain articulations.
In addition, a music type belongs to certain music classes. These are used to group together certain kinds of events that require similar processing. They are listed at Music classes in the Internals.
Music types are written in CamelCase, music classes in lowercase-with-dashes.
- (music-is-of-type? music class)
Test if music belongs to the music class class.
Music properties¶
Once you have a music object at hand, you can do cool processing
by changing its properties. The relevant functions are
ly:music-property
and ly:music-set-property!
. Refer
to Probs
for details.
Certain music expressions contain other music expressions. This is generally in one of these properties:
elements
, a list of music objects, forSequentialMusic
,SimultaneousMusic
and various other kinds of music containers.articulations
, also a list, for all post-events attached to a note or rest.element
, a single music object, for use by music objects that can only meaningfully contain one other music object. For example,RelativeOctaveMusic
has anelement
, the music that has been converted to relative octave.
The name
property of a music object holds its type (like
NoteEvent
) as a symbol. However, recognition based on event
classes should be preferred in most cases.
Constructing music from scratch¶
Music objects may also be built directly, allowing for algorithmic composition or simply adding articulations.
- (make-music name property1 value1 property2 value2 ...)
Make a music object.
name is the music type, given as symbol. The remaining arguments are paired: every property name (a symbol) is followed by the value of the property.
Properties may be given twice; later values override the former.
You may also pass a music object instead of one property-value pair. In this case, properties are taken from this object. Remaining property-values can override them. For example, here is how you might turn a
NoteEvent
into aClusterNoteEvent
:(make-music 'ClusterNoteEvent some-note-event)
Music transformation tools¶
Music objects are deeply nested structures. Often you cannot
know the nesting in advance. For example, note events may be
located at any depth in SequentialMusic
, RelativeOctaveMusic
,
SimultaneousMusic
, etc.
The tools described here allow for recursively processing music.
- (music-map function music)
Create a new music object by applying function deep-first. That is, function is first applied to the bottom music objects, those that do not contain any other music object. These are replaced in their containing music expressions, and the function is applied again, until the top expression is reached.
For the sake of efficiency,
music-map
acts destructively on its music input. This means that in some cases, Copying music is required.Here is an example making parts with all repeats changed to percent repeats. This is a matter of converting all types of repeats, characterized by the music class
repeated-music
, toPercentRepeatedMusic
.percentRepeats = #(define-music-function (music) (ly:music?) (music-map (lambda (m) (if (music-is-of-type? m 'repeated-music) (make-music 'PercentRepeatedMusic m) m)) music)) notes = \relative { \clef bass \repeat unfold 2 << { s4 <g a c ees> s <gis b d f> s <a c ees g> s <gis b d f> } \\ { c, s g s c s g s } >> } { \notes } \percentRepeats \notes
- (music-filter predicate music)
Remove all music expressions in music that do not satisfy predicate.
- (for-some-music function music)
This is similar
music-map
, but the function is applied on the top music expression, then on its children, etc. Also,for-some-music
does not return the result. The function should mutate its argument. This is useful for setting music properties, whilemusic-map
is of more use when constructing new music objects.The music is recursed into only if function returns false. Thus, function can be thought of as “Should we stop?”, except that it is also meant to change the music.
A simple example is a function to add a certain articulation on all notes. This takes advantage of the stop condition to avoid adding articulations on all notes in a chord, which would lead to duplicate marks.
addStaccato = #(define-music-function (music) (ly:music?) (for-some-music (lambda (m) (if (or (music-is-of-type? m 'note-event) (music-is-of-type? m 'event-chord)) (begin (ly:music-set-property! m 'articulations (cons (make-music 'ArticulationEvent 'articulation-type "staccato") (ly:music-property m 'articulations))) #t) #f)) music) music) \addStaccato { c' d' <e' f'> }
- (map-some-music function music)
Like
for-some-music
, butelements
andarticulations
resulting from applying function that are not music are ignored, allowing for filtering.
Copying music¶
Because music-map
and friends can mutate their input,
it is sometimes needed to copy music objects.
- (ly:music-deep-copy music)
Recursively make a deep copy of music.
Pitches¶
Pitches are the bread-and-butter of note entry. The are found in every
NoteEvent
and KeyChangeEvent
. It is not uncommon for music
functions to act on them.
The most common method for inputting a pitch is writing using the chosen
input note names given by \language
. This also works with variables
and inside #{ ... #}
.
myPitch = ces
\transpose c \myPitch { c' e' g' c'' }
$(let ((my-other-pitch #{ bes, #}))
#{ \transpose c #my-other-pitch { c' e' g' c'' } #})
You can also construct pitches programmatically from Scheme using
ly:make-pitch
shown below.
LilyPond defines pitches as having three components: the octave, the note name, and the alteration. Importantly, a pitch is not a mere frequency: C sharp and D flat are different pitches.
A number of functions are exported to deal with pitches. All are documented in the Internals page listing Scheme functions. Here are the most important ones.
- (ly:make-pitch octave note alteration)
Construct a pitch object.
octave is an integer. Zero is the octave containing middle C.
note is an index on the scale, from 0 (C) to 6 (B).
alteration (optional argument) is a fraction: 0 means natural, 1/2, sharp, and -1/2, flat. Arbitrary values may be passed, allowing for double or microtonal alterations.
The global constants
SHARP
andFLAT
are conveniently defined as 1/2 and -1/2, respectively. There are alsoSEMI-SHARP
,SEMI-FLAT
and others, all at the start of the source filescm/lily-library.scm
.
- (ly:pitch-octave pitch)
- (ly:pitch-notename pitch)
- (ly:pitch-alteration pitch)
Functions to extract the components from pitch.
- (ly:pitch-steps pitch)
The number of steps from middle C to pitch. This takes into account the octave and note name, but not the alteration. For instance,
dis''
is 8 steps above middle C whileees''
is 9 steps above.
- (ly:pitch-tones pitch)
The number of tones from middle C as a rational number. This adds up contributions from octave, note and alteration.
- (ly:pitch-transpose pitch delta)
Transpose pitch by delta. The alterations are added. The notes and octaves are added, then normalized so that the note falls between 0 and 6.
- (ly:pitch-diff pitch root)
Pitch delta such that root transposed by delta equals pitch.
Durations and moments¶
Every note has a duration, which defines how it is printed. It is
typically entered after the pitch of the note. Thus, 8
or
4..*3/8
are durations. More precisely, a duration is defined by a
main length indicator, a dot count and an optional multiplier
factor. The main length corresponds to 8
or 4
in the previous
examples. It is represented by a negative base-2 log: 0 means whole
note, 1 is a half note, 2 is a quarter note, etc. The multiplier, a
rational number, is the *3/8
part of 4..*3/8
. When it is given,
it scales the length of the duration without changing the way in which
the note is printed. The length matters for synchronization between
different voices, for horizontal spacing, and for MIDI
rendition. Observe how lengths are modified in this snippet:
<< { c''4 4*1/2 4*1/2 4..*4/7 4 } \\ { c'4 4 4 4 } >>
A moment is a length or point in time, as notes have in MIDI. It can be roughly thought of as a fraction. However, grace notes pose a particular challenge in that they would have zero length if moments were only expressed on this scale. Therefore, a moment actually consists of two rationals, a main part and a grace part.
You can obtain the length of a duration as a moment. The reverse
conversion is not possible, simply because several different durations
can have the same length. A moment lasting 7/8 of an eighth note is the
length of the duration 16..
, but also the length of 8*7/8
. In
the output, the first is reflected by a dotted sixteenth note while the
second is an eigth note (perhaps part of a Baroque score where complex
tuplets are written without too much care for exact values).
Durations are commonly entered using the familiar LilyPond syntax. This
also works. This also works inside #{ ... #}
; try:
myDuration = ##{ 4.. #}
{ c' $myDuration }
Durations can also be constructed via a Scheme interface. On the other hand, moments are not typically entered by users and only constructed via Scheme.
- (ly:make-duration length dot-count factor)
Make a duration object.
- (ly:duration-length duration)
The length of duration as a moment.
- (ly:duration-log duration)
- (ly:duration-dot-count duration)
- (ly:duration-scale duration)
Extract either component of a duration.
- (ly:make-moment main-part grace-part)
Make a moment object, with main-part and grace-part given as rational numbers.
- (ly:moment-main moment)
- (ly:moment-grace moment)
Extract the main or grace part of moment.
- (ly:moment-add moment1 moment2)
- (ly:moment-sub moment1 moment2)
- (ly:moment-mul moment1 moment2)
- (ly:moment-div moment1 moment2)
- (ly:moment-mod moment1 moment2)
Arithmetic on moments. All operations are performed on the main parts and the grace parts independently: for example, adding moments adds up both main parts and both grace parts.