lilypond-user
[Top][All Lists]

 From: Lukas-Fabian Moser Subject: Re: Questions about HorizontalBracket Date: Sun, 13 Sep 2020 19:22:13 +0200 User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.10.0

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.

\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