[ << Working with input files ] | [Top][Contents][Index] | [ Controlling output >> ] |
[ < Using global settings ] | [ Up: Working with input files ] | [ Substitution function syntax > ] |
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 | ||
22.3.2 Substitution function examples | ||
22.3.3 How to prevent sharing of music expressions | ||
22.3.4 Substitution functions and relative octave entry |
[ << Working with input files ] | [Top][Contents][Index] | [ Controlling output >> ] |
[ < Using music functions ] | [ Up: Using music functions ] | [ Substitution function examples > ] |
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
argN
The 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.
[ << Working with input files ] | [Top][Contents][Index] | [ Controlling output >> ] |
[ < Substitution function syntax ] | [ Up: Using music functions ] | [ How to prevent sharing of music expressions > ] |
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 }![]()
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 }![]()
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 }![]()
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 }![]()
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 }![]()
[ << Working with input files ] | [Top][Contents][Index] | [ Controlling output >> ] |
[ < Substitution function examples ] | [ Up: Using music functions ] | [ Substitution functions and relative octave entry > ] |
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> }![]()
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> }![]()
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> }![]()
[ << Working with input files ] | [Top][Contents][Index] | [ Controlling output >> ] |
[ < How to prevent sharing of music expressions ] | [ Up: Using music functions ] | [ Special characters > ] |
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> }![]()
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> }![]()
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> }![]()
[Top][Contents][Index] |