lilypond-user
[Top][All Lists]
Advanced

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

Re: DurationLine avoiding RehearsalMarks


From: Jean Abou Samra
Subject: Re: DurationLine avoiding RehearsalMarks
Date: Fri, 15 Apr 2022 10:39:54 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0



Le 15/04/2022 à 10:13, Thomas Morley a écrit :
Am Mi., 13. Apr. 2022 um 17:57 Uhr schrieb Jean Abou Samra <jean@abou-samra.fr>:
Le 13/04/2022 à 17:03, Thomas Morley a écrit :
Am Di., 12. Apr. 2022 um 11:54 Uhr schrieb Jean Abou Samra <jean@abou-samra.fr>:
Le 12/04/2022 à 11:16, Thomas Morley a écrit :
[...]
In many details DurationLine was tailored after Glissando and
Glissando _is_ effected by the breathing sign.
[...]

Well, if the goal is to have DurationLine similar to Glissando,
how about reusing line-spanner-interface code? I haven't reviewed
the code very thoroughly, but I assumed there was a difference
warranting a different code path. If you put
ly:line-spanner::calc-{left,right}-bound-info in
DurationLine.{left,righ}-bound-info, that gives you X values for free
in the bound info properties. Would that solve the problem?
If I go for ly:line-spanner::calc-{left,right}-bound-info then

\layout {
     \context {
       \Voice
       \consists Duration_line_engraver
     }
}

{ b1\- }

errors with
      "programming error: extremal broken spanner's bound has no parent
vertical axis group"
More complex examples may add:
      "programming error: bound item has no parent vertical axis group"
Both coming from `ly:line-spanner::calc-right-bound-info' based upon
`Line_spanner::calc_bound_info' in /lily/line-spanner.cc

As a mere user I'd say: "Nice error-message, but why should I care...?"

As a programmer, I doubt the example above can be made working with
ly:line-spanner::calc-right-bound-info.
At least, I don't know how.

Oh, I'm sorry, I missed that detail of my own code. A DurationLine will
always be horizontal, thus you can and should use
ly:horizontal-line-spanner::calc-{left,right}-bound-info (with 'horizontal'
in the name).  The difference is that the functions without 'horizontal'
try to compute vertical positions. This falls apart here, for understandable
reasons: the right bound of your DurationLine is a NonMusicalPaperColumn,
so how would one tell where the line should end vertically?
Using ly:horizontal-line-spanner::calc-{left,right}-bound-info makes
for huge simplifications.
Alas, it introduces a minor and reintroduces a major problem.

The minor: the X-value depends now on attach-dir. For the start of the
DurationLine this is ofcourse RIGHT. But if starting at a skip,
left-bound is PaperColumn there we would want LEFT. Can be fixed by
accurate conditions. Count it as done.

The major: `ly:horizontal-line-spanner::calc-right-bound-info' and
`unbroken-or-last-broken-spanner?' (and friends) don't agree what's
the last part of the spanner.
To illustrate:

\version "2.23.7"

\layout {
   \context {
     \Voice
     \consists "Duration_line_engraver"
   }
}

{
  \override DurationLine.bound-details.right.foo =
    "I am last part (bound-details)"
  \override DurationLine.bound-details.right-broken.foo =
    "I am not last part (bound-details)"

  \override DurationLine.after-line-breaking =
  #(lambda (grob)
    (pretty-print
      (if (unbroken-or-last-broken-spanner? grob)
          "I am last part (unbroken-or-last-broken-spanner?)"
          "I am not last part (unbroken-or-last-broken-spanner?)"))
    (pretty-print
      (assoc-get 'foo (ly:horizontal-line-spanner::calc-right-bound-info 
grob))))

  b1\-
}

=>
"I am last part (unbroken-or-last-broken-spanner?)"
"I am not last part (bound-details)"

The problem occurs if we have a broken DurationLine with end-items
running to the very end of the score.
To fix it one would again need something like:

{
   \override DurationLine.bound-details =
   #(grob-transformer 'bound-details
     (lambda (grob orig)
      (if (end-broken-spanner? grob)
          (cons
            (cons 'right-broken
              (cons '(end-style . arrow) (assoc-get 'right-broken orig)))
            orig)
          orig)))
   b1\-
   \break
   s1
   \break
   s1
   \bar "|."
}

Or like \lastEndStyle which you cleared with

commit 46671d13257f6ad68d1778a1cc850e59116c856a
Author: Jean Abou Samra <jean@abou-samra.fr>
Date:   Wed Dec 29 00:16:46 2021 +0100

     Fix broken spanner functions

     They were broken (pun intended) on spanners of which one bound is a
     non-musical column at a system boundary.  For example,
     unbroken-or-last-broken-spanner? would return false on a spanner
     running to the NonMusicalPaperColumn at the end of a score.  This
     fixes the known issue with duration lines running to the end of the
     piece, and will be needed in a refactoring of spanner-placement
     treatment for balloon-interface.

     While at it, document these functions.

This is unfortunate. Any chance making
`ly:horizontal-line-spanner::calc-right-bound-info' and friends
identify the last spanner-part correctly, i.e. like
`unbroken-or-last-broken-spanner?'
?



Ah, this one is showing up again. Yes, this is not too hard to
fix (but please allow me some time).



At any rate, many thanks for the hint to
ly:_horizontal:-line-spanner::calc-left/right-bound-info.
I may remember wrong, but I think I tried
ly:line-spanner::calc-left/right-bound-info already while implementing
DurationLine and excluded it for the known reasons, but was not aware
that ly:_horizontal:-line-spanner::calc-left/right-bound-info exists
at all.
Well, my bad, though, any chance to document
   ly:horizontal-line-spanner::calc-left-bound-info-and-text
   ly:horizontal-line-spanner::calc-left/right-bound-info
   ly:line-spanner::calc-left/right-bound-info
in IR 4. Scheme functions?



It's not your bad: they didn't exist when you implemented DurationLine :-)
They later came into existence with

commit 817d656cecb0f899ff6e7d1b5e900a5517c31f69
Author: Jean Abou Samra <jean@abou-samra.fr>
Date:   Sun Nov 21 16:36:16 2021 +0100

    Make user tweaks to line spanner Y positions relative to relevant group

    For example, the value of an adjustment to
    VoiceFollower.bound-details.left.Y is relative to the start note's
    staff, not to the end note's one.

    This requires some work.  The basic problem is that for this to work
    we need the line spanner to compute its own coordinate relative to the
    chosen refpoint.  This does not work for line spanners that are
    side-positioned, such as DynamicTextSpanner: their coordinate depends
    on their very stencil (side positioning is skyline-based). That's
    logical: if the Y positions are already fixed relative to the staff,
    it does not make sense to side-position afterwards.  In general, there
    are a number of differences in handling between horizontal line
    spanners, such as TextSpanner, DynamicTextSpanner, etc., and
    non-horizontal line spanners, like Glissando, FingerGlideSpanner and
    VoiceFollower.  This takes the stance of being explicit and introduces
    a horizontal-line-spanner-interface, which is a subset of the
    line-spanner-interface.  Horizontal line spanners now use callbacks
    from this interface to compute bound info.  These callbacks don't try
    to calculate Y values.  This also obviates having to set Y to 0 in
    bound-details for horizontal line spanners.  The repartition of the
    feature set is that while horizontal line spanners can be
    side-positioned, the non-horizontal ones can have their Y positions
    computed automatically.

    In the future, the horizontal-line-spanner-interface may prove useful
    for smarter cross-staff handling.

    Closes #5229


Re documenting: will take a look when I have more time.



If there is a reason to keep DurationLine calculations separate, you
could go for using ly:generic-bound-extent. The line-spanner-interface
uses its C++ equivalent internally.
Didn't try this so far.
But the description:
"Function: ly:generic-bound-extent grob common
Determine the extent of grob relative to common along the x axis,
finding its extent as a bound when it a has bound-alignment-interfaces
property list set and otherwise the full extent."
is kryptic to say the least.

It's in a sense similar to the (so far nonexistent/C++-only) function
ly:axis-group-interface::staff-extent we discussed, except that it
doesn't filter grobs for having a certain grob in their ancestry,
but for having one of certain interfaces, captured in the
bound-alignment-interfaces property. E.g., for NonMusicalPaperColumn,
this property defaults to '(break-alignment-interface), which means
that

    (ly:generic-bound-extent [NonMusicalPaperColumn] [System])

gives you the extent of the elements of the NonMusicalPaperColumn
that are part of a BreakAlignment, i.e. grobs with the
break-aligned-interface,
like BarLine, KeySignature, etc., but not those that are outside
of a BreakAlignment, i.e. those having the break-*aligned*-interface
(tricky difference, I know, I always need to look up which is 'alignable'
and which is 'aligned' ...), namely MetronomeMark, RehearsalMark, ...
There are some slightly fussy details, but that's the idea. Is that
clear?
Your description is far better than the doc-string. There I stumbled
across "extent as a bound", with not the slightest idea what this
could mean, especially compared with "the full extent".

In general I find typical usage examples like
    (ly:generic-bound-extent [NonMusicalPaperColumn] [System])
very helpful.


Will take a look at improving the docstring, too.

Cheers,
Jean



reply via email to

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