Re: Flexible lyric alignment

2022-11-22 Thread Jean Abou Samra

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

2022-11-22 Thread Abraham Lee
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

2022-11-21 Thread Abraham Lee
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

2022-11-21 Thread Jean Abou Samra

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

2022-11-20 Thread Kieren MacMillan
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

2022-11-20 Thread Kieren MacMillan
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

2022-11-19 Thread Abraham Lee
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

2022-11-19 Thread Abraham Lee
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

2022-11-19 Thread Abraham Lee
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

2022-11-19 Thread Jean Abou Samra
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

2022-11-19 Thread Abraham Lee
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

2022-11-19 Thread Abraham Lee
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

2022-11-19 Thread Jean Abou Samra

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

2022-11-17 Thread David Kastrup
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

2022-11-17 Thread Jean Abou Samra

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

2022-11-17 Thread Werner LEMBERG


>>> 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

2022-11-16 Thread Jean Abou Samra

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

2022-11-16 Thread Werner LEMBERG


>> * 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

2022-11-16 Thread David Kastrup
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

2022-11-16 Thread Jean Abou Samra

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

2022-11-16 Thread Werner LEMBERG

>> 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

2022-11-16 Thread Jean Abou Samra



> 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

2022-11-16 Thread Werner LEMBERG

> 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

2022-11-15 Thread Abraham Lee
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

2022-11-15 Thread Abraham Lee
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

2022-11-14 Thread Kieren MacMillan
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

2022-11-14 Thread Kieren MacMillan
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

2022-11-14 Thread Kieren MacMillan
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

2022-11-14 Thread Jean Abou Samra

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

2022-11-14 Thread Jean Abou Samra

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

2022-11-13 Thread Jean Abou Samra

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

2022-11-12 Thread Kieren MacMillan
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

2022-11-11 Thread Jean Abou Samra

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

2022-11-11 Thread Carl Sorensen
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

2022-11-11 Thread Jean Abou Samra


> 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

2022-11-11 Thread Jean Abou Samra



> 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

2022-11-11 Thread Kieren MacMillan
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

2022-11-10 Thread Carl Sorensen
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

2022-11-09 Thread Jean Abou Samra

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

2022-11-09 Thread Kieren MacMillan
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

2022-11-09 Thread Jean Abou Samra

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

2022-11-09 Thread Kieren MacMillan
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.