Musikobjekte#

Der erste Schritt in LilyPonds Arbeitsprozess besteht darin, die Musik einzulesen, in Musikobjekte umzuwandeln und Musikfunktionen anzuwenden.

Musikfunktionen definieren#

Musikfunktionen sind das Hauptwerkzeug, um Musikobjekte zu erstellen und zu modifizieren. Das Grundgerüst zum Definieren einer Musikfunktion lautet:

meineFunktion =
#(define-music-function (arg1 arg2 ...) (type1? type2? ...)
   body...)

Damit wird eine Funktion definiert, die mittels \meineFunktion aufgerufen wird. Die Parameter, die für die Argumente arg1, arg2 usw. übergeben werden, müssen dabei jeweils die Typenprädikate typ1?, typ2? usw. erfüllen. Der Funktionsrumpf („body“) ist eine Folge von Scheme-Ausdrücken; wie immer bei Scheme-Funktionen, werden diese Ausdrücke der Reihe nach ausgewertet, und der Wert des letzten Ausdrucks wird als Funktionswert zurückgegeben. Eine einfache Musikfunktion wäre:

\version "2.25.8"

vorlesen =
#(define-music-function (music) (ly:music?)
   #{
     <<
       \new Voice $music
       \new NoteNames $music
     >>
   #})

\vorlesen \relative c' { c d e c e f g e }
Output../../images/9bc5032f610d4aeb7a75acfba545c33eede4e592e5f7c1c52bfa0deab3bd3286.svg

Parameter-Typprüfung#

Alle Parameter, die einer Musikfunktion übergeben werden, werden darauf überprüft, ob sie den erwarteten Typ haben. Da Scheme latent typisiert ist (d.h. man kann den Typ eines gegebenen Objekts nicht direkt ablesen, sondern nur fragen, ob es zu einem bestimmten Typ gehört), sind typ1?, typ2? usw. Typenprädikate.

\version "2.25.8"

n-mal =
#(define-music-function (n music) (index? ly:music?)
   #{ \repeat unfold #n { #music } #})

\n-mal 4 aes
Output../../images/d6517920d83e778b175a0d5a322b1a198fa4c4f01cf8fcbc506e01e285e35e91.svg

Diese (ziemlich langweilige) Musikfunktion liefert ein Kürzel für \repeat unfold .... Sie benötigt zwei Argumente, die hier n und music heißen. Das erste muss eine nicht-negative ganze Zahl sein, das zweite ein Musikobjekt. Wenn die Funktion aufgerufen wird, werden zur Typ-Prüfung die Ausdrücke (index? n) und (ly:music? music) getestet.

Besonders interessant wird das in einem Beispiel wie dem folgenden:

\version "2.25.8"

kurzeTonart =
#(define-music-function (duration pitch) (ly:duration? ly:pitch?)
   #{ \key #pitch \major s $duration \key c \major #})

\new Staff <<
  { c'4 c' c' c' }
  { s2 \kurzeTonart 4 aes s4 }
>>
Output../../images/926048a54bd794c350f2c139f90c39f04dd84e3581fc1d058ee17613384f7bae.svg

Hier definieren wir eine weitere Musikfunktion namens \kurzeTonart, wieder mit zwei Argumenten. Sie liefert einen Musikausdruck, der mit unsichtbaren Pausen dafür sorgt, dass die verlangte Dur-Tonart für eine bestimmte Dauer eingestellt und danach nach C-Dur zurückgekehrt wird.

Wir haben nun zwei verschiedene Funktionsaufrufe verwendet:

\n-mal 4 aes
\kurzeTonart 4 aes

Even though the arguments are exactly the same, they were obtained with different types. The \nrepeats function got an integer and a music expression. The \keyDuring function, in contrast, got a duration and a pitch! This is thanks to the capabilities of the parser, coupled to the type predicates. When 4 and aes are encountered, different rules are tried, until one is found that allows for a successful match against the type predicate.

Vordefinierte Typenprädikate sind in der Notationsreferenz aufgeführt. Eine Tabelle der häufigsten findet sich im Abschnitt Das Wichtigste über Musikfunktionen.

Optionale Parameter#

Ein Funktionsargument wird als optional markiert, indem man sein Prädikat in Klammern (...) setzt. Wenn die Funktion ohne dieses Argument aufgerufen wird, hat der Parameter den Wert FALSCH (#f). Die folgende Funktion beispielsweise erzeugt eine Metronomangabe mit einem der häufigsten Werte, die jeder über ihren italienische Namen („Allegro“, „Andante“ usw.) ausgewählt werden. Der gedruckte Text ist optional; wird er nicht angegeben, so wird der italienische Name selbst verwendet.

\version "2.25.8"

tempi =
#'(("Largo" . 50)
   ("Lento" . 60)
   ("Adagio" . 70)
   ("Andante" . 90)
   ("Moderato" . 100)
   ("Allegro" . 140)
   ("Presto" . 170))


standardTempo =
#(define-music-function (gedruckter-name dauer name) ((markup?) ly:duration? string?)
   #{
     \tempo $(or gedruckter-name name) $dauer = $(assoc-ref tempi name)
   #})


\relative c' {
  \standardTempo 4 Adagio
  c8 d e4 d c
  \standardTempo "Allegro con brio" 4 Allegro
  g'4 e'2 g,4
}
Output../../images/f1da8ff28d0d9b284f7918590d407decc97198028a03d176c69e0320bd4cb41c.svg

Es ist auch möglich, innerhalb der Klammern einen anderen Standardwert als #f für den optionalen Parameter festzulegen.

\version "2.25.8"

hintergrundCluster =
#(define-music-function (grauwert mus) ((number? 0.5) ly:music?)
   #{
     <<
       $mus
       {
         \once \override ClusterSpanner.layer = 0
         \once \override ClusterSpanner.color = #(rgb-color grauwert grauwert grauwert)
         \makeClusters $mus
       }
     >>
   #})

\new Voice \hintergrundCluster { <g' b''>2 <c''' g'''> }
\new Voice \hintergrundCluster 0.3 { <g' b''>2 <c''' g'''> }
Output../../images/1e1393d68a9ccb85d070ed3c6202dc5b2534841db17305fbd3a538e2dbb0bcdd.svg

Obwohl optionale Parameter gelegentlich nützlich sind, haben sie auch ihre Grenzen.

Wenn der Parser bei einer Musikfunktion mit einem optionalen Argument rechnet, testet er den nächsten Parameter gegen das Typenprädikat für dieses optionale Argument. Wenn dieses Prädikat anschlägt, dann wird der Wert des Parameters für das optionale Argument benutzt. Andernfalls erhält das optionale Argument seinen Standardwert, und der Parameterwert wird für das nächste Argument getestet. Zu beachten ist die wichtige Einschränkung, dass ein Wert, der nicht das Prädikat des optionalen Parameters erfüllt hat, für eines der nachfolgenden Argumente des gleichen Funktionsaufrufs stehen muss, nicht für einen ganz anderen Ausdruck nach dem Funktionsaufruf. Falls das kompliziert klingt: Merken muss man sich nur, dass ein optionaler Parameter nur dann wirklich optional ist, wenn nach ihm noch erforderliche Argumente kommen, aber nicht, wenn er das letzte Argument ist. Versuchen wir, die Argumente der obigen Funktion \hintergrundCluster zu tauschen:

\version "2.25.8"

hintergrundCluster =
#(define-music-function (mus grauwert) (ly:music? (number? 0.5))
   #{
     <<
       $mus
       {
         \once \override ClusterSpanner.layer = 0
         \once \override ClusterSpanner.color = #(rgb-color grauwert grauwert grauwert)
         \makeClusters $mus
       }
     >>
   #})

\new Voice \hintergrundCluster { <g' b''>2 <c''' g'''> } 0.3
% \new Voice \hintergrundCluster { <g' b''>2 <c''' g'''> } % funktioniert nicht
\new Voice \hintergrundCluster { <g' b''>2 <c''' g'''> } \default % funktioniert!
Output../../images/ef6f4cef6e9bcb1e65241faebaca3421a0512e567d39443ecd63e1c9774de2b0.svg

Die letzte Zeile dieses Beispiels zeigt, wie man die beschriebene Einschränkung umgehen kann: Das Schlüsselwort \default kann als Platzhalter angegeben werden, wenn der Parser das Weglassen des Parameters nicht akzeptiert.

Beachten Sie auch, dass Funktionsparameter gierig eingelesen werden. Das kann man am besten an einem Beispiel erklären, indem wir die Argumente dauer und name der oben vorgestellten Funktion standardTempo vertauschen:

tempi =
#'(("Largo" . 50)
   ("Lento" . 60)
   ("Adagio" . 70)
   ("Andante" . 90)
   ("Moderato" . 100)
   ("Allegro" . 140)
   ("Presto" . 170))


standardTempo =
#(define-music-function (gedruckter-name name dauer) ((markup?) string? ly:duration?)
   #{
     \tempo $(or gedruckter-name name) $dauer = $(assoc-ref tempi name)
   #})


\relative c' {
  \standardTempo Adagio 4 % Fehler
  c8 d e4 d c
}

Wir Menschen verstehen, dass \standardTempo zwei Parameter übergeben werden (Adagiound 4), und da die Funktion drei Argumente hat, von denen eines optional ist, sollte dieses optionale Argument seinen Standardwert bekommen. Stattdessen aber produziert der obige Code einen Fehler! Der Grund dafür ist, dass der Parser zuerst überprüft, ob der String Adagio ein möglicher Wert für das erste, optionale Argument ist. Dieses hat den Typ markup?, und da Strings als Markup gelten, trifft dies zu: Also wird Adagio als Wert des optionalen Arguments gedruckter-name genommen. Als nächstes folgt der Wert 4, aber dies ist kein zulässiger Wert für das folgende Argument name, das ja als string? definiert ist. Das bedeutet: Wenn nach einem optionalen Argument ein verpflichtendes Argument kommt, dann darf ein Parameterwert für das verpflichtende Argument nicht auch als Wert für das optionale Argument interpretierbar sein.

Schließlich noch ein Wort zu mehrfachen optionalen Argumenten: Wenn mehrere optionale Argumente hintereinander auftreten, bedeutet das Weglassen eines einzelnen von ihnen automatisch, dass alle weggelassen sind.

All that being said, optional arguments are still very useful, and many of LilyPond’s built-in functions use them (e.g., \relative { ... } or \relative c' { ... }, \time 9/8 or \time 2,2,2,3 9/8). However, it may take some thinking to write your functions in a way that accommodates their restrictions. If you are running into trouble, a good strategy is to split out the function into several functions. For example, instead of injecting \overrides in the result if an optional argument is given, drop the optional argument, and make a separate function that does the \overrides.

Andere Typen von Funktionen#

Eine Musikfunktion liefert stets Musik. Es gibt andere Arten von Funktionen, die jeweils auf einen bestimmten Rückgabe-Typ festgelegt sind. Ihr Vorteil ist, dass sie in anderen syntaktischen Kontexten eingesetzt werden können, weil der Parser den Typ des Funktionswerts im Voraus weiß. (TODO: überprüfen)

Funktionstyp

Makro zum Definieren

Typ des Rückgabewerts

Musikfunktion

define-music-function

Musik (ly:music?)

Eventfunktion

define-event-function

Angehängtes Event [im deutschen Lilypond-Handbuch: „Nachereignis“] (ly:event?)

Scheme-Funktion

define-scheme-function

beliebig (scheme?)

Funktion ohne Rückgabewert

define-void-function

beliebig; ein eventueller Rückgabewert wird ignoriert

BAUSTELLE: Hier fehlt noch ein Beispiel.

Das Kürzel \etc#

Mit dem speziellen Syntaxelement \etc kann man besonders bequem Musikfunktionen definieren. Das Prinzip ist, dass \etc als Platzhalter für ein oder mehrere Parameter ganz am Ende einer Folge von Funktionsaufrufen verwendet werden kann. Ein Beispiel erklärt es am besten:

\version "2.25.8"

fürKlarinette = \compressMMRests \transpose bes c' \etc

\fürKlarinette { c' d' e' }
Output../../images/8c8f79d23158e9b445a87742bc5bc7e8bf6e24cdbc43c1e33683ea7250a2ba27.svg

\etc funktioniert auch in einigen anderen Situationen:

\version "2.25.8"

textAbstand = \once \override TextScript.padding = \etc

{ \textAbstand 1.8 c'4^"piu mosso" }
Output../../images/86e1625c8c9a36355fe2bb2381a7a1cb46be3521f68b0571c968f01d54570d09.svg
\version "2.25.8"

\markup rötlich = \markup \with-color "LightCoral" \etc

\markup \rötlich "Hallo"
Output../../images/5f7df4295bc6182b5b96107ca6970930bf419bf9364ca80df43fc14501f68c70.svg

Musikausdrücke#

In den bisherigen Beispielen wurden einfach die Parameter einer Musikfunktion dazu benutzt, um Ausdrücke in LilyPond-Syntax zu bilden. Das ist nützlich als syntaktischer Zucker. In Wirklichkeit sind Musikfunktionen aber viel mächtiger – man denke nur an \transpose: Sie erlauben es, Musikobjekte zu analysieren und neu zu konstruieren.

Der einfachste Weg, um zu sehen, wie eine bestimmte Musikfunktion aufgebaut ist, ist die Musikfunktion \displayMusic oder, gleichwertig, die Scheme-Funktion display-scheme-music. Sie versuchen, einen gültigen Scheme-Code auszugeben, der eine zur übergebenen Musik gleichwertigen Musikausdruck konstruiert. Betrachten wir ein erstes Beispiel:

\version "2.25.8"

\displayMusic { c' d'-> }
Output../../images/704978902f15234c5d689dd7c95a47e1c981b2b27a2268c12c9ea79601d66a7d.svg

Dies liefert die folgende Ausgabe auf der Konsole:

(make-music
  'SequentialMusic
  'elements
  (list (make-music
          'NoteEvent
          'pitch
          (ly:make-pitch 0 0)
          'duration
          (ly:make-duration 2))
        (make-music
          'NoteEvent
          'articulations
          (list (make-music
                  'ArticulationEvent
                  'midi-extra-velocity
                  20
                  'articulation-type
                  "accent"))
          'duration
          (ly:make-duration 2)
          'pitch
          (ly:make-pitch 0 1))))

Every music object has a type. Possible types are listed in the Internals Reference at Music expressions. Moreover, it holds properties that describe it. NoteEvent objects, for instance, typically have a pitch and a duration (pitch and duration properties). Optionally, they may contain articulations (articulations property). Note that the music type does not prescribe the set of properties; music objects are structured by conventions, not rules. It is allowed to read, define and set arbitrary music properties on arbitrary music objects, although the most common case is defining/setting properties that are understood by LilyPond’s built-in functions and engravers.

Jeder Musiktyp gehört außerdem zu gewissen Klassen von Musik. Diese dienen dazu, bestimmte Ereignistypen zusammenzufassen, die auf ähnliche Art verarbeitet werden müssen. Sie sind im Interna-Handbuch unter Music classes verzeichnet.

Die Namen von Musiktypen werden in GroßUndKleinschreibung (CamelCase) geschrieben, die von Musik-Klassen in kleinbuchstaben-mit-bindestrichen

(music-is-of-type? music class)

Testet, ob music zur Musikklasse class gehört.

Eigenschaften von Musik#

Sobald man ein Musikobjekt vorliegen hat, kann man tolle Dinge anstellen, indem man seine Eigenschaften manipuliert. Die einschlägigen Funktionen sind ly:music-property und ly:music-set-property! (vgl. Probs).

Manche Musikausdrücke enthalten andere Musikausdrücke. Diese sind dann normalerweise in einer der folgenden Eigenschaften enthalten:

  • elements ist eine Liste von Musikobjekten, etwa für die in SequentialMusic, SimultaneousMusic und anderen Behältern enthaltene Musik.

  • articulations ist ebenfalls eine Liste. Sie enthält alle an eine Note oder Pause angehängten Events.

  • element ist ein einzelnes Musikobjekt. Diese Eigenschaft ist relevant für Musikobjekte, die ihrer Aufgabe gemäß nur ein einziges Musikobjekt enthalten können. Ein Beispiel wäre RelativeOctaveMusic: Dieses Objekt enthält ein einziges element, nämlich die in ihr enthaltene Musik (in der im Fall von RelativeOctaveMusic die Konvertierung von relativen in absolute Tonhöhen als abgeschlossen angesehen wird).

Die Eigenschaft name eines Musikobjekts enthält seinen Typ (etwa NoteEvent) als Symbol. In den meisten Fällen sollte man Musiktypen aber anhand von Ereignisklassen erkennen, nicht anhand des Namens.

Konstruieren von Musikobjekten#

Man kann Musikobjekte auch direkt erzeugen, etwa für algorithmisches Komponieren, oder einfach zum Hinzufügen von Artikulationen.

(make-music name eigenschaft1 wert1 eigenschaft2 wert2 ...)

Erzeugt ein Musikobjekt.

name ist der Musiktyp, gegeben als Symbol. Die übrigen Argumente treten paarweise auf: Auf den Namen einer Eigenschaft (als Symbol) folgt jeweils der Wert, den diese Eigenschaft im Musikobjekt haben soll.

Werden Eigenschaften mehrfach genannt, überschreiben die späteren Werte die früheren.

Anstelle eines Paars aus Eigenschaft und Wert kann man der Funktion auch ein Musikobjekt übergeben. In diesem Fall werden die Eigenschaften dieses Objekts übernommen. Etwaige weitere Eigenschaft-Wert-Paare überschreiben dann ggf. diese übernommenen Eigenschaften. Beispielsweise könnte man ein NoteEvent folgendermaßen in ein ClusterNoteEvent verwandeln:

(make-music 'ClusterNoteEvent
            ein-note-event)

Werkzeuge zum Transformieren von Musik#

Musikobjekte sind tief verschachtelte Strukturen, und oftmals weiß man im voraus nicht, wie tief die Verschachtelung reicht. Beispielsweise können Noten in beliebiger Tiefe innerhalb von SequentialMusic, RelativeOctaveMusic, SimultaneousMusic usw. enthalten sein.

Die in diesem Abschnitt vorgestellten Funktionen erlauben das rekursive Verarbeiten von Musik.

(music-map function music)

Erstellt ein neues Musik-Objekt, indem die Funktion function auf die in music enthaltene Musik „von unten nach oben“ angewandt wird. Die Funktion wird also zuerst auf die ganz unten in der Verschachtelungs-Hierarchie stehenden Musikobjekte angewandt, die selbst keine weiteren Musikobjekte enthalten. Sie werden in den sie enthaltenen (eine Hierarchiestufe höher gelegenen) Musikobjekten durch die Musik, die durch das Anwenden der Funktion function entsteht. Dann wird die Funktion auf die Musik der nächsthöheren Schicht angewandt, und immer weiter, bis zuletzt der oberste Musikausdruck music selbst an der Reihe ist.

Aus Effizienzgründen arbeitet music-map destruktiv mit dem Musikobjekt music. Das bedeutet, dass man in manchen Fällen Musik kopieren muss.

Das folgende Beispiel ersetzt alle Wiederholungen in der Musik durch Faulenzerzeichen [Lilypond-Handbuch: „Prozent-Wiederholungen“]. Dazu werden alle Arten von Wiederholungen, die allesamt charakteristiert sind durch ihre gemeinsame Musikklasse repeated-music, in den Typ PercentRepeatedMusic verwandelt.

\version "2.25.8"

faulenzen =
#(define-music-function (music) (ly:music?)
   (music-map
     (lambda (m)
       (if (music-is-of-type? m 'repeated-music)
           (make-music 'PercentRepeatedMusic
                       m)
           m))
     music))

musik =
\relative {
  \clef bass
  \repeat unfold 2 <<
    { s4 <g a c ees> s <gis b d f> s <a c ees g> s <gis b d f> }
    \\
    { c, s g s c s g s }
  >>
}

{ \musik }
\faulenzen \musik
Output../../images/1d2b7f39310994c5c0b193adbe14ce63f661db627e9beb5ee816166461cf78c7.svg
(music-filter predicate? music)

Entfernt alle Musikausdrücke aus music, die nicht das Prädikat predicate? erfüllen.

(for-some-music function music)

Diese Funktion arbeitet ähnlich wie music-map, allerdings wird die Funktion function hier zunächst auf den obersten Musikausdruck music angewandt, dann auf dessen direkte Kinder, usw. Außerdem liefert for-some-music nicht die veränderte Musik zurück: Die Funktion function sollte die ihr übergebene Musik direkt verändert. Das ist oft nützlich, um Musik-Eigenschaften festzulegen, während music-map besser geeignet ist, um neue Musikobjekte zu konstruieren.

Weiter steigt for-some-music nur dann rekursiv zur Kinder-Ebene hinab, wenn function den Wert #f zurückgegeben hat. Man kann sich also vorstellen, dass function erstens die Musik verändert und zweitens die Frage „Aufhören?“ beantwortet.

Ein einfaches Beispiel wäre eine Funktion, die eine bestimmte Artikulation zu allen Noten hinzufügt. Hier wird die Stopp-Bedingung benutzt, um zu verhindern, dass im Falle von Akkorden die Artikulation nicht nur zum Akkord selbst, sondern auch zu allen seinen einzelnen Noten hinzugefügt wird, was sonst zu doppelten Artikulationszeichen führen würde.

\version "2.25.8"

mitStaccato =
#(define-music-function (music) (ly:music?)
   (for-some-music
     (lambda (m)
       (if (or (music-is-of-type? m 'note-event)
               (music-is-of-type? m 'event-chord))
           (begin
             (ly:music-set-property!
               m
               'articulations
               (cons
                 (make-music 'ArticulationEvent
                             'articulation-type
                             'staccato)
                 (ly:music-property m 'articulations)))
             #t)
           #f))
     music)
   music)


\mitStaccato { c' d' <e' f'> }
Output../../images/69226e6ed8bea96254c155c4f59fad4eefc1a02d2614f16b50cb11e82df5df63.svg
(map-some-music function music)

Wie for-some-music, aber Einträge in elements und articulations, die nach dem Anwenden von function keine Musikobjekte mehr sind, werden entfernt. Das ermöglicht das Konstruieren von Filtern.

Musik kopieren#

Weil music-map und verwandte Funktionen die ihnen übergebene Musik direkt verändern, muss man manchmal Musikobjekte kopieren.

(ly:music-deep-copy music)

Erstellt rekursiv („tief“) eine Kopie von music.

Tonhöhen#

Tonhöhen sind der wichtigste Teil der Noteneingabe. Sie sind in jedem NoteEvent (d.h. in jeder Note) enthalten, aber auch beispielsweise in jedem KeyChangeEvent (also einem Tonartwechsel). Viele Musikfunktionen arbeiten direkt mit ihnen.

Die wichtigste Methode, Tonhöhen einzugeben, ist das Verwenden derjenigen Notennamen, die durch die Spracheinstellung mittels \language festgelegt werden. Das funktioniert auch beim Zuweisen von Tonhöhen an Variablen und in #{ ... #}-Konstrukten.

\version "2.25.8"

meineTonhöhe = ces
\transpose c \meineTonhöhe { c' e' g' c'' }

$(let ((noch-eine-tonhöhe #{ bes, #}))
  #{ \transpose c #noch-eine-tonhöhe { c' e' g' c'' } #})
Output../../images/1ccbb1d2575a534c2a5d671a90b5984e779c18754907e66edb67181e3ca3735a.svg

Man kann aber Tonhöhen auch direkt in Scheme erzeugen, und zwar mit der unten vorgestellten Funktion ly:make-pitch.

Eine Tonhöhe in LilyPond besteht aus drei Teilen: Einer Oktavangabe, dem Notennamen und der Alteration. Wichtig ist, dass Tonhöhen nicht identisch sind nicht Frequenzen: Cis und Des sind verschiedene Tonhöhen!

LilyPond stellt eine ganze Anzahl von Funktionen bereit, um mit Tonhöhen zu arbeiten. Sie alle sind im Internals-Handbuch unter Scheme functions aufgeführt; wir stellen hier nur die wichtigsten vor:

(ly:make-pitch octave note alteration)

Konstruiert ein Tonhöhen-Objekt.

octave ist eine ganze Zahl. Null steht dabei für die Oktave, die das eingestrichene c („mittleres c“) enthält.

note (in LilyPond auch öfters notename genannt) ist ein Index innerhalb der Stammtonreihe, von 0 (c) bis 6 (h).

Der optionale Parameter alteration ist ein Bruch: 0 bezeichnet den Stammton, 1/2 die Erhöhung um einen Halbton (♯), -1/2 die Erniedrigung um einen Halbton (♭). Es können aber auch beliebige andere Brüche übergeben werden, so dass auch doppelte oder mikrotonale Alterationen möglich sind.

Nützlich sind die Konstanten SHARP und FLAT, die global als 1/2 bzw. -1/2 definiert sind. Es gibt aber auch SEMI-SHARP, SEMI-FLAT und weitere; sie alle finden sich am Beginn der Quelltext-Datei [scm/lily-library.scm][lily-library].

(ly:pitch-octave pitch)
(ly:pitch-notename pitch)
(ly:pitch-alteration pitch)

Diese Funktionen extrahieren jeweils eine der drei Komponenten aus der Tonhöhe pitch.

(ly:pitch-steps pitch)

Liefert die Anzahl der (diatonischen) Tonschritte vom c¹ zur Tonhöhe pitch. Hier werden also nur octave und notename genutzt, nicht jedoch alteration: Beispielsweise liegt dis² acht Schritte oberhalb von c¹, es² dagegen neun Schritte.

(ly:pitch-tones pitch)

Abstand zwischen c¹ und der Tonhöhe pitch in Ganztönen, angegeben als rationale Zahl. Hier werden octave, notename und alteration berücksichtigt.

(ly:pitch-transpose pitch delta)
(+ pitch delta)

Liefert die Tonhöhe, die sich ergibt, wenn man die Tonhöhe pitch um delta transponiert. Mit \transpose c' #delta wird genau diese Operation auf alle Tonhöhen der Musik angewandt.

Das Resultat des Transpositionsvorgangs ist durch folgende zwei Eigenschaften definiert:

  • (ly:pitch-steps ergebnis) ist die Summe von (ly:pitch-steps pitch) und (ly:pitch-steps delta),

  • (ly:pitch-steps ergebnis) ist die Summe von (ly:pitch-steps pitch) und (ly:pitch-steps delta),

Dass die tones-Zahlen addiert werden (Tonhöhen, gemessen in Ganztönen, als rationale Zahl), sorgt dafür, dass die Transposition die richtige klingende Tonhöhe ergibt. Dass die steps-Zahlen (Anzahl der diatonischen Tonschritte) addiert werden, sorgt für enharmonische Korrektheit der Transposition, also dass z.B. mit delta = ais um eine übermäßige Sexte transponiert wird, mit delta = b um eine kleine Septime.

The form with + is new in version 2.25.7.

(ly:pitch-diff pitch root)
(- pitch root)

Liefert die Differenz delta, um die man den Grundton root transponieren muss, um pitch zu erhalten.

\transpose #p1 #p2 ... verändert jede Tonhöhe pitch aus der Musik zu (ly:pitch-transpose pitch (ly:pitch-diff p2 p1)).

The form with - is new in version 2.25.7.

Dauern und Momente#

Jede Note hat eine Dauer (duration), die das Druckbild der Note bestimmt. Normalerweise wird sie in LilyPond direkt nach der Tonhöhe angegeben: Beispielsweise sind 8 oder 4..*3/8 Dauern. Genauer gesagt besteht eine Dauer aus einer Hauptlänge, einer Anzahl von (Augmentations-)Punkten und einem optionalen Faktor. Die Hauptlänge in den gerade genannten Beispielen ist 8 bzw. 4. Intern wird sie, mathematisch gesprochen, durch ihren negativen Zweierlogarithmus repräsentiert: 0 bezeichnet eine ganze Note, 1 eine halbe Note, 2 eine Viertelnote etc. Der optionale Faktor ist eine rationale Zahl, beispielsweise *3/8 in 4..*3/8. Wenn er angegeben ist, verändert sich die effektive Länge der Note, ohne dass sich ihr optisches Erscheinungsbild ändert. Die Länge spielt eine Rolle für die Synchronisierung mehrerer Stimmen, für die horizontale Positionierung, und für die MIDI-Wiedergabe. Die Auswirkung von Längenfaktoren kann man im folgenden Beispiel gut studieren:

\version "2.25.8"

<< { c''4 4*1/2 4*1/2 4..*4/7 4 } \\ { c'4 4 4 4 } >>
Output../../images/f408ed92284d8bc8fea5f0cc7130bd1d64023a7b328c018fbbc3ece1a0e32072.svg

Ein Moment ist eine Längenangabe oder ein Zeitpunkt (wie ihn etwa MIDI-Töne haben). Man kann ihn sich grob als rationale Zahl vorstellen; verkompliziert wird die Angelegenheit aber durch das Problem von Vorschlagnoten: Sie hätten in einer solchen gewöhnlichen Zeitskala die Länge Null. Aus diesem Grund besteht ein Moment in Wirklichkeit aus zwei rationalen Zahlen, nämlich einem Hauptteil und einem Vorschlagteil.

You can obtain the length of a duration as a moment. The reverse conversion is not possible, simply because several different durations can have the same length. A moment lasting 7/8 of an eighth note is the length of the duration 16.., but also the length of 8*7/8. In the output, the first is reflected by a double-dotted sixteenth note while the second is an eighth note (perhaps part of a Baroque score where complex tuplets are written without too much care for exact values).

Dauern werden meist in der vertrauten LilyPond-Syntax eingegeben. Das funktioniert auch innerhalb #{ ... #}:

\version "2.25.8"

meineDauer = ##{ 4.. #}
{ c' $meineDauer }
Output../../images/154602e1757165c93e659bfffff47954d5d81c9dc75144526d0676bc4ec8476a.svg

Dauern können aber auch mit einem Scheme-Interface konstruiert werden. Für Momente ist das Konstruieren in Scheme die einzige Möglichkeit, da sie normalerweise nicht von den Anwendern eingegeben werden.

(ly:make-duration längen-logarithmus punktierung faktor)

Erzeugt eine Dauer.

(ly:duration-length duration)

Liefert die effektive Länge der Dauer duration (als Moment).

(ly:duration-log duration)
(ly:duration-dot-count duration)
(ly:duration-scale duration)

Diese drei Funktionen extrahieren die drei Komponenten einer Dauer.

(ly:make-moment haupt vorschlag)

Erzeugt einen Moment, dessen Haupt- und Vorschlags-Anteil durch die rationalen Zahlen haupt und vorschlag gegeben sind.

(ly:music-length music)

Liefert die Gesamtlänge der Musik music als Moment.

(ly:moment-main moment)
(ly:moment-grace moment)

Extrahiert den Haupt- bzw. Vorschlaganteil des Moments moment.

(ly:moment-add moment1 moment2)
(+ moment1 moment2)
(ly:moment-sub moment1 moment2)
(- moment1 moment2)
(ly:moment-mul moment rational)
(* moment rational)
(ly:moment-div moment rational)
(/ moment rational)
(ly:moment-mod moment rational)

Arithmetic on moments.

Addition and subtraction simply add and subtract the main and grace parts, respectively. Multiplication and division work between a moment and a rational number (meaning a Scheme fraction like 5/6; integers are a special case of fractions). If you understand and like this formulation, moments are simply the isomorphically unique 2-dimensional vector space over ℚ.

The forms with standard Scheme operators (+, -, * and /) are new in version 2.25.7.