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

define-music-function

Music (ly:music?)

Event function

define-event-function

Post-event (ly:event?)

Scheme function

define-scheme-function

Any (scheme?)

Void function

define-void-function

Unspecified (*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, for SequentialMusic, 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 an element, 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 a ClusterNoteEvent:

   (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, to PercentRepeatedMusic.

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, while music-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, but elements and articulations 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 and FLAT are conveniently defined as 1/2 and -1/2, respectively. There are also SEMI-SHARP, SEMI-FLAT and others, all at the start of the source file scm/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 while ees'' 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.