multiple TextSpanners per voice
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
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
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
> > 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
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
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
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
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
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
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
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
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
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
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
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