Re: how to change extents of a grob?
Werner LEMBERG writes: > Dear LilyPonders, > > > I can get the extents of a grob with `ly:grob-extent`. What is the > corresponding Scheme function to set the extents? > > Or to ask in a different way: At the time when properties are > processed and you have to manipulate stencils, changing the stencil of > a grob doesn't change the extents of this grob, AFAICS. You are not supposed to change stencils at all. They are not entities with identity. It's like asking how to change the exponent of a floating point number. Whatever ability on the machine level exists for that, it does not make sense to export an interface. > How can I adjust the extents at this stage to fit the dimensions of > the stencil (even if LilyPond no longer needs and/or uses the values > for positioning)? Create a new stencil with different dimensions and use that. -- David Kastrup
Re: how to change extents of a grob?
>> Or to ask in a different way: At the time when properties are >> processed and you have to manipulate stencils, changing the stencil >> of a grob doesn't change the extents of this grob, AFAICS. > > You are not supposed to change stencils at all. They are not > entities with identity. > > Create a new stencil with different dimensions and use that. OK, thanks. Werner
Custom Spanner with variable length sections
I need a custom spanner that has x sections with different symbols. This is going to be tricky so any help is appreciated. I already have a hacky solution for fixed length spanners but it is pain to maintain it. I'd like a more usable solution that can handle variable lengths. It would be nice to have control over the percentage that each section takes. e.g. #'(20 30 50) results: --***# I imagine it would need to check the length of the section and divide it by the X-extent of the symbol and then round the number to get the number of symbols that fit inside the section. The problem is that the code needs to check somehow if the surrounding sections don't fill up or overflow to avoid missing symbols or collisions between sections especially the inner ones. Trills are concatenated symbols so they aren't always 100% of the computed width. Maybe it would be useful to also allow separate symbols for each transition between sections. That would help in some cases. Also line breaks are as always a problem. Not only the line breaks must work but also the pattern needs to apply for the whole spanner and not repeat for each broken part.
Re: Custom Spanner with variable length sections
Hi Dimitris, > I need a custom spanner that has x sections with different symbols. This is > going to be tricky so any help is appreciated. https://github.com/davidnalesnik/lilypond-text-spanner-inner-texts Hope that helps! Kieren.
Re: bug in magnetic snapping lyrics engraver
> There is a problem with ligatures at the syllable boundaries (and > kerning). [...] it is not sufficient to shift the right syllable > in a syllable pair to the left. Instead, the following should be > done. [...] Meanwhile I could implement this :-) I will submit a MR soon. Werner
Re: bug in magnetic snapping lyrics engraver
Le 14/04/2022 à 17:39, Werner LEMBERG a écrit : There is a problem with ligatures at the syllable boundaries (and kerning). [...] it is not sufficient to shift the right syllable in a syllable pair to the left. Instead, the following should be done. [...] Meanwhile I could implement this :-) I will submit a MR soon. How did you do that? Sorry to rain on your parade, but I would not want you to put a lot of work in it if it will not be of mergeable quality. Jean
Re: how to change extents of a grob?
Le 14/04/2022 à 11:41, Werner LEMBERG a écrit : Or to ask in a different way: At the time when properties are processed and you have to manipulate stencils, changing the stencil of a grob doesn't change the extents of this grob, AFAICS. You are not supposed to change stencils at all. They are not entities with identity. Create a new stencil with different dimensions and use that. OK, thanks. I believe you are talking about different things. You shouldn't mutate the internal expression contained in a stencil, sure. But a grob does have identity. I understood Werner's question as "how to get grob's extents recomputed when I do (ly:grob-set-property! grob 'stencil some-new-stencil)?". There is no general answer. If they have not been computed yet, no problem. If they have, it is almost certainly too late to get them recomputed. True, you can do (ly:grob-set-property! grob '{X,Y}-extent (ly:stencil-extent the-stencil {X,Y})). However, grob extents and coordinates are cached in C++ members as soon as they have been computed once, to make their retrieval cheaper because it's done often. Thus, modifying the {X,Y}-extent properties will not affect code that gets them via ly:grob-extent or its C++ equivalent. The solution is to try hard to write your code in a functional way, with properties computed on-demand via callbacks rather than set at a specific point of time. The grob-transformer often helps. Best, Jean
Re: bug in magnetic snapping lyrics engraver
> How did you do that? Sorry to rain on your parade, but I would not > want you to put a lot of work in it if it will not be of mergeable > quality. Attached. In the end the necessary modifications were surprisingly minor. Please comment, there is certainly room for improvements. Werner diff --git a/lily/lyric-hyphen.cc b/lily/lyric-hyphen.cc index 23cd76bd94..897de7d7f7 100644 --- a/lily/lyric-hyphen.cc +++ b/lily/lyric-hyphen.cc @@ -48,6 +48,10 @@ Lyric_hyphen::print (SCM smob) && !from_scm (get_property (me, "after-line-breaking" return SCM_EOL; + // Ensure that bounds are displaced first. + (void) get_property (bounds[LEFT], "after-line-breaking"); + (void) get_property (bounds[RIGHT], "after-line-breaking"); + Grob *common = bounds[LEFT]->common_refpoint (bounds[RIGHT], X_AXIS); Interval span_points; diff --git a/scm/scheme-engravers.scm b/scm/scheme-engravers.scm index 07e3be3691..5131beef1f 100644 --- a/scm/scheme-engravers.scm +++ b/scm/scheme-engravers.scm @@ -943,6 +943,101 @@ Engraver to print a line between two @code{Fingering} grobs."))) (description . "Create repeat counts within lyrics for modern transcriptions of Gregorian chant."))) +(define (Left_hyphen_pointer_engraver context) + (let ((hyphen #f) +(text #f)) +(make-engraver + (acknowledgers + ((lyric-syllable-interface engraver grob source-engraver) + (set! text grob))) + (end-acknowledgers + ((lyric-hyphen-interface engraver grob source-engraver) + (when (not (grob::has-interface grob 'lyric-space-interface)) + (set! hyphen grob + ((stop-translation-timestep engraver) + (when (and text hyphen) +(ly:grob-set-object! text 'left-hyphen hyphen)) + (set! text #f) + (set! hyphen #f) + +(define-public (lyric-text::apply-magnetic-offset! grob) + "If the space between two syllables is less than the value in +property @code{LyricText@/.details@/.squash-threshold}, move the right +syllable to the left so that it gets concatenated with the left +syllable. + +Use this function as a hook for +@code{LyricText@/.after-@/line-@/breaking} if the +@code{Left_@/hyphen_@/pointer_@/engraver} is active." + (let ((hyphen (ly:grob-object grob 'left-hyphen #f))) +(when hyphen + (let ((left-text (ly:spanner-bound hyphen LEFT))) +(when (grob::has-interface left-text 'lyric-syllable-interface) + (let* ((common (ly:grob-common-refpoint grob left-text X)) + (this-x-ext (ly:grob-extent grob common X)) + (left-x-ext + (begin +;; Trigger magnetism for left-text. +(ly:grob-property left-text 'after-line-breaking) +(ly:grob-extent left-text common X))) + ;; `delta` is the gap width between two syllables. + (delta (- (interval-start this-x-ext) + (interval-end left-x-ext))) + (details (ly:grob-property grob 'details)) + (threshold (assoc-get 'squash-threshold details 0.2))) +(when (< delta threshold) + (let* (;; We have to manipulate the input text so that + ;; ligatures crossing syllable boundaries are not + ;; disabled. For languages based on the Latin + ;; script this is essentially a beautification. + ;; However, for non-Western scripts it can be a + ;; necessity. + (lt (ly:grob-property left-text 'text)) + (rt (ly:grob-property grob 'text)) + ;; Append new syllable. + (ltrt (if (and (string? lt) (string? rt)) + (string-append lt rt) + (make-concat-markup (list lt rt + ;; Right-align `ltrt` to the right side. + (markup (grob-interpret-markup + grob + (make-translate-markup + (cons (interval-length this-x-ext) 0) + (make-right-align-markup ltrt) +(begin + ;; Don't print `left-text`. + (ly:grob-set-property! left-text 'stencil #f) + ;; Set text and stencil (which holds all collected + ;; syllables so far) and shift it to the left. + (ly:grob-set-property! grob 'text ltrt) + (ly:grob-set-property! grob 'stencil markup) + (ly:grob-translate-axis! grob (- delta) X)) + +(ly:register-translator + Left_hyphen_pointer_engraver 'Left_hyphen_pointer_engraver + '((grobs-created . ()) + (events-accepted . ()) + (properties-read . ()) + (properties-written . ()) + (description . "\ +Collect syllable-hyphen-syllable occurrences in lyrics and store them
Re: Custom Spanner with variable length sections
Le 14/04/2022 à 16:09, Kieren MacMillan a écrit : Hi Dimitris, I need a custom spanner that has x sections with different symbols. This is going to be tricky so any help is appreciated. https://github.com/davidnalesnik/lilypond-text-spanner-inner-texts Ok, I'm not sure if this solves the problem fully, so I'll post what I had started writing anyway: \version "2.22.2" #(define (define-grob! grob-name grob-entry) (set! all-grob-descriptions (cons ((@@ (lily) completize-grob-entry) (cons grob-name grob-entry)) all-grob-descriptions))) #(define (partial-sums lst) (cdr (reverse! (fold (lambda (new previous) (cons (+ new (car previous)) previous)) (list 0) lst #(define (symbol-filler::print grob) (let* ((widths (ly:grob-property grob 'widths)) (symbols (ly:grob-property grob 'symbols)) (orig (ly:grob-original grob)) (siblings (ly:spanner-broken-into orig)) (sib-widths (map (lambda (sib) (let ((sys (ly:grob-system sib)) (left (ly:spanner-bound sib LEFT)) (right (ly:spanner-bound sib RIGHT))) (- (ly:grob-relative-coordinate right sys X) (ly:grob-relative-coordinate left sys X siblings)) (sib-changes (partial-sums sib-widths)) (total-spanner-width (apply + sib-widths)) (total-sym-width (apply + widths)) (normalized-syms (map (lambda (x) (* x (/ total-spanner-width total-sym-width))) widths)) (sym-changes (partial-sums normalized-syms)) (sib-stil empty-stencil) (len-so-far 0) (retval #f)) ;; Let's do an exception. This is easier written in imperative style. (while (and (pair? sib-changes) (pair? sym-changes)) (let* ((sib (car siblings)) (next-sym-maybe (car symbols)) (next-stil-maybe (grob-interpret-markup sib next-sym-maybe)) (len (interval-length (ly:stencil-extent next-stil-maybe X))) (new-len-so-far (+ len len-so-far))) (cond ((> new-len-so-far (car sib-changes)) ;; Used full length of this broken piece. Set ;; its stencil and start using the next. (if (eq? grob (car siblings)) (set! retval sib-stil) (ly:grob-set-property! (car siblings) 'stencil sib-stil)) (set! sib-changes (cdr sib-changes)) (set! siblings (cdr siblings)) (set! sib-stil empty-stencil)) ((> new-len-so-far (car sym-changes)) ;; Done with this symbol, start using the next. (set! sym-changes (cdr sym-changes)) (set! symbols (cdr symbols))) (else (set! sib-stil (ly:stencil-stack sib-stil X RIGHT next-stil-maybe 0)) (set! len-so-far new-len-so-far) retval)) #(define-grob! 'SymbolFiller `((direction . ,DOWN) (normalized-endpoints . ,ly:spanner::calc-normalized-endpoints) (stencil . ,symbol-filler::print) (staff-padding . 3.0) (symbols . ,(grob::calc-property-by-copy 'symbols)) (widths . ,(grob::calc-property-by-copy 'widths)) (Y-offset . ,ly:side-position-interface::y-aligned-side) (meta . ((class . Spanner) (interfaces . (side-position-interface)) #(define (Symbol_filler_engraver context) (let ((filler #f) (ev #f)) (make-engraver (listeners ((symbol-filler-event engraver event) (set! ev event))) ((process-music engraver) (if ev (let ((d (ly:event-property ev 'span-direction))) (if (eqv? d LEFT) (begin (set! filler (ly:engraver-make-grob engraver 'SymbolFiller ev)) (ly:spanner-set-bound! filler LEFT (ly:context-property context 'currentMusicalColumn))) (begin (ly:spanner-set-bound! filler RIGHT (ly:context-property context 'currentMusicalColumn)) (ly:engraver-announce-end-grob engraver filler ev)) ((stop-translation-timestep engraver) (set! ev #f) \layout { \context { \Global \grobdescriptions #all-grob-descriptions } \context { \Voice \consists #Symbol_filler_engraver } } #(define (define-event! type properties) (set! properties (assoc-set! properties 'name type)) (hashq-set! music-name-to-property-table type properties) (set! music-descriptions
Off-topic: What do you guys think of the upside-down music?
Hi; Off-topic: What do you guys think of the upside-down music? On youtube: https://www.youtube.com/channel/UCrLBkLxyE7T1cyv_4ykGTrg Upside-down Scores Example: Für Elise Upside-down (new version, with Score) https://www.youtube.com/watch?v=q2vsAua8FxM How is this done? Can this be done with Lilypond? Just curious.. Amusing... Ken Wolcott
Re: Off-topic: What do you guys think of the upside-down music?
Le 14/04/2022 à 21:58, Kenneth Wolcott a écrit : Hi; Off-topic: What do you guys think of the upside-down music? On youtube: https://www.youtube.com/channel/UCrLBkLxyE7T1cyv_4ykGTrg Upside-down Scores Example: Für Elise Upside-down (new version, with Score) https://www.youtube.com/watch?v=q2vsAua8FxM How is this done? Can this be done with Lilypond? Just curious.. Amusing... Ken Wolcott \version "2.22.2" upsideDown = #(define-music-function (music) (ly:music?) (for-some-music (lambda (m) (let ((p (ly:music-property m 'pitch #f))) (if p (let ((n (ly:pitch-transpose #{ cis' #} (ly:pitch-diff #{ des' #} p (ly:music-set-property! m 'pitch n #f) music) music) RH = \relative { \time 3/8 \partial 8 e''16 dis e dis e b d c a8 r16 c, e a b8 r16 e, gis b c8 r16 } LH = \relative { \time 3/8 \partial 8 s8 s4. a,16 e' a r r8 e,16 e' gis r r8 a,16[ e' a] } \score { \header { piece = "Lettre à Élise" } << \new Staff \RH \new Staff { \clef bass \LH } >> } \score { \header { piece = \markup \scale #'(1 . -1) "Lettre à Élise" } \upsideDown << \new Staff { \key bes \major \LH } \new Staff { \clef bass \key bes \major \RH } >> }
Tags for contexts without duration
I often find myself in need of offsetting some tempo or rehearsal marks for certain parts but not the full score but tags won't work in this case since I can't have two marks at the same location on a single context. It is a lot of work to duplicate the whole context just to differentiate a few markings. Are there any tricks to apply tags on specific marks or markups only? That would be so useful Can Lilypond be made aware of which file it outputs to? if file A.ly do this else if file B.ly do that else do something else. Maybe that doesn't make sense. It would be cool if I could specify the offsets based on a file by file basis.
Cross-staff arpeggios with a grace note
I am having trouble with arpeggios and grace notes again. In this situation, I have a cross-staff arpeggio of a chord with a grace note (see attachment). LilyPond's default is to put the arpeggio and grace note on top of each other. Jean taught me the trick of putting the arpeggio on the grace note and adjusting the arpeggio's length and position from there, like this: %%% \version "2.22.2" rightHand = { e'2 } leftHand = \relative { \clef bass << { \slashedGrace { e8 \tweak positions #'(-4.5 . 5) \tweak extra-spacing-width #'(-1 . 0) \tweak X-offset -1 \arpeggio } 2 } \\ { 2 } >> } \new PianoStaff << \new Staff \rightHand \new Staff \leftHand >> %%% This almost produces what I want. The problem is I can't get the arpeggio to cross into the upper staff. If you make the arpeggio higher than a certain amount (that is, \tweak positions #'(-4.5 . 5) with a cdr of more than 5 or so) the upper staff shies away from the arpeggio. Any help getting the arpeggio past the lower part of the upper staff will be appreciated. -- Knute Snortum
Re: bug in magnetic snapping lyrics engraver
Hi all, On 4/6/22 20:17, Jean Abou Samra wrote: > Le 06/04/2022 à 14:33, Werner LEMBERG a écrit : >> Is someone taking care of bugs in the magnetic snapping lyrics >> engraver? Here is an example where it fails to position lyrics >> correctly (see last system in the image). >> >> >> Werner >> >> >> PS: I've attached a version of `magnetic-lyrics.ily` that actually >> works with the current development version (using an updated >> `add-grob-definition` routine). > > > > To be honest, I don't know why the snippet is so complicated. > I'd just have done: One of the reasons might be that all participants have been 8 years younger and less experienced back then, and *some* later touches (at least mine) have been made by the trusted techniques of shotgun debugging and interpreter error-driven (rather than test-driven) development. And folks like Harm only had so much chance to tidy up my mess. ;-) My literally last exposure to Lilypond was meeting you folks in Jan 2020 in Salzburg, and I'll need to dig out my old tests, but I'll give it a shot; having this integrated would be such an amazing improvement. When it comes to LyricHyphen handling, some pieces in this thread might be relevant as well: https://mail.gnu.org/archive/html/lilypond-user/2016-12/msg00361.html Unfortunately IMHO, Knut's work on automatic LyricExtenders has never reached its prime time... Cheers, Alex smime.p7s Description: S/MIME Cryptographic Signature
Re: Cross-staff arpeggios with a grace note
I think there might be a more beautiful solutions to your whole situation, but I’m too tired to figure it out right now, so: You can change the arpeggio’s Y-extent to prevent it from pushing away the other staff. %%% \version "2.22.2" rightHand = { e'2 } leftHand = \relative { \clef bass << { \slashedGrace { e8 \tweak positions #'(-4.5 . 7) \tweak extra-spacing-width #'(-1 . 0) \tweak X-offset -1 \tweak Y-extent #'(-4.5 . 2) \arpeggio } 2 } \\ { 2 } >> } \new PianoStaff << \new Staff \rightHand \new Staff \leftHand >> %%% HTH /Leo > 14 apr. 2022 kl. 23:06 skrev Knute Snortum : > > I am having trouble with arpeggios and grace notes again. In this > situation, I have a cross-staff arpeggio of a chord with a grace note > (see attachment). LilyPond's default is to put the arpeggio and grace > note on top of each other. Jean taught me the trick of putting the > arpeggio on the grace note and adjusting the arpeggio's length and > position from there, like this: > > %%% > \version "2.22.2" > > rightHand = { > e'2 > } > > leftHand = \relative { > \clef bass > << >{ > \slashedGrace { >e8 >\tweak positions #'(-4.5 . 5) >\tweak extra-spacing-width #'(-1 . 0) >\tweak X-offset -1 >\arpeggio > } > 2 >} >\\ >{ > 2 >} >>> > } > > \new PianoStaff << > \new Staff \rightHand > \new Staff \leftHand >>> > %%% > > This almost produces what I want. The problem is I can't get the > arpeggio to cross into the upper staff. If you make the arpeggio > higher than a certain amount (that is, \tweak positions #'(-4.5 . 5) > with a cdr of more than 5 or so) the upper staff shies away from the > arpeggio. > > Any help getting the arpeggio past the lower part of the upper staff > will be appreciated. > > -- > Knute Snortum >
Re: Cross-staff arpeggios with a grace note
Le 14/04/2022 à 23:06, Knute Snortum a écrit : I am having trouble with arpeggios and grace notes again. In this situation, I have a cross-staff arpeggio of a chord with a grace note (see attachment). LilyPond's default is to put the arpeggio and grace note on top of each other. Jean taught me the trick of putting the arpeggio on the grace note and adjusting the arpeggio's length and position from there, like this: %%% \version "2.22.2" rightHand = { e'2 } leftHand = \relative { \clef bass << { \slashedGrace { e8 \tweak positions #'(-4.5 . 5) \tweak extra-spacing-width #'(-1 . 0) \tweak X-offset -1 \arpeggio } 2 } \\ { 2 } >> } \new PianoStaff << \new Staff \rightHand \new Staff \leftHand %%% This almost produces what I want. The problem is I can't get the arpeggio to cross into the upper staff. If you make the arpeggio higher than a certain amount (that is, \tweak positions #'(-4.5 . 5) with a cdr of more than 5 or so) the upper staff shies away from the arpeggio. Any help getting the arpeggio past the lower part of the upper staff will be appreciated. The magic incantation would be \tweak vertical-skylines ##f. \version "2.22.2" rightHand = { e'2 } leftHand = \relative { \clef bass << { \slashedGrace { e8 \tweak positions #'(-4.5 . 10) \tweak extra-spacing-width #'(-1 . 0) \tweak X-offset -1 \tweak vertical-skylines ##f \arpeggio } 2 } \\ { 2 } >> } \new PianoStaff << \new Staff \rightHand \new Staff \leftHand >> Jean
Re: Cross-staff arpeggios with a grace note
On Thu, Apr 14, 2022 at 2:23 PM Jean Abou Samra wrote: >> You can change the arpeggio’s Y-extent to prevent it from pushing away the >> other staff. ... > The magic incantation would be \tweak vertical-skylines ##f. Thanks Jean and Leo, those work great! -- Knute Snortum
Re: bug in magnetic snapping lyrics engraver
Le 14/04/2022 à 18:18, Werner LEMBERG a écrit : How did you do that? Sorry to rain on your parade, but I would not want you to put a lot of work in it if it will not be of mergeable quality. Attached. In the end the necessary modifications were surprisingly minor. Please comment, there is certainly room for improvements. Thanks. This is a bit what I feared: in this state, there is potential for things going wrong with other after-line-breaking callbacks. Those are the kind of thing that can be buggy in obscure circumstances. I'm a little nervous on having my "off-the-top" / "first thing that seemed to work" solution in the code base :-) OTOH, it's *probably* not too difficult to refactor this to use a separate 'original-text property and a 'text property computed by a callback, with X-offset computed only after-line-breaking, X-extent left empty and springs-and-rods doing the magic that would otherwise be done by Separation_item::set_distance, at the condition of letting Grob::extent skip the X-offset calculation in case the extent is found to be empty (which could be a good idea regardless actually). Or something like that. Too bad that we don't have pure widths (we could if I finally managed to finish a big patch that has been pending for about a year), but it should be possible to do without I think. I think. But right now, I'm a bit swamped due to a somewhat important exam next Thursday. [Alex; glad to meet you BTW] My literally last exposure to Lilypond was meeting you folks in Jan 2020 in Salzburg, Well, not me ;-) (I knew little about LilyPond at that time and had not started to contribute.) and I'll need to dig out my old tests, but I'll give it a shot; having this integrated would be such an amazing improvement. If you guys are ready to clean up this thing, that would be a relief for me given the amount of other contributions that I am trying to get around to. I know I was a bit elliptic above (too tired ATM), but I am happy to provide guidance and discuss solutions. Jean
Re: Tags for contexts without duration
Le 14/04/2022 à 22:44, Dimitris Marinakis a écrit : I often find myself in need of offsetting some tempo or rehearsal marks for certain parts but not the full score but tags won't work in this case since I can't have two marks at the same location on a single context. Not sure I understand the problem? \version "2.22.2" mus = { \tag #'part \once \override Score.RehearsalMark.X-offset = 8 \mark \default c' } % Conductor \removeWithTag #'part \mus % Parts { \mus } Best, Jean
Re: Off-topic: What do you guys think of the upside-down music?
Thanks, Jean! This is cool! Not that I would do anything with it, but it sure is nice to know that there seems to be no limit to what Lilypond can do :-) On Thu, Apr 14, 2022 at 1:18 PM Jean Abou Samra wrote: > > > > Le 14/04/2022 à 21:58, Kenneth Wolcott a écrit : > > Hi; > > > >Off-topic: What do you guys think of the upside-down music? > > > > On youtube: > > > > https://www.youtube.com/channel/UCrLBkLxyE7T1cyv_4ykGTrg > > > > Upside-down Scores > > > > Example: > > Für Elise Upside-down (new version, with Score) > > https://www.youtube.com/watch?v=q2vsAua8FxM > > > > How is this done? Can this be done with Lilypond? Just curious.. > > > > Amusing... > > > > Ken Wolcott > > \version "2.22.2" > > upsideDown = > #(define-music-function (music) (ly:music?) > (for-some-music > (lambda (m) >(let ((p (ly:music-property m 'pitch #f))) > (if p > (let ((n (ly:pitch-transpose #{ cis' #} (ly:pitch-diff #{ > des' #} p >(ly:music-set-property! m 'pitch n >#f) > music) > music) > > RH = \relative { >\time 3/8 >\partial 8 >e''16 dis >e dis e b d c >a8 r16 c, e a >b8 r16 e, gis b >c8 r16 > } > > LH = \relative { >\time 3/8 >\partial 8 >s8 >s4. >a,16 e' a r r8 >e,16 e' gis r r8 >a,16[ e' a] > } > > > \score { >\header { > piece = "Lettre à Élise" >} ><< > \new Staff \RH > \new Staff { \clef bass \LH } >>> > } > > \score { >\header { > piece = \markup \scale #'(1 . -1) "Lettre à Élise" >} >\upsideDown << > \new Staff { \key bes \major \LH } > \new Staff { \clef bass \key bes \major \RH } >>> > } > > > >
Re: bug in magnetic snapping lyrics engraver
>> Attached. In the end the necessary modifications were surprisingly >> minor. Please comment, there is certainly room for improvements. > > Thanks. This is a bit what I feared: in this state, there is > potential for things going wrong with other after-line-breaking > callbacks. Those are the kind of thing that can be buggy in obscure > circumstances. I'm a little nervous on having my "off-the-top" / > "first thing that seemed to work" solution in the code base :-) I think your code is very clear and easy to understand. My extensions aren't complicated either. It also works nicely and flawless in combination with the new `VaticanaLyrics` context. So please be more specific about your fears. You told us that you are working on the breaking algorithm since a few months, so I guess you are the best person to voice objections and give counterexamples. Kieren, can you test this, too? We should probably continue the discussion on lilypond-devel, since it seems to get bloody technical. :-) > OTOH, it's *probably* not too difficult to refactor this to use a > separate 'original-text property and a 'text property computed by a > callback, with X-offset computed only after-line-breaking, X-extent > left empty and springs-and-rods doing the magic that would otherwise > be done by Separation_item::set_distance, at the condition of > letting Grob::extent skip the X-offset calculation in case the > extent is found to be empty (which could be a good idea regardless > actually). This is way too complicated for me, sorry. > Or something like that. Too bad that we don't have pure widths (we > could if I finally managed to finish a big patch that has been > pending for about a year), but it should be possible to do without I > think. I think. Well, I fear I can't help you with the coding if you think this is the best route to go. But as usual: The better is the enemy of the good :-) > But right now, I'm a bit swamped due to a somewhat important exam > next Thursday. I wish you success! > If you guys are ready to clean up this thing, that would be a relief > for me given the amount of other contributions that I am trying to > get around to. Define 'clean up'. AFAICS, what you have outlined above is not a cleanup but a complete reimplementation based on a different algorithm... Werner
Re: bug in magnetic snapping lyrics engraver
>> How did you do that? Sorry to rain on your parade, but I would not >> want you to put a lot of work in it if it will not be of mergeable >> quality. > > Attached. In the end the necessary modifications were surprisingly > minor. Please comment, there is certainly room for improvements. Attached is another version for testing without the need to patch LilyPond. Werner % magnetic-lyrics.ily % % written by % Jean Abou Samra % Werner Lemberg % % Version 2022-Apr-15 \version "2.23.7" #(define (Left_hyphen_pointer_engraver context) "Collect syllable-hyphen-syllable occurrences in lyrics and store them in properties. This engraver only looks to the left. For example, if the lyrics input is @code{foo -- bar}, it does the following. @itemize @bullet @item Set the @code{text} property of the @code{LyricHyphen} grob between @q{foo} and @q{bar} to @code{foo}. @item Set the @code{left-hyphen} property of the @code{LyricText} grob with text @q{foo} to the @code{LyricHyphen} grob between @q{foo} and @q{bar}. @end itemize Use this auxiliary engraver in combination with the @code{lyric-@/text::@/apply-@/magnetic-@/offset!} hook." (let ((hyphen #f) (text #f)) (make-engraver (acknowledgers ((lyric-syllable-interface engraver grob source-engraver) (set! text grob))) (end-acknowledgers ((lyric-hyphen-interface engraver grob source-engraver) (when (not (grob::has-interface grob 'lyric-space-interface)) (set! hyphen grob ((stop-translation-timestep engraver) (when (and text hyphen) (ly:grob-set-object! text 'left-hyphen hyphen)) (set! text #f) (set! hyphen #f) #(define (lyric-text::apply-magnetic-offset! grob) "If the space between two syllables is less than the value in property @code{LyricText@/.details@/.squash-threshold}, move the right syllable to the left so that it gets concatenated with the left syllable. Use this function as a hook for @code{LyricText@/.after-@/line-@/breaking} if the @code{Left_@/hyphen_@/pointer_@/engraver} is active." (let ((hyphen (ly:grob-object grob 'left-hyphen #f))) (when hyphen (let ((left-text (ly:spanner-bound hyphen LEFT))) (when (grob::has-interface left-text 'lyric-syllable-interface) (let* ((common (ly:grob-common-refpoint grob left-text X)) (this-x-ext (ly:grob-extent grob common X)) (left-x-ext (begin ;; Trigger magnetism for left-text. (ly:grob-property left-text 'after-line-breaking) (ly:grob-extent left-text common X))) ;; `delta` is the gap width between two syllables. (delta (- (interval-start this-x-ext) (interval-end left-x-ext))) (details (ly:grob-property grob 'details)) (threshold (assoc-get 'squash-threshold details 0.2))) (when (< delta threshold) (let* (;; We have to manipulate the input text so that ;; ligatures crossing syllable boundaries are not ;; disabled. For languages based on the Latin ;; script this is essentially a beautification. ;; However, for non-Western scripts it can be a ;; necessity. (lt (ly:grob-property left-text 'text)) (rt (ly:grob-property grob 'text)) ;; Append new syllable. (ltrt (if (and (string? lt) (string? rt)) (string-append lt rt) (make-concat-markup (list lt rt ;; Right-align `ltrt` to the right side. (markup (grob-interpret-markup grob (make-translate-markup (cons (interval-length this-x-ext) 0) (make-right-align-markup ltrt) (begin ;; Don't print `left-text`. (ly:grob-set-property! left-text 'stencil #f) ;; Set text and stencil (which holds all collected ;; syllables so far) and shift it to the left. (ly:grob-set-property! grob 'text ltrt) (ly:grob-set-property! grob 'stencil markup) (ly:grob-translate-axis! grob (- delta) X)) #(define (lyric-hyphen::displace-bounds-first grob) ;; Make very sure this callback isn't triggered too early. (let ((left (ly:spanner-bound grob LEFT)) (right (ly:spanner-bound grob RIGHT))) (ly:grob-property left 'after-line-breaking) (ly:grob-property right 'after-line-breaking) (ly:lyric-hyphen::print grob))) \layout { \context { \Lyrics \consists #Left_h