Discussion:
markup column with baseline-skip relative to font size
Kieren MacMillan
2018-11-17 01:35:58 UTC
Permalink
Hi all,

In the snippet below, you’ll see that I’m attempting to override Fingering in a custom context to add a caret (^) on top of the [formatted] finger number to make it into a scale degree.

The "padding" between the caret and the number isn’t relative, as I would like it to be: it should always be some fraction of the font height (either x-height or m-height or M-height or similar). Is there a way to accomplish this? Bonus points if the top of the caret and the baseline of the numbers remain the same even when using lowercase numerals.

Thanks,
Kieren.


%%% SNIPPET BEGINS

\version "2.19.80"

\layout {
\context {
\Voice
\name UrlinieVoice
\inherit-acceptability "UrlinieVoice" "Voice"
\stemUp
\override Beam.positions = #'(7 . 7)
\override NoteHead.duration-log = #1
\override Fingering.padding = #1
\override Fingering.stencil = #(lambda (grob)
(let ((text (ly:grob-property grob 'text)))
(grob-interpret-markup grob
(markup #:text
#:override '(baseline-skip . 1.75)
#:center-column ("^" text)))))
}
}

stuff = \fixed c'' { g8[-5 f-4 e-3 d-2 c-1] }

\new UrlinieVoice \stuff

\new UrlinieVoice \with { \override Fingering.font-size = #4 } \stuff

%%% SNIPPET ENDS
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: ***@kierenmacmillan.info
Thomas Morley
2018-11-17 11:03:36 UTC
Permalink
Hi Kieren,

Am Sa., 17. Nov. 2018 um 02:36 Uhr schrieb Kieren MacMillan
Post by Kieren MacMillan
Hi all,
In the snippet below, you’ll see that I’m attempting to override Fingering in a custom context to add a caret (^) on top of the [formatted] finger number to make it into a scale degree.
The "padding" between the caret and the number isn’t relative, as I would like it to be: it should always be some fraction of the font height (either x-height or m-height or M-height or similar).
I don't think that's the way to go.
Post by Kieren MacMillan
Is there a way to accomplish this?
Default \center-column does not adjust baseline-skip according to the
grobs font-size.
Below I wrote 'center-column-fontsize-adjusted-baseline-skip' (you
should probably rename it, lol), which does so. Modeled after how
\fontsize deals with baseline-skip.
Post by Kieren MacMillan
Bonus points if the top of the caret and the baseline of the numbers remain the same even when using lowercase numerals.
Not sure what you mean here, could you provide some example-code?

But here the code. I dropped all about 'UrlinieVoice', not needed for
a minimal, imho.
Is this what you aim at?

\version "2.19.82"


#(define-markup-command
(center-column-fontsize-adjusted-baseline-skip layout props args)
(markup-list?)
#:category align
#:properties ((font-size 0)
(baseline-skip))

;; 'general-column' is not public, thus copied from define-markup.scm
;; and inserted here
(define (general-column align-dir baseline mols)
"Stack @var{mols} vertically, aligned to @var{align-dir} horizontally."

(let* ((aligned-mols
(map (lambda (x) (ly:stencil-aligned-to x X align-dir)) mols))
(stacked-stencil (stack-lines -1 0.0 baseline aligned-mols))
(stacked-extent (ly:stencil-extent stacked-stencil X)))
(ly:stencil-translate-axis stacked-stencil (- (car stacked-extent)) X)))

(general-column CENTER (* baseline-skip (magstep font-size))
(interpret-markup-list layout props args)))


%% Rewritten for easy exchanging procedures while testing
#(define (caret-finger proc)
(lambda (grob)
(let ((text (ly:grob-property grob 'text)))
(grob-interpret-markup grob
(make-text-markup
(make-override-markup '(baseline-skip . 1.75)
(proc (list "^" text))))))))

mus = { a'8-4 8-3 8-2 8-1 }

%% default
{
\override Fingering.stencil =
#(caret-finger make-center-column-markup)
\mus
\override Fingering.font-size = #4
\mus
}

%% new code
{
\override Fingering.stencil =
#(caret-finger make-center-column-fontsize-adjusted-baseline-skip-markup)
\mus
\override Fingering.font-size = #4
\mus
}


Cheers,
Harm
Thomas Morley
2018-11-17 12:01:22 UTC
Permalink
Am Sa., 17. Nov. 2018 um 12:03 Uhr schrieb Thomas Morley
Post by Thomas Morley
Default \center-column does not adjust baseline-skip according to the
grobs font-size.
Below I wrote 'center-column-fontsize-adjusted-baseline-skip' (you
should probably rename it, lol), which does so. Modeled after how
\fontsize deals with baseline-skip.
And this causes a huge glitch.
'center-column-fontsize-adjusted-baseline-skip' is not compatible with
\fontsize, baseline-skip would be tackled twice ...

One could circumvent it by refusing to use /fontsize, but \magnify
#(magstep <value>).

Well, I'll should rethink the whole matter....


Cheers,
Harm
Kieren MacMillan
2018-11-17 12:39:51 UTC
Permalink
Hi Thomas,

Thanks for trying.

I really don’t understand why Lilypond’s text handling is so fussy. It should be easy for the user to say “lines in a multi-line markup must be exactly *this* far apart [regardless of individual glyph height]” — in fact, it should be the default.

Cheers,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: ***@kierenmacmillan.info
Aaron Hill
2018-11-17 15:57:07 UTC
Permalink
I really don’t understand why Lilypond’s text handling is so fussy. It
should be easy for the user to say “lines in a multi-line markup must
be exactly *this* far apart [regardless of individual glyph height]” —
in fact, it should be the default.
As far as I can see, LilyPond really does try to space lines from
baseline to baseline by the amount specified. However if a line is too
tall, the underlying composition of stencils does not permit overlap and
results in lines being further away than expected. But if you can
choose a suitably large value for baseline-skip, then the spacing really
is how you describe.

Consider this extravagantly contrived example:

%%%%
\version "2.19.82"

#(define-markup-command (show-baseline-skip layout props args) (markup?)
#:properties ((baseline-skip 0))
(let* ((stencil (interpret-markup layout props args))
(x-extent (ly:stencil-extent stencil 0))
(y-extent (ly:stencil-extent stencil 1))
(x-center (* (+ (car x-extent) (cdr x-extent)) 0.5))
(path `((moveto ,(car x-extent) 0)(lineto ,(cdr x-extent) 0)
(lineto ,x-center ,(- baseline-skip))(closepath)))
(thickness (* 0.5 (ly:output-def-lookup layout
'line-thickness))))
(interpret-markup layout props (markup #:combine args
#:with-dimensions x-extent y-extent
#:with-color (rgb-color 1 0.2 0.4)
#:path thickness path))))
#(define-markup-command (show-extents layout props args) (markup?)
(let* ((stencil (interpret-markup layout props args))
(x-extent (ly:stencil-extent stencil 0))
(y-extent (ly:stencil-extent stencil 1))
(path `((moveto ,(car x-extent) ,(car y-extent))
(lineto ,(cdr x-extent) ,(car y-extent))
(lineto ,(cdr x-extent) ,(cdr y-extent))
(lineto ,(car x-extent) ,(cdr y-extent))(closepath)))
(thickness (* 0.5 (ly:output-def-lookup layout
'line-thickness))))
(interpret-markup layout props (markup #:combine args
#:with-dimensions x-extent y-extent
#:with-color (rgb-color 0.2 0.4 1)
#:path thickness path))))

\fixed c'' {
\mark \markup \fontsize #-2 {
\center-column {
\show-extents \show-baseline-skip "qb"
\show-extents \show-baseline-skip "qb"
\show-extents \show-baseline-skip "qb"
}
\center-column {
\show-extents \show-baseline-skip "x"
\show-extents \show-baseline-skip "x"
\show-extents \show-baseline-skip "x"
}
}
\override Fingering.stencil = #(lambda (grob)
(let* ((text (ly:grob-property grob 'text))
(font-size (ly:grob-property grob 'font-size 0))
(baseline-skip (ly:grob-property grob 'baseline-skip 2))
(new-baseline-skip (* baseline-skip (magstep font-size))))
(grob-interpret-markup grob (markup #:text
#:override (cons 'baseline-skip new-baseline-skip)
#:center-column ((#:show-baseline-skip #:show-extents "^")
(#:show-baseline-skip #:show-extents text)
(#:show-baseline-skip #:show-extents text))))))
\override Fingering.font-size = #0
\override Fingering.baseline-skip = #2
g16[-\finger "q" f-\finger "x" e-\finger "b"]
\override Fingering.font-size = #3
g16[-\finger "q" f-\finger "x" e-\finger "b"]
\override Fingering.baseline-skip = #0.75
g16[-\finger "q" f-\finger "x" e-\finger "b"]
}
%%%%

The blue outlines are showing the extents of the stencils and the red
triangles are visualizing the baseline-skip. If lines are being spaced
properly, the point of a triangle will lie exactly on the baseline of
the subsequent line. Any gap between triangles indicates that the
baseline-skip was not honored.

Right away, you can see the default baseline-skip for RehearsalMarks is
too small for the font size, and so the lines with both ascenders and
descenders end up being further apart than expected because
\center-column does not want to overlap stencils.

My version of your fingering stencil function computes a idealized
baseline-skip based on the current font-size and baseline-skip. This
should be close to what you originally requested, I suspect; but be
advised that in the right-most example, I have constrained the
baseline-skip such that again we see abutting stencils where there
should be overlapping, if baseline-skip were strict.

-- Aaron Hill
Kieren MacMillan
2018-11-17 16:50:56 UTC
Permalink
Hi Aaron,

WOW! Thanks for this. So interesting.

Recall that earlier in the thread, I said "Bonus points if [the fix] handles lowercase numerals"? ;)

Here’s a screenshot from the actual score I’m trying to engrave, with your function in place (minus the text duplication):



Notice that the triangles of each figure are as hoped/expected
 but the *actual baseline of the glyph* is not being honoured consistently across the various numbers: where the numerals descend (e.g., 7 and 5), everything is shifted, including the caret’s [apparent] "padding".

What can be done about this? I’ve been struggling with this kind of thing for years, with every imaginable kind of text in Lilypond: Fingering, TextScript, RehearsalMark, MetronomeMark, etc. etc. etc.

I keep getting shown — as you’ve done so fabulously here — that Lilypond "*is* using the baseline as expected"; and as a programmer, I suppose I must concede the point. But as an end-user, it isn’t doing what I expect/want it to do: in the above example, I want the *baseline aligned*, so that the carets are aligned (though the visible bottom of the numerals will not necessarily be).

I assume the padding is using the lower edge of the glyph outline (i.e., the blue box) to align; and that perfectly matches the output as seen. What I *want* is the ability to set text/markup padding to the *baseline*. It doesn’t ever seem to be possible, which forces a lot of manual effort (i.e., extra-offset for every item in which the baseline and glyph bottom edge do not coincide).

Does Lilypond not know where the baseline is exactly? That is, is this graphic function you’ve created using properties of the glyph that can’t be used automagically by Lilypond?

If Lilypond could line up baselines consistently, it would save me *SO* much tweak time. And if I’m still not understanding something about how text alignment works in Lilypond — that is, if it *can* do what I’m asking, and I’m just not finding the correct incantations — then I pity any users without my [deep] experience and [slightly less deep] technical know-how, since they can’t possibly be achieving what they want except perhaps by blind luck.

Thanks,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info <http://www.kierenmacmillan.info/>
‣ email: ***@kierenmacmillan.info <mailto:***@kierenmacmillan.info>
Aaron Hill
2018-11-17 17:03:05 UTC
Permalink
Here’s a screenshot from the actual score I’m trying to engrave, with
Notice that the triangles of each figure are as hoped/expected… but
the *actual baseline of the glyph* is not being honoured consistently
across the various numbers: where the numerals descend (e.g., 7 and
5), everything is shifted, including the caret’s [apparent] "padding".
Ah, but the 7 and 5 in that font in fact have descenders. The baseline
is not the same as the bottom extent of a glyph. For instance, round
letters (e.g. "O") will sit below the baseline slightly in order to
combat an optic illusion.

Mind you I could be mistaken, but I suspect that if you append an "x" to
each number, you'll see that the number descends. (An "x" typically
should sit on the baseline, although I have seen some brush/script fonts
where the glyph straddles.)
Does Lilypond not know where the baseline is exactly? That is, is
this graphic function you’ve created using properties of the glyph
that can’t be used automagically by Lilypond?
The baseline is always at Y coordinate zero (0) for any stencil. So I
am not measuring the font, but rather working on the assumption that
pango will align glyphs properly.

For reference, what is the font you are using?

-- Aaron Hill
Kieren MacMillan
2018-11-17 17:05:15 UTC
Permalink
Hi Aaron,
Ah, but the 7 and 5 in that font in fact have descenders. The baseline is not the same as the bottom extent of a glyph.
Yes — we’re saying the same thing. =)
For reference, what is the font you are using?
Alegreya.

Thanks,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: ***@kierenmacmillan.info
Aaron Hill
2018-11-17 17:16:30 UTC
Permalink
Post by Kieren MacMillan
Hi Aaron,
Post by Aaron Hill
Ah, but the 7 and 5 in that font in fact have descenders. The
baseline is not the same as the bottom extent of a glyph.
Yes — we’re saying the same thing. =)
Oh, I'm a dumb dumb.

Your issue is that the padding between staff and markup is using the
bottom extent, not the baseline, hence it looks off.

You might just want to clip the descenders on offending lines. Not
recommended for general use, but try:

%%%%
\version "2.19.82"

#(define-markup-command (trim-descenders layout props args) (markup?)
(let* ((stencil (interpret-markup layout props args))
(x-extent (ly:stencil-extent stencil 0))
(y-extent (ly:stencil-extent stencil 1)))
(interpret-markup layout props (markup
#:with-dimensions x-extent (cons 0 (cdr y-extent)) args))))

\fixed c'' {
\override Fingering.font-name = #"Alegreya"
\override Fingering.font-size = #4
g8-\finger "q"
g8-\finger "x"
g8-\finger "b"
g8-\finger \markup \trim-descenders "q"
}
%%%%

Side effect is, of course, overlapping. But the padding should now be
relative to the baseline (Y-coord zero) regardless of descenders.

-- Aaron Hill
Kieren MacMillan
2018-11-17 17:53:14 UTC
Permalink
Hi Aaron,
Your issue is that the padding between staff and markup is using the bottom extent, not the baseline, hence it looks off.
Exactly. And this is generally true of markup/text, I’ve found.
You might just want to clip the descenders on offending lines.
Interesting! That works well for what I want in terms of padding. I’ve added it to the Fingering.stencil callback — hence it will be "for general use", in spite of your kind warning. ;)

Thanks!
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info
‣ email: ***@kierenmacmillan.info
Kieren MacMillan
2018-11-17 18:00:14 UTC
Permalink
Hi Aaron (et al.),

Thanks to your "trim-descenders" function, the output is as follows:



The carets all line up — because the text baselines do — WITH NO INDIVIDUAL TWEAKS REQUIRED! Taking tweak-and-recompile time into account, that probably saves me an hour over the course of engraving a score of this size and complexity.

Sure, the "gap" between the bottom of the glyph and the Beam varies according to the glyph
 but in this case (i.e., with this particular usage of these text objects in this font), this is the desired compromise.

Thank you! I’m going to see how to change all my current markup functions so this outcome is a settable option (likely the default setting).

Best,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info <http://www.kierenmacmillan.info/>
‣ email: ***@kierenmacmillan.info <mailto:***@kierenmacmillan.info>
David Kastrup
2018-11-17 17:01:28 UTC
Permalink
Post by Kieren MacMillan
I assume the padding is using the lower edge of the glyph outline
(i.e., the blue box) to align; and that perfectly matches the output
as seen. What I *want* is the ability to set text/markup padding to
the *baseline*. It doesn’t ever seem to be possible, which forces a
lot of manual effort (i.e., extra-offset for every item in which the
baseline and glyph bottom edge do not coincide).
Have you tried using staff-padding ?

‘staff-padding’ (dimension, in staff space):
‘0.25’

Maintain this much space between reference points and the
staff. Its effect is to align objects of differing sizes
(like the dynamics p and f) on their baselines.
--
David Kastrup
Kieren MacMillan
2018-11-17 17:07:25 UTC
Permalink
Hi David,
Post by David Kastrup
Have you tried using staff-padding ?
Yes. Here’s the same code with #'staff-padding = #3:



In this case, that’s a Beam the Fingerings are set above, which is itself *far* above the actual Staff. So #'padding is being applied, and we’re nowhere near close enough for #'staff-padding to take effect.

Thanks,
Kieren.
________________________________

Kieren MacMillan, composer
‣ website: www.kierenmacmillan.info <http://www.kierenmacmillan.info/>
‣ email: ***@kierenmacmillan.info <mailto:***@kierenmacmillan.info>
Loading...