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