Hi David, I don't understand the advantage of this coding compared with the one from your post before. Nevertheless I took the idea to separate a coding to find the wished bound-objects, see below.
Am Do., 4. März 2021 um 14:08 Uhr schrieb David Nalesnik <[email protected]>: > > 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!) The goal is to center a text between two notes. Though, I made the experience wanting to calculate said centering with different values depending on the combinations of the Stem directions. Going for TextSpanner seemed to be an easy method. Well, until I realised right-bound may be PaperColumn for consecutive TextSpanners. Other possibilities for bounds not being a NoteColumn are more or less trivial to filter or circumvent. Also, TextSpanner seemed to be a nice grob to set different behaviour for up/down-stemmed NoteColumns: simply adjust the relevant 'attach-dir I'd be open open for other suggestions, though :) For now I did: \version "2.22.0" #(define (get-bound-stem-dir spanner dir) "Get @code{Stem.direction} of the bounding @code{NoteColumn}. If @var{spanner} is bound to @code{NonMusicalPaperColumn} or @code{PaperColumn} try to find a a @code{Stem} grob in the same @code{Staff} at the same musical moment." (let* ((bound (ly:spanner-bound spanner dir))) (if (grob::has-interface bound 'note-column-interface) ;; If bound is a NoteColumn, then it will surely be in the same Staff ;; as the `spanner'. ;; If it contains NoteHeads get Stem.direction (let ((stem (ly:grob-object bound 'stem))) (and (ly:grob? stem) (ly:grob-array? (ly:grob-object bound 'note-heads)) (ly:grob-property stem 'direction))) ;; Select Stems by comparing the 'staff-symbol of `spanner' with ;; 'staff-symbol of Stems, found in (NonMusical)PaperColumn at same ;; musical moment (let* ((spanner-staff-symbol (ly:grob-object spanner 'staff-symbol)) (bound-elts (ly:grob-object bound 'elements)) (stems-from-bound (filter (lambda (elt) (grob::has-interface elt 'stem-interface)) (if (ly:grob-array? bound-elts) (ly:grob-array->list bound-elts) '()))) (stems (filter (lambda (stem) (equal? spanner-staff-symbol (ly:grob-object stem 'staff-symbol))) stems-from-bound))) ;; TODO In polyphonic situations there may be more than one Stem ;; How to select? (if (pair? stems) (ly:grob-property (car stems) 'direction) #f))))) #(define (text-stencil txt) "Hack @code{TextSpanner.stencil} to center a text between the bounds. If bounds are @code{NoteColumn} grobs, we take @code{Stem.direction} into account in order to get a nice output." (lambda (grob) (let* (;; For consecutive TextSpanner or TextSpanner started/ended at ;; spacers or at line break left/right bound may be PaperColumn or ;; NonMusicalPaperColumn. ;; Though, we are interested in the Stems, if there's a bounding ;; NoteColumn or a NoteColumn at the same musical moment as ;; PaperColumn. ;; Thus we look up Stem in the bound's elements-array, in order ;; to specify bound-details.right.attach-dir depending on ;; Stem.direction. (stem-left-dir (get-bound-stem-dir grob LEFT)) (stem-right-dir (get-bound-stem-dir grob RIGHT))) ;; adjust left/right padding and left/right attach-dir (if (and (number? stem-left-dir) (number? stem-right-dir)) (begin ;; compensate Stem.thickness ;; IR says it's 1.3 (ly:grob-set-nested-property! grob '(bound-details right padding) 0.13) (ly:grob-set-nested-property! grob '(bound-details left padding) 0) ;; always start at right edge of left bound (ly:grob-set-nested-property! grob '(bound-details left attach-dir) 1) (cond ((and (positive? stem-left-dir) (positive? stem-right-dir)) (ly:grob-set-nested-property! grob '(bound-details right attach-dir) 1)) ((and (positive? stem-left-dir) (negative? stem-right-dir)) (ly:grob-set-nested-property! grob '(bound-details right attach-dir) 0)) (else (ly:grob-set-nested-property! grob '(bound-details right attach-dir) -1))))) (let* ((stil (ly:line-spanner::print grob)) (stil-center (interval-center (ly:stencil-extent stil X))) (text-stil (grob-interpret-markup grob (if (not-first-broken-spanner? grob) (make-parenthesize-markup txt) txt))) (text-center (interval-center (ly:stencil-extent text-stil X)))) (ly:stencil-add ;; for reference or visual debugging add: ;stil (ly:stencil-translate-axis text-stil (- stil-center text-center) X) ) )))) %%%%%%%%%%%%%%%%%%%%%%%%%%% %% EXAMPLEs %%%%%%%%%%%%%%%%%%%%%%%%%%% \layout { \override TextSpanner.font-shape = #'upright \override TextSpanner.style = #'solid } mus = << { \repeat unfold 8 b4 } { g'-\tweak stencil #(text-stencil "1") \startTextSpan a'\stopTextSpan -\tweak stencil #(text-stencil "1½") \startTextSpan c''\stopTextSpan -\tweak stencil #(text-stencil "½") \startTextSpan b'\stopTextSpan -\tweak stencil #(text-stencil "0") \startTextSpan b'\stopTextSpan -\tweak stencil #(text-stencil "1") \startTextSpan a'\stopTextSpan -\tweak stencil #(text-stencil "0") \startTextSpan a'\stopTextSpan -\tweak stencil #(text-stencil "full") \startTextSpan b'\stopTextSpan } { \repeat unfold 8 b } >> \score { \mus \layout {} \layout { line-width = 120 ragged-right = ##f } \layout { ragged-right = ##f } } Thanks, Harm
