Re: Flexible lyric alignment
Le 22/11/2022 à 16:51, Abraham Lee a écrit : Ok, I can confirm that it works as expected. Thanks, again, Jean! No doubt I will be using this quite a lot over the coming months. Now added as https://lsr.di.unimi.it/LSR/Item?id=1154 (I didn't bother "downgrading" it to 2.22 because 2.24 should be released in December.) Best, Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
On Mon, Nov 21, 2022 at 11:21 PM Abraham Lee wrote: > > > On Mon, Nov 21, 2022 at 6:36 PM Jean Abou Samra > wrote: > >> Hi, >> >> >> Le 20/11/2022 à 21:50, Kieren MacMillan a écrit : >> >> Kieren, you've got to try this out! It will blow your mind! >> > I just took Jean’s example, and compared the output with and without >> the \include step… Truly astonishing. >> > (I haven’t tried it with my Real World Scores™, but can’t wait to do >> so!) >> > >> >> Jean, seriously, this is amazing! >> > Agreed. >> > >> >> This has turned a so-so day into an amazing one! >> >> >> >> >> Well, I didn't expect such success :) >> >> Attached is a revised version: >> >> - Stanza numbers now properly avoid the respaced lyric words >>just like they avoid lyric words by default (the problem was >>a consequence of what I said about this snippet breaking >>assumptions LilyPond makes; in this case it can be arranged), >> >> - There is a \doReserveSpace command doing what Kieren requested, >> >> - #(ly:set-option 'compile-scheme-code) is commented out for >>the time being, >> >> - Added some comments. >> >> If this looks fine to you, I'll upload it to LSR. >> >> Best, >> Jean >> > > That's exciting, Jean! Thanks so much for this. I'll test it as soon as > I'm able and report back. > Ok, I can confirm that it works as expected. Thanks, again, Jean! No doubt I will be using this quite a lot over the coming months. Best, Abraham
Re: Flexible lyric alignment
On Mon, Nov 21, 2022 at 6:36 PM Jean Abou Samra wrote: > Hi, > > > Le 20/11/2022 à 21:50, Kieren MacMillan a écrit : > >> Kieren, you've got to try this out! It will blow your mind! > > I just took Jean’s example, and compared the output with and without the > \include step… Truly astonishing. > > (I haven’t tried it with my Real World Scores™, but can’t wait to do so!) > > > >> Jean, seriously, this is amazing! > > Agreed. > > > >> This has turned a so-so day into an amazing one! > > > > > Well, I didn't expect such success :) > > Attached is a revised version: > > - Stanza numbers now properly avoid the respaced lyric words >just like they avoid lyric words by default (the problem was >a consequence of what I said about this snippet breaking >assumptions LilyPond makes; in this case it can be arranged), > > - There is a \doReserveSpace command doing what Kieren requested, > > - #(ly:set-option 'compile-scheme-code) is commented out for >the time being, > > - Added some comments. > > If this looks fine to you, I'll upload it to LSR. > > Best, > Jean > That's exciting, Jean! Thanks so much for this. I'll test it as soon as I'm able and report back. Best, Abraham
Re: Flexible lyric alignment
Hi, Le 20/11/2022 à 21:50, Kieren MacMillan a écrit : Kieren, you've got to try this out! It will blow your mind! I just took Jean’s example, and compared the output with and without the \include step… Truly astonishing. (I haven’t tried it with my Real World Scores™, but can’t wait to do so!) Jean, seriously, this is amazing! Agreed. This has turned a so-so day into an amazing one! Well, I didn't expect such success :) Attached is a revised version: - Stanza numbers now properly avoid the respaced lyric words just like they avoid lyric words by default (the problem was a consequence of what I said about this snippet breaking assumptions LilyPond makes; in this case it can be arranged), - There is a \doReserveSpace command doing what Kieren requested, - #(ly:set-option 'compile-scheme-code) is commented out for the time being, - Added some comments. If this looks fine to you, I'll upload it to LSR. Best, Jean \version "2.23.81" %{ Snippet author: Jean Abou Samra Original thread: https://lists.gnu.org/archive/html/lilypond-user/2022-11/msg00087.html This snippet gets rid of uglinesses in note spacing caused by lyrics. By default, LilyPond always puts a lyric word exactly centered under the note it attaches to. When there is a long lyric word, LilyPond reserves space between notes so that there will be no collisions in the lyrics. However, this can lead to uneven note spacing. This snippet completely removes the presence of lyrics in note spacing so that it is natural according to the note lengths, and uses a spacing algorithm that shifts lyrics automatically in order to avoid collisions. Some technical comments follow. The spacing problem is set up as a quadratic optimization problem. Each lyric word has a strength value (by default, all words have a strength of 1.0). The demerit associated to a lyric word is s(x-p)², where s is the strength, x is the X coordinate and p is the ideal X coordinate where the lyric word would be centered on its associated note. An acceptable solution is a solution where no lyric words collide. The weight of a solution is the sum of the demerits for each of the words. Solving the lyric spacing problem means finding an acceptable solution of minimal weight. In practice, words should not touch each other, but maintain a minimum distance between each other (controlled by LyricSpace.minimum-distance and LyricHyphen.minimum-distance). This is reduced to the form above by widening one of the two words for each LyricSpace or LyricHyphen grob, by the amount given by the minimum-space property. The algorithm to solve the lyric spacing problem uses dynamic programming and runs in linear time. We add words one by one from left to right. After adding each word, the problem given by the words added so far is solved. The base case (zero words) is trivial. To add a word, it is very intuitive, and not hard to prove, that the following technique works: if adding the word at its optimal position produces no collision, then keep it there; else, make this word 'push' on its left neighbor and move these two words simultaneously to the left until the optimal position for these two words together is reached; if this still produces a collision then add the third word and consider the three words stuck together, etc. Note that once two words have been stuck together, they won't need to be taken apart again: they will be adjacent ("stuck") in the final configuration. Written in this form, this algorithm looks quadratic. While probably acceptable in usual scores, this might become a problem with ly:one-line-breaking. However, with a bit of simple algebra, you can see that optimizing for two words stuck together (and, by extension, any finite number of words stuck together) is equivalent to optimizing for one single (imaginary) combined word, of which the length is the sum of the two lengths, the strength is the sum of the strengths, and the optimal coordinate is given by a simple formula (see the code). Therefore, instead of simultaneously considering two words stuck together, you can replace them with just one fresh problem variable. At each word added during the algorithm, there is a constant processing overhead, plus an overhead linear in the number of times a word is newly stuck to a group, forming a new group. If you imagine that all words start out black, and every word becomes white as soon as its group is stuck to the group on the left, it is clear that the total number of "add to group" operations is linear in the number of words. At the end, there is a step to compute the offset of each word from that of its group, which is made linear by caching the offset of a group as soon as it is visited. In this way, the total number of operations is linear. %} % #(ly:set-option 'compile-scheme-code) #(use-modules (ice-9 match) (ice-9 hash-table) (oop goops)) %% convenience stuff: #(define-syntax-rule (transform! lval proc) (se
Re: Flexible lyric alignment,Re: Flexible lyric alignment
Hi all, > Kieren, you've got to try this out! It will blow your mind! I just took Jean’s example, and compared the output with and without the \include step… Truly astonishing. (I haven’t tried it with my Real World Scores™, but can’t wait to do so!) > Jean, seriously, this is amazing! Agreed. > This has turned a so-so day into an amazing one! Between this and \alignTo, the last couple of days has advanced (accelerated, simplified, etc.) my Lilypond workflow to an almost unimaginable extent. > P.S. I hope my enthusiasm for this fix doesn't eclipse my sincere > appreciation for all the amazing work done by the regular developers past and > present. I've had lots of generous help over the years from many developers > and other users here. So grateful to you all for creating a truly awesome > tool and helping me and so many others! We are blessed here in the ’Pond. Kieren.
Re: Flexible lyric alignment
Hi Jean, > This is a vast refinement of the initial \autoMove function I love that you generate “magic” solutions with such facility, and that you still care enough to respect existing parameters (e.g., minimum-distance) and include new useful ones (e.g., details.strength). > - As said in a previous message, this is the other extreme compared > to what LilyPond does by default: lyrics are not taken into account > *at all* into note spacing. In your algorithm, is there a way to turn off the feature on a per-syllable basis? e.g., in the example you included, can we (e.g.) force the first word [“Would”] to be considered in note spacing but not any of the other syllables? Thanks again for this incredible tool! Kieren.
Re: Flexible lyric alignment,Re: Flexible lyric alignment
On Sat, Nov 19, 2022 at 6:59 PM Abraham Lee wrote: > > > On Sat, Nov 19, 2022 at 6:50 PM Abraham Lee > wrote: > >> >> >> On Sat, Nov 19, 2022 at 5:16 PM Jean Abou Samra >> wrote: >> >>> >>> >>> Le 20 nov. 2022 à 01:11, Abraham Lee a >>> écrit : >>> >>> Still running into compiler errors. I figured my version was just out of >>> date, but after downloading 2.23.81, I still get the following log: >>> >>> %<-SNIP--- >>> >>> Starting lilypond.exe 2.23.81 [tricky-lyrics.ly]... >>> Processing `K:/music-related/lilypond/snippets/lyric-autospacer/ >>> tricky-lyrics.ly' >>> Parsing... >>> K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:8:2: >>> error: Guile signaled an error for the expression beginning here >>> # >>> (use-modules (ice-9 match) >>> >>> In procedure bytevector-u64-set!: Value out of range: -149659645 >>> >>> >>> >>> >>> I have never seen this kind of error. >>> >>> First, can you try to comment out #(ly:set-option 'compile-scheme-code) >>> at the top and see what happens? >>> >> >> That actually did allow it to compile. Interesting. What am I missing out >> on without this option set? >> >> >>> Second, what OS are you running, Windows? How did you install LilyPond? >>> >> >> My apologies. I should have included that already. Yes, I'm on Windows >> and since the Windows download isn't an actual installer, I just unzipped >> it and ran it from there. >> >> > Jean, this is absolutely brilliant! It works perfectly for a HUGE majority > of the cases of my real score where I had to do so many manual adjustments. > Wow! Your code has reduced the tweaking to almost zero. Even then, it's > totally usable as-is. Thank you soo much! I'm definitely going to have > to study your code to see why this works so well. I've only created a > handful of Scheme fixes for things I'd done in the past, but this is way > out of my league. Well done! > > Kieren, you've got to try this out! It will blow your mind! > Jean, seriously, this is amazing! Thank you so much for this awesome tool. I can see how it's not going to be perfect for every situation, but, man, what a great job it does. I think I've ended up adjusting only 5 total places just a hair because of some close proximity to the Stanza text, but compared to the over 60 syllables I had to tweak before, your fix easily beats what I was trying to do manually!!! What a time saver! Follow-on realization: This code even works with the LSR snippet that ignores punctuation! ( http://lilypond.1069038.n5.nabble.com/LyricText-center-on-word-breaks-lyricMelismaAlignment-tt183456.html). This has turned a so-so day into an amazing one! Thank you, Jean! As a choir director for my local church congregation, this will save me so much time! Best, Abraham P.S. I hope my enthusiasm for this fix doesn't eclipse my sincere appreciation for all the amazing work done by the regular developers past and present. I've had lots of generous help over the years from many developers and other users here. So grateful to you all for creating a truly awesome tool and helping me and so many others!
Re: Flexible lyric alignment,Re: Flexible lyric alignment
On Sat, Nov 19, 2022 at 6:50 PM Abraham Lee wrote: > > > On Sat, Nov 19, 2022 at 5:16 PM Jean Abou Samra > wrote: > >> >> >> Le 20 nov. 2022 à 01:11, Abraham Lee a >> écrit : >> >> Still running into compiler errors. I figured my version was just out of >> date, but after downloading 2.23.81, I still get the following log: >> >> %<-SNIP--- >> >> Starting lilypond.exe 2.23.81 [tricky-lyrics.ly]... >> Processing `K:/music-related/lilypond/snippets/lyric-autospacer/ >> tricky-lyrics.ly' >> Parsing... >> K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:8:2: >> error: Guile signaled an error for the expression beginning here >> # >> (use-modules (ice-9 match) >> >> In procedure bytevector-u64-set!: Value out of range: -149659645 >> >> >> >> >> I have never seen this kind of error. >> >> First, can you try to comment out #(ly:set-option 'compile-scheme-code) >> at the top and see what happens? >> > > That actually did allow it to compile. Interesting. What am I missing out > on without this option set? > > >> Second, what OS are you running, Windows? How did you install LilyPond? >> > > My apologies. I should have included that already. Yes, I'm on Windows and > since the Windows download isn't an actual installer, I just unzipped it > and ran it from there. > > Jean, this is absolutely brilliant! It works perfectly for a HUGE majority of the cases of my real score where I had to do so many manual adjustments. Wow! Your code has reduced the tweaking to almost zero. Even then, it's totally usable as-is. Thank you soo much! I'm definitely going to have to study your code to see why this works so well. I've only created a handful of Scheme fixes for things I'd done in the past, but this is way out of my league. Well done! Kieren, you've got to try this out! It will blow your mind! Best, Abraham
Re: Flexible lyric alignment,Re: Flexible lyric alignment
On Sat, Nov 19, 2022 at 5:16 PM Jean Abou Samra wrote: > > > Le 20 nov. 2022 à 01:11, Abraham Lee a > écrit : > > Still running into compiler errors. I figured my version was just out of > date, but after downloading 2.23.81, I still get the following log: > > %<-SNIP--- > > Starting lilypond.exe 2.23.81 [tricky-lyrics.ly]... > Processing `K:/music-related/lilypond/snippets/lyric-autospacer/ > tricky-lyrics.ly' > Parsing... > K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:8:2: > error: Guile signaled an error for the expression beginning here > # > (use-modules (ice-9 match) > > In procedure bytevector-u64-set!: Value out of range: -149659645 > > > > > I have never seen this kind of error. > > First, can you try to comment out #(ly:set-option 'compile-scheme-code) at > the top and see what happens? > That actually did allow it to compile. Interesting. What am I missing out on without this option set? > Second, what OS are you running, Windows? How did you install LilyPond? > My apologies. I should have included that already. Yes, I'm on Windows and since the Windows download isn't an actual installer, I just unzipped it and ran it from there. Thanks for the tip! Abraham
Re: Flexible lyric alignment,Re: Flexible lyric alignment
Le 20 nov. 2022 à 01:11, Abraham Lee a écrit :Still running into compiler errors. I figured my version was just out of date, but after downloading 2.23.81, I still get the following log:%<-SNIP---Starting lilypond.exe 2.23.81 [tricky-lyrics.ly]...Processing `K:/music-related/lilypond/snippets/lyric-autospacer/tricky-lyrics.ly'Parsing...K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:8:2: error: Guile signaled an error for the _expression_ beginning here# (use-modules (ice-9 match)In procedure bytevector-u64-set!: Value out of range: -149659645I have never seen this kind of error.First, can you try to comment out #(ly:set-option 'compile-scheme-code) at the top and see what happens?Second, what OS are you running, Windows? How did you install LilyPond?Thanks,Jean
Re: Flexible lyric alignment,Re: Flexible lyric alignment
On Sat, Nov 19, 2022 at 4:34 PM Abraham Lee wrote: > > > On Sat, Nov 19, 2022 at 3:23 PM Jean Abou Samra > wrote: > >> Le 17/11/2022 à 23:02, Jean Abou Samra a écrit : >> > Le 17/11/2022 à 23:01, Werner LEMBERG a écrit : >> > But how do you take into account the constraints from lyrics here? >> > That is the whole problem. >> They should be completely ignored. >> >>> In that case, it should be completely doable even in Scheme now. >> >>> (I started writing some code yesterday in response to Abraham that >> >>> does essentially that, maybe I'll have it finished today). >> >> Aah, nice! >> > >> > No so fast, wait until it actually works before calling >> > it nice, otherwise if it doesn't work I'll feel bad :-) >> >> >> >> >> Here you go. >> >> This is a vast refinement of the initial \autoMove function that takes all >> lyric words into account simultaneously, finding an optimal solution that >> minimizes the distance from each lyric word to its note while respecting >> the minimal distances between lyric words as configured by >> LyricSpace.minimum-distance / LyricHyphen.minimum-distance. >> >> I used the first algorithm with acceptable complexity that I could >> think of, so there may be a simpler solution for this. Nevertheless, >> it runs in linear time, so I'm happy enough. (If it were quadratic >> or worse, the running time could potentially be problematic if >> ly:one-line-auto-height breaking is used, in which case there can >> be lots of lyrics on the same line.) >> >> Caveats: >> >> - As said in a previous message, this is the other extreme compared >>to what LilyPond does by default: lyrics are not taken into account >>*at all* into note spacing. In particular, LilyPond may produce >>a page breaking configuration in which there are too many notes on >>the same system to fit the lyrics comfortably. I expect that using >>\break in those cases will often be enough to get an acceptable result, >>but I have zero experience with typesetting music with lyrics. >>(And little actual practical experience with typesetting music at >>all, to be honest.) >> >> - I have barely tested it. >> >> Additional featurelets: >> >> - You can still set LyricText.self-alignment-X. It defines the position >>of the LyricText that the algorithm will consider optimal. >> >> - You can set LyricText.details.strength to tell the algorithm to >>place one specific syllable closer to its note at the expense >>of the others. See the example. >> >> Before someone asks: this is not good to integrate into LilyPond as-is, >> because it breaks assumptions that grob implementors and LilyPond in >> general make (namely, the assumption that the X-offset of an item is >> known before line breaking). One would have to either go for a full >> solution as brainstormed in one of my earlier messages, or at least >> find a way for an Item to declare that its positioning depends on other >> things (akin to the current cross-staff property, but preferably less >> invasive). >> >> Hope that helps, >> Jean >> >> > This looks absolutely amazing! I'm running into some compiler issues when > I try to run it on my machine, but I'll see if I can work out why and let > you know if I'm unable. Either way, bravo! The output looks like it will > fix many situations automagically. This seems to be a fantastic step in the > right direction. > > Generally, I end up controlling the system breaking in the end, anyway, so > I'm not too concerned about the possibility of too long a line. > > Many thanks, > Abraham > Still running into compiler errors. I figured my version was just out of date, but after downloading 2.23.81, I still get the following log: %<-SNIP--- Starting lilypond.exe 2.23.81 [tricky-lyrics.ly]... Processing `K:/music-related/lilypond/snippets/lyric-autospacer/ tricky-lyrics.ly' Parsing... K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:8:2: error: Guile signaled an error for the expression beginning here # (use-modules (ice-9 match) In procedure bytevector-u64-set!: Value out of range: -149659645 K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:14:2: error: Guile signaled an error for the expression beginning here # (define-syntax-rule (transform! lval proc) In procedure bytevector-u64-set!: Value out of range: -149659645 K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:17:2: error: Guile signaled an error for the expression beginning here # (define -> In procedure bytevector-u64-set!: Value out of range: -149659645 K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:36:2: error: Guile signaled an error for the expression beginning here # (define-class () In procedure bytevector-u64-set!: Value out of range: -149659645 K:/music-related/lilypond/snippets/lyric-autospacer/respace-lyrics.ily:44:2: error: Guile signaled an error for the expression beginning here #
Re: Flexible lyric alignment,Re: Flexible lyric alignment
On Sat, Nov 19, 2022 at 3:23 PM Jean Abou Samra wrote: > Le 17/11/2022 à 23:02, Jean Abou Samra a écrit : > > Le 17/11/2022 à 23:01, Werner LEMBERG a écrit : > > But how do you take into account the constraints from lyrics here? > > That is the whole problem. > They should be completely ignored. > >>> In that case, it should be completely doable even in Scheme now. > >>> (I started writing some code yesterday in response to Abraham that > >>> does essentially that, maybe I'll have it finished today). > >> Aah, nice! > > > > No so fast, wait until it actually works before calling > > it nice, otherwise if it doesn't work I'll feel bad :-) > > > > > Here you go. > > This is a vast refinement of the initial \autoMove function that takes all > lyric words into account simultaneously, finding an optimal solution that > minimizes the distance from each lyric word to its note while respecting > the minimal distances between lyric words as configured by > LyricSpace.minimum-distance / LyricHyphen.minimum-distance. > > I used the first algorithm with acceptable complexity that I could > think of, so there may be a simpler solution for this. Nevertheless, > it runs in linear time, so I'm happy enough. (If it were quadratic > or worse, the running time could potentially be problematic if > ly:one-line-auto-height breaking is used, in which case there can > be lots of lyrics on the same line.) > > Caveats: > > - As said in a previous message, this is the other extreme compared >to what LilyPond does by default: lyrics are not taken into account >*at all* into note spacing. In particular, LilyPond may produce >a page breaking configuration in which there are too many notes on >the same system to fit the lyrics comfortably. I expect that using >\break in those cases will often be enough to get an acceptable result, >but I have zero experience with typesetting music with lyrics. >(And little actual practical experience with typesetting music at >all, to be honest.) > > - I have barely tested it. > > Additional featurelets: > > - You can still set LyricText.self-alignment-X. It defines the position >of the LyricText that the algorithm will consider optimal. > > - You can set LyricText.details.strength to tell the algorithm to >place one specific syllable closer to its note at the expense >of the others. See the example. > > Before someone asks: this is not good to integrate into LilyPond as-is, > because it breaks assumptions that grob implementors and LilyPond in > general make (namely, the assumption that the X-offset of an item is > known before line breaking). One would have to either go for a full > solution as brainstormed in one of my earlier messages, or at least > find a way for an Item to declare that its positioning depends on other > things (akin to the current cross-staff property, but preferably less > invasive). > > Hope that helps, > Jean > > This looks absolutely amazing! I'm running into some compiler issues when I try to run it on my machine, but I'll see if I can work out why and let you know if I'm unable. Either way, bravo! The output looks like it will fix many situations automagically. This seems to be a fantastic step in the right direction. Generally, I end up controlling the system breaking in the end, anyway, so I'm not too concerned about the possibility of too long a line. Many thanks, Abraham
Re: Flexible lyric alignment,Re: Flexible lyric alignment
Le 17/11/2022 à 23:02, Jean Abou Samra a écrit : Le 17/11/2022 à 23:01, Werner LEMBERG a écrit : But how do you take into account the constraints from lyrics here? That is the whole problem. They should be completely ignored. In that case, it should be completely doable even in Scheme now. (I started writing some code yesterday in response to Abraham that does essentially that, maybe I'll have it finished today). Aah, nice! No so fast, wait until it actually works before calling it nice, otherwise if it doesn't work I'll feel bad :-) Here you go. This is a vast refinement of the initial \autoMove function that takes all lyric words into account simultaneously, finding an optimal solution that minimizes the distance from each lyric word to its note while respecting the minimal distances between lyric words as configured by LyricSpace.minimum-distance / LyricHyphen.minimum-distance. I used the first algorithm with acceptable complexity that I could think of, so there may be a simpler solution for this. Nevertheless, it runs in linear time, so I'm happy enough. (If it were quadratic or worse, the running time could potentially be problematic if ly:one-line-auto-height breaking is used, in which case there can be lots of lyrics on the same line.) Caveats: - As said in a previous message, this is the other extreme compared to what LilyPond does by default: lyrics are not taken into account *at all* into note spacing. In particular, LilyPond may produce a page breaking configuration in which there are too many notes on the same system to fit the lyrics comfortably. I expect that using \break in those cases will often be enough to get an acceptable result, but I have zero experience with typesetting music with lyrics. (And little actual practical experience with typesetting music at all, to be honest.) - I have barely tested it. Additional featurelets: - You can still set LyricText.self-alignment-X. It defines the position of the LyricText that the algorithm will consider optimal. - You can set LyricText.details.strength to tell the algorithm to place one specific syllable closer to its note at the expense of the others. See the example. Before someone asks: this is not good to integrate into LilyPond as-is, because it breaks assumptions that grob implementors and LilyPond in general make (namely, the assumption that the X-offset of an item is known before line breaking). One would have to either go for a full solution as brainstormed in one of my earlier messages, or at least find a way for an Item to declare that its positioning depends on other things (akin to the current cross-staff property, but preferably less invasive). Hope that helps, Jean % Copyright (C) 2022, Jean Abou Samra % Placed under the Creative Commons CC0 1.0 Universal license. \version "2.23.81" #(ly:set-option 'compile-scheme-code) #(use-modules (ice-9 match) (ice-9 hash-table) (oop goops)) %% convenience stuff: #(define-syntax-rule (transform! lval proc) (set! lval (proc lval))) #(define -> (make-procedure-with-setter (lambda (instance . path) (let loop ((instance instance) (path path)) (match path ((slot) (slot-ref instance slot)) ((slot . rest) (loop (slot-ref instance slot) rest) (lambda (instance . args) (let loop ((instance instance) (args args)) (match args ((slot new) (slot-set! instance slot new)) ((slot . rest) (loop (slot-ref instance slot) rest))) #(define-class () (ideal #:init-keyword #:ideal) (extent #:init-keyword #:extent) (strength #:init-keyword #:strength) (tied-to #:init-value #f) (tied-offset #:init-value #f) (final #:init-value #f)) #(define (merged-variable! group var) (let* ((delta (- (interval-end (-> group 'extent)) (interval-start (-> var 'extent (new (make #:ideal (/ (+ (* (-> group 'strength) (-> group 'ideal)) (* (-> var 'strength) (- (-> var 'ideal) delta))) (+ (-> group 'strength) (-> var 'strength))) #:extent (cons (interval-start (-> group 'extent)) (+ (interval-end (-> group 'extent)) (interval-length (-> var 'extent #:strength (+ (-> group 'strength) (-> var 'strength) (set! (-> group 'tied-to) new) (set! (-> group 'tied-offset) 0) (set! (-> var 'tied-to) new) (set! (-> var 'tied-offset) delta) new)) #(define (propagate! variables) (match variables ((var) variables) ((var group . rest) (let ((have-ov
Re: Flexible lyric alignment,Re: Flexible lyric alignment
Jean Abou Samra writes: > Le 17/11/2022 à 23:01, Werner LEMBERG a écrit : > But how do you take into account the constraints from lyrics here? > That is the whole problem. They should be completely ignored. >>> In that case, it should be completely doable even in Scheme now. >>> (I started writing some code yesterday in response to Abraham that >>> does essentially that, maybe I'll have it finished today). >> Aah, nice! > > No so fast, wait until it actually works before calling > it nice, otherwise if it doesn't work I'll feel bad :-) Even nicer! -- David Kastrup
Re: Flexible lyric alignment,Re: Flexible lyric alignment
Le 17/11/2022 à 23:01, Werner LEMBERG a écrit : But how do you take into account the constraints from lyrics here? That is the whole problem. They should be completely ignored. In that case, it should be completely doable even in Scheme now. (I started writing some code yesterday in response to Abraham that does essentially that, maybe I'll have it finished today). Aah, nice! No so fast, wait until it actually works before calling it nice, otherwise if it doesn't work I'll feel bad :-) OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment,Re: Flexible lyric alignment
>>> But how do you take into account the constraints from lyrics here? >>> That is the whole problem. >> >> They should be completely ignored. > > In that case, it should be completely doable even in Scheme now. > (I started writing some code yesterday in response to Abraham that > does essentially that, maybe I'll have it finished today). Aah, nice! > However, this may produce a page breaking configuration where > whatever horizontal spacing you choose, a system is too compressed > for its lyrics to fit, and LilyPond producing collisions by default > would be suboptimal, IMHO. Maybe there could be a loop that retries with different initial parameters? Werner
Re: Flexible lyric alignment
Le 17/11/2022 à 08:06, Werner LEMBERG a écrit : * In the first pass, typeset everything without stuff marked for a follow-up pass. Namely, typeset all notes? Yes. But how do you take into account the constraints from lyrics here? That is the whole problem. They should be completely ignored. In that case, it should be completely doable even in Scheme now. (I started writing some code yesterday in response to Abraham that does essentially that, maybe I'll have it finished today). However, this may produce a page breaking configuration where whatever horizontal spacing you choose, a system is too compressed for its lyrics to fit, and LilyPond producing collisions by default would be suboptimal, IMHO. OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment,Re: Flexible lyric alignment
>> * In the first pass, typeset everything without stuff marked for a >> follow-up pass. > > Namely, typeset all notes? Yes. > But how do you take into account the constraints from lyrics here? > That is the whole problem. They should be completely ignored. My idea was to make the first pass collect 'springs and rods constraints' so that note columns can't be stretched too much by lyrics in the second pass. Note that with a 'pass' I don't mean that LilyPond completely typesets everything. It's rather restricted to repeatedly solving the horizontal spacing problem. Werner
Re: Flexible lyric alignment
Jean Abou Samra writes: > Le 16/11/2022 à 10:05, Werner LEMBERG a écrit : >> I draw my idea from LaTeX, for example handling multi-page tables (see >> the 'longtable' package). > > > I looked at the documentation > (https://distrib-coffee.ipsl.jussieu.fr/pub/mirrors/ctan/macros/latex/required/tools/longtable.pdf). > The footnote on the first page says > > The new algorithm for aligning ‘chunks’ of a table used in > version 4 of this package was devised coded and documented > by David Kastrup. > > LOL. > > Obviously, David will be able to comment better than me. > But skimming the documentation of the package, it looked > more like the package had to use this technique to work > around the limitations of the extremely limited TeX > programming environment than to implement a smart > algorithm. Am I wrong here? Pretty much so. The principal constraint "longtable" is working around is that TeX is designed to keep not much more than one page of material in memory, so aligning multi-page tables needs a multipass algorithm. The principal problem the "new" algorithm addresses differently compared to the "old" one is that of cells spanning multiple horizontal table slots. This could make the "old" multipass algorithm converge to a table that was too wide for its material and might require manual intervention. The "new" algorithm always converges on its own though it may take a number of passes to do so. The new algorithm is rather tricky in how it ensures convergence. That programming in TeX is a horrible mess since TeX actually contains two programming systems, one blind (the "stomach" can change variables but not branch depending on their values) and one lame (the "mouth" can branch based on conditions but cannot affect variables) that are tied together with comparatively stretchy rope (they may execute for longer code pieces without involving the other). But this horrible programming mess is a given and not really related to the algorithm I implemented in particular. The algorithm is independently tricky. That the implementation language(s) suck has nothing to do with it. No idea how this would even apply to LilyPond since LilyPond _does_ keep everything in memory and thus does not require a similar multipass approach. -- David Kastrup
Re: Flexible lyric alignment
Le 16/11/2022 à 10:05, Werner LEMBERG a écrit : I draw my idea from LaTeX, for example handling multi-page tables (see the 'longtable' package). I looked at the documentation (https://distrib-coffee.ipsl.jussieu.fr/pub/mirrors/ctan/macros/latex/required/tools/longtable.pdf). The footnote on the first page says The new algorithm for aligning ‘chunks’ of a table used in version 4 of this package was devised coded and documented by David Kastrup. LOL. Obviously, David will be able to comment better than me. But skimming the documentation of the package, it looked more like the package had to use this technique to work around the limitations of the extremely limited TeX programming environment than to implement a smart algorithm. Am I wrong here? * In the first pass, typeset everything without stuff marked for a follow-up pass. Namely, typeset all notes? But how do you take into account the constraints from lyrics here? That is the whole problem. For what it's worth, the optimization problem can be formulated as a springs&rods problem: Add a problem variable for each lyric word. For each lyric word W, if C is W's column, add a rod from C to W to ensure W is not too far on the left of W. Also add a rod from W to C to ensure W does not go too far to the right. Add all other rods in the usual way (with skylines). Now rods may involve both column variables and lyric variables. Leave springs as they are (between columns only). Issue: this is not a springs&rods problem that the existing Simple_spacer will be able to solve (I didn't try, but I'm pretty sure). Simple_spacer's algorithm starts by stretching the line a lot, and iteratively compresses it. This implicitly assumes that stretching the line a lot will make rod constraints satisfied, i.e., there are no "reverse rods" (columns are ordered, and all rods are from a column to a column with a higher rank). The problems in the form above do have reverse rods. So the problem is essentially finding a method to solve springs&rods problems with this kind of reverse rods allowed. Now, springs&rods optimization is close to quadratic programming, which is well-studied, but in my understanding so far, it is not exactly quadratic programming (?) due to the fact that springs are allowed to have different strengths for stretching and compressing. Maybe one can find a different algorithm for Simple_spacer. Potentially, its start could be stretching the columns and putting each lyric word exactly on the column. Then what? That remains to be seen. Maybe one can adapt existing QP algorithms (caveat: a comment in simple-spacer.cc claims that it's "much simpler and much much faster than full-scale constrained QP"). Maybe there are papers that I haven't read that provide solutions or ideas for this problem. Maybe I am just being blind to an obvious solution, too. Another idea: instead of using two rods for describing the relationship between a lyric word and its column, use a spring with a somewhat large force, which allows lyrics to be completely "disconnected" from their column but makes it unlikely. I may well have said wrong things and I am not seeing clearly in the frame of the problem yet. Also, adding variables for lyrics would be a deep change in the C++ core. Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
>> I think that such a fine granularity of automatic lyric adjustment >> would only be possible with LilyPond doing (at least) two >> typesetting passes, if at all. > > Can you elaborate? What would it help with? I draw my idea from LaTeX, for example handling multi-page tables (see the 'longtable' package). * In the first pass, typeset everything without stuff marked for a follow-up pass. * Use the result of the first pass to 'fix' all spring and rods. With 'fixing' I mean that only a certain amount of deviation from the first-pass horizontal spacing is allowed in the second pass. * In the second pass, apply the additional stuff in the usual way, probably having a special 'lyrics floating mode' that allows the lyrics to flow horizontally around a given position (taken from the first pass). >> In general, implementing a second pass – note that I have *no* clue >> whether this is easy or hard to implement – might help solve other >> problems, too, for example typsetting primo and secondo layout for >> four-hand music >> (https://gitlab.com/lilypond/lilypond/-/issues/902). > > That issue looks like a lot of busywork to overhaul the page > breaking engine for working on several scores in parallel, but on > the conceptual level it doesn’t look difficult to me. Good to know, thanks. Werner
Re: Flexible lyric alignment
> Le 16 nov. 2022 à 09:36, Werner LEMBERG a écrit : > > I think that such a fine granularity of automatic lyric adjustment > would only be possible with LilyPond doing (at least) two typesetting > passes, if at all. Can you elaborate? What would it help with? > In general, implementing a second pass – note that I have *no* clue > whether this is easy or hard to implement – might help solve other > problems, too, for example typsetting primo and secondo layout for > four-hand music (https://gitlab.com/lilypond/lilypond/-/issues/902). That issue looks like a lot of busywork to overhaul the page breaking engine for working on several scores in parallel, but on the conceptual level it doesn’t look difficult to me. Jean
Re: Flexible lyric alignment
> The main problematic measures are 5, 7, and 9/10. My tweaks are > good bandaids, but not ideal, nor perfect, but they get the job > done. I think that such a fine granularity of automatic lyric adjustment would only be possible with LilyPond doing (at least) two typesetting passes, if at all. In general, implementing a second pass – note that I have *no* clue whether this is easy or hard to implement – might help solve other problems, too, for example typsetting primo and secondo layout for four-hand music (https://gitlab.com/lilypond/lilypond/-/issues/902). Werner
Re: Flexible lyric alignment
Ok, I realize this isn't really a MWE, but I needed a more real example of some of the issues I ran into. So, here we go. You'll find some of my favorite preferences for Lyrics in the extra global overrides. And, yes, I realize they are part of the problem, but even without them, the problems are still there. The main problematic measures are 5, 7, and 9/10. My tweaks are good bandaids, but not ideal, nor perfect, but they get the job done. Let me know what you think. Best, Abraham %<-- \version "2.23" \language "english" struct = { \numericTimeSignature \key bf \major \time 3/4 s2.*5 \break s2.*5 \break } nb = \markup { \small \italic "n.b." } melody = \relative { \clef treble \dynamicUp R2.*4 | d'8\mp ef f4. d8 | d4 \once \phrasingSlurDashed c2_\(^\nb | d8\) ef f4 bf, | c2. | d8\< ef f4. f8 | g8 a bf2\mf | } pianoRH = \relative { \clef treble d''8 ef f4 8 f' | << { g8 a bf2 } \\ { 2. } >> | << { ef4 c8 d ef bf } \\ { g2 g4 } >> | << { d'4. ef8 c4 } \\ { 2. } >> | 4 2 | << { d'4 c } \\ { 2 } >> ef'8 c' | 4 2 | 4 c ef8 c' | 4 f c8 f, | << { d'2. } \\ { bf8 a g2 } >> | } pianoLH = \relative { \clef treble bf8 f' ~ f4 a, | g8 d' bf' a g d | \clef bass c,8 g' ef'2 | ef,8 bf' c2 | bf,8 f' bf4 d | ef,8 gf bf c ef4 | bf,8 f' d'4 f | ef,8 c' ef gf ~ gf4 | bf,,8 f' d'4 a | g8 d' bf a g d | } melodyWordsDefault = \lyricmode { Would I know my Sav -- ior Wrapped in swad -- dling bands, Ly -- ing in a man -- ger bed, Light of hea -- ven ’round His head? } melodyWordsTweaked = \lyricmode { \once \override LyricText.self-alignment-X = #0.3 Would \once \override LyricText.self-alignment-X = #1 I \once \override LyricText.self-alignment-X = #-0.3 know my Sav -- ior \once \override LyricText.self-alignment-X = #0.3 wrapped \once \override LyricText.self-alignment-X = #-2.5 in \once \override LyricText.self-alignment-X = #-0.5 swad -- \once \override LyricText.self-alignment-X = #-0.5 dling bands, Ly -- ing in \once \override LyricText.self-alignment-X = #-5 a \once \override LyricText.self-alignment-X = #0.7 man -- \once \override LyricText.self-alignment-X = #-0.3 ger \once \override LyricText.self-alignment-X = #-1 bed, } #(set-global-staff-size 19) \paper { ragged-last = ##f ragged-bottom = ##t ragged-right = ##f ragged-last-bottom = ##t tagline = ##f } \layout { \context { \Lyrics \override LyricText.font-size = #0 \override LyricHyphen.font-size = #-0.5 \override LyricHyphen.padding = #0.15 \override LyricHyphen.length = #0.6 %#0.4 \override LyricHyphen.minimum-length = #0.66 \override LyricHyphen.minimum-distance = #1 %0.15 \override LyricHyphen.thickness = 2.0 \override LyricHyphen.dash-period = 8.0 \override LyricExtender.minimum-length = #0 \override LyricExtender.right-padding = #0.5 \override LyricSpace.minimum-distance = #1 \override VerticalAxisGroup.nonstaff-relatedstaff-spacing.padding = #1 } } \score { \header { piece = "Tricky lyrics BEFORE adjustments" } << \new Staff << \struct \new Voice = "melody" \melody >> \new Lyrics \lyricsto melody \melodyWordsDefault \new PianoStaff << \new Staff = "pianoRH" << \struct \pianoRH >> \new Staff = "pianoLH" << \struct \pianoLH >> >> >> \layout {} } \score { \header { piece = "Tricky lyrics AFTER adjustments" } << \new Staff << \struct \new Voice = "melody" \melody >> \new Lyrics \lyricsto melody \melodyWordsTweaked \new PianoStaff << \new Staff = "pianoRH" << \struct \pianoRH >> \new Staff = "pianoLH" << \struct \pianoLH >> >> >> \layout {} } %< On Tue, Nov 15, 2022 at 8:19 AM Abraham Lee wrote: > This looks awesome, Jean! Thanks so much for this great start! And thanks > to everyone else who has chimes in on this. We may get to a great solution > yet! > > In my recent score, again, a single vocal staff with two piano staves > below, I had instances where there were 2, 3, and 4-syllable clusters where > I had to adjust almost all the syllables’ positions, sometimes on just one > end, mostly on both ends, sometimes in the middle as well. I apologize that > I haven’t had a chance to test your fix out yet (work is a bit too busy at > the moment), but how well would you say it handles those kinds of groups? > > I’ll post some more specific examples later demonstrating the issues > before my manual tweaks versus after (not that they’re perfect). > > Best, > Abraham > > On Mon, Nov 14, 2022 at 11:40 AM Kieren MacMillan < > kie...@kierenmacmillan.info> wrote: > >> Hi Jean, >> >> > This just removes the lyric syllable's presence in horizontal >> > spacing, then adju
Re: Flexible lyric alignment
This looks awesome, Jean! Thanks so much for this great start! And thanks to everyone else who has chimes in on this. We may get to a great solution yet! In my recent score, again, a single vocal staff with two piano staves below, I had instances where there were 2, 3, and 4-syllable clusters where I had to adjust almost all the syllables’ positions, sometimes on just one end, mostly on both ends, sometimes in the middle as well. I apologize that I haven’t had a chance to test your fix out yet (work is a bit too busy at the moment), but how well would you say it handles those kinds of groups? I’ll post some more specific examples later demonstrating the issues before my manual tweaks versus after (not that they’re perfect). Best, Abraham On Mon, Nov 14, 2022 at 11:40 AM Kieren MacMillan < kie...@kierenmacmillan.info> wrote: > Hi Jean, > > > This just removes the lyric syllable's presence in horizontal > > spacing, then adjusts its placement if it collides with its > > right neighbor. It works in this case because there is nothing > > on the left that the lyric syllable in question could collide > > with. (It also does not handle collisions with other things > > than the next lyric syllable.) > > Well, between the two hacks you just hacked, a huge percentage of my > note-spacing tweaking effort has just been saved, so I thank you immensely! > > Can't wait to unleash these on my scores and get back you/list with some > real-world data. (I know one of the things I’ll run into almost immediately > is that I will need the *LAST* syllable to be shifted to the *RIGHT*, but > I’m going to take on that “upgrade” as a Scheme-ing challenge!) > > Gratefully, > Kieren.
Re: Flexible lyric alignment
Hi again! Given the success of my first sortie, here's another snippet that might be automated. (Note that this one matches the OP's situation.) This is definitely a tweak I do on a very regular basis in my music-with-text scores: sliding a text backwards, potentially under previous grobs. This one is obviously [intentionally] extreme, and again avoids some “dragons” (clefs, breaks, other lyrics, etc.). Then again, I had to trial-and-error it to find the final number I used (0.5), and don’t currently know what algorithm might be applied to remove the T&E process… In any case, I’m hopeful that lightning will strike twice, and a single “hacky” function might (a) be applicable to a huge percentage of real-world situations and (b) might be additional input/data for a potential general solution down the line. Best, Kieren. SNIPPET BEGINS \version "2.23.14" \paper { top-margin = 0.5\in left-margin = 0.5\in line-width = 6\in ragged-right = ##f } spacecase_notes = { R1 a'4 c'8 f' bes'4 a' g'8 8 \tuplet 3/2 { g'8 8 fis' } g'2 } spacecase_lyrics = \lyricmode { Scraunched is the long -- est sin -- gle syl -- la -- ble word! } \markup "1. Raw output:" \score { << \new Staff \new Voice = "melody" \spacecase_notes \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } \markup "2. Using LyricText.self-alignment-X to shift the initial text under preceding grobs:" tweaksTwo = { s1 \once \override Score.LyricText.self-alignment-X = #0.5 } \score { << \new Staff \new Voice = "melody" << \spacecase_notes \tweaksTwo >> \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } SNIPPET ENDS
Re: Flexible lyric alignment
Hi Jean, > this example isn't specific to lyrics, although this situation > probably occurs more often in lyrics than in other contexts. Definitely. > Here's one way to do this, but don't be too excited: not only > is it hacky (in "fixable" ways), but it makes lots of assumptions > that hold in the example and won't hold in anything more complicated. I'll use it in various situations and report back on what happens. > Basically, the idea is to read the rods between the (musical) columns > from a group of notes, and set them all to the max between them. Thanks for the insight! I’m hoping that us hacking through a few of these “isolated” examples will bring clarity to how (or even if) a general solution might be implemented. Thanks! Kieren.
Re: Flexible lyric alignment
Hi Jean, > This just removes the lyric syllable's presence in horizontal > spacing, then adjusts its placement if it collides with its > right neighbor. It works in this case because there is nothing > on the left that the lyric syllable in question could collide > with. (It also does not handle collisions with other things > than the next lyric syllable.) Well, between the two hacks you just hacked, a huge percentage of my note-spacing tweaking effort has just been saved, so I thank you immensely! Can't wait to unleash these on my scores and get back you/list with some real-world data. (I know one of the things I’ll run into almost immediately is that I will need the *LAST* syllable to be shifted to the *RIGHT*, but I’m going to take on that “upgrade” as a Scheme-ing challenge!) Gratefully, Kieren.
Re: Flexible lyric alignment
Le 14/11/2022 à 17:11, Kieren MacMillan a écrit : Hi again! Given the success of my first sortie, here's another snippet that might be automated. (Note that this one matches the OP's situation.) This is definitely a tweak I do on a very regular basis in my music-with-text scores: sliding a text backwards, potentially under previous grobs. This one is obviously [intentionally] extreme, and again avoids some “dragons” (clefs, breaks, other lyrics, etc.). Then again, I had to trial-and-error it to find the final number I used (0.5), and don’t currently know what algorithm might be applied to remove the T&E process… In any case, I’m hopeful that lightning will strike twice, and a single “hacky” function might (a) be applicable to a huge percentage of real-world situations and (b) might be additional input/data for a potential general solution down the line. \version "2.23.81" #(ly:set-option 'compile-scheme-code) \layout { \context { \Lyrics \consists #(lambda (context) (let ((previous #f)) (make-engraver (acknowledgers ((lyric-syllable-interface engraver grob source-engraver) (when previous (set! (ly:grob-object previous 'right-syllable) grob)) (set! previous grob)) } } autoMove = \tweak LyricSpace.springs-and-rods ##f \tweak LyricHyphen.springs-and-rods ##f % untested \tweak LyricText.extra-spacing-height #'(+inf.0 . -inf.0) \tweak LyricText.after-line-breaking #(lambda (grob) (let ((right (ly:grob-object grob 'right-syllable #f))) (when right (ly:grob-property right 'after-line-breaking) (let* ((refp (ly:grob-system grob)) (end (interval-end (ly:grob-extent grob refp X))) (right-begin (interval-start (ly:grob-extent right refp X))) (default-space (- right-begin end)) ;; Same as LyricSpace.minimum-distance default, should be ;; read there ... (padding 0.45)) (when (< default-space padding) (ly:grob-translate-axis! grob (- default-space padding) X)) \etc \paper { top-margin = 0.5\in left-margin = 0.5\in line-width = 6\in ragged-right = ##f } spacecase_notes = { R1 a'4 c'8 f' bes'4 a' g'8 8 \tuplet 3/2 { g'8 8 fis' } g'2 } spacecase_lyrics = \lyricmode { \autoMove Scraunched is the long -- est sin -- gle syl -- la -- ble word! } \score { << \new Staff \new Voice = "melody" \spacecase_notes \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } This just removes the lyric syllable's presence in horizontal spacing, then adjusts its placement if it collides with its right neighbor. It works in this case because there is nothing on the left that the lyric syllable in question could collide with. (It also does not handle collisions with other things than the next lyric syllable.) Best, Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
The bit with LyricHyphen was not working, this will be better: \version "2.23.81" #(ly:set-option 'compile-scheme-code) \layout { \context { \Lyrics \consists #(lambda (context) (let ((previous #f)) (make-engraver (acknowledgers ((lyric-syllable-interface engraver grob source-engraver) (when previous (set! (ly:grob-object previous 'right-syllable) grob)) (set! previous grob)) } \override Score.PaperColumn.show-horizontal-skylines = ##t } autoMove = \once { \override LyricSpace.springs-and-rods = ##f \override LyricHyphen.springs-and-rods = ##f \override LyricText.extra-spacing-height = #'(+inf.0 . -inf.0) \override LyricText.after-line-breaking = #(lambda (grob) (let ((right (ly:grob-object grob 'right-syllable #f))) (when right (ly:grob-property right 'after-line-breaking) (let* ((refp (ly:grob-system grob)) (end (interval-end (ly:grob-extent grob refp X))) (right-begin (interval-start (ly:grob-extent right refp X))) (default-space (- right-begin end)) ;; Same as LyricSpace.minimum-distance default, should be ;; read there ... (padding 0.45)) (when (< default-space padding) (ly:grob-translate-axis! grob (- default-space padding) X)) } \paper { top-margin = 0.5\in left-margin = 0.5\in line-width = 6\in ragged-right = ##f } spacecase_notes = { R1 a'4 c'8 f' bes'4 a' g'8 8 \tuplet 3/2 { g'8 8 fis' } g'2 } spacecase_lyrics = \lyricmode { \autoMove Scraunched is the long -- est sin -- gle syl -- la -- ble word! } \score { << \new Staff \new Voice = "melody" \spacecase_notes \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
Le 12/11/2022 à 16:38, Kieren MacMillan a écrit : Hi all, I know many of you follow a “Do first” process… so even though that’s not my process, here goes. ;) Here's a small example of this spacing “thorn”, and one way I might tweak it to fix the problem. Notes: – I realize it's constructed to avoid the very issue(s) that Jean raises (i.e., there are no lyrics in the measures on either side of the main one) – I realize the spacing I ended up with is not “perfect” (a.k.a. “enemy of the good”) – I realize there are at least a dozen other ways of tweaking the spacing to accomplish the same goal (i.e., making the tuplet notes evenly spaced) – I realize the fix to this constructed example wouldn't fix the OP's issue (i.e., shifting the LyricText “out of the way”) I just thought talking through a concrete example might bring clarity to what has so far been a pretty abstract discussion. My question: How can the tweak I've made here be automated *only considering the notes and lyrics in question, and not worrying about what might [or might not] happen once there are elements in the surrounding moments/measures that might collide? Well, we are kind of deviating from the topic of lyric spacing, because this example isn't specific to lyrics, although this situation probably occurs more often in lyrics than in other contexts. You would have the same with a long text script, for example. As you say yourself, what we'd like LilyPond to do automatically here is not shifting the lyric text out of the way, but adding more spacing to the other notes of the tuplet. Here's one way to do this, but don't be too excited: not only is it hacky (in "fixable" ways), but it makes lots of assumptions that hold in the example and won't hold in anything more complicated. Some of the "fixable" ones are: the group is made of notes (not rests), there are no clefs or such, the unevenness is caused by rods (not springs; those aren't transparent to Scheme). More importantly, it assumes that there are no notes interspersed between the notes of the group in another voice. Also, it needs to trigger before-line-breaking earlier than usual, so it might have bad side effects on scores not even using \equalRodsGroup. Basically, the idea is to read the rods between the (musical) columns from a group of notes, and set them all to the max between them. \version "2.23.80" \layout { \context { \Score \override System.before-line-breaking = #(lambda (grob) (let ((elements (ly:grob-array->list (ly:grob-object grob 'all-elements (for-each (lambda (elt) (when (not (eq? 'NoteHead (grob::name elt))) (ly:grob-property elt 'springs-and-rods))) elements))) } } #(use-modules (ice-9 match)) #(define (successive-pairs lst) (let loop ((lst lst) (acc '())) (match lst ((or () (_)) (reverse! acc)) ((a . (and rest (b . rest2))) (loop rest (cons (cons a b) acc)) equalRodsGroup = #(define-music-function (music) (ly:music?) (let ((cols '()) (done #f)) #{ { \temporary \override NoteHead.before-line-breaking = #(lambda (grob) (set! cols (cons (ly:item-get-column grob) cols))) \temporary \override NoteHead.springs-and-rods = #(lambda (grob) (when (not done) (set! done #t) (let* ((ordered-cols (sort cols (comparator-from-key (lambda (c) (ly:grob-property c 'when)) ly:moment (ly:grob-object left 'minimum-distances) -inf.0))) pairs (for-each (match-lambda ((left . right) (set! (ly:grob-object left 'minimum-distances) (assq-set! (ly:grob-object left 'minimum-distances) right max-rod pairs #music \revert NoteHead.before-line-breaking \revert NoteHead.springs-and-rods } #})) \paper { top-margin = 0.5\in left-margin = 0.5\in } spacecase_notes = { R1 a'8 8 \equalRodsGroup { \tuplet 3/2 { 8 8 8 } } 4 4 R1 } spacecase_lyrics = \lyricmode { This is spaced a bit poor -- ly! } \score { << \new Staff \new Voice = "melody" \spacecase_notes \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } Very much looking forward to seeing what comes of this thread! Speaking for myself, patches from me in this area are unlikely to come anytime soon. I'll
Re: Flexible lyric alignment
Hi all, I know many of you follow a “Do first” process… so even though that’s not my process, here goes. ;) Here's a small example of this spacing “thorn”, and one way I might tweak it to fix the problem. Notes: – I realize it's constructed to avoid the very issue(s) that Jean raises (i.e., there are no lyrics in the measures on either side of the main one) – I realize the spacing I ended up with is not “perfect” (a.k.a. “enemy of the good”) – I realize there are at least a dozen other ways of tweaking the spacing to accomplish the same goal (i.e., making the tuplet notes evenly spaced) – I realize the fix to this constructed example wouldn't fix the OP's issue (i.e., shifting the LyricText “out of the way”) I just thought talking through a concrete example might bring clarity to what has so far been a pretty abstract discussion. My question: How can the tweak I've made here be automated *only considering the notes and lyrics in question, and not worrying about what might [or might not] happen once there are elements in the surrounding moments/measures that might collide? Very much looking forward to seeing what comes of this thread! Kieren. p.s. Jean: “Coincidentally” ;), this example also includes the problem we’ve been discussing in the other thread, i.e., the inability to [natively] “inject” a tweak at a specific moment (without the use of spacer skips). SNIPPET BEGINS \version "2.23.14" \paper { top-margin = 0.5\in left-margin = 0.5\in } spacecase_notes = { R1 a'8 8 \tuplet 3/2 { 8 8 8 } 4 4 R1 } spacecase_lyrics = \lyricmode { This is spaced a bit poor -- ly! } \markup "1. Raw output:" \score { << \new Staff \new Voice = "melody" \spacecase_notes \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } \markup "2. Using NoteHead.extra-spacing-width to even out [only] tuplet note spacing:" tweaksTwo = { s1 s4 \temporary \override Score.NoteHead.extra-spacing-width = #'(0.5 . 4) s4 \revert Score.NoteHead.extra-spacing-width } \score { << \new Staff \new Voice = "melody" << \spacecase_notes \tweaksTwo >> \new Lyrics \lyricsto "melody" \spacecase_lyrics >> } SNIPPET ENDS
Re: Flexible lyric alignment
Le 12/11/2022 à 00:23, Carl Sorensen a écrit : IIUC, columns are spaced with springs and rods considering collisions between adjacent columns. The hope was that one could create negative space in the column with no lyricText, thus allowing the adjacent column to overlap the column with no lyrics and not have it be considered a collision. Then the standard spacing rules could be followed, but the columns could overlap. Maybe this makes no sense at all (I'm clearly not at expert -- or even a novice -- in the spacing engine). It was just a thought of a way to try to approach the problem by changing grobs, instead of the spacing engine. Preventing the spacing engine from seeing a collision somewhere is not a problem. You can use extra-spacing-width for that. The problem is that in this situation: | | | lyric_word exceedingly_long_lyric_word another_lyric_word | | | | | | column 1 column 2 column 3 If what you need is less space between column 1 and column 2, you can keep the long lyric word aligned on the right, making for a small space: Possibility 1 == | | | lyric_word exceedingly_long_lyric_word another_lyric_word | | | | | | column 1 column 2 column 3 If, on the other hand, what you need is less space between columns 2 and 3, you will do Possibility 2 = | | | lyric_word exceedingly_long_lyric_word another_lyric_word | | | | | | column 1 column 2 column 3 In order to prevent the lyric words from colliding, you normally need to set up a minimum distance from column 1 to column 2 and from column 2 to column 3. If you want to keep both alignment possibilities open in order to leave the spacing engine more freedom for spacing notes equally, the minimum distance from column 1 to column 2 needs to be as small as the distance there is in the first possibility. Otherwise, you will just prevent that possibility from happening by forcing columns 1 and 2 to be too far from each other. Similarly, the minimum distance from column 2 to column 3 needs to be no larger than the distance there is in possibility 2. The issue is that this doesn't tell the spacing engine that the distances from 1 to 2 and from 2 to 3 can both be small, but cannot be small *at the same time*. So, it might choose to do collision collision | | v v | | | lyric_word | another_lyric_word | exceedingly_long_lyric_word | | | column 1 column 2 column 3 I hope it's clearer explained in this way. Best, Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
On Fri, Nov 11, 2022 at 12:33 PM Jean Abou Samra wrote: > > > > Le 10 nov. 2022 à 18:22, Carl Sorensen a > écrit : > > > > Thinking about this in terms of Excel cells, where they can extend as > far as possible as long as there are no contents in adjacent cells > > > > Might it be possible for the lyrics engraver to add something like a > lyricPlaceholder grob into adjacent note columns that had no lyricText grob? > > The extent of the lyricPlaceholder could be the negative of the extent > of the lyricText in the current column. > > The lyricText in the current column could be aligned in the opposite > direction of the adjacent column. > > > > To those who are more familiar with the layout engine than I am -- could > this be a possible approach? > > > Sorry, I am not understanding your suggestion precisely. Would you mind > elaborating? > IIUC, columns are spaced with springs and rods considering collisions between adjacent columns. The hope was that one could create negative space in the column with no lyricText, thus allowing the adjacent column to overlap the column with no lyrics and not have it be considered a collision. Then the standard spacing rules could be followed, but the columns could overlap. Maybe this makes no sense at all (I'm clearly not at expert -- or even a novice -- in the spacing engine). It was just a thought of a way to try to approach the problem by changing grobs, instead of the spacing engine. Carl
Re: Flexible lyric alignment
> Le 11 nov. 2022 à 15:11, Kieren MacMillan a > écrit : > Now of course I realize the implementation of this idea is not necessarily > trivial… but I don't think we need to throw the whole spacing engine under > the bus on the first step of an [attempted] improvement plan. Before being able to treat the group as an atomic unit, you need to determine which length it should have, which also depends on the outside. How do you do that? It doesn’t look easier than the lyrics thing to me… Best, Jean
Re: Flexible lyric alignment
> Le 10 nov. 2022 à 18:22, Carl Sorensen a écrit : > > Thinking about this in terms of Excel cells, where they can extend as far as > possible as long as there are no contents in adjacent cells > > Might it be possible for the lyrics engraver to add something like a > lyricPlaceholder grob into adjacent note columns that had no lyricText grob? > The extent of the lyricPlaceholder could be the negative of the extent of the > lyricText in the current column. > The lyricText in the current column could be aligned in the opposite > direction of the adjacent column. > > To those who are more familiar with the layout engine than I am -- could this > be a possible approach? Sorry, I am not understanding your suggestion precisely. Would you mind elaborating? Thanks, Jean
Re: Flexible lyric alignment
Hi Carl, > Thinking about this in terms of Excel cells, where they can extend as far as > possible as long as there are no contents in adjacent cells > > Might it be possible for the lyrics engraver to add something like a > lyricPlaceholder grob into adjacent note columns that had no lyricText grob? > The extent of the lyricPlaceholder could be the negative of the extent of the > lyricText in the current column. > The lyricText in the current column could be aligned in the opposite > direction of the adjacent column. To my mind, an earlier — and hopefully simpler? — stage/implementation could be the addition of a "NoteColumnGroup" [or similar] grob (?) which would allow the user to say (e.g.) “in this three quarter-note chunk of music, the notes should be ‘correctly spaced’, any attached items should be moved to avoid internal collisions, and then the entire resulting chunk should be considered atomic for spacing purposes”. (The LyricWord implementation might be a good analogue/model?) I would estimate that 90% of my note-spacing issues (and thus edition-engraver tweak-writing time) are of the “I just want this set of triplet eighth notes to be evenly spaced” kind — the thing I'm thinking of (above) would solve those problems completely. Now of course I realize the implementation of this idea is not necessarily trivial… but I don't think we need to throw the whole spacing engine under the bus on the first step of an [attempted] improvement plan. Thoughts? Kieren.
Re: Flexible lyric alignment
On Wed, Nov 9, 2022 at 3:05 PM Jean Abou Samra wrote: > > To tackle this, the first step would be sitting down with paper, > formulating what new kind of problem we want, and figuring out > an algorithm to solve it, maybe a variant of the existing algorithm > to solve springs&rods problems (in lily/simple-spacer.cc), > or maybe an algorithm found or adapted from existing literature > in algorithmics. Then implementing, debugging and profiling it ... > Thinking about this in terms of Excel cells, where they can extend as far as possible as long as there are no contents in adjacent cells Might it be possible for the lyrics engraver to add something like a lyricPlaceholder grob into adjacent note columns that had no lyricText grob? The extent of the lyricPlaceholder could be the negative of the extent of the lyricText in the current column. The lyricText in the current column could be aligned in the opposite direction of the adjacent column. To those who are more familiar with the layout engine than I am -- could this be a possible approach? Thanks, Carl
Re: Flexible lyric alignment
Le 10/11/2022 à 00:16, Kieren MacMillan a écrit : As I've described to you before, that is my preferred approach to coding. :) Would be more than happy to do that — with or without you "live" (via video-conference) — and then watch as you take the next step(s): Sorry, I already have some big projects to work on (in the background) when I am not busy replying on mailing lists or reviewing code or squashing bugs, so I won't have serious time to spend on this in the near future. Best, Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
Hi Jean, > This is not easy to do and it cannot be done with Scheme only. That was clear the moment Janek and I started working on the problem… > To tackle this, the first step would be sitting down with paper, > formulating what new kind of problem we want, and figuring out > an algorithm to solve it, maybe a variant of the existing algorithm > to solve springs&rods problems (in lily/simple-spacer.cc), > or maybe an algorithm found or adapted from existing literature > in algorithmics. As I've described to you before, that is my preferred approach to coding. :) Would be more than happy to do that — with or without you "live" (via video-conference) — and then watch as you take the next step(s): > Then implementing, debugging and profiling it ... Cheers, Kieren.
Re: Flexible lyric alignment
Le 09/11/2022 à 19:51, Kieren MacMillan a écrit : Thoughts? I'm afraid my own Scheme skills aren't up to the task for this. I'm also fully aware that I can adjust this manually at the problematic places. I'd like to avoid that if possible, but will do that if needed. Please let's talk with some Great Developers, figure out a good implementation, and get the ball [re]rolling! I'm sure some of Janek's work is applicable (at least conceptually, if not actualy code). This is not easy to do and it cannot be done with Scheme only. If you move the long syllable to the left in order to reduce the spacing its column needs to the column of the next syllable, then it also largens the space needed from the column of the previous syllable to this syllable's column, since potentially, if you move the syllable too much to the left, it will collide with its left neighbor. This means that these two spacing constraints, from the syllable to its previous and to its next syllable, should be somehow related. However, LilyPond does horizontal spacing by setting up and solving "springs & rods problems", i.e. optimization problems with spacing constraints between columns that are either minimum distances ("rods"), either ideal distances with a stretchability factor ("springs" that are more or less strong). This kind of problem cannot express a dependency between several spacing constraints on different columns. To tackle this, the first step would be sitting down with paper, formulating what new kind of problem we want, and figuring out an algorithm to solve it, maybe a variant of the existing algorithm to solve springs&rods problems (in lily/simple-spacer.cc), or maybe an algorithm found or adapted from existing literature in algorithmics. Then implementing, debugging and profiling it ... Best, Jean OpenPGP_signature Description: OpenPGP digital signature
Re: Flexible lyric alignment
Hi Abraham, (Great to see you on-list again!) > It's been some time since I've posted anything here, but a recent project has > caused me to jump back into creating scores. I'm working on a relatively > simple choral piece with piano accompaniment and seeing all the ways the > lyric syllables mess up the horizontal spacing is... tolerable, but somewhat > irritating. Do not get me started… This is something I started working with Janek on over a decade ago, and — as someone who deals almost exclusively with sung text (art song, choral music, musicals, operas, pop songs, etc.), this is The Thorn™. > I'm not asking for perfect note spacing preservation, just less bad. Longer > syllables/words are, of course, more problematic (like in the attached > picture). > > In my head, I envision a springs-and-rods type of function for the lyric's > attachment (self-alignment-X?) that increases in "stretchability" as the > syllable length gets larger so that it is more likely to move than others. > Thus, enabling the notes to be more correctly spaced. > > Thoughts? I'm afraid my own Scheme skills aren't up to the task for this. I'm > also fully aware that I can adjust this manually at the problematic places. > I'd like to avoid that if possible, but will do that if needed. Please let's talk with some Great Developers, figure out a good implementation, and get the ball [re]rolling! I'm sure some of Janek's work is applicable (at least conceptually, if not actualy code). Best, Kieren.