3

How can this be done in lilypond? TTSTTTS

I've tried using analysis brackets, however they don't work when a bracket ends and start from the same note - it just joins the brackets into a large bracket.

slur_s = ^\markup {\halign #-7 "S"}

    \score {
      \relative {
      \omit Score.TimeSignature
      \omit Score.BarLine
      \override HorizontalBracketText.text = "T"
      c1'\startGroup 
      d\stopGroup
      e 
      (\slur_s f)
      g\startGroup
      a \stopGroup\startGroup 
      b\stopGroup 
      (\slur_s c)
      \end_it
      }
      \layout {
        \context {
          \Voice
          \consists "Horizontal_bracket_engraver"
        }
      }
    }

Not yet there... enter image description here

1 Answer 1

3

My slightly improved and cleaned version:

%% Creates a (optionally rounded) bracket with a gap in the middle.
%% lx = left x position, ly = left y position, rx, ry similar for right
%% p = the length of the protruders
%% th = line thickness
%% gap-w = horizontal width of the gap
%% rounded? = whether to create a round bracket
#(define (make-bracket-gap lx ly rx ry p th gap-w rounded?)
   (if rounded?
       (let* ((width (- rx lx))
              (height (- ry ly))
              (sep-width (/ (- width gap-w) 2))
              (sep-height (* height (/ sep-width width)))
              (line-left (make-path-stencil
                          `(moveto ,lx ,(+ ly p)
                            curveto 
                             ,(+ lx (* sep-width 1/5)) ,(+ ly (* sep-height 1/5))
                             ,(+ lx (* sep-width 2/3)) ,(+ ly (* sep-height 2/3))
                             ,(+ lx sep-width) ,(+ ly sep-height)) th 1 1 #f))
              (line-right (make-path-stencil
                          `(moveto ,rx ,(+ ry p)
                            curveto 
                             ,(- rx (* sep-width 1/5)) ,(- ry (* sep-height 1/5))
                             ,(- rx (* sep-width 2/3)) ,(- ry (* sep-height 2/3))
                             ,(- rx sep-width) ,(- ry sep-height)) th 1 1 #f)))
         (ly:stencil-add line-left line-right))
       (let* ((width (- rx lx))
              (height (- ry ly))
              (sep-width (/ (- width gap-w) 2))
              (sep-height (* height (/ sep-width width)))
              (line-left (make-line-stencil th lx ly
                                            (+ lx sep-width) (+ ly sep-height)))
              (line-right (make-line-stencil th rx ry
                                             (- rx sep-width) (- ry sep-height)))
              (prot-left (make-line-stencil th lx (+ ly p) lx ly))
              (prot-right (make-line-stencil th rx (+ ry p) rx ry)))
         (ly:stencil-add line-left line-right prot-left prot-right))))

%% create bracket with text in gap. Take text, direction, rounded from grob
#(define (center-text-gap L R p th grob)
   (let* ((text (ly:grob-property grob 'text ""))
          (direction (ly:grob-property grob 'direction UP))
          (lx (+ (car L) (* 2 th)))
          (rx (- (car R) (* 2 th)))
          (p (* p direction))
          (dir (if (< p 0) -1 1))
          (ly (- (cdr L) p))
          (ry (- (cdr R) p))
          (outside-staff-p (ly:grob-property grob 'outside-staff-priority))
          (is-outside-staff (number? outside-staff-p))
          (ly (if is-outside-staff (* dir (min (* dir ly) -4)) ly))
          (ry (if is-outside-staff (* dir (min (* dir ry) -4)) ry))
          (det (ly:grob-property grob 'details))
          (rounded? (assoc-get 'rounded det #t))
          (texs (grob-interpret-markup grob text))
          (ctex (ly:stencil-aligned-to (ly:stencil-aligned-to texs X CENTER) Y CENTER))
          (texex (ly:stencil-extent ctex X))
          (tex-width (interval-length texex))
          (brack (make-bracket-gap lx ly rx ry p th (+ tex-width 0.7) rounded?))
          (tex-tr (ly:stencil-translate ctex (cons (/ (+ lx rx) 2)
                                                   (/ (+ ly ry) 2)))))
     (ly:stencil-add brack tex-tr)))

%% print a slur as bracket with text
#(define (slur->bracket grob)
   (let* ((cpts (ly:grob-property grob 'control-points))
          (L (first cpts))
          (R (last cpts)))
     (center-text-gap L R -1 0.15 grob)))

#(define* ((from-details symb #:optional default) grob)
   (let ((det (ly:grob-property grob 'details)))
     (ly:assoc-get symb det default)))

hbracketStart = \tweak direction #(from-details 'direction DOWN)
                \tweak stencil #slur->bracket
                \tweak outside-staff-priority #(from-details 'outside-staff-priority)
                \="hb"(
hbracketStop = \="hb")

hb =
#(define-music-function (text rounded music) (markup? boolean? ly:music?)
   #{
     {
       <>\tweak text #text \tweak details.rounded #rounded \hbracketStart
       #music
       <>\hbracketStop
     }
   #})

hbT = \hb "T" ##f \etc
hbS = \hb "S" ##t \etc

%%% EXAMPLE

\paper {
  indent = 0
}

\score {
  \relative {
  \omit Score.TimeSignature
  \omit Score.BarLine
  \hbT c'1 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  \hbT c 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  c
  \break
  
  \override Slur.details.direction = #UP
  \hbT c,,1 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  \hbT c 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  c
  \break

  \override Slur.details.outside-staff-priority = #500
  \hbT c,,1 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  \hbT c 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  c
  \break
  
  \revert Slur.details.direction
  \hbT c,,1 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  \hbT c 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  c\break
  
  \override Slur.font-series = #'bold
  \override Slur.font-shape = #'italic
  \hbT c,,1 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  \hbT c 
  \hbT d
  \hbS e
  \hbT f
  \hbT g
  \hbT a
  \hbS b
  c
  }
  \layout {
  }
}

This results in something like this:

enter image description here

3
  • 😃 !! That's very close - the only difference is the last slur which is arguably improved in your version.
    – Vlad
    Apr 30, 2022 at 0:28
  • @Vlad I revised and cleaned up the code a bit.
    – Lazy
    Apr 30, 2022 at 1:25
  • \@Lazy - this does everything I need really well.
    – Vlad
    May 1, 2022 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.