Re: Custom Spanner with variable length sections

2022-04-17 Thread Dimitris Marinakis
> What are you using this spanner for, by the way?
>

I'll use it for various spanners that need gradual changes, primarily for
trills with variable speed. There are other more text-based notations but I
like the simplicity of the spanner.

 I am surprised by the font issue though. Is LilyPond preventing you
> from using a font because it lacks some accidentals even if you are not
> using these accidentals?


I can't remember the exact issue but I'm using microtonal accidentals for
some projects anyways.

Nothing wrong with the Feta font by the way. I just have an illogical
preference for SCORE's look so I'm using Scorlatti plus various tweaks to
approximate SCORE's slurs and ties. That sometimes causes me a lot of
trouble but at the end I get nice results.

I will try to share more details about what doesn't work as well as I'd
like but my use case is very specific and non standard so I feel bad asking
for help since some tweaks go pretty deep and complex.


Re: Custom Spanner with variable length sections

2022-04-15 Thread Jean Abou Samra

Le 15/04/2022 à 22:41, Dimitris Marinakis a écrit :

Thank you, much better now :)

The only thing to improve here would be to have separate paddings for 
each system. For some reason the staff-padding currently behaves more 
like a fixed offset. If you have very high notes they get clipped.




Well, that's exactly the meaning of staff-padding -- the padding
from the staff symbol. The setting for the distance from note heads
and such is padding. I just didn't implement distancing from note
heads because I didn't know if I had to. I thought you'd be putting
the grob on its own in some Dynamics-like context. See below for
an implementation that has it; it's just one added line of code.

What are you using this spanner for, by the way?



I'm using 2.23.0. I can't use the latest versions for all of my 
projects yet because I'm using a font that doesn't have the new 
microtonal accidentals. I hope the creator of the font finds the time 
to update it or I'll need to do it myself.
Besides, I have over 12K lines of code with custom stuff that some of 
it will most likely break with the version change.




Ok, ok, the code below works in 2.23.0. I am surprised
by the font issue though. Is LilyPond preventing you from
using a font because it lacks some accidentals even if
you are not using these accidentals?

Jean



\version "2.23.0"

#(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))
  (proto-siblings (ly:spanner-broken-into orig))
  (siblings (if (null? proto-siblings)
    (list grob)
    proto-siblings))
  (sib-exts-to-fill
   (map
    (lambda (sib)
  (define (on-dir sym dir)
    (let* ((details (ly:grob-property sib sym))
   (x (assoc-get 'X details))
   (pding (assoc-get 'padding details)))
  (+ x (* -1 dir pding
  (cons (on-dir 'left-bound-info LEFT)
    (on-dir 'right-bound-info RIGHT)))
    siblings))
  (sib-widths (map interval-length sib-exts-to-fill))
  (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.
   (let* ((sys (ly:grob-system sib))
  (tr (- (interval-start (car sib-exts-to-fill))
 (ly:grob-relative-coordinate sib sys X)))
  (tr-stil (ly:stencil-translate-axis sib-stil tr X)))
 (if (eq? grob (car siblings))
 (set! retval tr-stil)
 (ly:grob-set-property! (car siblings)
    'stencil
    tr-stil)))
   (set! sib-changes (cdr sib-changes))
   (set! siblings (cdr siblings))
   (set! sib-stil empty-stencil)
   (set! sib-exts-to-fill (cdr sib-exts-to-fill)))
  ((> 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
   `((bound-details . ((left . ((padding . 0)
    (Y . 0)))
   (right . ((padding . 0)
 (Y . 0)
 (direction . ,DOWN)

Re: Custom Spanner with variable length sections

2022-04-15 Thread Dimitris Marinakis
Thank you, much better now :)

The only thing to improve here would be to have separate paddings for each
system. For some reason the staff-padding currently behaves more like a
fixed offset. If you have very high notes they get clipped.
[image: customspannerclippednotes.jpg]


I'm using 2.23.0. I can't use the latest versions for all of my projects
yet because I'm using a font that doesn't have the new microtonal
accidentals. I hope the creator of the font finds the time to update it or
I'll need to do it myself.
Besides, I have over 12K lines of code with custom stuff that some of it
will most likely break with the version change.

I'll do must best to update to the latest version as soon as possible.
Thanks again for your help.

Best,
Dimitris

On Fri, Apr 15, 2022 at 10:07 PM Jean Abou Samra  wrote:

> Le 15/04/2022 à 16:35, Dimitris Marinakis a écrit :
> > Thank you so much Jean. That looks amazing for a first try. Great work!
> >
> > Sorry it took me a while to test it.
>
>
> Less than a day? I didn't find that long :-)
>
>
> > Upon testing I found out that it only works when there are line breaks
> > (not on a single system).
>
>
>
> Right, I intended to add this code, but forgot it along the way.
>
>
>
> > 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.
>
>
>
> See the second attempt below. This SymbolFiller implements a subset
> of the horizontal-line-spanner-interface. You can override padding and
> end-on-note in bound-details.
>
> I hope you don't mind that this now requires a development version.
>
> Best,
> Jean
>
>
>
> \version "2.23.7"
>
> #(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))
>(proto-siblings (ly:spanner-broken-into orig))
>(siblings (if (null? proto-siblings)
>  (list grob)
>  proto-siblings))
>(sib-exts-to-fill
> (map
>  (lambda (sib)
>(define (on-dir sym dir)
>  (let* ((details (ly:grob-property sib sym))
> (x (assoc-get 'X details))
> (pding (assoc-get 'padding details)))
>(+ x (* -1 dir pding
>(cons (on-dir 'left-bound-info LEFT)
>  (on-dir 'right-bound-info RIGHT)))
>  siblings))
>(sib-widths (map interval-length sib-exts-to-fill))
>(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.
> (let* ((tr (- (interval-start (car sib-exts-to-fill))
>   (ly:grob-relative-coordinate sib
> (ly:grob-system sib)
>X)))
>(tr-stil (ly:stencil-translate-axis sib-stil tr X)))
>   (if (eq? grob (car siblings))
>   (set! retval tr-stil)
>   (ly:grob-set-property! (car siblings)
>  'stencil
>  

Re: Custom Spanner with variable length sections

2022-04-15 Thread Jean Abou Samra

Le 15/04/2022 à 16:35, Dimitris Marinakis a écrit :

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

Sorry it took me a while to test it.



Less than a day? I didn't find that long :-)


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




Right, I intended to add this code, but forgot it along the way.



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.




See the second attempt below. This SymbolFiller implements a subset
of the horizontal-line-spanner-interface. You can override padding and
end-on-note in bound-details.

I hope you don't mind that this now requires a development version.

Best,
Jean



\version "2.23.7"

#(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))
  (proto-siblings (ly:spanner-broken-into orig))
  (siblings (if (null? proto-siblings)
    (list grob)
    proto-siblings))
  (sib-exts-to-fill
   (map
    (lambda (sib)
  (define (on-dir sym dir)
    (let* ((details (ly:grob-property sib sym))
   (x (assoc-get 'X details))
   (pding (assoc-get 'padding details)))
  (+ x (* -1 dir pding
  (cons (on-dir 'left-bound-info LEFT)
    (on-dir 'right-bound-info RIGHT)))
    siblings))
  (sib-widths (map interval-length sib-exts-to-fill))
  (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.
   (let* ((tr (- (interval-start (car sib-exts-to-fill))
 (ly:grob-relative-coordinate sib
(ly:grob-system sib)
  X)))
  (tr-stil (ly:stencil-translate-axis sib-stil tr X)))
 (if (eq? grob (car siblings))
 (set! retval tr-stil)
 (ly:grob-set-property! (car siblings)
    'stencil
    tr-stil)))
   (set! sib-changes (cdr sib-changes))
   (set! siblings (cdr siblings))
   (set! sib-stil empty-stencil)
   (set! sib-exts-to-fill (cdr sib-exts-to-fill)))
  ((> 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
   `((bound-details . ((left . ((padding . 0)))
   (right . ((padding . 0)
 (direction . ,DOWN)
 (left-bound-info . ,ly:horizontal-line-spanner::calc-left-bound-info)
 (normalized-endpoints . ,ly:spanner::calc-normalized-endpoints)
 (right-bound-info . 
,ly:horizontal-line-spanner::calc-right-bound-info)

 (stencil . ,symbol-filler::print)
 (staff-padding . 3.0)
 (symbols . ,(grob::calc-property-by-copy 'symbols))
 (widths . 

Re: Custom Spanner with variable length sections

2022-04-15 Thread Dimitris Marinakis
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  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 

Re: Custom Spanner with variable length sections

2022-04-14 Thread Jean Abou Samra

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
 

Re: Custom Spanner with variable length sections

2022-04-14 Thread Kieren MacMillan
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

Hope that helps!
Kieren.