Recently I managed (with considerable help from here) to write a
function that can a) center some arbitrary stuff in a measure and b)
print markup above/below that measure that pushes the surrounding
barlines so the markup fits in the measure. However, before I can make
this nice function available I have to resolve at least one further problem.
The function works by
- creating a markup stencil from the to-be-centered music
- creating the actual markup stencils and measuring their width
- inserting a MMR, setting its minimum-length to the determined width
(plus some padding)
- replacing the MMR's stencil with the combined stencils created earlier.
As can be seen in the attached image this works smoothly in regular
cases (first instance). However, it works *not* correctly when there is
some stuff like clefs, key or time signatures at the beginning of the
measure. The second and third instances in the image show cases where
stuff of varying width is at the beginning of the measure, and in both
cases the measure is not pushed wide enough. The same is true at the
beginning of a system.
So what I need to do is determine if there's anything at that beginning,
determine its width and calculate a value from there that I have to add
to the minimum-length override.
I know that this is not linear. In the first instance (the 4/4 time sig)
it would probably be ok to simply add the time signature's width, but in
the other instance the to-be-added width is significantly less than the
width of the combined time and the key signatures. I recall having to
deal with that issue once, I think the calculation starts from a fixed
width (2.0) and interpolates that up to a certain width when things work
"normal" again.
First thing I need is to know: is it possible to know the width of these
elements in a before-line-breaking callback? I have serious doubts
because at that point we don't even know yet whether we're at a line
break. However, in later callbacks I can't set minimum-length anymore.
If that is possible at all I'd need some help how to find the column
where all these objects may be or some property of the current measure
or the previous barline. From there I'd probably be able to get further
on my own.
Thanks
Urs
\version "2.19.82"
\include "oll-core/package.ily"
% Center a (markup) stencil against an (original) MultiMeasureRest grob
#(define (center-stencil rest-grob markup-stencil)
(let*
((rest-stencil (ly:multi-measure-rest::print rest-grob))
(centered-markup-stencil (ly:stencil-aligned-to markup-stencil X 0))
(rest-offset (interval-center (ly:stencil-extent rest-stencil X))))
;; return the self-centered time stencil offset by the rest's offset
(ly:stencil-translate-axis centered-markup-stencil rest-offset X)))
#(define (annotate-centered rest-grob markup-stencil upper-padding upper
lower-padding lower)
(let*
((base-stencil (center-stencil rest-grob markup-stencil))
(base-y-extent (ly:stencil-extent base-stencil Y))
(upper-offset (- 2 (cdr base-y-extent)))
(lower-offset (+ (car base-y-extent) 2))
(upper-stencil
(center-stencil rest-grob
(grob-interpret-markup rest-grob
(markup
#:override '(baseline-skip . 2.5) upper))))
(lower-stencil
(center-stencil rest-grob
(grob-interpret-markup rest-grob
(markup
#:override '(baseline-skip . 2.5) lower))))
(combined-stencil
(ly:stencil-combine-at-edge
(ly:stencil-combine-at-edge
base-stencil Y DOWN
lower-stencil
(+ lower-offset lower-padding))
Y UP
upper-stencil
(+ upper-offset upper-padding))))
combined-stencil))
% Center some (annotated) music in a measure
% Wrap the music in a bare \markup \score context
% and return its stencil
getBareScoreMarkupStencil =
#(define-scheme-function (grob music)(ly:grob? ly:music?)
(grob-interpret-markup grob
#{
\markup \score {
\new Staff = "centered" {
% Necessary to remove some offset to the right
% (caused by the regular system-start gap)
\once \override NoteColumn.X-offset = -2
$music
}
\layout {
ragged-right = ##t
\context {
\Score
\omit StaffSymbol
\omit Clef
\omit TimeSignature
\omit KeySignature
\omit BarLine
}
}
}
#}))
annotateCenteredMusic =
#(with-options define-music-function (music)(ly:music?)
`(strict
(? above ,markup? ,#{ \markup \null #})
(? below ,markup? ,(markup #:null)))
;; Store data in a closure to drag it over from the music-function stage
;; to before-line-breaking and stencil
(let ((upper (assq-ref props 'above))
(lower (assq-ref props 'below))
(music-stil #f)
(upper-stil #f)
(lower-stil #f)
(upper-padding 2)
(lower-padding 2))
#{
\tweak before-line-breaking
#(lambda (grob)
;; Create the three markup stencils *now* and store it in the closure
;; so we can use its dimensions to affect the layout.
(set! music-stil #{ \getBareScoreMarkupStencil #grob #music #})
(set! upper-stil (grob-interpret-markup grob upper))
(set! lower-stil (grob-interpret-markup grob lower))
(ly:grob-set-property! grob 'Y-extent
;; Include the markups in the Y-extent of the MMR
;; so it won't get cut off the page
(cons
(- 0 2 lower-padding (interval-length (ly:stencil-extent
lower-stil Y)))
(+ 2 upper-padding (interval-length (ly:stencil-extent upper-stil
Y)))))
(ly:grob-set-property! grob 'minimum-length
;; widen the measure to encompass music content, upper, and lower
markup
; TODO: This still is confused by leading Clef/Time/Key
(+ 2
(max
(interval-length (ly:stencil-extent upper-stil X))
(interval-length (ly:stencil-extent lower-stil X))
(interval-length (ly:stencil-extent music-stil X)))))
)
\tweak stencil
#(lambda (grob)
;; Replace the MMR stencil with the combined stencil created earlier
(annotate-centered grob music-stil
upper-padding upper lower-padding lower))
% TODO: make this length variable/configurable
% Ideally take it from the surrounding music/time signature
R1
#}))
\relative {
R1
\annotateCenteredMusic \with {
above = "Upper text"
below = "Lower"
} { r8 }
R1
\numericTimeSignature
\time 4/4
\annotateCenteredMusic \with {
above = "Upper text"
below = "Lower"
} { r16 }
\time 3/4
R2.
\time 4/4
\key b \major
\annotateCenteredMusic \with {
above = "Upper text"
below = "Lower"
} { r32 }
R1
}
_______________________________________________
lilypond-user mailing list
lilypond-user@gnu.org
https://lists.gnu.org/mailman/listinfo/lilypond-user