22.3 Using music functions

Where tweaks need to be reused with different music expressions, it is often convenient to make the tweak part of a music function. In this section, we discuss only substitution functions, where the object is to substitute a variable into a piece of LilyPond input code. Other more complex functions are described in Music functions.


22.3.1 Substitution function syntax

Making a function that substitutes a variable into LilyPond code is easy. The general form of these functions is

function =
#(define-music-function
     (arg1 arg2 …)
     (type1? type2? …)
   #{
     …music…
   #})

where

argNThe nth argument.
typeN?A Scheme type predicate for which argN must return #t.
…music…Normal LilyPond input, using ‘$’ (in places where only LilyPond constructs are allowed) or ‘#’ (to use it as a Scheme value or music function argument or music inside of music lists) to reference arguments (e.g., ‘#arg1’).

The list of type predicates is required. Some of the most common type predicates used in music functions are:

  • boolean?
  • cheap-list? (use instead of ‘list?’ for faster processing)
  • ly:duration?
  • ly:music?
  • ly:pitch?
  • markup?
  • number?
  • pair?
  • string?
  • symbol?

For a list of available type predicates, see Predefined type predicates. User-defined type predicates are also allowed.

See also

Notation Reference: Predefined type predicates.

Extending LilyPond: Music functions.

Installed Files: lily/music-scheme.cc, scm/c++.scm, scm/lily.scm.


22.3.2 Substitution function examples

This section introduces some substitution function examples. These are not intended to be exhaustive, but rather to demonstrate some of the possibilities of simple substitution functions.

In the first example, a function is defined that simplifies setting the padding of a TextScript grob:

padText =
#(define-music-function
     (padding)
     (number?)
   #{
     \once \override TextScript.padding = #padding
   #})

\relative {
  c''4^"piu mosso" b a b
  \padText 1.8
  c4^"piu mosso" b a b
  \padText 2.6
  c4^"piu mosso" b a b
}
[image of music]

In addition to numbers, we can use music expressions such as notes for arguments to music functions:

custosNote =
#(define-music-function
     (note)
     (ly:music?)
   #{
     \tweak NoteHead.stencil #ly:text-interface::print
     \tweak NoteHead.text
        \markup \musicglyph "custodes.mensural.u0"
     \tweak Stem.stencil ##f
     #note
   #})

\relative { c'4 d e f \custosNote g }
[image of music]

Both of those functions are simple single expressions where only the last element of a function call or override is missing. For those particular function definitions, there is a simpler alternative syntax, namely just writing out the constant part of the expression and replacing its final missing element with \etc:

padText =
  \once \override TextScript.padding = \etc

\relative {
  c''4^"piu mosso" b a b
  \padText 1.8
  c4^"piu mosso" b a b
  \padText 2.6
  c4^"piu mosso" b a b
}
[image of music]
custosNote =
  \tweak NoteHead.stencil #ly:text-interface::print
  \tweak NoteHead.text
     \markup \musicglyph "custodes.mensural.u0"
  \tweak Stem.stencil ##f
  \etc

\relative { c'4 d e f \custosNote g }
[image of music]

Substitution functions with multiple arguments can be defined:

tempoPadded =
#(define-music-function
     (padding tempotext)
     (number? markup?)
   #{
     \once \override Score.MetronomeMark.padding = #padding
     \tempo \markup { \bold #tempotext }
   #})

\relative {
  \tempo \markup { "Low tempo" }
  c''4 d e f g1
  \tempoPadded 4.0 "High tempo"
  g4 f e d c1
}
[image of music]

22.3.3 How to prevent sharing of music expressions

When writing music functions, it is important to abide by a rule: the same music expressions must not be shared in several places. As an example, here is a problematic function:

simpleAccompaniment =
#(define-music-function
   (bass-1 bass-2 chord) (ly:music? ly:music? ly:music?)
   #{
     #bass-1 #chord #bass-2 #chord
   #})

{
  \clef bass
  \simpleAccompaniment c g, <e g>
  \simpleAccompaniment d g, <f g>
}
[image of music]

The problem with this function becomes clear if the result is transposed:

simpleAccompaniment =
#(define-music-function
   (bass-1 bass-2 chord) (ly:music? ly:music? ly:music?)
   #{
     #bass-1 #chord #bass-2 #chord
   #})

\transpose c e {
  \clef bass
  \simpleAccompaniment c g, <e g>
  \simpleAccompaniment d g, <f g>
}
[image of music]

While the bass notes are correct, the chord is not transposed properly – in fact, it is being transposed twice. The reason for this is that the music expression chord was used twice in the result of the function, without copying it. Functions such as \transpose modify the music object directly (in the case of \transpose, the pitches are changed). If the same music object is reused, modifications made in one place where it is used affect both places, since they hold the same object. In this case, \transpose encounters the object twice and transposes it twice.

One way to fix this function is to use ‘$’ instead of ‘#’ to reference the variables, which makes a copy. The difference between ‘#’ and ‘$’ is detailed in LilyPond Scheme syntax.

simpleAccompaniment =
#(define-music-function
   (bass-1 bass-2 chord) (ly:music? ly:music? ly:music?)
   #{
     $bass-1 $chord $bass-2 $chord
   #})

\transpose c e {
  \clef bass
  \simpleAccompaniment c g, <e g>
  \simpleAccompaniment d g, <f g>
}
[image of music]

22.3.4 Substitution functions and relative octave entry

When \relative is applied to a music expression, it traverses it searching for pitched notes, and modifies the pitches in the order they are found, changing the octave of each pitch according to its octave marks (‘'’ and ‘,’) and the previous pitch. When writing substitution functions, this may lead to the situation that a music expression is ‘relativized’ in a surprising way because the output of the function uses the parameters several times and/or in a different order. Consider this function and how its output reacts to \relative:

simpleAccompaniment =
#(define-music-function
   (bass-1 bass-2 chord) (ly:music? ly:music? ly:music?)
   #{
     $bass-1 $chord $bass-2 $chord
   #})

\relative {
  \clef bass
  \simpleAccompaniment c g <e' g>
  \simpleAccompaniment d g, <f' g>
}
[image of music]

In this example, the output is the same as that of

\relative {
  \clef bass
  c <e' g> g <e' g>
  d <f' g>  g, <f' g>
}
[image of music]

However, this is not the desired output when using the \simpleAccompaniment function. The pitch g, is relative to the first note of the chord that precedes it, <e' g>, although it comes after c in the input. Clearly, the pitches should be made relative according to the order in which they are input when using the function, not in the order they appear in the output of the function. This can be achieved using the make-relative Scheme macro. Its arguments are: a list of variables, a reference expression, and a main music expression. The reference expression is intended to be a mock-up of how the variables were entered in the input. Most of the time, it can be a simple expression made with #{ … #} containing the variables in order. Beware not to make copies in the reference expression (in particular, use ‘#’, not ‘$’). The example above can be fixed using make-relative in this way:

simpleAccompaniment =
#(define-music-function
   (bass-1 bass-2 chord) (ly:music? ly:music? ly:music?)
   (make-relative
    (bass-1 bass-2 chord)
    #{ #bass-1 #bass-2 #chord #}
    #{ $bass-1 $chord $bass-2 $chord #}))

\relative {
  \clef bass
  \simpleAccompaniment c g <e' g>
  \simpleAccompaniment d g, <f' g>
}
[image of music]

LilyPond Notation Reference v2.25.27 (development-branch).