multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
Hi all,

I'm experimenting with a way to support multiple text spanners in a single
voice, using the 'spanner-id property which already enables multiple slurs
and phrasing slurs.

The attached code works--until the spanners cross a line break.  Then the
order of the spanners is reversed.  I've experimented with different start
and end points of the spanners, reversing lists within the engraver--no
change.

The second example shows that tweaks can mess up this reversed ordering
even further.

Does anyone know what is happening here?  I really have no idea :(

Thanks,

David
\version "2.19"

%% Based on the rewrite of Text_spanner_engraver in
%% input/regression/scheme-text-spanner.ly

#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
   (ly:spanner-set-bound! spanner LEFT item)
   (ly:spanner-set-bound! spanner RIGHT item)))

#(define (axis-offset-symbol axis)
   (if (eq? axis X) 'X-offset 'Y-offset))

#(define (set-axis! grob axis)
   (if (not (number? (ly:grob-property grob 'side-axis)))
   (begin
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
 grob
 (if (eq? axis X)
 ly:side-position-interface::x-aligned-side
 side-position-interface::y-aligned-side)
 (axis-offset-symbol axis)

schemeTextSpannerEngraver =
#(lambda (context)
   (let ((span '()) ; list of started spanner
  (finished '()) ; list of spanners in completion stage
  (event-start '()) ; list of START events
  (event-stop '())) ; list of STOP events
 (make-engraver
  ;; \startTextSpan, \stopTextSpan, and the like create events
  ;; which we collect here.
  (listeners
   ((text-span-event engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! event-start (cons event event-start))
(set! event-stop (cons event event-stop)
  ;; Populate 'note-columns property of spanners.  Bounds are
  ;; set to note columns, and each spanner keeps a record of
  ;; the note columns it traverses.
  (acknowledgers
   ((note-column-interface engraver grob source-engraver)
(for-each (lambda (s)
(ly:pointer-group-interface::add-grob
 s 'note-columns grob)
(add-bound-item s grob))
  span)
(for-each (lambda (f)
(ly:pointer-group-interface::add-grob
 f 'note-columns grob)
(add-bound-item f grob))
  finished)))

  ((process-music trans)
   ;; Move begun spanners from 'span' to 'finished'.  We do this
   ;; on the basis of 'spanner-id.  If we find a match--either
   ;; the strings are the same, or both are unset--a transfer
   ;; can be made.  Return a warning if we find no match: spanner
   ;; hasn't been properly begun.
   (for-each
(lambda (es)
  (let ((es-id (ly:event-property es 'spanner-id)))
(let loop ((sp span))
  (let ((sp-id (ly:event-property
(event-cause (car sp)) 'spanner-id)))
(cond
 ((null? sp) (ly:warning "No spanner to end!!"))
 ((and
   (string? sp-id)
   (string? es-id)
   (string=? sp-id es-id))
  (set! finished (cons (car sp) finished))
  (set! span (remove (lambda (s) (eq? s (car sp))) span)))
 ((and
   (null? sp-id)
   (null? es-id))
  (set! finished (cons (car sp) finished))
  (set! span (remove (lambda (s) (eq? s (car sp))) span)))
 (else (loop (cdr sp
event-stop)

   ;; The end of our spanners can be acknowledged by other engravers.
   (for-each
(lambda (f)
  (ly:engraver-announce-end-grob trans f (event-cause f)))
finished)

   ;; Make spanners called for by START events.
   (for-each
(lambda (es)
  (set! span
(cons
 (ly:engraver-make-grob trans 'TextSpanner es)
 span))
  (set-axis! (car span) Y))
event-start)

   ;; Events have served their purpose for this timestep.  Clear
   ;; the way for new events in later timesteps.
   (set! event-start '())
   (set! event-stop '()))

  ((stop-translation-timestep trans)
   ;; Set bounds of spanners to PaperColumns if they haven't been set.
   ;; This allows spanners to be drawn between spacers.  Other uses?
   ;; Doesn't appear to affect whether spanners can de drawn between
   ;; rests.
   (for-each
(lambda (s)
  (if (null? (ly:spanner-bound s LEFT))
  (ly:spanner-set-bound! s LEFT
(ly:context-property context 'currentMusicalColumn
span)

   (for-each

Re: multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
On Fri, Oct 2, 2015 at 10:00 AM, David Nalesnik 
wrote:

> Hi all,
>
> I'm experimenting with a way to support multiple text spanners in a single
> voice, using the 'spanner-id property which already enables multiple slurs
> and phrasing slurs.
>
> The attached code works--until the spanners cross a line break.  Then the
> order of the spanners is reversed.  I've experimented with different start
> and end points of the spanners, reversing lists within the engraver--no
> change.
>
> The second example shows that tweaks can mess up this reversed ordering
> even further.
>
> Does anyone know what is happening here?  I really have no idea :(
>

Here's an image.

(I'm running 2.19.27 with Windows 10, 64-bit, if that's has anything to do
with it.)

David
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread David Kastrup
David Nalesnik  writes:

> Hi all,
>
> I'm experimenting with a way to support multiple text spanners in a single
> voice, using the 'spanner-id property which already enables multiple slurs
> and phrasing slurs.
>
> The attached code works--until the spanners cross a line break.  Then the
> order of the spanners is reversed.  I've experimented with different start
> and end points of the spanners, reversing lists within the engraver--no
> change.
>
> The second example shows that tweaks can mess up this reversed ordering
> even further.
>
> Does anyone know what is happening here?  I really have no idea :(

Sounds like room-saving stacking of elements with equal
outside-staff-priority (?).  Perhaps distribute ascending priorities?

-- 
David Kastrup

___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread Michael Gerdau
> > The second example shows that tweaks can mess up this reversed ordering
> > even further.
> > 
> > Does anyone know what is happening here?  I really have no idea :(
> 
> Here's an image.
> 
> (I'm running 2.19.27 with Windows 10, 64-bit, if that's has anything to do
> with it.)

Just for the record:
I'm running 2.19.28 on Linux 4.2.2-1-ARCH x86_64 and see the very same
image you posted.

Kind regards,
Michael
-- 
 Michael Gerdau   email: m...@qata.de
 GPG-keys available on request or at public keyserver

signature.asc
Description: This is a digitally signed message part.
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
David,

On Fri, Oct 2, 2015 at 11:26 AM, David Kastrup  wrote:

> David Nalesnik  writes:
>
> > Hi all,
> >
> > I'm experimenting with a way to support multiple text spanners in a
> single
> > voice, using the 'spanner-id property which already enables multiple
> slurs
> > and phrasing slurs.
> >
> > The attached code works--until the spanners cross a line break.  Then the
> > order of the spanners is reversed.  I've experimented with different
> start
> > and end points of the spanners, reversing lists within the engraver--no
> > change.
> >
> > The second example shows that tweaks can mess up this reversed ordering
> > even further.
> >
> > Does anyone know what is happening here?  I really have no idea :(
>
> Sounds like room-saving stacking of elements with equal
> outside-staff-priority (?).  Perhaps distribute ascending priorities?


Exactly!  Thanks so much.

The following is one of the examples from the file, with
outside-staff-priority tweaks.  The order is preserved.

\relative c' {
  \override TextSpanner.outside-staff-padding = 2
  \override TextSpanner.thickness = 4
  \override TextSpanner.style = ##f
  a4
  -\tweak color #red
  \startTextSpan
  b c
  -\tweak color #darkred
  -\offset outside-staff-priority 1
  \startTextSpanOne
  d

  a4
  -\tweak color #magenta
  -\offset outside-staff-priority 2
  \startTextSpanTwo
  b c
  -\tweak style #'zigzag
  -\offset outside-staff-priority 3
  \startTextSpanThree
  d
  \break

  a4 b c d\stopTextSpanThree

  a4 b\stopTextSpanTwo
  c d\stopTextSpanOne
  a4 b c d\stopTextSpan
}

%

Naturally, it would be nice to do this without needing the extra tweaks.
 outside-staff-priority could be altered behind-the-scenes, but that seems
somehow...dishonest.  Though, of course, two spanner with priorities 350
and 351 would be unlikely to interfere with placement of other objects.

DN
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
Michael,

On Fri, Oct 2, 2015 at 11:33 AM, Michael Gerdau  wrote:

> > > The second example shows that tweaks can mess up this reversed ordering
> > > even further.
> > >
> > > Does anyone know what is happening here?  I really have no idea :(
> >
> > Here's an image.
> >
> > (I'm running 2.19.27 with Windows 10, 64-bit, if that's has anything to
> do
> > with it.)
>
> Just for the record:
> I'm running 2.19.28 on Linux 4.2.2-1-ARCH x86_64 and see the very same
> image you posted.
>
>
Thanks for trying that out!

Looks like David Kastrup has identified the cross-platform cause.

DN
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
On Fri, Oct 2, 2015 at 12:09 PM, David Nalesnik 
wrote:

> David,
>
> On Fri, Oct 2, 2015 at 11:26 AM, David Kastrup  wrote:
>
>> David Nalesnik  writes:
>>
>> > Hi all,
>> >
>> > I'm experimenting with a way to support multiple text spanners in a
>> single
>> > voice, using the 'spanner-id property which already enables multiple
>> slurs
>> > and phrasing slurs.
>> >
>> > The attached code works--until the spanners cross a line break.  Then
>> the
>> > order of the spanners is reversed.  I've experimented with different
>> start
>> > and end points of the spanners, reversing lists within the engraver--no
>> > change.
>> >
>> > The second example shows that tweaks can mess up this reversed ordering
>> > even further.
>> >
>> > Does anyone know what is happening here?  I really have no idea :(
>>
>> Sounds like room-saving stacking of elements with equal
>> outside-staff-priority (?).  Perhaps distribute ascending priorities?
>
>
>
Horizontal_bracket_engraver achieves correct ordering of nested brackets
through the side-position-interface array 'side-position-elements.
Brackets closer to the staff are added to the support of brackets further
away.  However, this only works because 'outside-staff-priority is set to
#f by default.  As soon as you set it to a numerical value, chaos ensues:
the initial ordering is flipped AND the brackets flip orientation across
line breaks.  (See attached images.)

Try this code:

\version "2.19.27"

\new Staff {
  \override HorizontalBracket.direction = #UP
  \override HorizontalBracket.thickness = 4
  c
  -\tweak color #red
  \startGroup
  -\tweak color #green
  \startGroup d
  -\tweak color #blue
  \startGroup
  e f
  \break
  c d e f
  c\stopGroup d\stopGroup e d\stopGroup
  \bar "||"
  \override HorizontalBracket.outside-staff-priority = 100
  c
  -\tweak color #red
  \startGroup
  -\tweak color #green
  \startGroup d
  -\tweak color #blue
  \startGroup
  e f
  \break
  c d e f
}

\layout {
  \context {
\Voice
\consists #"Horizontal_bracket_engraver"
  }
}

%

This must be a bug...

BTW, correct ordering is achieved with the TextSpanner code if the same
approach is taken: any spanner in force is added to the
'side-support-elements of a new spanner.  Again, this works only if
'outside-staff-priority is set to #f.

DN
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-02 Thread David Nalesnik
On Fri, Oct 2, 2015 at 5:49 PM, David Nalesnik 
wrote:

>
> Horizontal_bracket_engraver achieves correct ordering of nested brackets
> through the side-position-interface array 'side-position-elements.
> Brackets closer to the staff are added to the support of brackets further
> away.  However, this only works because 'outside-staff-priority is set to
> #f by default.  As soon as you set it to a numerical value, chaos ensues:
> the initial ordering is flipped AND the brackets flip orientation across
> line breaks.  (See attached images.)
>
>
So much for my analytical skills.  The blue bracket simply changes
orientation across the line break with outside-staff-priority set to a
number.

DN
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-03 Thread David Nalesnik
On Fri, Oct 2, 2015 at 5:59 PM, David Nalesnik 
wrote:

>
>
> On Fri, Oct 2, 2015 at 5:49 PM, David Nalesnik 
> wrote:
>
>>
>> Horizontal_bracket_engraver achieves correct ordering of nested brackets
>> through the side-position-interface array 'side-position-elements.
>> Brackets closer to the staff are added to the support of brackets further
>> away.  However, this only works because 'outside-staff-priority is set to
>> #f by default.  As soon as you set it to a numerical value, chaos ensues:
>> the initial ordering is flipped AND the brackets flip orientation across
>> line breaks.  (See attached images.)
>>
>>
> So much for my analytical skills.  The blue bracket simply changes
> orientation across the line break with outside-staff-priority set to a
> number.
>
>
The problems with HorizontalBracket and TextSpanner may be "fixed" by
setting 'padding to a value ever-so-slightly higher than the value of
'outside-staff-padding. Both grobs are assigned an outside-staff-padding of
0.46 in lily/axis-group-interface.cc.  So, if we set padding to
0.46001, the ordering comes out OK when staff-priority is set.  (My
conjecture is that by setting 'padding higher than 'outside-staff-padding
we are signalling a collision, which is resolved by
avoid_outside_staff_collisions in axis-group-interface.cc.)

So here is a revised version of the TextSpanner code.  The intention is to
allow as many spanners per voice as you'd like.  This works with
'outside-staff-priority (set to 350 for TextSpanner, by default), but for
the time being, you need to add the 'padding override to handle line
breaks.  (Alternately, you could specify different staff-priorities for
individual spanners, as was done earlier in this thread.)

I hope this is useful.  Suggestions for improvement welcome!

DN
\version "2.19.12"

\header {
  texidoc = "Use @code{define-event-class}, scheme engraver methods,
and grob creation methods to create a fully functional text spanner
in scheme."
}

#(define-event-class 'scheme-text-span-event 'span-event)

#(define (add-grob-definition grob-name grob-entry)
   (let* ((meta-entry   (assoc-get 'meta grob-entry))
  (class(assoc-get 'class meta-entry))
  (ifaces-entry (assoc-get 'interfaces meta-entry)))
 (set-object-property! grob-name 'translation-type? ly:grob-properties?)
 (set-object-property! grob-name 'is-grob? #t)
 (set! ifaces-entry (append (case class
  ((Item) '(item-interface))
  ((Spanner) '(spanner-interface))
  ((Paper_column) '((item-interface
 paper-column-interface)))
  ((System) '((system-interface
   spanner-interface)))
  (else '(unknown-interface)))
  ifaces-entry))
 (set! ifaces-entry (uniq-list (sort ifaces-entry symbol___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-03 Thread David Nalesnik
On Sat, Oct 3, 2015 at 12:02 PM, David Nalesnik 
wrote:

>
>
> So here is a revised version of the TextSpanner code.
>
>
Oh *drat*  Attached the wrong file.  Apologies...

DN
\version "2.19"

%% Based on the rewrite of Text_spanner_engraver in
%% input/regression/scheme-text-spanner.ly

#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
   (ly:spanner-set-bound! spanner LEFT item)
   (ly:spanner-set-bound! spanner RIGHT item)))

#(define (axis-offset-symbol axis)
   (if (eq? axis X) 'X-offset 'Y-offset))

#(define (set-axis! grob axis)
   (if (not (number? (ly:grob-property grob 'side-axis)))
   (begin
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
 grob
 (if (eq? axis X)
 ly:side-position-interface::x-aligned-side
 side-position-interface::y-aligned-side)
 (axis-offset-symbol axis)

schemeTextSpannerEngraver =
#(lambda (context)
   (let ((span '()) ; list of started spanners
  (finished '()) ; list of spanners in completion stage
  (event-start '()) ; list of START events
  (event-stop '())) ; list of STOP events
 (make-engraver
  ;; \startTextSpan, \stopTextSpan, and the like create events
  ;; which we collect here.
  (listeners
   ((text-span-event engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! event-start (cons event event-start))
(set! event-stop (cons event event-stop)
  ;; Populate 'note-columns property of spanners.  Bounds are
  ;; set to note columns, and each spanner keeps a record of
  ;; the note columns it traverses.
  (acknowledgers
   ((note-column-interface engraver grob source-engraver)
(for-each (lambda (s)
(ly:pointer-group-interface::add-grob
 s 'note-columns grob)
(add-bound-item s grob))
  span)
(for-each (lambda (f)
(ly:pointer-group-interface::add-grob
 f 'note-columns grob)
(add-bound-item f grob))
  finished)))

  ((process-music trans)
   ;; Move begun spanners from 'span' to 'finished'.  We do this
   ;; on the basis of 'spanner-id.  If we find a match--either
   ;; the strings are the same, or both are unset--a transfer
   ;; can be made.  Return a warning if we find no match: spanner
   ;; hasn't been properly begun.
   (for-each
(lambda (es)
  (let ((es-id (ly:event-property es 'spanner-id)))
(let loop ((sp span))
  (let ((sp-id (ly:event-property
(event-cause (car sp)) 'spanner-id)))
(cond
 ((null? sp) (ly:warning "No spanner to end!!"))
 ((and
   (string? sp-id)
   (string? es-id)
   (string=? sp-id es-id))
  (set! finished (cons (car sp) finished))
  (set! span (remove (lambda (s) (eq? s (car sp))) span)))
 ((and
   (null? sp-id)
   (null? es-id))
  (set! finished (cons (car sp) finished))
  (set! span (remove (lambda (s) (eq? s (car sp))) span)))
 (else (loop (cdr sp
event-stop)

   ;; The end of our spanners can be acknowledged by other engravers.
   (for-each
(lambda (f)
  (ly:engraver-announce-end-grob trans f (event-cause f)))
finished)

   ;; Make spanners called for by START events.  To each new spanner,
   ;; add any existing spanners to the 'side-support-elements array.
   ;; This ensures correct ordering over line breaks when 'outside-
   ;; staff-priority is set to #f.  Ordinarily, for TextSpanner this
   ;; is 350.
   (for-each
(lambda (es)
  (let ((new (ly:engraver-make-grob trans 'TextSpanner es)))
(for-each
 (lambda (sp)
   (ly:pointer-group-interface::add-grob new
 'side-support-elements sp))
 span)
(set! span (cons new span))
(set-axis! (car span) Y)))
event-start)

   ;; Events have served their purpose for this timestep.  Clear
   ;; the way for new events in later timesteps.
   (set! event-start '())
   (set! event-stop '()))

  ((stop-translation-timestep trans)
   ;; Set bounds of spanners to PaperColumns if they haven't been set.
   ;; This allows spanners to be drawn between spacers.  Other uses?
   ;; Doesn't appear to affect whether spanners can de drawn between
   ;; rests.
   (for-each
(lambda (s)
  (if (null? (ly:spanner-bound s LEFT))
  (ly:spanner-set-bound! s LEFT
(ly:context-property context 'currentMusicalColumn
span)


   (for-eac

Re: multiple TextSpanners per voice

2015-10-05 Thread David Nalesnik
Ok, this should do it.

The intention is to provide extra functionality to text spanners.  By using
this code, you have all the functionality of normal text spanners, but you
are able to have multiple spanners per voice.

You simply need to swap the regular engraver for this one in a layout
block, and use the commands I've defined: \startTextSpanOne, and the like.
 (You can change the names, of course, and add more.  This is crying out
for a better interface, I know,)

Regarding difficulties mentioned earlier in the thread:

The spanners should nest properly and maintain their orientation across
line breaks.  Here this is achieved by assigning minute variations of
outside-staff-priority behind the scenes.  (Turns out you can use
outside-staff-priorities like 350.0001 ) You can still override and
tweak outside-staff-priority of TextSpanner if you want.

I believe that this manipulation may be avoided by inventing a new
alignment grob "to bind them all." but I'm not sure.  Since the attached
seems sufficient, this could wait until time came (if ever) to add this to
the code base.

DN

%%%
\version "2.19"

%% Incorporating some code from the rewrite in Scheme of
%% Text_spanner_engraver in input/regression/scheme-text-spanner.ly

#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
   (ly:spanner-set-bound! spanner LEFT item)
   (ly:spanner-set-bound! spanner RIGHT item)))

#(define (axis-offset-symbol axis)
   (if (eq? axis X) 'X-offset 'Y-offset))

#(define (set-axis! grob axis)
   (if (not (number? (ly:grob-property grob 'side-axis)))
   (begin
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
 grob
 (if (eq? axis X)
 ly:side-position-interface::x-aligned-side
 side-position-interface::y-aligned-side)
 (axis-offset-symbol axis)

#(define (assign-spanner-index spanner orig-ls)
   "Determine the position of a new spanner in an ordered sequence
of spanners.  The goal is for the sequence to begin with zero and
contain no gaps.  Return the index representing the spanner's position."
   (if (null? orig-ls)
   0
   (let loop ((ls orig-ls) (insert? #t) (result 0))
 (cond
  ((null? ls) result)
  ;; position at head of list
  ((and insert? (> (caar orig-ls) 0))
   (loop ls #f 0))
  ;; no gaps, put at end of list
  ((and insert? (null? (cdr ls)))
   (loop (cdr ls) #f (1+ (caar ls
  ;; fill lowest position of gap
  ((and insert?
(> (caadr ls) (1+ (caar ls
   (loop (cdr ls) #f (1+ (caar ls
  (else (loop (cdr ls) insert? result))

alternateTextSpannerEngraver =
#(lambda (context)
   (let (;; a list of pairs comprising a spanner index
  ;;  (not spanner-id) and a spanner which has been begun
  (spanners '())
  (finished '()) ; list of spanners in completion stage
  (start-events '()) ; list of START events
  (stop-events '())) ; list of STOP events
 (make-engraver
  ;; \startTextSpan, \stopTextSpan, and the like create events
  ;; which we collect here.
  (listeners
   ((text-span-event engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! start-events (cons event start-events))
(set! stop-events (cons event stop-events)
  ;; Populate 'note-columns property of spanners.  Bounds are
  ;; set to note columns, and each spanner keeps a record of
  ;; the note columns it traverses.
  (acknowledgers
   ((note-column-interface engraver grob source-engraver)
(for-each (lambda (s)
(ly:pointer-group-interface::add-grob
 (cdr s) 'note-columns grob)
(add-bound-item (cdr s) grob))
  spanners)
;; finished only contains spanners, no indices
(for-each (lambda (f)
(ly:pointer-group-interface::add-grob
 f 'note-columns grob)
(add-bound-item f grob))
  finished)))

  ((process-music trans)
   ;; Move begun spanners from 'span' to 'finished'.  We do this
   ;; on the basis of 'spanner-id.  If we find a match--either
   ;; the strings are the same, or both are unset--a transfer
   ;; can be made.  Return a warning if we find no match: spanner
   ;; hasn't been properly begun.
   (for-each
(lambda (es)
  (let ((es-id (ly:event-property es 'spanner-id)))
(let loop ((sp spanners))
  (if (null? sp)
  (ly:warning "No spanner to end!!")
  (let ((sp-id (ly:event-property
(event-cause (cdar sp)) 'spanner-id)))
(cond
 ((or
   (and
(string? sp-id)
 

Re: multiple TextSpanners per voice

2015-10-20 Thread Trevor Bača
Hi,

I'd like to add that I'm *incredibly* excited by this work. The ability to
have multiple text spanners in a voice -- and to tweak each independently
-- is something I've wanted in LilyPond for many years. (I responded to a
different thread about this a touch too early only moments ago; apologies,
catching up on list mail.) This is really incredibly exciting to me, and I
think it will be to very many other composers once the ability is made
clear in a public release (and in the docs).

For what it's worth, I'd very much like to request the promotion of this
work to a fully acknowledged new feature (respecting, of course, the needs
of feature sequencing in the release process).

I'm not quite sure what the best (user) interface for this is. I suppose
\startTextSpan[One|Two|Three|Four] will work. Though it seems like
\startTextSpan #1 or \startTextSpan #"fancy-spanner-name" would be a more
complete generalization of the feature.

Regardless of the user interface, this work is important. Please consider
elevating the change to a full feature (with a NEWS entry and a graphic
example or two) with user syntax that is as streamlined and clear as
possible. I think we will be surprised at the amount of uptake among many
composers.

Thanks so much for this, David.

Trevor.






On Mon, Oct 5, 2015 at 10:09 AM, David Nalesnik 
wrote:

> Ok, this should do it.
>
> The intention is to provide extra functionality to text spanners.  By
> using this code, you have all the functionality of normal text spanners,
> but you are able to have multiple spanners per voice.
>
> You simply need to swap the regular engraver for this one in a layout
> block, and use the commands I've defined: \startTextSpanOne, and the like.
>  (You can change the names, of course, and add more.  This is crying out
> for a better interface, I know,)
>
> Regarding difficulties mentioned earlier in the thread:
>
> The spanners should nest properly and maintain their orientation across
> line breaks.  Here this is achieved by assigning minute variations of
> outside-staff-priority behind the scenes.  (Turns out you can use
> outside-staff-priorities like 350.0001 ) You can still override and
> tweak outside-staff-priority of TextSpanner if you want.
>
> I believe that this manipulation may be avoided by inventing a new
> alignment grob "to bind them all." but I'm not sure.  Since the attached
> seems sufficient, this could wait until time came (if ever) to add this to
> the code base.
>
> DN
>
> %%%
>
>
> ___
> lilypond-user mailing list
> lilypond-user@gnu.org
> https://lists.gnu.org/mailman/listinfo/lilypond-user
>
>


-- 
Trevor Bača
www.trevorbaca.com
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-20 Thread David Kastrup
Trevor Bača  writes:

> Hi,
>
> I'd like to add that I'm *incredibly* excited by this work. The ability to
> have multiple text spanners in a voice -- and to tweak each independently
> -- is something I've wanted in LilyPond for many years. (I responded to a
> different thread about this a touch too early only moments ago; apologies,
> catching up on list mail.) This is really incredibly exciting to me, and I
> think it will be to very many other composers once the ability is made
> clear in a public release (and in the docs).
>
> For what it's worth, I'd very much like to request the promotion of this
> work to a fully acknowledged new feature (respecting, of course, the needs
> of feature sequencing in the release process).
>
> I'm not quite sure what the best (user) interface for this is. I suppose
> \startTextSpan[One|Two|Three|Four] will work. Though it seems like
> \startTextSpan #1 or \startTextSpan #"fancy-spanner-name" would be a more
> complete generalization of the feature.

\=1\startTextSpan ... \=1\endTextSpan already work as a user interface.
It's just that there is nothing that would actually _heed_ the settings
of "spanner-id" achieved in that manner yet.

-- 
David Kastrup

___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user


Re: multiple TextSpanners per voice

2015-10-20 Thread David Nalesnik
On Tue, Oct 20, 2015 at 11:50 AM, David Kastrup  wrote:

> Trevor Bača  writes:
>
> > Hi,
> >
> > I'd like to add that I'm *incredibly* excited by this work. The ability
> to
> > have multiple text spanners in a voice -- and to tweak each independently
> > -- is something I've wanted in LilyPond for many years. (I responded to a
> > different thread about this a touch too early only moments ago;
> apologies,
> > catching up on list mail.) This is really incredibly exciting to me, and
> I
> > think it will be to very many other composers once the ability is made
> > clear in a public release (and in the docs).
> >
> > For what it's worth, I'd very much like to request the promotion of this
> > work to a fully acknowledged new feature (respecting, of course, the
> needs
> > of feature sequencing in the release process).
> >
> > I'm not quite sure what the best (user) interface for this is. I suppose
> > \startTextSpan[One|Two|Three|Four] will work. Though it seems like
> > \startTextSpan #1 or \startTextSpan #"fancy-spanner-name" would be a more
> > complete generalization of the feature.
>
> \=1\startTextSpan ... \=1\endTextSpan already work as a user interface.
> It's just that there is nothing that would actually _heed_ the settings
> of "spanner-id" achieved in that manner yet.
>
>
This works wonderfully well as an interface with the engraver I posted.
Thank you so much!  Now it is possible to remove all the extra definitions
of \startTextSpanEightyFour and the like.

See attached.

DN

%
\version "2.19"

%% Incorporating some code from the rewrite in Scheme of
%% Text_spanner_engraver in input/regression/scheme-text-spanner.ly

#(define (add-bound-item spanner item)
   (if (null? (ly:spanner-bound spanner LEFT))
   (ly:spanner-set-bound! spanner LEFT item)
   (ly:spanner-set-bound! spanner RIGHT item)))

#(define (axis-offset-symbol axis)
   (if (eq? axis X) 'X-offset 'Y-offset))

#(define (set-axis! grob axis)
   (if (not (number? (ly:grob-property grob 'side-axis)))
   (begin
(set! (ly:grob-property grob 'side-axis) axis)
(ly:grob-chain-callback
 grob
 (if (eq? axis X)
 ly:side-position-interface::x-aligned-side
 side-position-interface::y-aligned-side)
 (axis-offset-symbol axis)

#(define (assign-spanner-index spanner orig-ls)
   "Determine the position of a new spanner in an ordered sequence
of spanners.  The goal is for the sequence to begin with zero and
contain no gaps.  Return the index representing the spanner's position."
   (if (null? orig-ls)
   0
   (let loop ((ls orig-ls) (insert? #t) (result 0))
 (cond
  ((null? ls) result)
  ;; position at head of list
  ((and insert? (> (caar orig-ls) 0))
   (loop ls #f 0))
  ;; no gaps, put at end of list
  ((and insert? (null? (cdr ls)))
   (loop (cdr ls) #f (1+ (caar ls
  ;; fill lowest position of gap
  ((and insert?
(> (caadr ls) (1+ (caar ls
   (loop (cdr ls) #f (1+ (caar ls
  (else (loop (cdr ls) insert? result))

alternateTextSpannerEngraver =
#(lambda (context)
   (let (;; a list of pairs comprising a spanner index
  ;;  (not spanner-id) and a spanner which has been begun
  (spanners '())
  (finished '()) ; list of spanners in completion stage
  (start-events '()) ; list of START events
  (stop-events '())) ; list of STOP events
 (make-engraver
  ;; \startTextSpan, \stopTextSpan, and the like create events
  ;; which we collect here.
  (listeners
   ((text-span-event engraver event)
(if (= START (ly:event-property event 'span-direction))
(set! start-events (cons event start-events))
(set! stop-events (cons event stop-events)
  ;; Populate 'note-columns property of spanners.  Bounds are
  ;; set to note columns, and each spanner keeps a record of
  ;; the note columns it traverses.
  (acknowledgers
   ((note-column-interface engraver grob source-engraver)
(for-each (lambda (s)
(ly:pointer-group-interface::add-grob
 (cdr s) 'note-columns grob)
(add-bound-item (cdr s) grob))
  spanners)
;; finished only contains spanners, no indices
(for-each (lambda (f)
(ly:pointer-group-interface::add-grob
 f 'note-columns grob)
(add-bound-item f grob))
  finished)))

  ((process-music trans)
   ;; Move begun spanners from 'spanners' to 'finished'.  We do this
   ;; on the basis of 'spanner-id.  If we find a match--either
   ;; the strings are the same, or both are unset--a transfer
   ;; can be made.  Return a warning if we find no match: spanner
   ;; hasn't been properly begun.
   (for-each
(lambda (es)
  (let ((es-id

Re: multiple TextSpanners per voice

2015-10-20 Thread Trevor Bača
This is excellent.

The combination of the engraver and the ID labeling work perfectly.

I think it would be wonderful to consider including David's engraver in a
coming public release.

On Tue, Oct 20, 2015 at 1:28 PM, David Nalesnik 
wrote:

>
>
> On Tue, Oct 20, 2015 at 11:50 AM, David Kastrup  wrote:
>
>> Trevor Bača  writes:
>>
>> > Hi,
>> >
>> > I'd like to add that I'm *incredibly* excited by this work. The ability
>> to
>> > have multiple text spanners in a voice -- and to tweak each
>> independently
>> > -- is something I've wanted in LilyPond for many years. (I responded to
>> a
>> > different thread about this a touch too early only moments ago;
>> apologies,
>> > catching up on list mail.) This is really incredibly exciting to me,
>> and I
>> > think it will be to very many other composers once the ability is made
>> > clear in a public release (and in the docs).
>> >
>> > For what it's worth, I'd very much like to request the promotion of this
>> > work to a fully acknowledged new feature (respecting, of course, the
>> needs
>> > of feature sequencing in the release process).
>> >
>> > I'm not quite sure what the best (user) interface for this is. I suppose
>> > \startTextSpan[One|Two|Three|Four] will work. Though it seems like
>> > \startTextSpan #1 or \startTextSpan #"fancy-spanner-name" would be a
>> more
>> > complete generalization of the feature.
>>
>> \=1\startTextSpan ... \=1\endTextSpan already work as a user interface.
>> It's just that there is nothing that would actually _heed_ the settings
>> of "spanner-id" achieved in that manner yet.
>>
>>
> This works wonderfully well as an interface with the engraver I posted.
> Thank you so much!  Now it is possible to remove all the extra definitions
> of \startTextSpanEightyFour and the like.
>
> See attached.
>
> DN
>
> %
>
>



-- 
Trevor Bača
www.trevorbaca.com
___
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user