[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Custom Spanner with variable length sections
From: |
Jean Abou Samra |
Subject: |
Re: Custom Spanner with variable length sections |
Date: |
Thu, 14 Apr 2022 18:44:36 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Thunderbird/91.7.0 |
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
- Custom Spanner with variable length sections, Dimitris Marinakis, 2022/04/14
- Re: Custom Spanner with variable length sections, Kieren MacMillan, 2022/04/14
- Re: Custom Spanner with variable length sections,
Jean Abou Samra <=
- Re: Custom Spanner with variable length sections, Dimitris Marinakis, 2022/04/15
- Re: Custom Spanner with variable length sections, Jean Abou Samra, 2022/04/15
- Re: Custom Spanner with variable length sections, Dimitris Marinakis, 2022/04/15
- Re: Custom Spanner with variable length sections, Jean Abou Samra, 2022/04/15
- Re: Custom Spanner with variable length sections, Dimitris Marinakis, 2022/04/17