Re: how to repeat a scheme function that creates a Score

2022-04-06 Thread Jeff Olson

On 4/6/2022 12:35 AM, Jean Abou Samra wrote:
The attached MWE file has lots of my failed attempts commented out 
(I'm at a teachable moment if someone has a moment to teach).  Or 
just point me to the right manual page(s).



Here is a piece of code that works:


$@(map (lambda (i) (scr)) (iota 10))


Now let's go through your attempt to see why they are failing. 


This is an amazing user group! Thank you times three to Aaron, Valentin 
and Jean for your immediate and expert responses!


And special thanks to you, Jean, for giving me a full course explaining 
why all my previous attempts had failed.  That was a very valuable 
learning experience!


The code I'm using now is:


% scors generates a specified number of scores
% e.g. invoke $@(scors 10) from lilypond to generate ten scores
#(define (scors num) (map (lambda (i) (scr)) (iota num)))


This works nicely as I can make a series of invocations in different 
bookparts (simulating separate chapters) while preserving the overall 
sequence of piece numbers.


I'd like you to check my learning on "$@" ...

Per the ER section 1.2.1, "There are also ‘list splicing’ operators |$@| 
and |#@| that insert all elements of a list in the surrounding context."


So it's not part of scheme but part of lilypond, as a bridge between 
scheme and lilypond.


And that it tells lilypond to preserve all the elements of scheme list 
value as a sequence of expressions/values to be parsed/interpreted by 
lilypond, as opposed to getting just the value of the last element of 
the list.


And so it is analogous (at least mnemonically) to the meaning of "$%" in 
bash (if I remember correctly), which preserves a sequence of command 
line arguments as separate values rather than combining them as one 
argument.


But may I ask, why are "$@" and "#@" called 'list splicing' operators?  
The same terminology is used in Perl for what appears to me to be very 
different behaviors (list editing, insertion and removal), so I'd 
appreciate learning why 'splicing' is considered descriptive in lilypond.


Jeff




Re: how to repeat a scheme function that creates a Score

2022-04-06 Thread Jeff Olson

On 4/5/2022 11:58 PM, Aaron Hill wrote:

On 2022-04-05 10:40 pm, Jeff Olson wrote:

Question (b):

My secondary question is very simple.  How do you set the seed for
scheme's "random" function (used in my gen-music.ily).  I'd like to
get the repeatability of a pseudo-random number generator.



(set! *random-state* (seed->random-state 42))


Review the Guile documentation [1]:

[1]: 
https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/Random.html#Random



-- Aaron Hill


Thanks, Aaron, for answering the ultimate question [2].

[2] https://en.wikipedia.org/wiki/42_(number)

Jeff




Re: just two questions

2022-04-06 Thread Jean Abou Samra

Hi Dario,

Le 06/04/2022 à 22:46, Dario Marrini a écrit :
hi people, I tried to search for these into docs, but I found 
everything but not what I needed, so, please, can you explain to me 
what's the meaning of these notation kinds? :


 *


_\p_ or _ \p _ ( I don't remember well), where 'p' is a dynamic mark
  * [ a b c d ] (notes written between square brackets

thank you

cheers

dario


If you do not remember what a command or piece of syntax does, your best 
bet is to look into the function index from the notation manual.


https://lilypond.org/doc/v2.23/Documentation/notation/lilypond-command-index

The entries for \p and [ will redirect to pages explaining that the 
underscore _\p means to place the dynamic mark below the note (whereas 
^\p places it above), and note[ ... note] is an explicit beaming (note 
the grouping, it's not "[note ... note]" but "note[ ... note]").


Best regards,
Jean




just two questions

2022-04-06 Thread Dario Marrini
hi people, I tried to search for these into docs, but I found everything
but not what I needed, so, please, can you explain to me what's the meaning
of these notation kinds? :

   -
   _\p_ or _ \p _ ( I don't remember well), where 'p' is a dynamic mark
   - [ a b c d ] (notes written between square brackets

thank you

cheers

dario


Re: bug in magnetic snapping lyrics engraver

2022-04-06 Thread Jean Abou Samra

Le 06/04/2022 à 20:17, Jean Abou Samra a écrit :

Did I miss something?


Whoops, big problem at line breaks ...

\version "2.23.7"

#(define (Left_hyphen_pointer_engraver context)
   (let ((hyphen #f)
 (text #f))
 (make-engraver
  (acknowledgers
   ((lyric-syllable-interface engraver grob source-engraver)
  (set! text grob)))
  (end-acknowledgers
   ((lyric-hyphen-interface engraver grob source-engraver)
  (when (not (grob::has-interface grob 'lyric-space-interface))
    (set! hyphen grob
  ((stop-translation-timestep engraver)
 (when (and text hyphen)
   (ly:grob-set-object! text 'left-hyphen hyphen))
 (set! text #f)
 (set! hyphen #f)

#(define (lyric-text::apply-magnetic-offset! grob)
   (let ((hyphen (ly:grob-object grob 'left-hyphen #f)))
 (when hyphen
   (let ((left-text (ly:spanner-bound hyphen LEFT)))
 (when (grob::has-interface left-text 'lyric-syllable-interface)
   (let* ((common (ly:grob-common-refpoint grob left-text X))
  (my-x-ext (ly:grob-extent grob common X))
  (left-x-ext (begin
    ;; Trigger magnetism for left-text
    (ly:grob-property left-text 
'after-line-breaking)

    (ly:grob-extent left-text common X)))
  (delta (- (interval-start my-x-ext)
    (interval-end left-x-ext)))
  (details (ly:grob-property grob 'details))
  (threshold (assoc-get 'squash-threshold details 0.2)))
 (when (< delta threshold)
   (ly:grob-translate-axis! grob
    (- delta)
    X

#(define (lyric-hyphen::displace-bounds-first grob)
   ;; Make very sure this callback isn't triggered too early.
   (let ((left (ly:spanner-bound grob LEFT))
 (right (ly:spanner-bound grob RIGHT)))
 (ly:grob-property left 'after-line-breaking)
 (ly:grob-property right 'after-line-breaking)
 (ly:lyric-hyphen::print grob)))

\layout {
  \context {
    \Lyrics
    \consists #Left_hyphen_pointer_engraver
    \override LyricText.after-line-breaking = 
#lyric-text::apply-magnetic-offset!

    \override LyricHyphen.stencil = #lyric-hyphen::displace-bounds-first
    \override LyricText.details.squash-threshold = 10
    \override LyricHyphen.minimum-distance = 0
    \override LyricHyphen.minimum-length = 0.2
    \override LyricSpace.minimum-distance = 1
  }
}




Re: bug in magnetic snapping lyrics engraver

2022-04-06 Thread Kieren MacMillan
Hi Jean,

> To be honest, I don't know why the snippet is so complicated.

Perhaps a corollary to Clarke's Law?
“Every sufficiently primitive technology is indistinguishable from garbage.”  ;)
[No offence to the wonderful coders who wrote the existing snippet! Just a 
funny observation re: Clarke.]

> I'd just have done:

I was the main squeaky wheel for whom this grease was originally created.
I'll test out your version and see if it solves all the use-cases I had/have.

Cheers,
Kieren.


Re: bug in magnetic snapping lyrics engraver

2022-04-06 Thread Jean Abou Samra

Le 06/04/2022 à 14:33, Werner LEMBERG a écrit :

Is someone taking care of bugs in the magnetic snapping lyrics
engraver?  Here is an example where it fails to position lyrics
correctly (see last system in the image).


 Werner


PS: I've attached a version of `magnetic-lyrics.ily` that actually
 works with the current development version (using an updated
 `add-grob-definition` routine).




To be honest, I don't know why the snippet is so complicated.
I'd just have done:

\version "2.23.7"

#(define (Left_hyphen_pointer_engraver context)
   (let ((hyphen #f)
 (text #f))
 (make-engraver
  (acknowledgers
   ((lyric-syllable-interface engraver grob source-engraver)
  (set! text grob)))
  (end-acknowledgers
   ((lyric-hyphen-interface engraver grob source-engraver)
  (when (not (grob::has-interface grob 'lyric-space-interface))
(set! hyphen grob
  ((stop-translation-timestep engraver)
 (when (and text hyphen)
   (ly:grob-set-object! text 'left-hyphen hyphen))
 (set! text #f)
 (set! hyphen #f)

#(define (lyric-text::apply-magnetic-offset! grob)
   (let ((hyphen (ly:grob-object grob 'left-hyphen #f)))
 (when hyphen
   (let* ((left-text (ly:spanner-bound hyphen LEFT))
  (common (ly:grob-common-refpoint grob left-text X))
  (my-x-ext (ly:grob-extent grob common X))
  (left-x-ext (begin
;; Trigger magnetism for left-text
(ly:grob-property left-text 'after-line-breaking)
(ly:grob-extent left-text common X)))
  (delta (- (interval-start my-x-ext)
(interval-end left-x-ext)))
  (details (ly:grob-property grob 'details))
  (threshold (assoc-get 'squash-threshold details 0.2)))
 (when (< delta threshold)
   (ly:grob-translate-axis! grob
(- delta)
X))

#(define (lyric-hyphen::displace-bounds-first grob)
   ;; Make very sure this callback isn't triggered too early.
   (let ((left (ly:spanner-bound grob LEFT))
 (right (ly:spanner-bound grob RIGHT)))
 (ly:grob-property left 'after-line-breaking)
 (ly:grob-property right 'after-line-breaking)
 (ly:lyric-hyphen::print grob)))

\layout {
  \context {
\Lyrics
\consists #Left_hyphen_pointer_engraver
\override LyricText.after-line-breaking = 
#lyric-text::apply-magnetic-offset!
\override LyricHyphen.stencil = #lyric-hyphen::displace-bounds-first
\override LyricText.details.squash-threshold = 0.7
\override LyricHyphen.minimum-distance = 0
\override LyricHyphen.minimum-length = 0
\override LyricSpace.minimum-distance = 1
  }
}
   


<<
  \new Voice = "foo" \relative c' {
\repeat unfold 16 { a8 b a2 a8 b }
  }
  \new Lyrics \lyricsto "foo" {
\repeat unfold 10 { foo }
\repeat unfold 10 { foo -- \markup \caps bar }
\repeat unfold 10 { \markup \bold syl -- la -- ble }
a \markup \with-color #red ran -- \markup \box dom string of mo -- no -- 
syl -- la -- bic
and mul -- ti -- \markup \fontsize #5 syl -- la -- bic
\markup \bold \underline ver -- \markup \italic bi -- age
\markup {
  \stencil #(make-circle-stencil 0.5 0 #f)
}
  }





Which seems to work, and doesn't have your first bug.

Did I miss something?

The second bug is super hard to fix: when you tell LilyPond about
spacing constraints between lyrics, before line breaking, you need
to assume a lyric syllable won't be moved to the left by 'magnetism',
because if you do, the spacer might think it can space its right neighbor
more to the left due to the space left by moving the syllable to the
left, and if the compression cannot actually be done, it will collide.
But when the compression does get done, and the room is left empty,
horizontal spacing has already been done and it is too late to tell
the right neighbor that it would have room on its left. Am I making
sense?


Jean




Re: Grace note between arpeggio mark and chord

2022-04-06 Thread Knute Snortum
On Wed, Apr 6, 2022 at 10:15 AM Jean Abou Samra  wrote:
...
> It's much simpler to put the arpeggio on the grace note and tweak its
> positions.
>
> \version "2.22.2"
>
> \relative {
>4 
>\grace {
>  g'8\tweak positions #'(-4 . -1.5) \tweak extra-spacing-width
> #'(-1.0 . 0) \arpeggio
>}
>4  |
> }

An arpeggio on the grace note works beautifully, thank you.



Re: Grace note between arpeggio mark and chord

2022-04-06 Thread Jean Abou Samra




Le 06/04/2022 à 17:44, Knute Snortum a écrit :

Hi everyone.  I have another engraving question.

Without intervention, LilyPond puts a grace note to the left of an
arpeggio mark.  I want it to the right, between the arpeggio mark and
the chord notes.  Here is a snippet of the default behavior:

%%%
\version "2.22.2"

\relative {
   4  \grace { g'8 } 4\arpeggio  |
}
%%%

(I put in the other chords to show the horizontal spacing.)

How I want it to look is like the attached picture.  (I don't need the
"a" cross-staff.)

Just to show what I've tried, here is an example of one of my
(horrible) attempts at solving the problem:

%%%
\relative {
   4 4*1/4 \hideNotes -\tweak X-offset 3 \arpeggio
 \unHideNotes \once \override NoteColumn.X-offset = 2 \magnifyMusic #2/3
 { g'8 } 4  |
}
%%%

The horizontal spacing is way off and can never be tweaked to get it
right.  Any assistance would be greatly appreciated.



It's much simpler to put the arpeggio on the grace note and tweak its 
positions.


\version "2.22.2"

\relative {
  4 
  \grace {
    g'8\tweak positions #'(-4 . -1.5) \tweak extra-spacing-width 
#'(-1.0 . 0) \arpeggio

  }
  4  |
}


Best,
Jean





Grace note between arpeggio mark and chord

2022-04-06 Thread Knute Snortum
Hi everyone.  I have another engraving question.

Without intervention, LilyPond puts a grace note to the left of an
arpeggio mark.  I want it to the right, between the arpeggio mark and
the chord notes.  Here is a snippet of the default behavior:

%%%
\version "2.22.2"

\relative {
  4  \grace { g'8 } 4\arpeggio  |
}
%%%

(I put in the other chords to show the horizontal spacing.)

How I want it to look is like the attached picture.  (I don't need the
"a" cross-staff.)

Just to show what I've tried, here is an example of one of my
(horrible) attempts at solving the problem:

%%%
\relative {
  4 4*1/4 \hideNotes -\tweak X-offset 3 \arpeggio
\unHideNotes \once \override NoteColumn.X-offset = 2 \magnifyMusic #2/3
{ g'8 } 4  |
}
%%%

The horizontal spacing is way off and can never be tweaked to get it
right.  Any assistance would be greatly appreciated.

--
Knute Snortum


Re: bug in magnetic snapping lyrics engraver

2022-04-06 Thread Werner LEMBERG

> Here is an example where it fails to position lyrics correctly (see
> last system in the image).

And while we are at it: Here is another bug, already reported in

  https://lists.gnu.org/archive/html/lilypond-user/2020-03/msg00289.html

I've slightly sharpened the test to exclude the possibility of kerning
being the cause of the (buggy) result.


Werner
\version "2.20.0"

\include "magnetic-lyrics.ily"

\new Lyrics \lyricmode {
  "|foobar|" "|foobar|" \break
  foo -- "|bar|" "|foobar|"
}

\layout {
  \context {
\Lyrics
\override LyricWord.after-line-breaking = #(lyric-word-compressor 0.5)
  }

  \context {
\Score
\remove "Bar_number_engraver"
  }
}

\paper {
  indent = 0
  ragged-right = ##t
  system-system-spacing.basic-distance = 0
  system-system-spacing.minimum-distance = 0
  system-system-spacing.padding = 0
}


Re: problem with extending 'magnetic snapping lyrics' engraver

2022-04-06 Thread Werner LEMBERG

>> but how about just
>> changing
>>
>>    (let* ((hyphen-sten (ly:lyric-hyphen::print hyphen))
>>
>> to
>>
>>    (let* ((hyphen-sten (ly:grob-property hyphen 'stencil))
>>
>>
>> ? Then you can do \override LyricHyphen.stencil = #what-you-want to
>> get the result.
> 
> D'oh, so simple, thanks again!

Well, it doesn't work :-) The magnetic snapping engraver sets the
stencil of all affected `hyphen` grobs to `empty-stencil`.  On the
other hand, the solution with a separate property for the formatter to
be accessed with `ly:grob-property-data` seems to work just fine.


Werner


bug in magnetic snapping lyrics engraver

2022-04-06 Thread Werner LEMBERG

Is someone taking care of bugs in the magnetic snapping lyrics
engraver?  Here is an example where it fails to position lyrics
correctly (see last system in the image).


Werner


PS: I've attached a version of `magnetic-lyrics.ily` that actually
works with the current development version (using an updated
`add-grob-definition` routine).

\version "2.23.7"

\include "magnetic-lyrics.ily"

<<
  \new Voice = "foo" \relative c'' {
d1 ~ | d1 | e16 f e2.. ~ | e1 | f1 | d1 |
d1 ~ | d1 | e16 f e2.. ~ | e1 | f1 | d1 |
d1 ~ | d1 | e16 f e2.. ~ | e1 | f1 | d1 |
d1 ~ | d1 | e16 f e2.. ~ | e1 | f1 | d1 |
d1 ~ | d1 | e16 f e2.. ~ | e1 | f1 | d1 |
  }

  \new Lyrics \lyricsto "foo" {
Foo -- bar -- foo -- bar -- foo -- bar.
Foo -- bar -- foo -- bar -- foo -- bar.
Foo -- bar -- foo -- bar -- foo -- bar.
Foo -- bar -- foo -- bar -- foo -- bar.
Foo -- bar -- foo -- bar -- foo -- bar.
  }
>>


\paper {
  indent = 0
  ragged-right = ##f
  line-width = 90\mm
}


\layout {
  \context {
\Lyrics
\override LyricWord.after-line-breaking = #(lyric-word-compressor 0.5)
\override LyricHyphen.minimum-distance = #0
\override LyricSpace.minimum-distance = #1
  }
}
\version "2.23.7"

%% CHANGELOG
%%
%% 2022-04-21 Werner Lemberg
%%
%%   * Update `add-grob-definition` to make it work with current development
%% version (2.23.7).
%%
%% 2019-05-28 Thomas Morley
%% 
%%   * s/map/for-each/.
%%   * Fix comment typo.
%%   * New function `remove-line-starting-hyphens` to exclude line-starting
%% `LyricHyphen`.
%%
%% 2014-03-19
%%
%%   * Initial version.

\header {
  snippet-title = "Magnetic snapping lyric syllables"
  snippet-author = "David Nalesnik, Mike Solomon, Thomas Morley,
Werner Lemberg"
  % snippet-source = 
"http://lists.gnu.org/archive/html/lilypond-user/2014-03/msg00489.html;
  % snippet-source = 
"https://lists.gnu.org/archive/html/lilypond-user/2019-05/msg00388.html;
  snippet-source = 
"https://lists.gnu.org/archive/html/lilypond-user/2022-04/msg00062.html;
  % https://lists.gnu.org/archive/html/lilypond-user/2022-04/msg00062.html
  snippet-description = \markup {
This snippet handles lyric syllables that belong to one word together
and ensures that there are no irritating gaps between them (solves issue 
2458).
  }
  % add comma-separated tags to make searching more effective:
  tags = "lyrics, syllable, gap, hyphen"
  % is this snippet ready?  See meta/status-values.md
  status = "undecided"
}

%%
% here goes the snippet: %
%%

% ADD NEW GROB INTERFACE %%

#(ly:add-interface
  'lyric-word-interface
  "A word of lyrics. Includes syllables and hyphens."
  '(text-items))

%%%

% CREATE NEW GROB PROPERTY 

#(define (define-grob-property symbol type? description)
   (if (not (equal? (object-property symbol 'backend-doc) #f))
   (ly:error (_ "symbol ~S redefined") symbol))

   (set-object-property! symbol 'backend-type? type?)
   (set-object-property! symbol 'backend-doc description)
   symbol)

#(for-each
  (lambda (x)
(apply define-grob-property x))

  `(
 (text-items ,list? "Syllables and hyphens of a word of lyrics")))

%%%

 ADD DEFINITION OF GROB %%%

#(define (add-grob-definition grob-name grob-entry)
   (let* ((meta-entry   (assoc-get 'meta grob-entry))
  (class(assoc-get 'class meta-entry #f))
  (ifaces-entry (assoc-get 'interfaces meta-entry)))
 (set-object-property! grob-name 'translation-type? ly:grob-properties?)
 (set-object-property! grob-name 'is-grob? #t)
 (set! ifaces-entry (uniq-list (sort ifaces-entry symbol (interval-length hyphen-ex) threshold)
 '() ; no compression--DO NOTHING!

 (let*
  ((syl-a-text (ly:grob-property syl-a 'text))
   (syl-a-text (if (markup? syl-a-text) syl-a-text (markup syl-a-text)))
   (syl-b-text (ly:grob-property syl-b 'text))
   (syl-b-text (if (markup? syl-b-text) syl-b-text (markup syl-b-text)))
   (full-text (make-concat-markup (list syl-a-text syl-b-text

  (set! (ly:grob-property syl-a 'text) full-text)
  (set! (ly:grob-property syl-b 'text) empty-markup)
  (set! (ly:grob-property syl-a 'stencil) lyric-text::print)
  (set! (ly:grob-property syl-b 'stencil) lyric-text::print)
  (set! (ly:grob-property hyphen 'stencil) empty-stencil)

#(define (lyric-word-compressor threshold)
   (lambda (grob) ; LyricWord
 (let* ((items (ly:grob-object grob 'text-items))
(item-list (ly:grob-array->list items)))
   (if (> (length item-list) 1) ; do nothing to monosyllabic words

Re: problem with extending 'magnetic snapping lyrics' engraver

2022-04-06 Thread Werner LEMBERG

> It's uncomfortable to have grob properties of procedure type, since
> they are automatically resolved as callbacks.  You set
> LyricWord.hyphen-formatter to ly:lyric-hyphen::print.  Then, when
> you do
>
>   (ly:grob-property grob 'hyphen-formatter)
>
> this not only looks up ly:lyric-hyphen::print in the property, but
> executes it on the LyricWord and returns the result.  Since
> ly:lyric-hyphen::print is written to work on a LyricHyphen and not a
> LyricWord, it gives up and returns '().  Then you try to apply the
> "formatter" '() to the hyphen, which goes wrong.  You could use
> ly:grob-property-data, which skips callbacks, [...]

Thanks a lot for the explanation!

> but how about just
> changing
>
>    (let* ((hyphen-sten (ly:lyric-hyphen::print hyphen))
>
> to
>
>    (let* ((hyphen-sten (ly:grob-property hyphen 'stencil))
>
>
> ? Then you can do \override LyricHyphen.stencil = #what-you-want to
> get the result.

D'oh, so simple, thanks again!


Werner


Re: problem with extending 'magnetic snapping lyrics' engraver

2022-04-06 Thread Jean Abou Samra

Le 06/04/2022 à 09:49, Werner LEMBERG a écrit :

I'm trying to generalize the 'magnetic snapping lyrics' engraver (the
most recent version posted as
https://lists.gnu.org/archive/html/lilypond-user/2019-05/msg00389.html)
by providing a new property `hyphen-formatter`, to be used instead of
the hard-coded `ly:lyric-hyphen::print`.  Attached you can see the
final file together with a diff to the original version (ignoring
whitespace), and an example.  Unfortunately, it doesn't work, and I
can't find the problem: It aborts with

```
ERROR: Wrong type to apply: ()
```

Please advise.



It's uncomfortable to have grob properties of procedure type,
since they are automatically resolved as callbacks. You set
LyricWord.hyphen-formatter to ly:lyric-hyphen::print. Then,
when you do

  (ly:grob-property grob 'hyphen-formatter)

this not only looks up ly:lyric-hyphen::print in the property,
but executes it on the LyricWord and returns the result. Since
ly:lyric-hyphen::print is written to work on a LyricHyphen and
not a LyricWord, it gives up and returns '(). Then you try to
apply the "formatter" '() to the hyphen, which goes wrong. You
could use ly:grob-property-data, which skips callbacks, but how
about just changing

   (let* ((hyphen-sten (ly:lyric-hyphen::print hyphen))

to

   (let* ((hyphen-sten (ly:grob-property hyphen 'stencil))


? Then you can do \override LyricHyphen.stencil = #what-you-want to
get the result.


Jean



problem with extending 'magnetic snapping lyrics' engraver

2022-04-06 Thread Werner LEMBERG

I'm trying to generalize the 'magnetic snapping lyrics' engraver (the
most recent version posted as
https://lists.gnu.org/archive/html/lilypond-user/2019-05/msg00389.html)
by providing a new property `hyphen-formatter`, to be used instead of
the hard-coded `ly:lyric-hyphen::print`.  Attached you can see the
final file together with a diff to the original version (ignoring
whitespace), and an example.  Unfortunately, it doesn't work, and I
can't find the problem: It aborts with

```
ERROR: Wrong type to apply: ()
```

Please advise.


Werner
\version "2.23.7"

%% CHANGE-LOG harm ()
%%
%% line 52:
%% map becomes for-each
%%
%% line 133:
%% typo in comment
%%
%% lines 234 ff, 260:
%% exclude line-starting LyricHyphen

\header {
  snippet-title = "Magnetic snapping lyric syllables"
  snippet-author = "David Nalesnik, Mike Solomon, harm"
  % snippet-source = 
"http://lists.gnu.org/archive/html/lilypond-user/2014-03/msg00489.html;
  snippet-source = "see 
https://lists.gnu.org/archive/html/lilypond-user/2019-05/msg00388.html;
  snippet-description = \markup {
This snippet handles lyric syllables that belong to one word together
and ensures that there are no irritating gaps between them (solves issue 
2458).
  }
  % add comma-separated tags to make searching more effective:
  tags = "lyrics, syllable, gap, hyphen"
  % is this snippet ready?  See meta/status-values.md
  status = "undecided"
}

%%
% here goes the snippet: %
%%

% ADD NEW GROB INTERFACE %%

#(ly:add-interface
  'lyric-word-interface
  "A word of lyrics. Includes syllables and hyphens."
  '(text-items
hyphen-formatter))

%%%

% CREATE NEW GROB PROPERTY 

#(define (define-grob-property symbol type? description)
   (if (not (equal? (object-property symbol 'backend-doc) #f))
   (ly:error (_ "symbol ~S redefined") symbol))

   (set-object-property! symbol 'backend-type? type?)
   (set-object-property! symbol 'backend-doc description)
   symbol)

%% harm:
#(for-each
  (lambda (x)
(apply define-grob-property x))

  `(
(text-items ,list? "Syllables and hyphens of a word of lyrics")
(hyphen-formatter ,ly:stencil? "Stencil for formatting hyphens")))

%%%

 ADD DEFINITION OF GROB %%%

#(define (add-grob-definition grob-name grob-entry)
   (let* ((meta-entry   (assoc-get 'meta grob-entry))
  (class(assoc-get 'class meta-entry #f))
  (ifaces-entry (assoc-get 'interfaces meta-entry)))
 (set-object-property! grob-name 'translation-type? ly:grob-properties?)
 (set-object-property! grob-name 'is-grob? #t)
 (set! ifaces-entry (uniq-list (sort ifaces-entry symbol (interval-length hyphen-ex) threshold)
 '() ; no compression--DO NOTHING!

 (let*
 ((syl-a-text (ly:grob-property syl-a 'text))
  (syl-a-text (if (markup? syl-a-text) syl-a-text (markup 
syl-a-text)))
  (syl-b-text (ly:grob-property syl-b 'text))
  (syl-b-text (if (markup? syl-b-text) syl-b-text (markup 
syl-b-text)))
  (full-text (make-concat-markup (list syl-a-text syl-b-text

   (set! (ly:grob-property syl-a 'text) full-text)
   (set! (ly:grob-property syl-b 'text) empty-markup)
   (set! (ly:grob-property syl-a 'stencil) lyric-text::print)
   (set! (ly:grob-property syl-b 'stencil) lyric-text::print)
   (set! (ly:grob-property hyphen 'stencil) empty-stencil)

#(define (lyric-word-compressor threshold)
   (lambda (grob) ; LyricWord
 (let* ((items (ly:grob-object grob 'text-items))
(item-list (ly:grob-array->list items)))
   (if (> (length item-list) 1) ; do nothing to monosyllabic words
   (let* ((formatter (ly:grob-property grob 'hyphen-formatter))
  (text-grobs
   (filter
(lambda (item)
  (grob::has-interface item 'lyric-syllable-interface))
item-list))
  (hyphen-grobs
   (filter
(lambda (item)
  (grob::has-interface item 'lyric-hyphen-interface))
item-list)))

 (define (helper fmt seed tx-list hy-list)
   (if (and (pair? (cdr tx-list))
(pair? hy-list))
   (let ((next-syl (cadr tx-list))
 (hyphen (car hy-list)))
 (compress-pair fmt seed hyphen next-syl threshold)
 (if (equal? empty-markup (ly:grob-property next-syl 'text))
 (helper fmt seed (cdr tx-list) (cdr hy-list))
 (helper fmt 

Re: how to repeat a scheme function that creates a Score

2022-04-06 Thread Jean Abou Samra

Le 06/04/2022 à 07:40, Jeff Olson a écrit :

Two questions below re: (a) looping and (b) random seed.


In order to investigate some other problems I'm having in a large 
project (pagination, memory usage) I learned enough scheme (barely) to 
define a function that generates a new score with each invocation:


--

\version "2.22.0"

\include "gen-music.ily"

% each invocation of scr generates a new score of different length
pcn = 0
scr = #(define-scheme-function () ()
   (set! pcn (1+ pcn))
   #{
 \score {
   \header { piece = \markup{ "Piece " #(number->string pcn) } }
   { \gen-music \bar "|."} }
   #} )

--

(The include file, gen-music.ily, is attached, and the above ~MWE is 
also attached as MWE-do-scr.ly.)


Question (a):

My main question is how to write a scheme function that will invoke my 
scr function N times, where N could be a number like 1000.


So far the only way I know how to do multiple invocations is by 
explicitly hard-coding "\scr \scr ..." in blocks and copy/pasting 
those blocks.


Looking for a better way, I realized I don't even know how to get one 
line of scheme to do 2 invocations (needed for tail recursion 
approach).  I can make them execute, in some cases, but not to produce 
pdf output (never gets to "Interpreting music...").  Part of this may 
be #(scr) vs $(scr).  The attached MWE file has lots of my failed 
attempts commented out (I'm at a teachable moment if someone has a 
moment to teach).  Or just point me to the right manual page(s).



Here is a piece of code that works:


$@(map (lambda (i) (scr)) (iota 10))


Now let's go through your attempt to see why they are failing.


#(define scors (lambda (n) (if (= n 1) (scr) ((scr) (scors (- n 1) )
#(scors 2)

This one is trying to apply a score (the result of (scr)) as a
function. A score is not a function. Also, if n = 1, (src) is
generated, which is not a list, so at the end of the day you
get an "improper list" (something that looks like a list but
doesn't have the empty list at the end of the cdr chain).
Rather do

#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )
#(scors 2)


That doesn't error out (scors is applied successfully), but no output
either, as you noticed. The problem is that when LilyPond reads a
toplevel expression introduced by #, it refrains from interpreting the
result, since that is the main way you can write code that operates via
side effects on the toplevel (think #(define ...) and such). You need
to be a little more insistent, with $.

#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )
$(scors 2)

Now that gives the error "bad expression type". Indeed, LilyPond knows how
to interpret a score, but not a list of scores. So you need to splice
the list into several scores that LilyPond will interpret separately.
You can do that with $@. Thus, this works:

#(define scors (lambda (n) (if (= n 0) '() (cons (scr) (scors (- n 1) )
$@(scors 2)


Now to your second attempt:

#(for-each (lambda (ignore) (scr)) '(1 2 3 4 5))

This has the same problem of # vs. $@. Also, it is using for-each, which
applies a function for its side effect but does not remember the result.
In this case, you want a list of the results, which is what map is for.

$@(map (lambda (ignore) (scr)) '(1 2 3 4 5))


Now to

#(begin (scr) (scr) (scr))

and

$(begin (scr) (scr) (scr))

The first discards the result because of #. The second calls src thrice, and
discards the results of the two first invocations -- that's what begin is
for. As Valentin pointed out while I was writing this, you could use 
add-score
to let LilyPond know about your score via a side effect rather than by 
returning

them.

#(begin
  (add-score (scr))
  (add-score (scr))
  (add-score (scr)))


For the examples at the end, you need $@mine, which is the only one you 
didn't try :-)


Best,
Jean




Re: how to repeat a scheme function that creates a Score

2022-04-06 Thread Aaron Hill

On 2022-04-05 10:40 pm, Jeff Olson wrote:

Question (a):

My main question is how to write a scheme function that will invoke my
scr function N times, where N could be a number like 1000.



#(for-each add-score (map (lambda (x) #{ \scr #}) (iota 5)))


Replace 5 with whatever.


-- Aaron Hill



Re: Temporary div. multiple staffs

2022-04-06 Thread Xavier Scheuer
On Wed, 6 Apr 2022 at 08:39, Xavier Scheuer  wrote:
> Hello,
>
> One way mentioned in the documentation is to use the
"Keep_alive_together_engraver" in combination with keepAliveInterfaces and
VerticalAxisGroup.remove-layer.
> See NR 1.6.2 Modifying single staves > Hiding staves
>
https://lilypond.org/doc/v2.23/Documentation/notation/writing-parts#hiding-staves

Wrong link, correct one:
https://lilypond.org/doc/v2.23/Documentation/notation/modifying-single-staves.html#hiding-staves

Cheers,
Xavier

-- 
Xavier Scheuer 


Re: Temporary div. multiple staffs

2022-04-06 Thread Xavier Scheuer
On Wed, 6 Apr 2022 at 07:21, Evan Driscoll  wrote:
>
> Another question, one I've struggled with before.
>
> The part splits out temporarily into divisi parts on multiple staffs. I
always have trouble getting the correct incantations to get the correct
result.
>
> A naive attempt results in http://lilybin.com/1l8whf/5. This is enough to
keep working, but it looks bad -- barlines don't cross between staffs, and
there's no grouping a la
https://lilypond.org/doc/v2.22/Documentation/69/lily-9c91c2b7.png from the
manual.
>
> I can get a pair of staffs that are correct on their own by creating a
StaffGroup with two new staffs -- http://lilybin.com/1l8whf/9 -- but the
original staff continues through. Omitting the explicit \new Staff
invocations doesn't help -- http://lilybin.com/1l8whf/11.
>
> What's the right way to do this?

Hello,

One way mentioned in the documentation is to use the
"Keep_alive_together_engraver" in combination with keepAliveInterfaces and
VerticalAxisGroup.remove-layer.
See NR 1.6.2 Modifying single staves > Hiding staves
https://lilypond.org/doc/v2.23/Documentation/notation/writing-parts#hiding-staves

Cheers,
Xavier

-- 
Xavier Scheuer 


Re: Temporary div. multiple staffs

2022-04-06 Thread Aaron Hill

(Please keep the mailing list on all replies.)

On 2022-04-05 11:06 pm, Evan Driscoll wrote:
On Wed, Apr 6, 2022 at 12:37 AM Aaron Hill  
wrote:



Unsure there is a definitively "right" way... but here's an option:

http://lilybin.com/1l8whf/12

Move the StaffGroup declaration outside the music.  Also, you can name
contexts so you can reference an existing one to avoid creating new 
ones

(explicitly or implicitly).



Perfect, thanks!

As a final tweak, in case anyone finds this thread in the future, 
here's

how to omit the time signature on the new staff:
http://lilybin.com/1l8whf/15

Though a question -- I discovered that adding *just* the \new 
StaffGroup on

the "outside" made things work -- on the simplified example, that'd be
something like http://lilybin.com/1l8whf/16. In other words, that works
even without explicitly naming the existing Staff context and referring 
to

it with \context. Is there any difference between these, aside from
possible readability arguments?


In many cases, you can rely on the implicit handling of contexts.  Your 
example #16 above relies on the implicit continuation of the current 
context as only the divisi staff is explicitly created, so things do 
work as expected.


But note that this new staff appears below the original one.  If you 
wanted it to be above, consider:


http://lilybin.com/1l8whf/17

(I added color just to make it easier to see which context is which.)


-- Aaron Hill



Re: TextScript vertical alignment in Dynamics context

2022-04-06 Thread Mark Knoop

At 12:21 on 05 Apr 2022, Jean Abou Samra wrote:

Le 05/04/2022 à 09:48, Mark Knoop a écrit :

Hi,

I'm trying to align markups in a Dynamics context to their baseline, but they 
always align their tops. Can't figure out what property to set to achieve this.

Example follows - I'd like the markups on the first line (which are in a 
Dynamics context) to align DOWN rather than UP, i.e. to match the behaviour of 
the markups on the second line (which are in a Voice context).

Thanks in advance for any help on this.



The alignment of text scripts is done via side positioning 
(side-position-interface). Here they position against nothing, so the alignment 
code just keeps them aligned on a fictive line at 0. The direction of these 
text scripts is DOWN, so in effect they align on their tops. If you want them 
aligned on their bottoms, set them to the other direction.


\new Dynamics \with {
  \override TextScript.direction = #UP
} ...


Alternatively, use a mechanism that makes more sense for your use case, self 
alignment (self-alignment-interface).


\new Dynamics \with {
  \override TextScript.Y-offset =
#ly:self-alignment-interface::y-aligned-on-self
  \override TextScript.self-alignment-Y = #DOWN
} ...



Best,
Jean


Thanks Jean!


--
Mark Knoop



Re: how to repeat a scheme function that creates a Score

2022-04-06 Thread Valentin Petzel
Hello Jeff,

A scheme-function will only be able to output a single top-level-score like 
this. You should rather do a void-function that calls (add-score #{ \score 
{...} #}) directly. Similarly you can use (add-text ...) to add top-level 
markups.

Cheers,
Valentin

Am Mittwoch, 6. April 2022, 07:40:00 CEST schrieb Jeff Olson:
> Two questions below re: (a) looping and (b) random seed.
> 
> 
> In order to investigate some other problems I'm having in a large
> project (pagination, memory usage) I learned enough scheme (barely) to
> define a function that generates a new score with each invocation:
> 
> --
> 
> \version "2.22.0"
> 
> \include "gen-music.ily"
> 
> % each invocation of scr generates a new score of different length
> pcn = 0
> scr = #(define-scheme-function () ()
> (set! pcn (1+ pcn))
> #{
>   \score {
> \header { piece = \markup{ "Piece " #(number->string pcn) } }
> { \gen-music \bar "|."} }
> #} )
> 
> --
> 
> (The include file, gen-music.ily, is attached, and the above ~MWE is
> also attached as MWE-do-scr.ly.)
> 
> Question (a):
> 
> My main question is how to write a scheme function that will invoke my
> scr function N times, where N could be a number like 1000.
> 
> So far the only way I know how to do multiple invocations is by
> explicitly hard-coding "\scr \scr ..." in blocks and copy/pasting those
> blocks.
> 
> Looking for a better way, I realized I don't even know how to get one
> line of scheme to do 2 invocations (needed for tail recursion
> approach).  I can make them execute, in some cases, but not to produce
> pdf output (never gets to "Interpreting music...").  Part of this may be
> #(scr) vs $(scr).  The attached MWE file has lots of my failed attempts
> commented out (I'm at a teachable moment if someone has a moment to
> teach).  Or just point me to the right manual page(s).
> 
> Question (b):
> 
> My secondary question is very simple.  How do you set the seed for
> scheme's "random" function (used in my gen-music.ily).  I'd like to get
> the repeatability of a pseudo-random number generator.
> 
> TIA,
> Jeff
> 
> P.S. May you smile when you see the generated music.



signature.asc
Description: This is a digitally signed message part.