Thanks a lot.
You help advance a lot, but still i have problems to resolve.
(First question is : is it better to answer before or after what we have
written before ?)
I try to use optional arguments, but may be it would not be possible from
within LilyPond code call this function. I give that example :
upper = {
  \time 6/8
  ...
  <g' b'>4 <g' b'>8 <b' d''>8. <a' c''>16 <g' b'>8 |
  <f' a'>8. <g' b'>16 <f' a'>8 <d' f'>4 r8 |

  % \MTKey JM d'4 Hello ##t e'4 #'(9 . 8)
  \MTKeyExp JM d'4 Hello ##t e'4 2 3  *%ok*
  \MTKeyExp JM d'4 Hello ##t   *%wrong because following c' d' e'*
  c' d' e'
}
Now i give definition of MTKeyExp :
*MTKeyExp *=  #(define-music-function
            (parser location name mainNote textBelowMain cyclic . rest)
            (string? ly:music? string? boolean? ly:music? number? number?)
    (let-optional rest ((note1 d'4) (num1 2) (den1 1))

     #{
       \key c \major
       \cadenzaOn
        ...
 * \setAlterationNote* #num1 #den1 #note1
...
  \setRightBracket s4
  \cadenzaOff
 ...
     #}
     ))
My idea was to use a conditional call giving  *note1* a default value of
null :
*setAlterationNote *=
#(define-music-function
        (parser location num den note)
        (number? number? ly:music?)

        (let
         ;;((stencil (ly:stencil-add (ly:stencil-add altV
(getAltPlaceNumStencil 1 2)) (getAltPlaceNumStencil 2 -3))))
         ((stencil (ly:stencil-add altV
                 (do ((primes '(2 3 5 7 11 13 17 19 23) (cdr primes))
                     (place 0 place)
                     (st altV (ly:stencil-add st (getAltPlaceNumStencil
place  (- (ntimesdivide num (car primes)) (ntimesdivide den (car
primes)))))))
                 ((null? primes) st)
                 (set! place (+ place 1))
                 )
                                          )))
         (if (null? note) '()

        #{
  \once \override  Stem.stencil = $stencil
  ...
  \grace
  c4
  #note
        #})))
But you see at beginning that i can not give optional arguments. LilyPond
interpret following 3 musical elements as optional parameters of MTKeyExp.
If i use a list as a argument, there will be a mixt of musical expressions
and numbers, but would not be possible to use commas ',' because that can
be part of a musical expression like "d,4".
Have you some idea to resolve this ? Thanks a lot for any help. However i
am a good C++ programmer, i am newcommer at Scheme, but a big fan of
LilyPond, and i will try to use my microtonal expressions through LilyPond.
I also already plane how to change that midi file in order to listen
correct tunings. But this step which i ask you is like a stone for my.

Daniel Tomas

On Wed, Nov 25, 2020 at 8:44 AM Aaron Hill <[email protected]> wrote:

> On 2020-11-24 3:00 pm, Daniel Tomas wrote:
> > I am working on a Microtonal key for LilyPond, but I need help to
> > construct
> > a function which I will try to simplify here. I have some questions :
> > 1) In Scheme can be possible to write a function which is variadic with
> > a
> > point :
> > ( function (arg1 arg2 . m )  ( ... ))
> > And here  m contains not only one parameter passed. m1, m2, ...
> > I have not found in any place information about how to access m, is it
> > a
> > list ? But in this case, we can directly use a list like
> > (function (arg1 arg2 ls) ( ... ))
>
> m is a list, although there are helpers for destructuring it.  This is
> documented in the Guile manual [1].
>
> [1]: https://www.gnu.org/software/guile/docs/docs-1.8/guile-ref/
>
> %%%%
> \version "2.20.0"
>
> #(define (func first second . rest)
>    (let-optional rest ((third 'default) (fourth 'default))
>     (format #t "\n -- func --")
>     (format #t "\n     required args: first=~s, second=~s" first second)
>     (format #t "\n destructured args: third=~s, fourth=~s" third fourth)
>     (format #t "\n   additional args: rest=~s" rest)))
>
> #(func 'a 'b)
> #(func 'c 'd 'e)
> #(func 'f 'g 'h 'i 'j)
> %%%%
> ====
> Parsing...
>   -- func --
>       required args: first=a, second=b
>   destructured args: third=default, fourth=default
>     additional args: rest=()
>   -- func --
>       required args: first=c, second=d
>   destructured args: third=e, fourth=default
>     additional args: rest=()
>   -- func --
>       required args: first=f, second=g
>   destructured args: third=h, fourth=i
>     additional args: rest=(j)
> Success: compilation successfully completed
> ====
>
> The advantage of (lambda args) over (lambda (args)) is that the list is
> implicit.  Callers can invoke the procedure more naturally.  Imagine if
> one had to say (+ (list 1 2 3)) instead of simply (+ 1 2 3).
>
>
> > 2) Now i need to do this with music information like :
> > Function =  #(define-music-function
> >             (parser location cyclic  ls)
> >             (boolean? list?)
> >      #{
> >       ...
> > How call to another function which arguments are musical elements and 2
> > numbers passed n times by <ls> ?
> >      ...
> >      #}
> >      )
> >
> > Function need to be called with unfixed number N of arguments :
> > \Function #t c4 2 3 d 2 5 e 4 1 f2 1 1 ... musicN nN1 nN2
> > Please , somebody can help me ?
>
> The above cannot be done as LilyPond's scheme functions cannot handle
> such open-ended arity.  The only variability is optional arguments, and
> even then there are some restrictions due to how the parser works.
>
> To provide arbitrary numbers of things, you must use a list of some
> form.
>
> %%%%
> \version "2.20.0"
>
> foo =
> #(define-void-function (args) (list?) (format #t "\n args=~s" args))
>
> \foo #'(this is a literal scheme list)
> \foo 3,1,4,1,5,9,2,6 % ..a list of natural numbers
> \foo This.Is.A.Symbol.List
>
> baz =
> #(define-void-function (prop args) (symbol? ly:music?)
>    (set! args (map (lambda (m) (ly:music-property m prop))
>                    (extract-typed-music args 'rhythmic-event)))
>    (format #t "\n args=~s" args))
>
> \baz pitch { c d e f }
> \baz duration { 1 2. 4 }
> \baz text \lyricmode { Here are some words. }
> %%%%
> ====
> Parsing...
>   args=(this is a literal scheme list)
>   args=(3 1 4 1 5 9 2 6)
>   args=(This Is A Symbol List)
>   args=(#<Pitch c > #<Pitch d > #<Pitch e > #<Pitch f >)
>   args=(#<Duration 1 > #<Duration 2. > #<Duration 4 >)
>   args=("Here" "are" "some" "words.")
> Success: compilation successfully completed
> ====
>
> With \foo, we are leveraging some of LilyPond's syntactic elements that
> ultimately resolve to a list.  There are limitations on what types of
> data can appear, but it is certainly an option to consider.
>
> \baz demonstrates working with music as a container for data.  This
> option is ideal when inputting a variable number of musical things as it
> largely resembles other LilyPond syntax.
>
>
> -- Aaron Hill
>

Reply via email to