lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Questions about HorizontalBracket


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.

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

[Prev in Thread] Current Thread [Next in Thread]