[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' }
>>