lilypond-user
[Top][All Lists]
Advanced

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

Re: TupletBrackets edge thickness


From: Karim Haddad
Subject: Re: TupletBrackets edge thickness
Date: Sat, 10 Aug 2024 19:10:55 +0200

Dear Lukas-Fabian,

Works like a charm. Thank you for this hack.
Thanx a lot all of you.

Best
K

On Sat, Aug 10, 2024 at 02:17:07PM +0200, Lukas-Fabian Moser wrote:
> Hi Kieren, hi Karim,
> 
> Am 09.08.24 um 16:40 schrieb Kieren MacMillan:
> > > Just trying to find out how to manage the thickness of the edges of 
> > > tupletbrackets and if this is possible (cf. screenshot). In the 
> > > documentation we can adjust the thickness of the whole bracket but not 
> > > just the edges. Any idea?
> > I would imagine that either TupletBracket.edge-text or 
> > TupletBracket.stencil could be tweaked… Unfortunately I’ve spent 15 minutes 
> > and can’t find the magic incantation — hopefully someone else can!
> 
> Well, trying to teach how to fish :-):
> 
> In the Internals Reference
> https://lilypond.org/doc/v2.23/Documentation/internals/tupletbracket we see
> that the TupletBracket stencil is ly:tuplet-bracket::print. Moving to the
> source, git grep "tuplet-bracket::print" on the command line yields:
> 
> Documentation/ly-examples/stockhausen-klavierstueckII.ly:
> (ly:tuplet-bracket::print grob)))
> lily/tuplet-bracket.cc:MAKE_SCHEME_CALLBACK (Tuplet_bracket, print,
> "ly:tuplet-bracket::print", 1);
> scm/define-grobs.scm:        (stencil . ,ly:tuplet-bracket::print)
> scm/define-grobs.scm:        (stencil . ,ly:tuplet-bracket::print)
> 
> The second line shows that the procedure is in the C++ part of LilyPond
> (alas...); the third and fourth lines show _two_ grobs using this procedure
> as stencil. (Reading in scm/define-grobs.scm reveals that the other one
> besides TupletBracket is LigatureBracket).
> 
> Now in lily/tuplet-bracket.cc we find:
> 
> MAKE_SCHEME_CALLBACK (Tuplet_bracket, print, "ly:tuplet-bracket::print", 1);
> SCM
> Tuplet_bracket::print (SCM smob)
> {
>   Spanner *me = LY_ASSERT_SMOB (Spanner, smob, 1);
>   Stencil mol;
> 
>   bool tuplet_slur = scm_is_true (get_property (me, "tuplet-slur"));
> 
>   bool bracket_visibility = bracket_basic_visibility (me);
>   SCM bracket_vis_prop = get_property (me, "bracket-visibility");
> 
>   /*
>     Don't print a tuplet bracket and number if
>     no X or Y positions were calculated.
>   */
>   SCM scm_x_span = get_property (me, "X-positions");
>   SCM scm_positions = get_property (me, "positions");
>   if (!scm_is_pair (scm_x_span) || !scm_is_pair (scm_positions))
>     {
>       me->suicide ();
>       return SCM_EOL;
>     }
> 
>   Interval x_span = from_scm (scm_x_span, Interval (0.0, 0.0));
>   Interval positions = from_scm (scm_positions, Interval (0.0, 0.0));
> 
>   Drul_array<Offset> points;
>   for (const auto d : {LEFT, RIGHT})
>     points[d] = Offset (x_span[d], positions[d]);
> 
>   Grob *number_grob = unsmob<Grob> (get_object (me, "tuplet-number"));
> 
>   /*
>     Don't print the bracket when it would be smaller than the number.
>     ...Unless the user has coded bracket-visibility = #t, that is.
>   */
> 
>   Real gap = 0.;
>   if (bracket_visibility && number_grob)
>     {
>       Interval ext = number_grob->extent (number_grob, X_AXIS);
>       if (!ext.is_empty ())
>         {
>           gap = ext.length () + 1.0;
> 
>           if (!from_scm<bool> (bracket_vis_prop) && gap > x_span.length ())
>             bracket_visibility = false;
>         }
>     }
> 
>   if (bracket_visibility)
>     {
>       Drul_array<Real> zero (0, 0);
> 
>       Drul_array<Real> shorten
>         = from_scm (get_property (me, "shorten-pair"), zero);
> 
>       Real ss = Staff_symbol_referencer::staff_space (me);
>       scale_drul (&shorten, ss);
> 
>       Stencil brack;
> 
>       if (tuplet_slur)
>         {
>           brack = make_tuplet_slur (me, points[LEFT], points[RIGHT],
> shorten);
>           mol.add_stencil (brack);
>         }
>       else
>         {
> *          Drul_array<Stencil> edge_stencils;
> *
>           Drul_array<Real> height
>             = from_scm (get_property (me, "edge-height"), zero);
>           Drul_array<Real> flare
>             = from_scm (get_property (me, "bracket-flare"), zero);
>           Direction dir = get_grob_direction (me);
> 
>           scale_drul (&height, -ss * dir);
>           scale_drul (&flare, ss);
> 
>           const auto connect_to_other = from_scm (
>             get_property (me, "connect-to-neighbor"), Drul_array<bool> ());
> 
> *          for (const auto d : {LEFT, RIGHT})
> *            {
> *              if (connect_to_other[d])
> *                {
> *                  height[d] = 0.0;
>                   flare[d] = 0.0;
>                   shorten[d] = 0.0;
> *
> *                  SCM edge_text = get_property (me, "edge-text");
> *
>                   if (scm_is_pair (edge_text))
>                     {
> *                      SCM text = index_get_cell (edge_text, d);
> *                      if (Text_interface::is_markup (text))
>                         {
> *                          auto &es = edge_stencils[d];
>                           es = Text_interface::grob_interpret_markup (me,
> text);
> *                          es.translate_axis (x_span[d] - x_span[LEFT],
> X_AXIS);
>                         }
>                     }
>                 }
>             }
> 
>           Stencil brack;
>           if (tuplet_slur)
>             brack = make_tuplet_slur (me, points[LEFT], points[RIGHT],
> shorten);
>           else
> *brack = Bracket::make_bracket (
>               me, Y_AXIS, points[RIGHT] - points[LEFT], height,
>               /*
>                                              0.1 = more space at right due
> to italics
>                                              TODO: use italic correction of
> font.
>                                            */
>               Interval (-0.5, 0.5) * gap + 0.1, flare, shorten);*
> 
>           for (const auto d : {LEFT, RIGHT})
>             {
>               if (!edge_stencils[d].is_empty ())
> *brack.add_stencil (edge_stencils[d])*;
>             }
> 
>           mol.add_stencil (brack);
>           mol.translate (points[LEFT]);
>         }
>     }
>   return mol.smobbed_copy ();
> }
> 
> I highlighted the relevant lines in bold face. These show that edge-text is
> only being used for TupletBrackets that connect to their neighbors (i.e.
> broken TupletBracket grobs), which can also be observed in the regression
> test input/regression/tuplet-broken.ly). I admit that this is not so clear
> from reading the description of edge-text in 
> https://lilypond.org/doc/v2.23/Documentation/internals/tuplet_002dbracket_002dinterface
> ...
> 
> So in any case: The bracket itself gets drawn by Bracket::make_bracket,
> which has the following signature (found in lily/bracket.cc):
> 
> Stencil
> Bracket::make_bracket (Grob *me, // for line properties.
>                        Axis protrusion_axis, Offset dz, Drul_array<Real>
> height,
>                        Interval gap, Drul_array<Real> flare,
>                        Drul_array<Real> shorten)
> 
> So there's no parameter for thickness only for the side lines, and indeed
> line properties are taken from the grob itself for all three lines.
> Conclusion: There's no easy way to influence the way the bracket is drawn.
> 
> So we have to do something else. One brute-force possibility would be to
> just crack the finished stencil open and change the line width of the edge
> lines. If we look at the stencil expression of a TupletBracket, using
> 
> \version "2.24.0"
> 
> {
>   \override TupletBracket.stencil =
>   #(grob-transformer 'stencil
>                      (lambda (grob stil)
>                      (pretty-print (ly:stencil-expr stil))
>                      stil))
> 
>   \tuplet 3/2 { c'4 d' c''' }
> }
> 
> we find:
> 
> (translate-stencil
>   (1.1742119999999971 . 3.954403577019947)
>   (combine-stencil
>     (draw-line
>       0.16
>       5.465341561078519
>       2.323245692493028
>       5.465341561078519
>       1.6232456924930279)
>     (draw-line
>       0.16
>       -0.1840604182213724
>       -0.07824169249302755
>       -0.1840604182213724
>       -0.7782416924930275)
>     (draw-line
>       0.16
>       5.465341561078519
>       2.323245692493028
>       3.632732022820297
>       1.544227186842694)
>     (draw-line
>       0.16
>       -0.1840604182213724
>       -0.07824169249302755
>       1.8326095382582217
>       0.7790185056503338)))
> 
> This looks as if the left and right line are the first two lines in the
> stencil (those have constant x coordinates). This aligns with the definition
> of make_bracket that adds the corner stencils first.
> 
> So we might do:
> 
> \version "2.24.0"
> 
> {
>   \override TupletBracket.stencil =
>   #(grob-transformer 'stencil
>                      (lambda (grob stil)
>                        (let*
>                         ((expr (ly:stencil-expr stil))
>                          (xext (ly:stencil-extent stil X))
>                          (yext (ly:stencil-extent stil Y))
>                          (lines (cdaddr expr))
>                          (line1 (first lines))
>                          (line2 (second lines)))
> 
>                         (list-set! line1 1 0.5)
>                         (list-set! line2 1 0.5)
> 
>                         (ly:make-stencil expr xext yext))))
> 
>   \tuplet 3/2 { c'4 d' c''' }
>   \tuplet 3/2 { c'4 d' e' }
> }
> 
> But note that this is a) an dirty hack since it assumes that the
> TupletBracket stencil always comes in the form we expect, b) not yet ideal
> since the rounded lines still have to be moved down. At least the second
> issue can be remedied:
> 
> \version "2.24.0"
> 
> {
>   \override TupletBracket.stencil =
>   #(grob-transformer 'stencil
>                      (lambda (grob stil)
>                        (let*
>                         ((expr (ly:stencil-expr stil))
>                          (xext (ly:stencil-extent stil X))
>                          (yext (ly:stencil-extent stil Y))
>                          (lines (cdaddr expr))
>                          (line1 (first lines))
>                          (thick (second line1))
>                          (new-thick 0.6)  ;; adjust at will
>                          (offset (/ (- new-thick thick) 2))
>                          (line2 (second lines)))
> 
>                         (list-set! line1 1 new-thick)
>                         (list-set! line2 1 new-thick)
> 
>                         (list-set! line1 3 (- (list-ref line1 3) offset))
>                         (list-set! line2 3 (- (list-ref line2 3) offset))
> 
>                         (ly:make-stencil expr xext yext))))
> 
>   \tuplet 3/2 { c'4 d' c''' }
>   \tuplet 3/2 { c'4 d' e' }
> }
> 
> Left to do: We probably also should modify the extents of the resulting
> stencil to avoid collisions...
> 
> Lukas

-- 
Karim Haddad

Music Representations Team, IRCAM
Research and development manager.
email   : karim.haddad@ircam.fr
webpage : http://karim.haddad.free.fr



reply via email to

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