Hi Francesco,

I’m trying to use HorizontalBracket to annotate the intervals between notes of
a scale.

The example (perhaps not minimal, but almost working) attached shows something
very close to what I want to achieve.

However there are a few things that need to be fixed, or improved:
1) the brackets remain outside the staff no matter how I fiddle with staff-
padding and padding properties, while I would like them to stay closer to the
notes;
2) I cannot find an (obvious and) automatic way to have the ends of a bracket
to align with the center of the note heads. I found a manual workaround by
setting the shorten-pair property, which is a far from being an optimal
solution;
3) is there a way to create a V-shaped bracket? The hack I came up with is
ugly;
4) to have brackets both above and below the notes I have used two voices, one
with the notes hidden. Is there a faster/less verbose way to obtain the same
result?

Besides these, it would be nice (but not essential) to have these bracket to
also follow the slope of an interval.

LilyPond's horizontal brackets are not very flexible, as far as I know. But it occurred to me that for everything you listed, the necessary mechanisms are in LilyPond as part of the mechanism typesetting slurs: 1), 2) is automatic for slurs, 3) is a matter of distorting a slur to a simple three-point line, and 4) is possible by virtue of the \=... construct.

Hence, how about:

\version "2.21.0"

% Some routines for calculating with 2D vectors (given as scheme pairs)
#(define (vector-sum v w)
   (cons (+ (car v) (car w))
         (+ (cdr v) (cdr w))))

#(define (vector-factor factor v)
   (cons (* (car v) factor)
         (* (cdr v) factor)))

#(define (scalar-product v w)
   (+ (* (car v) (car w))
      (* (cdr v) (cdr w))))

#(define (midpoint p1 p2)
   (vector-factor 1/2 (vector-sum p1 p2)))

#(define (normal p q)
   ; yields a normal vector to the line from p to q.
   ; the length of the normal vector will be proportional to
   ; the distance [pq].
   (cons (- (cdr p) (cdr q))
         (- (car q) (car p))))

#(define (side v normal start)
   ; A line through "start" with fixed normal vector "normal" cuts the plane
   ; into two half-planes. This function returns
   ; 0 if v lies on the line itself,
   ; +1 if v lies in the half plane that the normal vector points to,
   ; -1 otherwise.
   (let ((dist (- (scalar-product normal v)
                  (scalar-product normal start))))
     (cond ((> dist 0) 1) ; is there no "sgn" function in guile?!
           ((< dist 0) -1)
           (else 0))
     ))

% Shortcuts for using pairs inside a \markup \path ...
#(define (moveto p) (list 'moveto (car p) (cdr p)))
#(define (lineto p) (list 'lineto (car p) (cdr p)))

VShapeSlur =
\tweak stencil
#(lambda (grob)
   (let* ((control-points (ly:grob-property grob 'control-points))
          (start (first control-points))
          (1st-directional-point (second control-points))
          (2nd-directional-point (third control-points))
          (stop (fourth control-points)))
     (grob-interpret-markup grob #{
       \markup {
         \path #0.1 #(list (moveto start)
                           (lineto (midpoint 1st-directional-point 2nd-directional-point))
                           (lineto stop))
       } #})))
\etc

bracketSlur =
\tweak stencil
#(lambda (grob)
   (let* ((control-points (ly:grob-property grob 'control-points))
          (start (first control-points))
          (1st-directional-point (second control-points))
          (stop (fourth control-points))
          (normal (normal start stop))
          (scaled-normal
           (vector-factor
            (* 0.075 (side 1st-directional-point normal start))
            normal)))
     (grob-interpret-markup grob #{
       \markup {
         \path #0.1
         #(list (moveto start)
                (lineto (vector-sum start scaled-normal))
                (lineto (vector-sum stop scaled-normal))
                (lineto stop))
       } #})))
\etc

\relative c' {
  c1 \bracketSlur ( d) e \bracketSlur( f g a g f')
  c,1 \VShapeSlur ( d) e \VShapeSlur( f g a g f')
}

\relative c' {
  c4 \VShapeSlur \=0_( \VShapeSlur \=1^( d e \bracketSlur \=2_( f\=1) e d\=2) c b\=0)
}

Best
Lukas

Reply via email to