2.6.1 Context evaluation

Contexts can be modified during interpretation with Scheme code. In a LilyPond code block, the syntax for this is:

\applyContext function

In Scheme code, the syntax is:

(make-apply-context function)

function should be a Scheme function that takes a single argument: the context in which the \applyContext command is being called. The function can access as well as override/set grob properties and context properties. Any actions taken by the function that depend on the state of the context are limited to the state of the context when the function is called. Also, changes effected by a call to \applyContext remain in effect until they are directly modified again, or reverted, even if the initial conditions that they depended on have changed.

The following Scheme functions are useful when using \applyContext:

ly:context-property

look up a context property value

ly:context-set-property!

set a context property

ly:context-grob-definition
ly:assoc-get

look up a grob property value

ly:context-pushpop-property

do a \temporary \override or a \revert on a grob property

The following example looks up the current fontSize value, and then doubles it:

doubleFontSize =
\applyContext
  #(lambda (context)
     (let ((fontSize (ly:context-property context 'fontSize)))
       (ly:context-set-property! context 'fontSize (+ fontSize 6))))

{
  \set fontSize = -3
  b'4
  \doubleFontSize
  b'
}

[image of music]

The following example looks up the current colors of the NoteHead, Stem, and Beam grobs, and then changes each to a less saturated shade.

desaturate =
\applyContext
  #(lambda (context)
     (define (desaturate-grob grob)
       (let* ((grob-def (ly:context-grob-definition context grob))
              (color (ly:assoc-get 'color grob-def black))
              (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
         (ly:context-pushpop-property context grob 'color new-color)))
     (for-each desaturate-grob '(NoteHead Stem Beam)))

\relative {
  \time 3/4
  g'8[ g] \desaturate g[ g] \desaturate g[ g]
  \override NoteHead.color = #darkred
  \override Stem.color = #darkred
  \override Beam.color = #darkred
  g[ g] \desaturate g[ g] \desaturate g[ g]
}

[image of music]

This also could be implemented as a music function, in order to restrict the modifications to a single music block. Notice how ly:context-pushpop-property is used both as a \temporary \override and as a \revert:

desaturate =
#(define-music-function
   (music) (ly:music?)
   #{
     \applyContext
     #(lambda (context)
        (define (desaturate-grob grob)
          (let* ((grob-def (ly:context-grob-definition context grob))
                 (color (ly:assoc-get 'color grob-def black))
                 (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
            (ly:context-pushpop-property context grob 'color new-color)))
        (for-each desaturate-grob '(NoteHead Stem Beam)))
     #music
     \applyContext
     #(lambda (context)
        (define (revert-color grob)
          (ly:context-pushpop-property context grob 'color))
        (for-each revert-color '(NoteHead Stem Beam)))
   #})

\relative {
  \override NoteHead.color = #darkblue
  \override Stem.color = #darkblue
  \override Beam.color = #darkblue
  g'8 a b c
  \desaturate { d c b a }
  g b d b g2
}

[image of music]


Extending LilyPond v2.25.22 (development-branch).