6.3.4 Adding articulation to notes (example)

The easy way to add articulation to notes is to merge two music expressions into one context, as explained in Creating contexts. However, suppose that we want to write a music function which does this.

A $variable inside the #{...#} notation is like using a regular \variable in classical LilyPond notation. We know that

{ \music -. -> }

will not work in LilyPond. We could avoid this problem by attaching the articulation to a fake note,

{ << \music s1*0-.-> }

but for the sake of this example, we will learn how to do this in Scheme. We begin by examining our input and desired output,

%  input
\displayMusic c4
===>
(make-music
  'EventChord
  'elements
  (list (make-music
          'NoteEvent
          'duration
          (ly:make-duration 2 0 1 1)
          'pitch
          (ly:make-pitch -1 0 0))))
=====
%  desired output
\displayMusic c4->
===>
(make-music
  'EventChord
  'elements
  (list (make-music
          'NoteEvent
          'duration
          (ly:make-duration 2 0 1 1)
          'pitch
          (ly:make-pitch -1 0 0))
        (make-music
          'ArticulationEvent
          'articulation-type
          "marcato")))

We see that a note (c4) is represented as an EventChord expression, with a NoteEvent expression in its elements list. To add a marcato articulation, an ArticulationEvent expression must be added to the elements property of the EventChord expression.

To build this function, we begin with

(define (add-marcato event-chord)
  "Add a marcato ArticulationEvent to the elements of `event-chord',
  which is supposed to be an EventChord expression."
  (let ((result-event-chord (ly:music-deep-copy event-chord)))
    (set! (ly:music-property result-event-chord 'elements)
          (cons (make-music 'ArticulationEvent
                  'articulation-type "marcato")
                (ly:music-property result-event-chord 'elements)))
    result-event-chord))

The first line is the way to define a function in Scheme: the function name is add-marcato, and has one variable called event-chord. In Scheme, the type of variable is often clear from its name. (this is good practice in other programming languages, too!)

"Add a marcato..."

is a description of what the function does. This is not strictly necessary, but just like clear variable names, it is good practice.

(let ((result-event-chord (ly:music-deep-copy event-chord)))

let is used to declare local variables. Here we use one local variable, named result-event-chord, to which we give the value (ly:music-deep-copy event-chord). ly:music-deep-copy is a function specific to LilyPond, like all functions prefixed by ly:. It is use to make a copy of a music expression. Here we copy event-chord (the parameter of the function). Recall that our purpose is to add a marcato to an EventChord expression. It is better to not modify the EventChord which was given as an argument, because it may be used elsewhere.

Now we have a result-event-chord, which is a NoteEventChord expression and is a copy of event-chord. We add the marcato to its elements list property.

(set! place new-value)

Here, what we want to set (the ‘place’) is the ‘elements’ property of result-event-chord expression.

(ly:music-property result-event-chord 'elements)

ly:music-property is the function used to access music properties (the 'elements, 'duration, 'pitch, etc, that we see in the \displayMusic output above). The new value is the former elements property, with an extra item: the ArticulationEvent expression, which we copy from the \displayMusic output,

(cons (make-music 'ArticulationEvent
        'articulation-type "marcato")
      (ly:music-property result-event-chord 'elements))

cons is used to add an element to a list without modifying the original list. This is what we want: the same list as before, plus the new ArticulationEvent expression. The order inside the elements property is not important here.

Finally, once we have added the marcato articulation to its elements property, we can return result-event-chord, hence the last line of the function.

Now we transform the add-marcato function into a music function,

addMarcato = #(define-music-function (parser location event-chord)
                                     (ly:music?)
    "Add a marcato ArticulationEvent to the elements of `event-chord',
    which is supposed to be an EventChord expression."
    (let ((result-event-chord (ly:music-deep-copy event-chord)))
      (set! (ly:music-property result-event-chord 'elements)
            (cons (make-music 'ArticulationEvent
                    'articulation-type "marcato")
                  (ly:music-property result-event-chord 'elements)))
      result-event-chord))

We may verify that this music function works correctly,

\displayMusic \addMarcato c4

Other languages: espaƱol.

Notation Reference