On Mon, 25 Feb 2019 at 23:14, Urs Liska <[email protected]> wrote:
> 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
> [email protected]
> https://lists.gnu.org/mailman/listinfo/lilypond-user
Hi Urs,
FWIW, I don’t really see key signatures & time signatures as part of the
measure proper, and don’t mind the look of those examples.
That’s some impressive coding!
Vaughan
_______________________________________________
lilypond-user mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/lilypond-user