lilypond-user
[Top][All Lists]
Advanced

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

Re: How to get bounding NoteColumns of the first of consecutive TextSpan


From: David Nalesnik
Subject: Re: How to get bounding NoteColumns of the first of consecutive TextSpanners
Date: Thu, 4 Mar 2021 07:08:39 -0600

On Wed, Mar 3, 2021 at 4:11 PM Jean Abou Samra <jean@abou-samra.fr> wrote:
>
>
> Le 03/03/2021 à 13:55, Thomas Morley a écrit :
> > Hi,
> >
> > please have a look at the following minimal, producing three staves,
> > the middle one with consecutive TextSpanners:
> >
> > mus = { bes \startTextSpan b\stopTextSpan \startTextSpan bis\stopTextSpan }
> > << { a4 a a } \mus { c' c' c' } >>
> >
> > Now I want to know the starting and ending NoteColumns of the _first_
> > TextSpanner.
> > Though, the first TextSpanner is left-bounded by NoteColumn and
> > right-bounded by PaperColumn.
> >
> > How to get the NoteColumn at first TextSpanner's end?
> >
> > Below some test-code.
> > Obviously I can filter PaperColumn's elements for NoteColumns, but
> > PaperColumn is a Score-grob, thus I get all three.
> > How to select?
> > (I may not know the position of the Staff with the TextSpanners)
> >
> > #(define tst
> >    (lambda (grob)
> >      (let* ((left-bound (ly:spanner-bound grob LEFT))
> >             (right-bound (ly:spanner-bound grob RIGHT))
> >             (ncs-from-grob
> >               (ly:grob-array->list (ly:grob-object grob 'note-columns)))
> >             (right-bound-elts
> >               (ly:grob-array->list
> >                 (ly:grob-object right-bound 'elements)))
> >             (ncs-from-right-bound
> >               (filter
> >                 (lambda (elt) (grob::has-interface elt 
> > 'note-column-interface))
> >                 right-bound-elts))
> >                 )
> >      (pretty-print
> >        (list
> >          left-bound
> >          right-bound
> >          ncs-from-grob
> >          (equal? left-bound (car ncs-from-grob))
> >          ncs-from-right-bound
> >          )))))
> >
> > mus = {
> >    bes4-\tweak #'after-line-breaking #tst
> >     \startTextSpan
> >    b\stopTextSpan
> >     \startTextSpan
> >    bis\stopTextSpan
> > }
> >
> > <<
> >    { a4 a a }
> >    \mus
> >    { c' c' c' }
> > Thanks,
> >    Harm
>
>
> Hi,
>
> This looks tricky indeed.
>
> Maybe an engraver operating in Voice context? Here's my attempt:
>
> \version "2.23.1"
>
> #(set-object-property! 'bounding-note-columns 'backend-type? pair?)
>
> Set_bounding_note_columns_engraver =
> #(lambda (context)
>     (let ((spanner-starting #f)
>           (spanner-ending #f)
>           (note-column #f))
>       (make-engraver
>         (acknowledgers
>           ((line-spanner-interface engraver grob source-engraver)
>              (set! spanner-starting grob)
>              (ly:grob-set-property! grob
>                                     'bounding-note-columns
>                                     ; Huh, '(#f . #f) makes a unique object?
>                                      (cons #f #f)))
>           ((note-column-interface engraver grob source-engraver)
>              (set! note-column grob)))
>         (end-acknowledgers
>           ((line-spanner-interface engraver grob source-engraver)
>              (set! spanner-ending grob)))
>         ((stop-translation-timestep engraver)
>            (if spanner-starting
>                (set-car! (ly:grob-property spanner-starting
> 'bounding-note-columns)
>                         note-column))
>            (if spanner-ending
>                (set-cdr! (ly:grob-property spanner-ending
> 'bounding-note-columns)
>                          note-column))
>            (set! spanner-starting #f)
>            (set! spanner-ending #f)
>            (set! note-column #f)))))
>
>
> % For testing
> #(use-modules (srfi srfi-26))
> #(define (visualize-note-column-bounds grob)
>     (let* ((cols (ly:grob-property grob 'bounding-note-columns))
>            (left-col (car cols))
>            (right-col (cdr cols))
>            (left-note-heads (ly:grob-array->list (ly:grob-object
> left-col 'note-heads)))
>            (right-stem (ly:grob-object right-col 'stem)))
>       (for-each
>          (cute ly:grob-set-property! <> 'color red)
>          left-note-heads)
>       (ly:grob-set-property! right-stem 'color blue)))
>
> \layout {
>    \context {
>      \Voice
>      \consists \Set_bounding_note_columns_engraver
>      \override TextSpanner.after-line-breaking =
> #visualize-note-column-bounds
>    }
> }
>
> mus = {
>    bes4\startTextSpan
>    b\stopTextSpan
>     \startTextSpan
>    bis\stopTextSpan\startTextSpan
>    b\stopTextSpan
> }
>
> <<
>    { a4 a a }
>    \mus
>    { c' c' c' }
>  >>
>
>
> Like David's solution, this of course won't give you the note columns
> for each of the broken pieces. Well, I am in fact not sure that a notion
> of the bounding note columns for a broken text spanner can even be
> defined. Thoughts?

Right, the bounds of the broken pieces would be NonMusicalPaperColumn
grobs.  I've adapted Harm's code to deal with this.  I don't know how
you'd deal with this in an engraver--if using ly:item-break-dir would
be an option, for example.  (@Harm: I don't know of course what the
ultimate goal of your experiment is, so I hope I haven't taken this
too far, or removed code you still want in place!)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

#(define get-note-columns-from-bound
   (lambda (bound)
     (if (grob::has-interface bound 'note-column-interface)
         (ly:grob-array->list (ly:grob-object grob 'note-columns))
         (let ((elts (ly:grob-array->list
                      (ly:grob-object bound 'elements))))
           '()
           (filter
            (lambda (elt) (grob::has-interface elt 'note-column-interface))
            elts)))))

#(define tst
   (lambda (grob)
     (let* ((left-bound (ly:spanner-bound grob LEFT))
            (right-bound (ly:spanner-bound grob RIGHT))
            (ncs-from-right-bound (get-note-columns-from-bound right-bound)))
       (if (not (null? ncs-from-right-bound))
           (let* ((spanner-staff-symbol (ly:grob-object grob 'staff-symbol))
                  (same-staff-right-nc
                   (filter
                    (lambda (nc)
                      (eq? (ly:grob-object nc 'staff-symbol)
spanner-staff-symbol))
                    ncs-from-right-bound)))
             (map
              (lambda (nh) (ly:grob-set-property! nh 'color red))
              (ly:grob-array->list (ly:grob-object (car
same-staff-right-nc) 'note-heads))))))))

mus = {
  bes4-\tweak #'after-line-breaking #tst
   \startTextSpan
  b\stopTextSpan
   \startTextSpan
  bis\stopTextSpan
}

<<
  { a4 a a }
  \mus
  { c' c' c' }
>>

musB = {
  bes4-\tweak #'after-line-breaking #tst
  \startTextSpan
  bes bes bes
  \break
  bes <b c' d'>\stopTextSpan
  \startTextSpan
  b b b b bis\stopTextSpan
}

<<
  { a4 a a a a a a a a a a }
  \musB
  { c' c' c' c' c' c' c' c' c' c' c' }
>>



reply via email to

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