Re: shifting accidentals horizontally

2023-06-12 Thread Werner LEMBERG

> @Werner I’ve added a small fix concerning the case when there is no
> NoteCollision grob (in which case this should not be relevant in the
> first place).

Thanks a lot!  I think this would be a great snippet for the
LSR.

Note, however, that there are alignment problems with other staves,
see below.  For this particular case I can fix it by using
`NoteColumn.X-offset`, but this isn't a sustainable solution.


Werner


==


#(define (which lst)
   (define (impl lst count)
 (if (null? lst)
 #f
 (if (car lst)
 count
 (impl (cdr lst) (1+ count)
   (impl lst 0))


#(define (custom_accidental_placement_engraver context)
   (define (grob-array->list x)
 (if (ly:grob-array? x)
 (ly:grob-array->list x)
 '()))
   (let ((placement #f))
 (make-engraver
  (acknowledgers
   ((accidental-interface engraver grob source-engraver)
(if (assoc-get 'capture (ly:grob-property grob 'details) #f)
(begin
  (if (not placement)
  (begin
   (set! placement (ly:engraver-make-grob engraver 
'AccidentalPlacement '()))
   (ly:grob-set-parent! placement X (ly:grob-parent 
(ly:grob-parent grob Y) X))
   (let ((padding (ly:grob-property-data placement 
'right-padding)))
 (ly:grob-set-property!
  placement
  'right-padding
  (lambda (grob)
(let* ((grobs (ly:grob-object placement 
'accidental-grobs))
   (grobs (apply append (map cdr grobs)))
   (heads (map (lambda (x) (ly:grob-parent x Y)) 
grobs))
   (stems (map (lambda (x) (ly:grob-object x 
'stem)) heads))
   (cols (map (lambda (x) (ly:grob-parent x X)) 
heads))
   (collisions (map (lambda (x) (ly:grob-parent x 
X)) cols))
   (cols2 (apply append
 (map 
  (lambda (x)
(grob-array->list 
(ly:grob-object x 'elements)))
  collisions)))
   (heads2 (apply append
  (map
   (lambda (x)
 (grob-array->list 
(ly:grob-object x 'note-heads)))
   cols2)))
   (stems2 (map (lambda (x) (ly:grob-object x 
'stem)) heads))
   (grob-set1 (ly:grob-list->grob-array (append 
heads stems)))
   (grob-set2 (ly:grob-list->grob-array (append 
heads stems heads2 stems2)))
   (refp (ly:grob-common-refpoint-of-array grob 
grob-set1 X))
   (refp2 (ly:grob-common-refpoint-of-array grob 
grob-set2 X))
   (ext (ly:grob-extent refp refp2 X))
   (ext2 (ly:grob-extent refp2 refp2 X))
   (offset (car ext))
   (offset (- offset (car ext2
  (- (if (procedure? padding) (padding grob) padding) 
offset)))
  (let* ((src-placement (ly:grob-parent grob X))
 (grobs (ly:grob-object src-placement 'accidental-grobs))
 (has-grob? (map (lambda (pair) (memq grob (cdr pair))) 
grobs))
 (pair (list-ref grobs (which has-grob?)))
 (notename (car pair))
 (groblist (cdr pair))
 (new-grobs (ly:grob-object placement 'accidental-grobs))
 (new-groblist (assoc-get notename new-grobs '()))
 (groblist (delete grob groblist eq?))
 (new-groblist (cons grob new-groblist))
 (grobs (assoc-set! grobs notename groblist))
 (new-grobs (assoc-set! new-grobs notename new-groblist)))
(ly:grob-set-object! src-placement 'accidental-grobs grobs)
(ly:grob-set-object! placement 'accidental-grobs new-grobs)
(ly:grob-set-parent! grob X placement))
  ((finish-timestep engraver)
   (set! placement #f)

\layout {
  \context {
\Voice
\consists #custom_accidental_placement_engraver
  }
}

<<
  \new Staff {
<< { 2. 4 |
 2. 4 } \\
   { \once \override NoteColumn.force-hshift = #2.4
 bes'!8 a' g' f' bes' a' g' f' |
 \once \override NoteColumn.force-hshift = #3.4
 \once \override Accidental.details.capture = ##t
 bes'!8 a' g' f' bes' a' g' f' } >>
  }
  \new Staff 

Re: shifting accidentals horizontally

2023-06-12 Thread Werner LEMBERG

> Even though I can imagine this happening, I don't recall seeing it
> as a pianist.  Even if you tweak it to swap the note columns, I
> think it will still be a bit confusing.

As Damian has observed, there are plenty of examples in Bartók's piano
sonata.  Other, similar situations can be found in Berg's vocal scores
of Lulu or Wozzeck, say, which both contain highly complex, polyphonal
music, and where the creators of the vocal scores took great pains to
retain the polyphony in the piano reduction.

> There are two obvious fixes: if you are the composer, you could
> consider changing the B♭ into an A♯. And the other solution is to
> move the B♭ note to the lower staff in a local treble clef.

I'm aware of that, thanks, but neither is a good solution for my use
case.


Werner


Re: shifting accidentals horizontally

2023-06-12 Thread Damian leGassick


> Even though I can imagine this happening, I don't recall seeing
> it as a pianist. Even if you tweak it to swap the note columns,
> I think it will still be a bit confusing.
> 
> There are two obvious fixes: if you are the composer, you could
> consider changing the B♭ into an A♯. And the other solution is
> to move the B♭ note to the lower staff in a local treble clef.

there’s many examples in Bartok, e.g. Sonata, p9 has about 10 of them

D


Re: shifting accidentals horizontally

2023-06-12 Thread Valentin Petzel
Hello Jean,

I think a possible case would be something like the appended case, so if we 
have some sort of superimposed patterns.

@Werner I’ve added a small fix concerning the case when there is no 
NoteCollision grob (in which case this should not be relevant in the first 
place).

Cheers,
Valentin

Am Montag, 12. Juni 2023, 22:32:17 CEST schrieb Jean Abou Samra:
> Le lundi 12 juin 2023 à 17:02 +, Werner LEMBERG a écrit :
> > Please consider the example code below.  The first line shows
> > LilyPond's default, the second line shows what I need.  As can be
> > seen, the solution in the second line is imperfect – I just did the
> > most basic changes to demonstrate what I want, namely the down-stemmed
> > note to be positioned after the up-stemmed chord.
> > 
> > Is there an automated solution for this problem (namely correctly
> > positioned and spaced naturals for the chord)?  The LSR doesn't really
> > help, unfortunately.
> > 
> > BTW, such situations happen from time to time in piano music.
> > 
> > ```
> > \version "2.25.6"
> > 
> > << { 2. } \\
> >{ bes'!8 } >>
> > 
> > << { 2. } \\
> >{
> >  \once \override NoteColumn.force-hshift = #3.3
> >  \once \override Accidental.extra-offset = #'(4.7 . 0)
> >  bes'!8 } >>
> > ```
> 
> Even though I can imagine this happening, I don't recall seeing
> it as a pianist. Even if you tweak it to swap the note columns,
> I think it will still be a bit confusing.
> 
> There are two obvious fixes: if you are the composer, you could
> consider changing the B♭ into an A♯. And the other solution is
> to move the B♭ note to the lower staff in a local treble clef.

#(define (which lst)
   (define (impl lst count)
 (if (null? lst)
 #f
 (if (car lst)
 count
 (impl (cdr lst) (1+ count)
   (impl lst 0))


#(define (custom_accidental_placement_engraver context)
   (define (grob-array->list x)
 (if (ly:grob-array? x)
 (ly:grob-array->list x)
 '()))
   (let ((placement #f))
 (make-engraver
  (acknowledgers
   ((accidental-interface engraver grob source-engraver)
(if (assoc-get 'capture (ly:grob-property grob 'details) #f)
(begin
  (if (not placement)
  (begin
   (set! placement (ly:engraver-make-grob engraver 'AccidentalPlacement '()))
   (ly:grob-set-parent! placement X (ly:grob-parent (ly:grob-parent grob Y) X))
   (let ((padding (ly:grob-property-data placement 'right-padding)))
 (ly:grob-set-property!
  placement
  'right-padding
  (lambda (grob)
(let* ((grobs (ly:grob-object placement 'accidental-grobs))
   (grobs (apply append (map cdr grobs)))
   (heads (map (lambda (x) (ly:grob-parent x Y)) grobs))
   (stems (map (lambda (x) (ly:grob-object x 'stem)) heads))
   (cols (map (lambda (x) (ly:grob-parent x X)) heads))
   (collisions (map (lambda (x) (ly:grob-parent x X)) cols))
   (cols2 (apply append
 (map 
  (lambda (x)
(grob-array->list (ly:grob-object x 'elements)))
  collisions)))
   (heads2 (apply append
  (map
   (lambda (x)
 (grob-array->list (ly:grob-object x 'note-heads)))
   cols2)))
   (stems2 (map (lambda (x) (ly:grob-object x 'stem)) heads))
   (grob-set1 (ly:grob-list->grob-array (append heads stems)))
   (grob-set2 (ly:grob-list->grob-array (append heads stems heads2 stems2)))
   (refp (ly:grob-common-refpoint-of-array grob grob-set1 X))
   (refp2 (ly:grob-common-refpoint-of-array grob grob-set2 X))
   (ext (ly:grob-extent refp refp2 X))
   (ext2 (ly:grob-extent refp2 refp2 X))
   (offset (car ext))
   (offset (- offset (car ext2
  (- (if (procedure? padding) (padding grob) padding) offset)))
  (let* ((src-placement (ly:grob-parent grob X))
 (grobs (ly:grob-object src-placement 'accidental-grobs))
 (has-grob? (map (lambda (pair) (memq grob (cdr pair))) grobs))
 (pair (list-ref grobs (which has-grob?)))
 (notename (car pair))
 

Re: shifting accidentals horizontally

2023-06-12 Thread Jean Abou Samra
Le lundi 12 juin 2023 à 17:02 +, Werner LEMBERG a écrit :
> Please consider the example code below.  The first line shows
> LilyPond's default, the second line shows what I need.  As can be
> seen, the solution in the second line is imperfect – I just did the
> most basic changes to demonstrate what I want, namely the down-stemmed
> note to be positioned after the up-stemmed chord.
> 
> Is there an automated solution for this problem (namely correctly
> positioned and spaced naturals for the chord)?  The LSR doesn't really
> help, unfortunately.
> 
> BTW, such situations happen from time to time in piano music.
> 
> ```
> \version "2.25.6"
> 
> << { 2. } \\
>    { bes'!8 } >>
> 
> << { 2. } \\
>    {
>  \once \override NoteColumn.force-hshift = #3.3
>  \once \override Accidental.extra-offset = #'(4.7 . 0)
>  bes'!8 } >>
> ```


Even though I can imagine this happening, I don't recall seeing
it as a pianist. Even if you tweak it to swap the note columns,
I think it will still be a bit confusing.

There are two obvious fixes: if you are the composer, you could
consider changing the B♭ into an A♯. And the other solution is
to move the B♭ note to the lower staff in a local treble clef.


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


Re: shifting accidentals horizontally

2023-06-12 Thread Valentin Petzel
Hello Werner,

I’ve tried something using an engraver that sends of accidentals from the 
given context to a separate AccidentalPlacement grob:

%
#(define (which lst)
   (define (impl lst count)
 (if (null? lst)
 #f
 (if (car lst)
 count
 (impl (cdr lst) (1+ count)
   (impl lst 0))

#(define (custom_accidental_placement_engraver context)
   (let ((placement #f))
 (make-engraver
  (acknowledgers
   ((accidental-interface engraver grob source-engraver)
(if (not placement)
(begin
 (set! placement (ly:engraver-make-grob engraver 
'AccidentalPlacement '()))
 (ly:grob-set-parent! placement X (ly:grob-parent (ly:grob-parent 
grob Y) X
(let* ((src-placement (ly:grob-parent grob X))
   (grobs (ly:grob-object src-placement 'accidental-grobs))
   (has-grob? (map (lambda (pair) (memq grob (cdr pair))) grobs))
   (pair (list-ref grobs (which has-grob?)))
   (notename (car pair))
   (groblist (cdr pair))
   (new-grobs (ly:grob-object placement 'accidental-grobs))
   (new-groblist (assoc-get notename new-grobs '()))
   (groblist (delete grob groblist eq?))
   (new-groblist (cons grob new-groblist))
   (grobs (assoc-set! grobs notename groblist))
   (new-grobs (assoc-set! new-grobs notename new-groblist)))
  (ly:grob-set-object! src-placement 'accidental-grobs grobs)
  (ly:grob-set-object! placement 'accidental-grobs new-grobs)
  (ly:grob-set-parent! grob X placement
  ((finish-timestep engraver)
   (set! placement #f)

{
  << { 2. } \\
   \new Voice \with { \consists #custom_accidental_placement_engraver } { 
\once \override NoteColumn.force-hshift = #3.3 bes'!8 } >>
}
%


Sadly this does not really do the trick because the Accidental-Placement grob 
uses the NoteCollision grob to gain access to all heads and stems and 
positions relative to the common refpoint. In my opinion this could be 
improved by using this common refpoint as offset for the AccidentalPlacement, 
and then position the Accidentals relative to this AccidentalPlacement. This 
would give us the ability to shift the Accidentals by shifting the X-offset.

We can still do something like

{
  << { 2. } \\
   \new Voice \with { \consists #custom_accidental_placement_engraver }
   { \once\override AccidentalPlacement.right-padding = #-3.7 \once \override 
NoteColumn.force-hshift = #3.4 bes'!8 } >>
},

So what I’ve done now is to use that property to automatically determine a 
"correct" value. Note that this may cause collisions!


%
#(define (which lst)
   (define (impl lst count)
 (if (null? lst)
 #f
 (if (car lst)
 count
 (impl (cdr lst) (1+ count)
   (impl lst 0))

#(define (custom_accidental_placement_engraver context)
   (let ((placement #f))
 (make-engraver
  (acknowledgers
   ((accidental-interface engraver grob source-engraver)
(if (not placement)
(begin
 (set! placement (ly:engraver-make-grob engraver 
'AccidentalPlacement '()))
 (ly:grob-set-parent! placement X (ly:grob-parent (ly:grob-parent 
grob Y) X))
 (let ((padding (ly:grob-property-data placement 'right-padding)))
   (ly:grob-set-property!
placement
'right-padding
(lambda (grob)
  (let* ((grobs (ly:grob-object placement 'accidental-grobs))
 (grobs (apply append (map cdr grobs)))
 (heads (map (lambda (x) (ly:grob-parent x Y)) grobs))
 (stems (map (lambda (x) (ly:grob-object x 'stem)) 
heads))
 (cols (map (lambda (x) (ly:grob-parent x X)) heads))
 (collisions (map (lambda (x) (ly:grob-parent x X)) 
cols))
 (cols2 (apply append
   (map 
(lambda (x)
  (ly:grob-array->list (ly:grob-object 
x 'elements)))
collisions)))
 (heads2 (apply append
(map
 (lambda (x)
   (ly:grob-array->list (ly:grob-
object x 'note-heads)))
 cols2)))
 (stems2 (map (lambda (x) (ly:grob-object x 'stem)) 
heads))
 (grob-set1 (ly:grob-list->grob-array (append heads 
stems)))
 (grob-set2 (ly:grob-list->grob-array (append heads 
stems heads2 stems2)))
 (refp (ly:grob-common-refpoint-of-array grob grob-
set1 X))
 (refp2 (ly:grob-common-refpoint-of-array 

Re: shifting accidentals horizontally

2023-06-12 Thread Werner LEMBERG

> Not the answer to the Lilypond question, but as a reference of
> comparison, here is what Dorico does in this situation by default,
> and I believe this to be correct standard practice.

Well, it can't be generalized – sometimes LilyPond's default is the
right choice.  However, it would be nice to have a simple command to
get the 'other' solution (that Dorico defaults to).


Werner


Re: shifting accidentals horizontally

2023-06-12 Thread Andrew Bernard
Not the answer to the Lilypond question, but as a reference of 
comparison, here is what Dorico does in this situation by default, and I 
believe this to be correct standard practice.


Andrew



shifting accidentals horizontally

2023-06-12 Thread Werner LEMBERG

Please consider the example code below.  The first line shows
LilyPond's default, the second line shows what I need.  As can be
seen, the solution in the second line is imperfect – I just did the
most basic changes to demonstrate what I want, namely the down-stemmed
note to be positioned after the up-stemmed chord.

Is there an automated solution for this problem (namely correctly
positioned and spaced naturals for the chord)?  The LSR doesn't really
help, unfortunately.

BTW, such situations happen from time to time in piano music.

```
\version "2.25.6"

<< { 2. } \\
   { bes'!8 } >>

<< { 2. } \\
   {
 \once \override NoteColumn.force-hshift = #3.3
 \once \override Accidental.extra-offset = #'(4.7 . 0)
 bes'!8 } >>
```


Werner


Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Jean Abou Samra
Le lundi 12 juin 2023 à 13:49 +0200, Lib Lists a écrit :
> 
> Dear Jean, fantastic, thank you so much! And all clear.
> 
> Concerning the staff size and page layout, I think I've found
> something that is not clear to me from the documentation. When
> reducing the staff size to accommodate all the staves in one page, I
> noticed that the StaffGroup bracket doesn't become smaller, and
> similarly, it doesn't become bigger with a staff size of let's say 30.
> See MWE below.  I can solve the issue by defining a paper size big
> enough, but I somehow always assumed that set-staff-size was affecting
> all the elements in a score (even though it is about the *staff*
> size).
> I'm wondering if there is a command to actually resize all elements in
> a score (with the possibility of excluding for example the header,
> page numbers, and so on)?
> 
> \version "2.25.5"
> 
> \new StaffGroup  <<
>   \new Staff {
>     c'' c'' c'' c''
>   }
>   \new Staff {
>     c'' c'' c'' c''
>   }
> > > 
> \layout {
>  #(layout-set-staff-size 9)
> }


Well, at the current point of time, layout-set-staff-size is unfortunately
known for being a pretty buggy command.

If you don't need the ability to set the staff size per-score, use
set-global-staff-size instead. It behaves much better.


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


Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Lib Lists
On Mon, 12 Jun 2023 at 12:44, Jean Abou Samra  wrote:
>
> [Adding back the list]

Oops, thank you!

>
> Le lundi 12 juin 2023 à 12:23 +0200, Lib Lists a écrit :
>
> > On Mon, 12 Jun 2023 at 10:58, Jean Abou Samra 
> > <[j...@abou-samra.fr](mailto:j...@abou-samra.fr)> wrote:
> > Dear Jean, all clear, thank you so much! I was exactly trying to
> > figure out the accidental issue and realised there was a problem
> > there.
> > Thank you for the help with the Scheme/Lily syntax, it's now obvious
> > what was wrong in my attempt.
> >
> >
> > > By the way, \remove'ing Timing_translator sounds a bit... scary, it's a 
> > > kind of
> > > fundamental translator, I don't know if we really support removing it 
> > > entirely.
> > > Also, your method of removing bar lines will still make LilyPond insert 
> > > them.
> > > I think it's better to just use \cadenzaOn.
> >
> >
> > Thank you for the tip. Reading the docs and various online examples I
> > automatically associated removing Timing_translator to a requisite for
> > every polyrhythmic / polymetric music notation, and kept it there (I
> > admit that I don't always accurately understand the meaning of all the
> > lilypond options,  at times I just experiment until it works)
>
>
> Basically, for polymeter, you move it from Score level to Staff level.
> Namely, you remove it from Score and you add it to Staff. That is also
> exactly what \enablePolymeter does (it is a relatively recent command,
> which explains why you might still find online examples that move
> Timing_translator explicitly).
>
> Now I realize that you did in fact have \enablePolymeter, so
> Timing_translator was present in Staff, not completely removed, and
> \remove Timing_translator in Score was simply redundant.
>
> For unmetered music, I maintain that \cadenzaOn is the easiest solution.
>
>
> > > \version "2.25.5"
> > > [...]
> >
> > That's fabulous, thank you!
> > I'm trying to add ottava signs to only some of the pitches (the top
> > staff is the piano's highest note). I changed mus = {\ottava #2
> > \repeat unfold 1 \relative c'  { c c c c }}, which obviously prints
> > the ottava on all the pitches.
> > The solution I found is to have multiple map loops,
> > depending on the pitch's need for ottava sign (15, 8, 8b, 15b) and
> > clef. It works, but I'm wondering if there's a
> > smarter solution.
> > Thank you again for your help!
> >
> > mus = {\ottava #2 \repeat unfold 1 \relative c'  { c c c c }}
> > musLower = { \repeat unfold 1 \relative c'  { c c c c }}
> > musLowest = { \clef bass \repeat unfold 1 \relative c,  { c c c c }}
> >
> > #(define my-semitone->pitch
> >(make-semitone->pitch
> > (music-pitches #{ { c cis d ees e f fis g gis a bes b } #})))
> >
> > \score {
> >   \new StaffGroup  <<
> > #@(map (lambda (i)
> >  #{
> > \new Staff {
> >   \scaleDurations #(cons 60 i) {
> > \transpose c' #(my-semitone->pitch (- (- 60 i))) {
> >   \mus
> > }
> >   }
> > }
> >   #})
> >(iota 3 60 -1))
> >#@(map (lambda (i)
> >  #{
> > \new Staff {
> >   \scaleDurations #(cons 63 i) {
> > \transpose c' #(my-semitone->pitch (- (- 60 i))) {
> >   \musLower
> > }
> >   }
> > }
> >   #})
> >(iota 3 60 -1))
> >#@(map (lambda (i)
> >  #{
> > \new Staff {
> >   \scaleDurations #(cons 66 i) {
> > \transpose c' #(my-semitone->pitch (- (- 60 i))) {
> >   \musLowest
> > }
> >   }
> > }
> >   #})
> >(iota 3 60 -1))
> >   >>
>
>
> Sure, use a cond form:
>
> \version "2.25.5"
>
>
> mus = {\repeat unfold 5 \relative c'  { c c c c }}
>
> #(define my-semitone->pitch
>(make-semitone->pitch
> (music-pitches #{ { c cis d ees e f fis g gis a bes b } #})))
>
> \layout {
>   \context {
> \Score
> \cadenzaOn
>   }
> }
>
> \new StaffGroup  <<
>   #@(map (lambda (i)
>#{
>   \new Staff {
> \scaleDurations #(cons 60 i) {
>   \transpose c' #(my-semitone->pitch (- (- 60 i))) {
> #(cond
>   ((<= 55 i 60) #{ \ottava 3 #})
>   ((<= 51 i 54) #{ \ottava 2 #})
>   (else #{ #}))
> \mus
>   }
> }
>   }
> #})
>  (iota 10 60 -1))
> >>

Dear Jean, fantastic, thank you so much! And all clear.

Concerning the staff size and page layout, I think I've found
something that is not clear to me from the documentation. When
reducing the staff size to accommodate all the staves in one page, I

Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Jean Abou Samra
[Adding back the list]

Le lundi 12 juin 2023 à 12:23 +0200, Lib Lists a écrit :

> On Mon, 12 Jun 2023 at 10:58, Jean Abou Samra 
> <[j...@abou-samra.fr](mailto:j...@abou-samra.fr)> wrote:
> Dear Jean, all clear, thank you so much! I was exactly trying to
> figure out the accidental issue and realised there was a problem
> there.
> Thank you for the help with the Scheme/Lily syntax, it's now obvious
> what was wrong in my attempt.
> 
> 
> > By the way, \remove'ing Timing_translator sounds a bit... scary, it's a 
> > kind of
> > fundamental translator, I don't know if we really support removing it 
> > entirely.
> > Also, your method of removing bar lines will still make LilyPond insert 
> > them.
> > I think it's better to just use \cadenzaOn.
> 
> 
> Thank you for the tip. Reading the docs and various online examples I
> automatically associated removing Timing_translator to a requisite for
> every polyrhythmic / polymetric music notation, and kept it there (I
> admit that I don't always accurately understand the meaning of all the
> lilypond options,  at times I just experiment until it works)


Basically, for polymeter, you move it from Score level to Staff level.
Namely, you remove it from Score and you add it to Staff. That is also
exactly what \enablePolymeter does (it is a relatively recent command,
which explains why you might still find online examples that move
Timing_translator explicitly).

Now I realize that you did in fact have \enablePolymeter, so
Timing_translator was present in Staff, not completely removed, and
\remove Timing_translator in Score was simply redundant.

For unmetered music, I maintain that \cadenzaOn is the easiest solution.


> > \version "2.25.5"
> > [...]
> 
> That's fabulous, thank you!
> I'm trying to add ottava signs to only some of the pitches (the top
> staff is the piano's highest note). I changed mus = {\ottava #2
> \repeat unfold 1 \relative c'  { c c c c }}, which obviously prints
> the ottava on all the pitches.
> The solution I found is to have multiple map loops,
> depending on the pitch's need for ottava sign (15, 8, 8b, 15b) and
> clef. It works, but I'm wondering if there's a
> smarter solution.
> Thank you again for your help!
> 
> mus = {\ottava #2 \repeat unfold 1 \relative c'  { c c c c }}
> musLower = { \repeat unfold 1 \relative c'  { c c c c }}
> musLowest = { \clef bass \repeat unfold 1 \relative c,  { c c c c }}
> 
> #(define my-semitone->pitch
>    (make-semitone->pitch
>     (music-pitches #{ { c cis d ees e f fis g gis a bes b } #})))
> 
> \score {
>   \new StaffGroup  <<
>     #@(map (lambda (i)
>  #{
>     \new Staff {
>   \scaleDurations #(cons 60 i) {
>     \transpose c' #(my-semitone->pitch (- (- 60 i))) {
>   \mus
>     }
>   }
>     }
>   #})
>    (iota 3 60 -1))
>    #@(map (lambda (i)
>  #{
>     \new Staff {
>   \scaleDurations #(cons 63 i) {
>     \transpose c' #(my-semitone->pitch (- (- 60 i))) {
>   \musLower
>     }
>   }
>     }
>   #})
>    (iota 3 60 -1))
>    #@(map (lambda (i)
>  #{
>     \new Staff {
>   \scaleDurations #(cons 66 i) {
>     \transpose c' #(my-semitone->pitch (- (- 60 i))) {
>   \musLowest
>     }
>   }
>     }
>   #})
>    (iota 3 60 -1))
>   >>


Sure, use a cond form:

\version "2.25.5"


mus = {\repeat unfold 5 \relative c'  { c c c c }}

#(define my-semitone->pitch
   (make-semitone->pitch
(music-pitches #{ { c cis d ees e f fis g gis a bes b } #})))

\layout {
  \context {
\Score
\cadenzaOn
  }
}

\new StaffGroup  <<
  #@(map (lambda (i)
   #{
  \new Staff {
\scaleDurations #(cons 60 i) {
  \transpose c' #(my-semitone->pitch (- (- 60 i))) {
#(cond
  ((<= 55 i 60) #{ \ottava 3 #})
  ((<= 51 i 54) #{ \ottava 2 #})
  (else #{ #}))
\mus
  }
}
  }
#})
 (iota 10 60 -1))
>>







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


Re: How to make a blank page

2023-06-12 Thread Valentin Petzel
Hello Silvain,

it might help to understand that \pageBreak is not an instruction to insert a 
pageBreak. Think of \noPageBreak: This is a token that prevents a pageBreak to 
happen at the given place. Similarly \pageBreak is a token that enforces a 
pageBreak to happen at the given place (in other words the token must not 
happen within one page).

Now, if you have

[ page1 ]
\pageBreak
[ page2 ]

and [page1] and [page2] are already two different pages the \pageBreak will not 
do anything, as there already is a pageBreak. This is similar to how adding 
\break at a line break will not cause an empty line. I’d suggest you do

\pageBreak
\markup\null
\pageBreak

The first \pageBreak will ensure that a new page is started, the second 
guarantees that the follwing content starts on a new page. All in all this 
will create an empty page, no matter where you insert it. You can even do a 
function for this:

emptyPage =
#(define-scheme-function () ()
   (collect-music-aux add-score #{ \pageBreak #})
   (add-text (markup #:null))
   (collect-music-aux add-score #{ \pageBreak #}))

\emptyPage
\markup "a"
\emptyPage
\markup "b"

Cheers,
Valentin

Am Montag, 12. Juni 2023, 08:28:36 CEST schrieb Silvain Dupertuis:
> I tried this trick, which seems to work :
> 
> \markup " "
> \pageBreak
> 
> produces a blank page
> 
> It seems that there must be something on the page for \pageBreak to produce
> a page.
> 
> Of course, there is also possibilities to add blank pages to a PDF document.
> Le 11.06.23 à 15:41, Paul McKay a écrit :
> > \version "2.24.0"
> > \language "en"
> > myScore = \score { \relative { c'4 d e f g }}
> > \pageBreak
> > \myScore



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


Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Valentin Petzel
Hello Lib,

#(ly:music-transpose {\mus} i)

does not make sense. \mus is Lilypond syntax, not scheme. Either do #{ \mus #} 
to parse this as Lilypond expression, or do mus (instead of { \mus }) to scope 
this as Scheme object. Also ly:music-transpose does take a pitch as second 
argument, so if you want to diatonically transpose up do something like

#(ly:music-transpose mus (ly:make-pitch 0 i))

Cheers,
Valentin

Am Montag, 12. Juni 2023, 10:23:14 CEST schrieb Lib Lists:
> On Mon, 12 Jun 2023 at 00:08, Jean Abou Samra  wrote:
> > Le dimanche 11 juin 2023 à 23:55 +0200, Lib Lists a écrit :
> > 
> > Hello, I'm (re)working on a series of pieces for player piano. I'd like to
> > find a way to generate all the \scaleDurations values so that I don't
> > have to type them by hand. In the example below they follow a simple
> > pattern (60/60k 60/59, 60/58, etc.). Unfortunately my knowledge of Scheme
> > is very limited. Moreover, I wouldn't know how to insert the generated
> > values to the right staves. Any hint would be really appreciated!
> > 
> > Like this?
> > 
> > \version "2.25.5"
> > 
> > mus = \repeat unfold 3 { c c c c }
> > 
> > 
> > \score {
> > 
> >   \new StaffGroup  <<
> >   
> > #@(map (lambda (i)
> > 
> >  #{ \new Staff { \scaleDurations #(cons 60 i) \mus } #})
> >
> >(iota 10 60 -1))
> >
> >\layout {
> >
> > \enablePolymeter
> > \context {
> > 
> >   \Score
> >   \override SpacingSpanner.base-shortest-duration = #(ly:make-moment
> >   1/4)
> >   proportionalNotationDuration = #(ly:make-moment 1/10)
> >   \override SpacingSpanner.uniform-stretching = ##t
> >   \override SpacingSpanner.strict-note-spacing = ##t
> >   \remove "Timing_translator"
> >   forbidBreakBetweenBarLines = ##f
> > 
> > }
> > 
> > \context {
> > 
> >   \Staff
> >   \remove "Time_signature_engraver"
> >   \override BarLine.stencil = ##f
> >   \override BarLine.allow-span-bar = ##f
> > 
> > }
> > 
> > \context {
> > 
> >   \Voice
> >   \remove Forbid_line_break_engraver
> > 
> > }
> >   
> >   }
> > 
> > }
> > 
> > The 60/59 notation is just LilyPond syntax for the Scheme pair (60 . 59).
> > 
> > There is some info about #@ here (and if you didn't know about pairs, you
> > can read this).
> > 
> > Best,
> > 
> > Jean
> 
> Hi Jean,
> thank you so much, that works perfectly! And thank you also for the
> resources. If I may still ask for some help, I now tried to transpose the
> pitches so that the first staff has 'c', the second staff 'b', and so on.
> In other words, each staff's pitch is one semitone lower than the
> previous (or other transposition interval). I tried to add the
> transpose function but got stuck.
> 
> In your example, I changed the line:
> #{ \new Staff { \scaleDurations #(cons 60 i) \mus } #})
> 
> to this:
> #{ \new Staff { \scaleDurations #(cons 60 i)  #(ly:music-transpose
> {\mus} i)  } #})
> 
> but clearly there's something wrong,
> 
> Thank you and
> best regards,
> 
> Lib



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


Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Jean Abou Samra
Le lundi 12 juin 2023 à 10:23 +0200, Lib Lists a écrit :

> In your example, I changed the line: #{ \new Staff { \scaleDurations #(cons 
> 60 i) \mus } #})
> to this: #{ \new Staff { \scaleDurations #(cons 60 i)  #(ly:music-transpose 
> {\mus} i)  } #})
> but clearly there's something wrong,

Well, there are a couple problems.

{\mus} is LilyPond syntax, but within the #(ly:music-transpose ...), you
are in Scheme syntax due to the # . Curly brackets have a totally different
meaning in Scheme (namely usually no meaning, so in this case it literally
looks up a variable called “{\mus}” which doesn't exist, but you can also
activate syntax extensions that make use of curly brackets). If you want
to switch to LilyPond syntax inside the Scheme code, you should use #{ #} again.
Or, in this case, you can just use the variable “mus”, which is defined since
LilyPond variables are also Scheme variables (except that Scheme doesn't need
a \ to reuse a variable). But in that case, you will get into trouble
because ly:music-transpose is destructive, so the calls will mutate it
and their effects will accumulate. So you would actually need 
(ly:music-deep-copy mus).
If you stay in LilyPond syntax with \transpose c' #(...) \mus, there is no such
problem (the \ in LilyPond makes a copy). See also
https://extending-lilypond.gitlab.io/en/extending/music.html#copying-music

Also, it is not meaningful in general to “transpose music X by i semitones”,
because that does not tell whether C transposed by 2 semitones down should be
B♭ or A♯. That is why the second argument to ly:music-transpose is not a number
but a pitch. See

https://extending-lilypond.gitlab.io/en/extending/music.html#pitches
For this type of case, LilyPond has a make-semitone->pitch function that helps
you to pick one or the other.

Lastly, i takes values from 60 to 51 so you should use (- 60 i) for the index
of the staff.

By the way, \remove'ing Timing_translator sounds a bit... scary, it's a kind of
fundamental translator, I don't know if we really support removing it entirely.
Also, your method of removing bar lines will still make LilyPond insert them.
I think it's better to just use \cadenzaOn.

\version "2.25.5"

mus = \repeat unfold 3 \relative { c'' c c c }

#(define my-semitone->pitch
   (make-semitone->pitch
(music-pitches #{ { c cis d ees e f fis g gis a bes b } #})))

\score {
  \new StaffGroup  <<
#@(map (lambda (i)
 #{
\new Staff {
  \scaleDurations #(cons 60 i) {
\transpose c' #(my-semitone->pitch (- (- 60 i))) {
  \mus
}
  }
}
  #})
   (iota 10 60 -1))
  >>

   \layout {
\context {
  \Score
  \override SpacingSpanner.base-shortest-duration = #(ly:make-moment 1/4)
  proportionalNotationDuration = #(ly:make-moment 1/10)
  \override SpacingSpanner.uniform-stretching = ##t
  \override SpacingSpanner.strict-note-spacing = ##t
  forbidBreakBetweenBarLines = ##f
  \cadenzaOn
}
\context {
  \Staff
  \remove Time_signature_engraver
}
\context {
  \Voice
  \remove Forbid_line_break_engraver
}
  }
}







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


Re: How to generate \scaleDurations values procedurally

2023-06-12 Thread Lib Lists
On Mon, 12 Jun 2023 at 00:08, Jean Abou Samra  wrote:
>
> Le dimanche 11 juin 2023 à 23:55 +0200, Lib Lists a écrit :
>
> Hello, I'm (re)working on a series of pieces for player piano. I'd like to 
> find a way to generate all the \scaleDurations values so that I don't have to 
> type them by hand. In the example below they follow a simple pattern (60/60k 
> 60/59, 60/58, etc.). Unfortunately my knowledge of Scheme is very limited. 
> Moreover, I wouldn't know how to insert the generated values to the right 
> staves. Any hint would be really appreciated!
>
> Like this?
>
> \version "2.25.5"
>
> mus = \repeat unfold 3 { c c c c }
>
>
> \score {
>   \new StaffGroup  <<
> #@(map (lambda (i)
>  #{ \new Staff { \scaleDurations #(cons 60 i) \mus } #})
>(iota 10 60 -1))
>   >>
>
>\layout {
> \enablePolymeter
> \context {
>   \Score
>   \override SpacingSpanner.base-shortest-duration = #(ly:make-moment 1/4)
>   proportionalNotationDuration = #(ly:make-moment 1/10)
>   \override SpacingSpanner.uniform-stretching = ##t
>   \override SpacingSpanner.strict-note-spacing = ##t
>   \remove "Timing_translator"
>   forbidBreakBetweenBarLines = ##f
> }
>
> \context {
>   \Staff
>   \remove "Time_signature_engraver"
>   \override BarLine.stencil = ##f
>   \override BarLine.allow-span-bar = ##f
> }
>
> \context {
>   \Voice
>   \remove Forbid_line_break_engraver
> }
>   }
> }
>
> The 60/59 notation is just LilyPond syntax for the Scheme pair (60 . 59).
>
> There is some info about #@ here (and if you didn't know about pairs, you can 
> read this).
>
> Best,
>
> Jean

Hi Jean,
thank you so much, that works perfectly! And thank you also for the resources.
If I may still ask for some help, I now tried to transpose the pitches
so that the first staff has 'c', the second staff 'b', and so on. In
other words, each staff's pitch is one semitone lower than the
previous (or other transposition interval). I tried to add the
transpose function but got stuck.

In your example, I changed the line:
#{ \new Staff { \scaleDurations #(cons 60 i) \mus } #})

to this:
#{ \new Staff { \scaleDurations #(cons 60 i)  #(ly:music-transpose
{\mus} i)  } #})

but clearly there's something wrong,

Thank you and
best regards,

Lib



Re: How to make a blank page

2023-06-12 Thread Silvain Dupertuis

I tried this trick, which seems to work :

\markup " "
\pageBreak

produces a blank page

It seems that there must be something on the page for \pageBreak to produce a 
page.

Of course, there is also possibilities to add blank pages to a PDF document.

Le 11.06.23 à 15:41, Paul McKay a écrit :

\version "2.24.0"
\language "en"
myScore = \score { \relative { c'4 d e f g }}
\pageBreak
\myScore



--
Silvain Dupertuis
Route de Lausanne 335
1293 Bellevue (Switzerland)
tél. +41-(0)22-774.20.67
portable +41-(0)79-604.87.52
web: silvain-dupertuis.org