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
>