Piano "Half Sustain Pedal" Indications

When playing the piano, there a quite a few songs that require you to only press the sustain pedal half way (or even a quarter of the way in some cases).
There is currently not a way to show these indications on the generated music in an intuitive way. This snippet provides functions that allow you to easily do this.
The implementation is quite complicated, but basically there are two music functions that get defined, sustainHalfOn and sustainHalfOff. You can use these just like you would normally use sustainOn and sustainOff. You can use any of the sustain pedal styles, and everything will work as expected. You do need to add an explicit call to sustainHalfOff when you want the half pedal to end. Calling sustainOn does not automatically turn off sustainHalfOn.

Under the covers, this works by representing sustain half on/half off as Una Corda pedal events. The logic temporarily changes the rendering of Una Corda pedals when you call sustainHalfOn, and changes it back when you call sustainHalfOff. We also temporarily change the value of Staff.unaCordaPedalStyle to match the value of Staff.sustainPedalStyle for the duration of the half sustain event so that the intended sustain pedal style will be used.

\version "2.24.0"

%% This snippet defines functions that enable "1/2" pedal indications
%% to be used.  Using this is quite easy, just add \sustainHalfOn
%% in place of \sustainOn and \sustainHalfOff in place of \sustainOff
%%
%% This implementation fully supports 'mixed, 'text, and 'bracket pedal modes
%%
%% The new functions will honor the value of Staff.sustainPedalStyle when
%% doing the rendering.
%%
%% The implementation of these functions is a bit complicated.  In order to
%% force a new pedal indication when changing from half pedal to full pedal
%% or vice versa in mixed or bracket mode, internally this implementation
%% represents the half pedal events as UnaCorda pedal events.  Basically,
%% when \sustainHalfOn is called, we temporarily change the rendering
%% of the UnaCorda pedal indications so they look like a half pedal.
%% When \sustainHalfOff is called, they are changed back.  A side effect of
%% this is that having the UnaCorda pedal and 1/2 pedal active at the
%% same time is not possible with this implementation.

%% Definitions of half-pedal functions.  Moving these to a Lilypond include file is recommended.

#(define (half-pedal-stencil grob)
  (grob-interpret-markup 
    grob 
    (markup #:raise 0.1 "½" #:hspace -0.5 #:musicglyph "pedal.Ped")))

#(define (add-sustain-on note-event)
  (set! (ly:music-property note-event 'articulations)
   (cons
    (make-music 'UnaCordaEvent 'span-direction -1)
    (ly:music-property note-event 'articulations)))
  note-event)

#(define (override-una-corda-strings)
  (context-spec-music
   (make-sequential-music
    (list
     (make-property-set 'pedalUnaCordaStrings (list "Ped." "*Ped." "*"))
     (make-apply-context
      (lambda (context)
       (ly:context-set-property! 
         context 
         'pedalUnaCordaStyle 
         (ly:context-property context 'pedalSustainStyle))))))
   'Staff))

#(define (revert-una-corda-strings)
  (context-spec-music
   (make-sequential-music
    (list
     (make-property-unset 'pedalUnaCordaStrings)
     (make-property-unset 'pedalUnaCordaStyle)))
   'Staff))

#(define (add-sustain-off note-event)
  (set! (ly:music-property note-event 'articulations)
   (cons
    (make-music 'UnaCordaEvent 'span-direction 1)
    (ly:music-property note-event 'articulations)))
  note-event)

#(define (use-half-pedal-stencil)
  (context-spec-music
   (make-grob-property-set
    'UnaCordaPedal
    'stencil
    half-pedal-stencil)
   'Staff))

#(define (revert-pedal-stencil)
  (context-spec-music
   (make-grob-property-revert
    'UnaCordaPedal
    'stencil)
   'Staff))

sustainHalfOn =
#(define-music-function
  (note)
  (ly:music?)

  (make-sequential-music
   (list
    (override-una-corda-strings)
    (use-half-pedal-stencil)
    (add-sustain-on note))))

sustainHalfOff =
#(define-music-function
  (note)
  (ly:music?)
  (make-sequential-music
   (list
    (revert-pedal-stencil)
    (add-sustain-off note)
    (revert-una-corda-strings))))

%% Half Pedal Example

\new Staff {

  \set Staff.pedalSustainStyle = #'mixed

  \sustainHalfOn
  b'16 c' d' e'
  \sustainHalfOff
  f'
  \sustainOn
  g' a' a' a' a' a' c'
  \sustainOff
  a' a'
  \sustainOn
  a'
  a'
  \sustainOff\sustainOn
 
  a' a' a' a'
  \sustainOff
  \set Staff.pedalSustainStyle = #'text
  a'
  \sustainHalfOn
  a' a' a' a'
  \sustainHalfOff
  a'
  \sustainOn
  a' a' a' a' a'
  \sustainOff
  a'
}