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

Reply via email to