1.3.4 Artikulationszeichen zu Noten hinzufügen (Beispiel)

Am einfachsten können Artikulationszeichen zu Noten hinzugefügt werden, indem man zwei musikalische Funktionen in einen Kontext einfügt, wie erklärt in Kontexte erstellen und referenzieren. Hier soll jetzt eine musikalische Funktion entwickelt werden, die das vornimmt. Daraus ergibt sich der zusätzliche Vorteil, dass diese musikalische Funktion eingesetzt werden kann, um eine Artikulation (wie etwa eine Fingersatzanweisung) einer einzigen Note innerhalb eines Akkordes hinzugefügt werden kann, was nicht möglich ist, wenn einfach unabhängige Noten ein einem Kontext miteinander verschmolzen werden.

Eine $variable innerhalb von #{...#} ist das gleiche wie die normale Befehlsform \variable in üblicher LilyPond-Notation. Es ist bekannt dass

{ \music -. -> }

in LilyPond nicht funktioniert. Das Problem könnte vermieden werden, indem das Artikulationszeichen an einen leeren Akkord gehängt wird:

{ << \music <> -. -> >> }

aber in diesem Beispiel soll gezeigt werden, wie man das in Scheme vornimmt. Zunächst wird die Eingabe und die gewünschte Ausgabe examiniert:

%  Eingabe
\displayMusic c4
===>
(make-music
  'NoteEvent
  'duration
  (ly:make-duration 2 0 1/1)
  'pitch
  (ly:make-pitch -1 0 0))))
=====
%  gewünschte Ausgabe
\displayMusic c4->
===>
(make-music
  'NoteEvent
  'articulations
  (list (make-music
          'ArticulationEvent
          'articulation-type 'accent))
  'duration
  (ly:make-duration 2 0 1/1)
  'pitch
  (ly:make-pitch -1 0 0))
\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))))

Dabei ist zu sehen, dass eine Note (c4) als NoteEvent-Ausdruck repräsentiert ist. Um eine Akzent-Artikulation hinzuzufügen, muss ein ArticulationEvent-Ausdruck zu der Elementeigenschaft articulations des NoteEvent-Ausdrucks hinzugefügt werden.

Um diese Funktion zu bauen, wird folgendermaßen begonnen:

(define (add-accent note-event)
  "Add an accent ArticulationEvent to the articulations of `note-event',
  which is supposed to be a NoteEvent expression."
  (set! (ly:music-property note-event 'articulations)
        (cons (make-music 'ArticulationEvent
                'articulation-type 'accent)
              (ly:music-property note-event 'articulations)))
  note-event)

Die erste Zeile definiert eine Funktion in Scheme: Die Bezeichnung der Funktion ist add-accent und sie hat eine Variable mit der Bezeichnung note-event. In Scheme geht der Typ einer Variable oft direkt aus der Bezeichnung hervor (das ist auch eine gute Methode für andere Programmiersprachen).

"Add an accent..."

ist eine (englische) Beschreibung, was diese Funktion tut. Sie ist nicht unbedingt notwendig, aber genauso wie klare Variablen-Bezeichnungen ist auch das eine gute Methode.

Es kann seltsam scheinen, warum das Notenereignis direkt verändert wird, anstatt mit einer Kopie zu arbeiten (ly:music-deep-copy kann dafür benützt werden). Der Grund ist eine stille Übereinkunft: musikalische Funktionen dürfen ihre Argumente verändern: sie werden entweder von Grund auf erstellt (wie Eingabe des Benutzers) oder sind schon kopiert (etwa Verweis auf eine Variable mit ‘\Bezeichnung’ oder Noten aus einem Scheme-Ausdruck ‘$(…)’ sind Kopien). Weil es uneffizient wäre, unnötige Kopien zu erstellen, wird der Wiedergabewert einer musikalischen Funktion nicht kopiert. Um sich also an die Übereinkunft zu halten, dürfen Argumente nicht mehr als einmal benützt werden, und sie wiederzugeben zählt als eine Benutzung.

In einem früheren Beispiel wurden Noten konstruiert, indem ein musikalisches Argument wiederholt wurde. In diesem Fall muss wenigstens eine Wiederholung eine Kopie ihres Arguments sein. Wenn es keine Kopie ist, können seltsame Dinge passieren. Wenn man beispielsweise \relative oder \transpose auf die resultierenden Noten anwendet, die die gleichen Elemente mehrmals enthalten, werden die Elemente mehrmals der \relative-Veränderung oder Transposition unterworfen. Wenn man sie einer musikalischen Variable zuweist, wird dieser Fluch aufgehoben, denn der Verweis auf ‘\Bezeichnung’ erstellt wiederum eine Kopie, die nicht die Identität der wiederholten Elemente überträgt.

Während die Funktion oben keine musikalische Funktion ist, wird sie normalerweise inmitten musikalischer Funktionen eingesetzt. Darum ist es sinnvoll, der gleichen Übereinkunft zu folgen, die für musikalische Funktionen gelten: Die Eingabe kann verändert worden sein, um die Ausgabe zu produzieren, und der den Aufruf erstellt, ist verantwortlich für die Erstellung von Kopien, wenn er immernoch die unveränderten Argumente benötigt. Wenn man sich LilyPonds eigene Funktionen wie etwa music-map anschaut, sieht man, dass sie denselben Prinzipien folgen.

Aber wo waren wir? Jetzt gibt es ein note-event, das verändert werden kann, nicht unter Einsatz von ly:music-deep-copy sondern aufgrund einer langen Erklärung. Der Akzent wird zu seiner 'articulations-Liste hinzugefügt:

(set! place neuer-Wert)

Was in diesem Fall „gesetzt“ werden soll („place“) ist die ‚’articulations‘-Eigenschaft des note-event-Ausdrucks.

(ly:music-property note-event 'articulations)

ly:music-property ist die Funktion, mit der musikalische Eigenschaften erreicht werden können (die 'articulations, 'duration, 'pitch usw., die in der Ausgabe von \displayMusic weiter oben angezeigt werden). Der neue Wert ist, was ehemals die 'articulations-Eigenschaft war, mit einem zusätzlichen Element: dem ArticulationEvent-Ausdruck, der aus der Ausgabe von \displayMusic kopiert werden kann:

(cons (make-music 'ArticulationEvent
        'articulation-type 'accent)
      (ly:music-property result-event-chord 'articulations))

cons wird benutzt, um ein Element vorne an eine Liste hinzuzufügen, ohne dass die originale Liste verändert wird. Das ist es, was die Funktion tun soll: die gleiche Liste wie vorher, aber mit dem neuen ArticulationEvent-Ausdruck. Die Reihenfolge innerhalb der Elementeeigenschaft ist hier nicht relevant.

Wenn schließlich die Akzent-Artikulation zu der entsprechenden elements-Eigenschaft hinzugefügt ist, kann note-event ausgegeben werden, darum die letzte Zeile der Funktion.

Jetzt wird die add-accent-Funktion in eine musikalische Funktion umgewandelt (hierzu gehört etwas syntaktischer Zuckerguß und eine Deklaration des Typs ihres einzigen „wirklichen“ Arguments:

addAccent = #(define-music-function (note-event)
                                     (ly:music?)
  "Add an accent ArticulationEvent to the articulations of `note-event',
  which is supposed to be a NoteEvent expression."
  (set! (ly:music-property note-event 'articulations)
        (cons (make-music 'ArticulationEvent
                'articulation-type 'accent)
              (ly:music-property note-event 'articulations)))
  note-event)

Eine Überprüfung, dass die Funktion richtig arbeitet, geschieht folgendermaßen:

\displayMusic \addAccent c4

LilyPond erweitern v2.25.21 (Entwicklungszweig).