Hello David,

> My conundrum is that I want to call the same music expression (that is
> declared as a variable) from different staves, but also cause markup
> functions inside the music expression to behave differently from outside
> the music expression. Using tags is the only way I have found to do
> that. I am glad that I have a method that works. Thank you for clearly
> conveying to me that I should keep global variables static!

There is nothing that speaks against using tags for this, but you can do this 
totally fine using music function. Not that it is necessary here, but if you 
want to create scores in a more dynamic manner at some point going for music 
functions is a way to go.

> My noob thought is - why not allow custom variables to be declared when
> making a \new Staff in its \with statement? These variables would have
> the scope of working only on those calls to them that are from within
> that particular staff. Different staves could create the same variable
> with different values in their \with statement and thus change the
> behavior of different functions within the same called music expression.
> These variables would take precedence over global variables of the same
> name. Please, take or leave.

We can in fact do that to some extent, which is context properties. The 
problem with this is again the time at which things are evaluated. Basically 
Lilypond works more or less like this:

 1) Parse and evaluate your ly file
 2) Now we should have a collection of scores. For each score:
 3) Iterate over the music expressions and send the events therein to the 
relevant engravers in the relevant contexts
 4) We should now have a collection of grobs created by the engravers
 5) Position the grobs
 6) Position the scores
 7) Render everything

Context relevant properties only matter in step 3. The problem is that music 
expressions are resolved in step 1, where we do not have such information.

What you are thinking about would need to get the context variables into the 
music expression before it is evaluated, so you’d need some sort of 
preprocessing step before step 1.

One way to do this would be to write your music function as string and parse 
it everywhere you need it

#(define a "1")

myLilyCode = "
 { c'^\markup #a }
"

{ $(ly:parser-include-string myLilyCode) }

#(define a "2")
{ $(ly:parser-include-string myLilyCode) }

But essentially this will provide the same function as a music function, just 
more prone to errors. Of course you could also do some non standard evaluation 
stuff like this

myCode = #'#{ c^\markup #var #}

#(define var "1")
{ $(primitive-eval myCode) }

#(define var "2")
{ $(primitive-eval myCode) }

Of course, if we want to get funky we can do something like this:

evalWith =
#(define-scheme-function (alist expr) (list? scheme?)
   (primitive-eval `(let ,(map (lambda (x) `(,(car x) ,(cdr x))) alist) 
,expr)))

#(define var "1")

expr = #'#{ c'^\markup#var #}

{
 \evalWith #'() \expr
 \evalWith #'((var . "2")) \expr
}

which is like doing a music function, but will allow us to inject any kinds of 
variables into an expression, while resolving to global bindings by default. 
But I do not think it would be a particularly good idea to do so...

Cheers,
Valentin

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

Reply via email to