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
(lambda (f)
(if (null? (ly:spanner-bound f RIGHT))
(ly:spanner-set-bound! f RIGHT
(ly:context-property context 'currentMusicalColumn))))
finished)
(set! finished '()))
((finalize trans)
;; If spanner ends on spacer at end of context?
(for-each
(lambda (f)
(if (null? (ly:spanner-bound f RIGHT))
(ly:spanner-set-bound! f RIGHT
(ly:context-property context 'currentMusicalColumn))))
finished)
(set! finished '())
;; User didn't end spanner.
(for-each
(lambda (sp)
(ly:warning "incomplete spanner removed!")
(ly:grob-suicide! sp))
span)
(set! span '())))))
startTextSpanOne =
#(make-music 'TextSpanEvent 'span-direction START 'spanner-id "1")
stopTextSpanOne =
#(make-music 'TextSpanEvent 'span-direction STOP 'spanner-id "1")
startTextSpanTwo =
#(make-music 'TextSpanEvent 'span-direction START 'spanner-id "2")
stopTextSpanTwo =
#(make-music 'TextSpanEvent 'span-direction STOP 'spanner-id "2")
startTextSpanThree =
#(make-music 'TextSpanEvent 'span-direction START 'spanner-id "3")
stopTextSpanThree =
#(make-music 'TextSpanEvent 'span-direction STOP 'spanner-id "3")
%%%%%%%%%%%%%%%%%%%%%%%%%%%%% EXAMPLE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\layout {
\context {
\Voice
\remove #"Text_spanner_engraver"
\consists \schemeTextSpannerEngraver
}
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Order of lines is reversed at line break.
\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 \startTextSpanOne
d
a4
-\tweak color #magenta \startTextSpanTwo
b c
-\tweak style #'zigzag \startTextSpanThree
d
\break %% ugh--order not preserved!
a4 b c d\stopTextSpanThree
a4 b\stopTextSpanTwo
c d\stopTextSpanOne
a4 b c d\stopTextSpan
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Order is again reversed. Commenting tweaks in and out
%% modifies order in strange ways.
\relative c' {
\override TextSpanner.outside-staff-padding = 2
a4
-\tweak style ##f
-\tweak color #red
-\tweak thickness 4
\startTextSpan
b c
-\tweak style ##f
-\tweak color #darkred
-\tweak thickness 4
\startTextSpanOne
d
a4
-\tweak style ##f
-\tweak color #magenta
-\tweak thickness 4
\startTextSpanTwo
b c
-\tweak style #'zigzag
%% Comment in and watch position of zigzag line!
%-\tweak thickness 4
\startTextSpanThree
d
\break %% ugh--order not preserved!
a4 b c d\stopTextSpan
a4 b\stopTextSpanOne
c d\stopTextSpanTwo
a4 b c d\stopTextSpanThree
}
_______________________________________________
lilypond-devel mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-devel