Lilypond functions

2021-03-03 Thread Silvain Dupertuis

Hello everyone,

Functions in Lilypond can also be written in pure Sheme syntax like this
#(define abcd
    (lambda (x y ... )
        PROCEDURE USING x y ...))

and then called within Lilypond with the syntax
\abcd x y ...
or within a Sheme fucntion with the syntax
(abcd x y ...)

If anyone is interested, I made an exercise for myself to explore *the use of 
functions*
and create a score of the *first Prelude of Book I of J.S. Bach's Well-Tempered 
Clavier*

As this piece has 32 bars using the same pattern based on 5 notes, plus an 
ending in 3 bars,
I used a simple list of notes (without any rythmic indications) as my main data
and designed functions to extract the groups of 5 notes, apply the patterns to create 
voices and scores, including a chord version on the piece in addition to the standard score.


notes = {
  c e g c e
  c d a' d f
  b d g d' f ... etc.
)

Files (Lilypond, PDF and midi) are in this online folder
(midi files need to be downloaded to listen to them)


Silvain Dupertuis

Merci

This is a perfect solution, and, a clear explanation about why my solution 
failed.

Thank you very much


Ken Ledeen

Mobile:                617-817-3183
www.nevo.com 
www.bitsbook.com 
tiny.cc/KenLedeen 
tiny.cc/KenLedeenAmazon 

ᐧ

On Sat, Feb 27, 2021 at 10:43 AM Jean Abou Samra > wrote:


   Le 27/02/2021 à 02:16, Ken Ledeen a écrit :

> I am struggling to understand the restrictions on substitution functions.
>
> For example:
>
> 1) can a function include "\score { ...}"  or can it only be invoked
> INSIDE a \score?
>
> 2) is it possible to include \header { ...}  inside a substitution
> function?  It fails when I try, but I don't understand why.
>
> I assume I am missing some basic concepts regarding their use.
>
> Thanks!


   Hello,

   Music functions must return music objects; \score blocks are not music
   but general containers that enclose music as well as other objects such
   as \header and \layout blocks.

   However, replacing define-music-function with define-scheme-function,
   you can define more versatile functions that are allowed to return any
   kind of object for interpretation. For example:

   \version "2.23.1"

   failingFunction =
   #(define-music-function () ()
    #{
  \score {
    \header {
  piece = "Piece A"
    }
    { c' }
  }
    #})

   % \failingFunction

   succeedingFunction =
   #(define-scheme-function () ()
    #{
  \score {
    \header {
  piece = "Piece B"
    }
    { c' }
  }
    #})

   \succeedingFunction


   Hope that helps,
   Jean



Re: How to get bounding NoteColumns of the first of consecutive TextSpanners

2021-03-03 Thread David Nalesnik
On Wed, Mar 3, 2021 at 3:17 PM David Nalesnik  wrote:

>
> The only thing I can think of at the moment is to compare the
> StaffSymbol of the left bound with that of each of the NoteColumns on
> the right.  Of course, I realize right away that that will break down
> if the spanner crosses a line break. (Use an override of
> 'before-line-breaking?)
>
> Here's the code I hacked up.  I'll keep thinking about this.
>
> Best,
> David
>
> %%
>
> #(define tst
>(lambda (grob)
>  (let* ((left-bound (ly:spanner-bound grob LEFT))
> (right-bound (ly:spanner-bound grob RIGHT))
> (ncs-from-grob
>  (ly:grob-array->list (ly:grob-object grob 'note-columns)))
> (right-bound-elts
>  (ly:grob-array->list
>   (ly:grob-object right-bound 'elements)))
> (ncs-from-right-bound
>  (filter
>   (lambda (elt) (grob::has-interface elt 'note-column-interface))
>   right-bound-elts))
> (left-bound-staff-symbol (ly:grob-object left-bound 
> 'staff-symbol))
> (same-staff-right-bound-nc
>  (filter
>   (lambda (nc)
> (eq? (ly:grob-object nc 'staff-symbol)
>  left-bound-staff-symbol))
>   ncs-from-right-bound))
> )
>(ly:grob-set-property!
> (ly:grob-array-ref
>  (ly:grob-object (car same-staff-right-bound-nc) 'note-heads)
>  0)
> 'color red)
>(pretty-print
> (list
>  left-bound
>  right-bound
>  ncs-from-grob
>  (equal? left-bound (car ncs-from-grob))
>  ncs-from-right-bound
>  same-staff-right-bound-nc
>  )
>
> mus = {
>   bes4-\tweak #'after-line-breaking #tst
>   \startTextSpan
>   b\stopTextSpan
>   \startTextSpan
>   bis\stopTextSpan
> }
>
> <<
>   { a4 a a }
>   \mus
>   { c' c' c' }
> >>

Rather than comparing with the StaffSymbol of the left bound, it would
be better to look at the StaffSymbol of the TextSpanner:

#(define tst
   (lambda (grob)
 (let* ((left-bound (ly:spanner-bound grob LEFT))
(right-bound (ly:spanner-bound grob RIGHT))
(ncs-from-grob
 (ly:grob-array->list (ly:grob-object grob 'note-columns)))
(right-bound-elts
 (ly:grob-array->list
  (ly:grob-object right-bound 'elements)))
(ncs-from-right-bound
 (filter
  (lambda (elt) (grob::has-interface elt 'note-column-interface))
  right-bound-elts))
(spanner-staff-symbol (ly:grob-object grob 'staff-symbol))
(same-staff-right-nc
 (filter
  (lambda (nc)
(eq? (ly:grob-object nc 'staff-symbol)
 spanner-staff-symbol))
  ncs-from-right-bound))
)
   (ly:grob-set-property!
(ly:grob-array-ref
 (ly:grob-object (car same-staff-right-nc) 'note-heads)
 0)
'color red)
   (pretty-print
(list
 left-bound
 right-bound
 ncs-from-grob
 (equal? left-bound (car ncs-from-grob))
 ncs-from-right-bound
 same-staff-right-nc
 )

mus = {
  bes4-\tweak #'after-line-breaking #tst
  \startTextSpan
  b\stopTextSpan
  \startTextSpan
  bis\stopTextSpan
}

<<
  { a4 a a }
  \mus
  { c' c' c' }
>>

%%%
HTH,
David



Re: How to get bounding NoteColumns of the first of consecutive TextSpanners

2021-03-03 Thread Jean Abou Samra



Le 03/03/2021 à 13:55, Thomas Morley a écrit :

Hi,

please have a look at the following minimal, producing three staves,
the middle one with consecutive TextSpanners:

mus = { bes \startTextSpan b\stopTextSpan \startTextSpan bis\stopTextSpan }
<< { a4 a a } \mus { c' c' c' } >>

Now I want to know the starting and ending NoteColumns of the _first_
TextSpanner.
Though, the first TextSpanner is left-bounded by NoteColumn and
right-bounded by PaperColumn.

How to get the NoteColumn at first TextSpanner's end?

Below some test-code.
Obviously I can filter PaperColumn's elements for NoteColumns, but
PaperColumn is a Score-grob, thus I get all three.
How to select?
(I may not know the position of the Staff with the TextSpanners)

#(define tst
   (lambda (grob)
 (let* ((left-bound (ly:spanner-bound grob LEFT))
(right-bound (ly:spanner-bound grob RIGHT))
(ncs-from-grob
  (ly:grob-array->list (ly:grob-object grob 'note-columns)))
(right-bound-elts
  (ly:grob-array->list
(ly:grob-object right-bound 'elements)))
(ncs-from-right-bound
  (filter
(lambda (elt) (grob::has-interface elt 'note-column-interface))
right-bound-elts))
)
 (pretty-print
   (list
 left-bound
 right-bound
 ncs-from-grob
 (equal? left-bound (car ncs-from-grob))
 ncs-from-right-bound
 )

mus = {
   bes4-\tweak #'after-line-breaking #tst
\startTextSpan
   b\stopTextSpan
\startTextSpan
   bis\stopTextSpan
}

<<
   { a4 a a }
   \mus
   { c' c' c' }
Thanks,
   Harm



Hi,

This looks tricky indeed.

Maybe an engraver operating in Voice context? Here's my attempt:

\version "2.23.1"

#(set-object-property! 'bounding-note-columns 'backend-type? pair?)

Set_bounding_note_columns_engraver =
#(lambda (context)
   (let ((spanner-starting #f)
 (spanner-ending #f)
 (note-column #f))
 (make-engraver
   (acknowledgers
 ((line-spanner-interface engraver grob source-engraver)
    (set! spanner-starting grob)
    (ly:grob-set-property! grob
   'bounding-note-columns
   ; Huh, '(#f . #f) makes a unique object?
    (cons #f #f)))
 ((note-column-interface engraver grob source-engraver)
    (set! note-column grob)))
   (end-acknowledgers
 ((line-spanner-interface engraver grob source-engraver)
    (set! spanner-ending grob)))
   ((stop-translation-timestep engraver)
  (if spanner-starting
  (set-car! (ly:grob-property spanner-starting 
'bounding-note-columns)

   note-column))
  (if spanner-ending
  (set-cdr! (ly:grob-property spanner-ending 
'bounding-note-columns)

    note-column))
  (set! spanner-starting #f)
  (set! spanner-ending #f)
  (set! note-column #f)


% For testing
#(use-modules (srfi srfi-26))
#(define (visualize-note-column-bounds grob)
   (let* ((cols (ly:grob-property grob 'bounding-note-columns))
  (left-col (car cols))
  (right-col (cdr cols))
  (left-note-heads (ly:grob-array->list (ly:grob-object 
left-col 'note-heads)))

  (right-stem (ly:grob-object right-col 'stem)))
 (for-each
    (cute ly:grob-set-property! <> 'color red)
    left-note-heads)
 (ly:grob-set-property! right-stem 'color blue)))

\layout {
  \context {
    \Voice
    \consists \Set_bounding_note_columns_engraver
    \override TextSpanner.after-line-breaking = 
#visualize-note-column-bounds

  }
}

mus = {
  bes4\startTextSpan
  b\stopTextSpan
   \startTextSpan
  bis\stopTextSpan\startTextSpan
  b\stopTextSpan
}

<<
  { a4 a a }
  \mus
  { c' c' c' }
>>


Like David's solution, this of course won't give you the note columns 
for each of the broken pieces. Well, I am in fact not sure that a notion 
of the bounding note columns for a broken text spanner can even be 
defined. Thoughts?


Cheers,
Jean




Re: How to get bounding NoteColumns of the first of consecutive TextSpanners

2021-03-03 Thread David Nalesnik
Hi Harm,

On Wed, Mar 3, 2021 at 6:56 AM Thomas Morley  wrote:
>
> Hi,
>
> please have a look at the following minimal, producing three staves,
> the middle one with consecutive TextSpanners:
>
> mus = { bes \startTextSpan b\stopTextSpan \startTextSpan bis\stopTextSpan }
> << { a4 a a } \mus { c' c' c' } >>
>
> Now I want to know the starting and ending NoteColumns of the _first_
> TextSpanner.
> Though, the first TextSpanner is left-bounded by NoteColumn and
> right-bounded by PaperColumn.
>
> How to get the NoteColumn at first TextSpanner's end?
>
> Below some test-code.
> Obviously I can filter PaperColumn's elements for NoteColumns, but
> PaperColumn is a Score-grob, thus I get all three.
> How to select?
> (I may not know the position of the Staff with the TextSpanners)
>
> #(define tst
>   (lambda (grob)
> (let* ((left-bound (ly:spanner-bound grob LEFT))
>(right-bound (ly:spanner-bound grob RIGHT))
>(ncs-from-grob
>  (ly:grob-array->list (ly:grob-object grob 'note-columns)))
>(right-bound-elts
>  (ly:grob-array->list
>(ly:grob-object right-bound 'elements)))
>(ncs-from-right-bound
>  (filter
>(lambda (elt) (grob::has-interface elt 'note-column-interface))
>right-bound-elts))
>)
> (pretty-print
>   (list
> left-bound
> right-bound
> ncs-from-grob
> (equal? left-bound (car ncs-from-grob))
> ncs-from-right-bound
> )
>
> mus = {
>   bes4-\tweak #'after-line-breaking #tst
>\startTextSpan
>   b\stopTextSpan
>\startTextSpan
>   bis\stopTextSpan
> }
>
> <<
>   { a4 a a }
>   \mus
>   { c' c' c' }
> >>
>
> Thanks,
>   Harm
>

The only thing I can think of at the moment is to compare the
StaffSymbol of the left bound with that of each of the NoteColumns on
the right.  Of course, I realize right away that that will break down
if the spanner crosses a line break. (Use an override of
'before-line-breaking?)

Here's the code I hacked up.  I'll keep thinking about this.

Best,
David

%%

#(define tst
   (lambda (grob)
 (let* ((left-bound (ly:spanner-bound grob LEFT))
(right-bound (ly:spanner-bound grob RIGHT))
(ncs-from-grob
 (ly:grob-array->list (ly:grob-object grob 'note-columns)))
(right-bound-elts
 (ly:grob-array->list
  (ly:grob-object right-bound 'elements)))
(ncs-from-right-bound
 (filter
  (lambda (elt) (grob::has-interface elt 'note-column-interface))
  right-bound-elts))
(left-bound-staff-symbol (ly:grob-object left-bound 'staff-symbol))
(same-staff-right-bound-nc
 (filter
  (lambda (nc)
(eq? (ly:grob-object nc 'staff-symbol)
 left-bound-staff-symbol))
  ncs-from-right-bound))
)
   (ly:grob-set-property!
(ly:grob-array-ref
 (ly:grob-object (car same-staff-right-bound-nc) 'note-heads)
 0)
'color red)
   (pretty-print
(list
 left-bound
 right-bound
 ncs-from-grob
 (equal? left-bound (car ncs-from-grob))
 ncs-from-right-bound
 same-staff-right-bound-nc
 )

mus = {
  bes4-\tweak #'after-line-breaking #tst
  \startTextSpan
  b\stopTextSpan
  \startTextSpan
  bis\stopTextSpan
}

<<
  { a4 a a }
  \mus
  { c' c' c' }
>>



How to get bounding NoteColumns of the first of consecutive TextSpanners

2021-03-03 Thread Thomas Morley
Hi,

please have a look at the following minimal, producing three staves,
the middle one with consecutive TextSpanners:

mus = { bes \startTextSpan b\stopTextSpan \startTextSpan bis\stopTextSpan }
<< { a4 a a } \mus { c' c' c' } >>

Now I want to know the starting and ending NoteColumns of the _first_
TextSpanner.
Though, the first TextSpanner is left-bounded by NoteColumn and
right-bounded by PaperColumn.

How to get the NoteColumn at first TextSpanner's end?

Below some test-code.
Obviously I can filter PaperColumn's elements for NoteColumns, but
PaperColumn is a Score-grob, thus I get all three.
How to select?
(I may not know the position of the Staff with the TextSpanners)

#(define tst
  (lambda (grob)
(let* ((left-bound (ly:spanner-bound grob LEFT))
   (right-bound (ly:spanner-bound grob RIGHT))
   (ncs-from-grob
 (ly:grob-array->list (ly:grob-object grob 'note-columns)))
   (right-bound-elts
 (ly:grob-array->list
   (ly:grob-object right-bound 'elements)))
   (ncs-from-right-bound
 (filter
   (lambda (elt) (grob::has-interface elt 'note-column-interface))
   right-bound-elts))
   )
(pretty-print
  (list
left-bound
right-bound
ncs-from-grob
(equal? left-bound (car ncs-from-grob))
ncs-from-right-bound
)

mus = {
  bes4-\tweak #'after-line-breaking #tst
   \startTextSpan
  b\stopTextSpan
   \startTextSpan
  bis\stopTextSpan
}

<<
  { a4 a a }
  \mus
  { c' c' c' }
>>

Thanks,
  Harm