Thank you so much Jean. That looks amazing for a first try. Great work!

Sorry it took me a while to test it.

Upon testing I found out that it only works when there are line breaks (not
on a single system).

Also it would be useful to have control over the broken.left/right
paddings. This is an issue especially if the spanner is used above the
stave (clef collisions).

Is it too hard to an option to align the broken sections on the first and
last notes in the system instead of the system edges? The current behaviour
isn't wrong. It's just not suitable for all use cases.

Best,
Dimitris

On Thu, Apr 14, 2022 at 7:44 PM Jean Abou Samra <j...@abou-samra.fr> wrote:

> Le 14/04/2022 à 16:09, Kieren MacMillan a écrit :
> > Hi Dimitris,
> >
> >> I need a custom spanner that has x sections with different symbols.
> This is going to be tricky so any help is appreciated.
> > https://github.com/davidnalesnik/lilypond-text-spanner-inner-texts
>
>
> Ok, I'm not sure if this solves the problem fully, so I'll post what I had
> started writing anyway:
>
>
> \version "2.22.2"
>
> #(define (define-grob! grob-name grob-entry)
>     (set! all-grob-descriptions
>           (cons ((@@ (lily) completize-grob-entry)
>                  (cons grob-name grob-entry))
>                 all-grob-descriptions)))
>
> #(define (partial-sums lst)
>     (cdr (reverse! (fold
>                     (lambda (new previous)
>                       (cons (+ new (car previous))
>                             previous))
>                     (list 0)
>                     lst))))
>
> #(define (symbol-filler::print grob)
>     (let* ((widths (ly:grob-property grob 'widths))
>            (symbols (ly:grob-property grob 'symbols))
>            (orig (ly:grob-original grob))
>            (siblings (ly:spanner-broken-into orig))
>            (sib-widths
>             (map (lambda (sib)
>                    (let ((sys (ly:grob-system sib))
>                          (left (ly:spanner-bound sib LEFT))
>                          (right (ly:spanner-bound sib RIGHT)))
>                      (- (ly:grob-relative-coordinate right sys X)
>                         (ly:grob-relative-coordinate left sys X))))
>                  siblings))
>            (sib-changes (partial-sums sib-widths))
>            (total-spanner-width (apply + sib-widths))
>            (total-sym-width (apply + widths))
>            (normalized-syms (map (lambda (x)
>                                 (* x (/ total-spanner-width
> total-sym-width)))
>                               widths))
>            (sym-changes (partial-sums normalized-syms))
>            (sib-stil empty-stencil)
>            (len-so-far 0)
>            (retval #f))
>       ;; Let's do an exception.  This is easier written in imperative
> style.
>       (while (and (pair? sib-changes)
>                   (pair? sym-changes))
>         (let* ((sib (car siblings))
>                (next-sym-maybe (car symbols))
>                (next-stil-maybe (grob-interpret-markup sib next-sym-maybe))
>                (len (interval-length (ly:stencil-extent next-stil-maybe
> X)))
>                (new-len-so-far (+ len len-so-far)))
>           (cond
>            ((> new-len-so-far (car sib-changes))
>             ;; Used full length of this broken piece.  Set
>             ;; its stencil and start using the next.
>             (if (eq? grob (car siblings))
>                (set! retval sib-stil)
>                (ly:grob-set-property! (car siblings)
>                                       'stencil
>                                       sib-stil))
>             (set! sib-changes (cdr sib-changes))
>             (set! siblings (cdr siblings))
>             (set! sib-stil empty-stencil))
>            ((> new-len-so-far (car sym-changes))
>             ;; Done with this symbol, start using the next.
>             (set! sym-changes (cdr sym-changes))
>             (set! symbols (cdr symbols)))
>            (else
>             (set! sib-stil (ly:stencil-stack sib-stil X RIGHT
> next-stil-maybe 0))
>             (set! len-so-far new-len-so-far)))))
>       retval))
>
> #(define-grob! 'SymbolFiller
>     `((direction . ,DOWN)
>       (normalized-endpoints . ,ly:spanner::calc-normalized-endpoints)
>       (stencil . ,symbol-filler::print)
>       (staff-padding . 3.0)
>       (symbols . ,(grob::calc-property-by-copy 'symbols))
>       (widths . ,(grob::calc-property-by-copy 'widths))
>       (Y-offset . ,ly:side-position-interface::y-aligned-side)
>       (meta . ((class . Spanner)
>                (interfaces . (side-position-interface))))))
>
> #(define (Symbol_filler_engraver context)
>     (let ((filler #f)
>           (ev #f))
>       (make-engraver
>        (listeners
>         ((symbol-filler-event engraver event)
>          (set! ev event)))
>        ((process-music engraver)
>         (if ev
>             (let ((d (ly:event-property ev 'span-direction)))
>               (if (eqv? d LEFT)
>                   (begin
>                    (set! filler (ly:engraver-make-grob engraver
> 'SymbolFiller ev))
>                    (ly:spanner-set-bound! filler
>                                           LEFT
>                                           (ly:context-property context
> 'currentMusicalColumn)))
>                   (begin
>                    (ly:spanner-set-bound! filler
>                                           RIGHT
>                                           (ly:context-property context
> 'currentMusicalColumn))
>                    (ly:engraver-announce-end-grob engraver filler ev))))))
>        ((stop-translation-timestep engraver)
>         (set! ev #f)))))
>
> \layout {
>    \context {
>      \Global
>      \grobdescriptions #all-grob-descriptions
>    }
>    \context {
>      \Voice
>      \consists #Symbol_filler_engraver
>    }
> }
>
> #(define (define-event! type properties)
>     (set! properties (assoc-set! properties 'name type))
>     (hashq-set! music-name-to-property-table type properties)
>     (set! music-descriptions
>           (sort (cons (cons type properties)
>                       music-descriptions)
>                 alist<?)))
>
> #(define-event-class 'symbol-filler-event 'span-event)
>
> #(define-event! 'SymbolFillerEvent
>     '((types . (symbol-filler-event span-event post-event event))))
>
> startFiller =
> #(define-music-function (widths symbols) (number-list? markup-list?)
>     (make-music 'SymbolFillerEvent
>                 'span-direction LEFT
>                 'widths widths
>                 'symbols symbols))
>
> stopFiller = #(make-music 'SymbolFillerEvent 'span-direction RIGHT)
>
> {
>    g'1\startFiller #'(5 5 10 30 50) \markuplist { * \musicglyph
> "scripts.trill_element" + × "#" }
>     1 1 1 1
>    \break
>    1 1 1 1 1
>    1 1 1 1 1
>    \break
>    1 1 1 1 1
>    \break
>    1 1 1 1 1
>    \break
>    1 1 1\stopFiller
> }
>
>
> Jean
>
>
>

Reply via email to