Jump to content

Using arbitrary markup as lyric hyphen

From LilyPond wiki
Revision as of 10:20, 6 December 2025 by Lemzwerg (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Lyric hyphens have several user-modifiable properties such as length and thickness; this doesn’t allow, however, for further tweaking, for example, rendering hyphens as rounded boxes to better match the font possibly used for LyricText, or even printing hyphens as actual glyphs rather than drawing basic boxes.

This snippet rewrites the LyricHyphen stencil procedure to use a proper glyph – or indeed any arbitrary markup.

\version "2.24"

% Originally contributed by Aaron Hill:
% https://lists.gnu.org/archive/html/lilypond-user/2019-03/msg00257.html

#(define (lyric-hyphen-text-stencil grob)
   "Draws a LyricHyphen using an arbitrary text markup."
   
   (define (span-point side common dir)
     (let ((iv
            (ly:generic-bound-extent side common)))
       (if (interval-empty? iv)
           (ly:grob-relative-coordinate side common X)
           (interval-bound iv dir))))
           
   (define (get-text-stencil grob)
     (let* ((orig (ly:grob-original grob))
            (into (ly:spanner-broken-into orig)))
       (grob-interpret-markup
        (ly:spanner-bound (if (null? into) orig (first into)) LEFT)
        (ly:grob-property grob 'text "-"))))
        
   (let* ((left-bound (ly:spanner-bound grob LEFT))
          (right-bound (ly:spanner-bound grob RIGHT))
          (common (ly:grob-common-refpoint left-bound right-bound X))
          (left-span (span-point left-bound common RIGHT))
          (right-span (span-point right-bound common LEFT))
          (span-length (- right-span left-span))
          (padding (ly:grob-property grob 'padding 0.1))
          (minimum-length (ly:grob-property grob 'minimum-length 0.3))
          (usable-length 
            (- span-length
               (if (zero? (ly:item-break-dir left-bound)) padding 0)
               (if (zero? (ly:item-break-dir right-bound)) padding 0))))
     (if (< usable-length minimum-length) '()
         (let* ((dash-sten (get-text-stencil grob))
                (dash-extent (ly:stencil-extent dash-sten X))
                (dash-length (min (interval-length dash-extent) usable-length))
                (scaled-sten (ly:stencil-scale
                              (ly:stencil-translate-axis
                               dash-sten (- (interval-start dash-extent)) X)
                              (/ dash-length (interval-length dash-extent)) 1))
                (dash-period 
                  (max (ly:grob-property grob 'dash-period 1.0) dash-length))
                (dash-count 
                  (1+ (floor (/ (- usable-length dash-length) dash-period))))
                (extra 
                  (- usable-length 
                     dash-length 
                     (* (- dash-count 1) dash-period)))
                (offset 
                  (+ (- left-span (ly:grob-relative-coordinate grob common X))
                     (if (zero? (ly:item-break-dir left-bound)) padding 0)
                     (/ extra 2))))
           (apply 
             ly:stencil-add 
             (map 
               (lambda (n)
                 (ly:stencil-translate-axis 
                   scaled-sten 
                   (+ offset (* n dash-period)) 
                   X))
               (iota dash-count)))))))

\paper {
  indent = 0
  ragged-right = ##f
  tagline = ##f
}

\relative c' {
  \omit Staff.TimeSignature
  \repeat unfold 3 {
    b4. b8 b4 b4 |
    b8 b8 b8 b8 b2 \break
  }
  r2 b'2~ \break b1~ \break b2 b2
}
\addlyrics {
  \override Score.RehearsalMark.self-alignment-X = #LEFT
  
  \mark "LyricHyphen.text is \"-\""
  \override LyricHyphen.dash-period = #5
  \override LyricHyphen.padding = #0.2
  \override LyricHyphen.stencil = #lyric-hyphen-text-stencil
  
  Lo -- rem ip -- sum do -- lor sit a -- met.
  
  \mark "LyricHyphen.text is \"–\""
  \override LyricHyphen.text = #"–" %#"\xe2\x80\x93" % U+2013
  \override LyricText.font-series = #'bold
  Lo -- rem ip -- sum do -- lor sit a -- met.
  
  \mark \markup { "LyricHyphen.text is " \circle \with-color #red "♥" }
  \override LyricHyphen.text = \markup \circle \with-color #red "♥"
  \override LyricText.font-size = #3
  Lo -- rem ip -- sum do -- lor sit a -- met.

  \mark \markup { "LyricHyphen.text is blue" \with-color #blue #"≋" }
  \override LyricHyphen.text = 
    \markup \scale #'(3 . 1) \with-color #blue #"≋"
  \override LyricText.font-size = #6
  Break -- ing
}