Music Functions 1. Getting to Grips with Scheme in LilyPond

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.

Being able to include Scheme code in LilyPond files is one of the foundations of Lily’s higher powers, as this isn’t “just some scripting interface” but allows you to interact with its processing on the lowest level. Basically LilyPond works through a combination of compiled C++ code and Scheme code interpreted at runtime. Injecting Scheme code in input files is therefore literally extending LilyPond’s built-in capabilities.

Unfortunately Scheme isn’t the most straightforward language to learn, and learning how it interacts with LilyPond can be a real challenge. While LilyPond’s documentation is generally excellent and comprehensive, everything beyond the Learning manual is deliberately concise (a reference, that is), sometimes to the degree of being hardly digestible. And the part about extending LilyPond with Scheme code definitely belongs to that area. Therefore I think it might be helpful to provide a more gentle introduction to some of its aspects. However, this won’t be a comprehensive introduction to Scheme as a language – this would definitely be over my head. Instead I’ll be presenting the things that one will want to start with when extending LilyPond, trying to be more verbose and more casual than the official documentation. I’m always open for suggestions how to improve the explanations, and if others would like to join the effort and provide tutorials for specific aspects, I’d be more than happy.

Preface: Including Scheme in LilyPond

As mentioned in the manual LilyPond will interpret anything after the # hash character as inline Scheme code. To be more precise it will evaluate the single expression that follows the hash. Everything in Scheme is an expression that will be evaluated. This is quite different from the idea of a program executing commands, and this is what makes Scheme and other LISP dialects difficult to approach for people coming from other programming languages.

LilyPond very much “thinks” like Scheme. There is even a dedicated section in the manual called “Score is a (single) compound musical expression” in the learning manual – which is a direct consequence of this conceptual affinity.
Another thing to note here is that LilyPond variables are interchangeable with Scheme variables in LilyPond input files. Let’s have a look at this with a concrete example:

\version "2.18.0"

% define a variable using the usual LilyPond syntax
bpmA = 60

% define a variable using Scheme
#(define bpmB 72)

{
  % assign a tempo literally
  \tempo 8 = 54
  R1
  
  % assign tempos using the LilyPond syntax for variables
  \tempo 8 = \bpmA
  R1
  
  \tempo 8 = \bpmB
  R1
  
   % assign tempos by referencing variables using Scheme
  \tempo 8 = #bpmA
  R1
  
  \tempo 8 = #bpmB
  R1 
}

First we define a normal LilyPond variable bpmA, then we do the same thing in Scheme syntax. We tell LilyPond with the # that there will be a Scheme expression, which is enclosed in parentheses (the parens are another “hot” topic for beginners, but we may come to this at another occasion). The expression itself defines a variable with the name bpmB and assigns it the value 72. Now we have two variables, bpmA and bpmB, which have different values but are technically the same for LilyPond.

first-music-function

As you can see we can use the literal value, the LilyPond or the Scheme variable. And LilyPond doesn’t care whether we pass it as through LilyPond or Scheme syntax.

The First Basic Scheme Function

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:

\version "2.18.0"

myFunction = { c2 }

\relative c' {
  c4 \myFunction c
}

first-music-function

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:

mySchemeFunction =
#(define-music-function (parser location)()
   #{
     c2
   #})

\relative c' {
  c4 \mySchemeFunction c
}

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 arguments define-music-function expects.
  • The list of arguments
    the two arguments parser and location 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 of c2. 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.

16 thoughts on “Music Functions 1. Getting to Grips with Scheme in LilyPond

  1. vvillenave

    Here’s how I like to introduce Scheme variables to my students; the code is similar to yours but it demonstrates what sort of things Scheme can be useful for:

    #(define myList
      (list
       #{ c2 #}
       #{ d2 #}
       #{ e2 #}))
    
    mySchemeFunction =
    #(define-music-function (parser location) ()
      (list-ref myList (random (length myList))))
    
    \relative c' {
      c4 \mySchemeFunction c
    }
    Reply
      1. Phil Holmes

        I assume it’s _intended_ to return a random note from the list. In practice, it always returns the same note – and if you use it multiple times, always the same set of notes, because the random seed hasn’t been initialised to make it different on each run.

        Here’s an alternative that overcomes that limitation: unfortunately it’s not as simple.

        #(define myList
          (list
           #{ b2 #}
           #{ c'2 #}
           #{ d'2 #}
           #{ e'2 #}))
        
        mySchemeFunction =
        #(define-music-function (parser location) ()
          (list-ref myList (random (length myList))))
        
        mySetSeed = 
        #(define-void-function (parser location) ()
             (let ((time (gettimeofday)))
               (set! *random-state*
                     (seed->random-state (+ (car time)
                                            (cdr time))))))
        
        
        {
          \mySetSeed c'4 \mySchemeFunction c' \mySchemeFunction c' \mySchemeFunction c' \mySchemeFunction c' \mySchemeFunction c'
        }
        Reply
        1. vvillenave

          Well, yes, one is not supposed to run it twice 🙂
          It does, however, work well when presenting it to my students, since they will get different results by running the code on their own computers. And at least, it makes them get the point about what sort of things Scheme can be useful for.

          Reply
  2. Helge

    Great introduction!

    When you continue to write the announced blog entries,. it would be very interesting to understand when to pass what kind of parameter, the difference between notes and music and markup. When to usu what.

    Just nitpicking: when you define mySchemeFunction you comment it as schemeFunction.

    Reply
    1. Urs Liska

      Thanks for the encouragment. I don’t know how it will develop yet. The next post is mostly written, the third one already has a clear idea, but then I’ll soon reach the point where I will have to learn topics myself before I can write about them 😉

      And thanks for the nitpick, I updated the text.
      I had changed the name(s) in order to make it clearer that the names can be chosen aribtrarily and overlooked that instance.

      Reply
  3. Pingback: Music Functions 2: Start Doing Something Useful | Scores of Beauty

  4. LEGRAND Jean-Marc

    Dear Urs,

    First many thanks for this series of posts which will be a perfect complement to the official documentation !

    Would you be insterested in a French translation : I’d be glad to write it so I’ll be sure to understand everything in Scheme within the next months ;o)

    Best regards
    JMarc

    Reply
      1. LEGRAND Jean-Marc

        Great !

        To be honest, I’ve begun to translate. Just a try, but I couldn’t wait ;o)

        OK I’ll give you the translations asap, with some questions for you before publishing.

        best wishes !
        JMarc

        Reply
        1. LEGRAND Jean-Marc

          That’s it : I’ve finished the translation for the first post. Could you send me a mail so I can send it to you ?

          Best wishes
          JMarc

          Reply
  5. Erich

    remark at “The First Basic Scheme Function”

    myFunction = { c2 }
    
    \relative c' {
      c4 \myFunction c
    }

    it is not like a substitution because \relative c' { c4 {c2} c} would give another result.

    Reply
  6. Erich

    The First Basic Scheme Function

    another remark

    mySchemeFunction =
    #(define-music-function (parser location)()
       #{
         c2
       #})
    
    \relative c' {
      c4 \mySchemeFunction c
    }

    indeed it is a parameterless function and the types mustn’t be declared

    it may be easier to explain fist an example with one proper parameter

    Reply
  7. Erich

    another remark

    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.

    please delete it here and explain it in your second post

    Reply
  8. Pingback: Les fonctions musicales 1. Premier contact avec Scheme dans Lilypond | Scores of Beauty

Leave a Reply

Your email address will not be published. Required fields are marked *