With this post I intend to start a series of posts introducing writing Scheme music functions in LilyPond input files. Please note that this is not a guru's wisdom poured into blog posts but rather a documentation of my own thorny learning process.
Now we're going to write our first music function as described in the Extending manual. Actually it will be a quite useless function but at least it will work - and hopefully get you an understanding how to do it. But let's start with doing it the normal LilyPond way:
{% lilypond %} \version "2.18.0"
myFunction = { c2 }
\relative c' { c4 \myFunction c } {% endlilypond %}
Here we define a variable with the (unusual) name of myFunction
, which we can later insert in the main music expression. As you can see it will insert a half note c
into the music. But as you can also see it does so without affecting the parser - the next note will be a quarter note again, referencing the previous duration encountered in the source code.
Now we'll do the same with a Scheme music function:
{% lilypond %} mySchemeFunction = #(define-music-function (parser location)() #{ c2 #})
\relative c' { c4 \mySchemeFunction c } {% endlilypond %}
First we define a LilyPond variable mySchemeFunction
and assign it - a Scheme expression (as you can see from the hash with consecutive parentheses). This expression consists of four parts:
- The keyword
define-music-function
This isn't a Scheme keyword but a function defined by LilyPond. As the name suggests it defines a “music function”, which is a function that returns some music. And as such it can be used like a music expression as you see it in the last line of the example. The following three items are the argumentsdefine-music-function
expects. - The list of arguments
the two arguments
parser
andlocation
are mandatory, and as long as you won't need to make use of the information in them you can just forget about them and type it out for each music function you define. If you want your function to process individual arguments (which we'll see in a later post) you will add telling names to this list, for example(parser location slope)
for one additional argument. - The types of your individual arguments.
In the example given for
slope
you would add a type (or “predicate”) here, e.g.(number?)
, but in the example we used you have to provide an empty pair of parens. - The actual music expression to be returned
As we've said a music function returns a music expression. Scheme functions generally return what the evaluation of the last expression produces, so this is where we have to do it. Instead of having to write some Scheme code producing a LilyPond music expression (for which we don't have any means so far) we fortunately can use the
#{ ... #}
construct which allows us to switch to LilyPond mode within Scheme code. Concretely this means the section enclosed in the hash+curly braces is treated as one Scheme expression but can be written with LilyPond code. In our case this returns a music expression with the content ofc2
. So our whole music function returns{ c2 }
. And so our second example produces exactly the same result as the first one:{ c4 c2 c4 }
.
Of course it doesn't make much sense to write a function that returns a hard-coded value. But I think it was a good example to understand the first steps of integrating LilyPond and Scheme code. And I promise that in the next post we'll do something useful.
{% credits %}{% endcredits %}