X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Fde%2Fextending%2Fprogramming-interface.itely;h=6ee61875f0d4103de7a2109277e1da775506cb8d;hb=c054eb280fd9953596eb164f67b0f9d5555c5a32;hp=ec445d886dccac35788ba2073700619cd8ab93f7;hpb=a7210078ea5ed650743536c8fcd8b7291322d0e7;p=lilypond.git diff --git a/Documentation/de/extending/programming-interface.itely b/Documentation/de/extending/programming-interface.itely index ec445d886d..6ee61875f0 100644 --- a/Documentation/de/extending/programming-interface.itely +++ b/Documentation/de/extending/programming-interface.itely @@ -1,14 +1,14 @@ @c -*- coding: utf-8; mode: texinfo; -*- @ignore - Translation of GIT committish: 3d7ffa1f82bb44673134b28becf7898482fe7316 + Translation of GIT committish: e5a609e373eae846857f9a6d70a402a3d42b7d94 When revising a translation, copy the HEAD committish of the version that you are working on. For details, see the Contributors' Guide, node Updating translation committishes.. @end ignore -@c \version "2.12.0" +@c \version "2.19.2" @c Translators: Till Paala @@ -19,906 +19,561 @@ Fortgeschrittene Anpassungen können mithilfe der Programmiersprache Scheme vorgenommen werden. Wenn Sie Scheme nicht kennen, gibt es eine grundlegende Einleitung in LilyPonds -@rlearning{Scheme-Übung}. +@ref{Scheme-Übung}. @menu +* LilyPond-Codeabschnitte:: +* Scheme-Funktionen:: * Musikalische Funktionen:: -* Schnittstelle für Programmierer:: -* Komplizierte Funktionen erstellen:: -* Programmierungsschnittstelle für Textbeschriftungen:: +* Ereignisfunktionen:: +* Textbeschriftungsfunktionen:: * Kontexte für Programmierer:: -* Scheme-Vorgänge als Eigenschaften:: -* Scheme-Code anstelle von \tweak verwenden:: +* Callback-Funktionen:: +* Scheme-Code innerhalb LilyPonds:: * Schwierige Korrekturen:: @end menu -@node Musikalische Funktionen -@section Musikalische Funktionen -@translationof Music functions - -Dieser Abschnitt behandelt die Erstellung von musikalischen Funktionen -innerhalb von LilyPond. - -@menu -* Überblick über musikalische Funktionen:: -* Einfache Ersetzungsfunktionen:: -* Paarige Ersetzungsfunktionen:: -* Mathematik in Funktionen:: -* Leere Funktionen:: -* Funktionen ohne Argumente:: -* Überblick über vorhandene musikalische Funktionen:: -@end menu - -@node Überblick über musikalische Funktionen -@subsection Überblick über musikalische Funktionen -@translationof Overview of music functions +@node LilyPond-Codeabschnitte +@section LilyPond-Codeabschnitte +@translationof Lilypond code blocks -Es ist einfach, eine Funktion zu erstellen, die Variablen -im LilyPond-Code ersetzt. Die allgemeine Form derartiger -Funktionen ist +Codeabschnitte in LilyPond sehen etwa so aus: @example -function = -#(define-music-function (parser location @var{var1} @var{var2}...@var{vari}... ) - (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) - #@{ - @emph{...Noten...} - #@}) + #@{ @var{Lilypond code} #@} @end example -@noindent -wobei - -@multitable @columnfractions .33 .66 -@item @var{vari} @tab die @var{i}te Variable -@item @var{vari-type?} @tab die Art der @var{i}ten Variable -@item @var{...Noten...} @tab normaler LilyPond-Code, in dem Variablen -wie @code{#$var1} usw. benutzt werden. -@end multitable +Sie können überall eingesetzt werden, wo man Scheme-Code schreiben +kann: der Scheme-Einleser wurde geändert, um LilyPond-Codeabschnitte +zu akzeptieren und kann mit eingebetteten Scheme-Ausdrücken umgehen, +die mit @code{$} und@w{ }@code{#} beginnen. -Die folgenden Eingabetypen können als Variablen in einer musikalischen -Funktion benutzt werden. Diese Liste ist nicht vollständig -- siehe -auch andere Dokumentationen überScheme für weitere Variablenarten. +Er extrahiert den LilyPond-Codeabschnitt und erstellt einen Aufruf +zum LilyPond-Parser, welcher während der Prorammausführung zur +Interpretation des LilyPond-Codeabschnittes aufgerufen wird. Alle +eingebetteten Scheme-Ausdrücke werden in der lokalen Umgebung des +LilyPond-Codeabschnittes ausgeführt, sodass man Zugruff auf lokale +Variablen und Funktionsparameter zu dem Zeitpunkt hat, an dem +der LilyPond-Codeabschnitt geschrieben wird. -@multitable @columnfractions .33 .66 -@headitem Eingabetyp @tab @var{vari-type?}-Notation -@item Ganzzahl @tab @code{integer?} -@item Float (Dezimalzahl) @tab @code{number?} -@item Zeichenkette @tab @code{string?} -@item Textbeschriftung @tab @code{markup?} -@item Musikalischer Ausdruck @tab @code{ly:music?} -@item Ein Variablenpaar @tab @code{pair?} -@end multitable +Ein LilyPond-Codeabschnitt kann jeden Inhalt haben, den man auf +der rechten Seite einer Zuweisung einsetzt. Zusätzlich entspricht +ein leerer LilyPond-Abschnitt einem gültigen musikalischen Ausdruck, +und ein LilyPond-Abschnitt, der mehrere musikalische Ereignisse enthält, +wird in einen sequenziellen musikalischen Ausdruck umgewandelt. -Die Argumente @code{parser} und @code{location} sind zwingend erforderlich -und werden in einigen fortgeschrittenen Situationen eingesetzt. Das -Argument @code{parser} wird benutzt, um auf den Wert einer weiteren -LilyPond-Variable zuzugreifen. Das Argument @code{location} wird -benutzt, um den @qq{Ursprung} des musikalischen Ausdrucks zu definieren, der von -der musikalischen Funktion erzeugt wird. Das hilft, wenn ein -Syntaxfehler auftaucht: in solchen Fällen kann LilyPond mitteilen, -an welcher Stelle in der Eingabedatei sich der Fehler befindet. +@node Scheme-Funktionen +@section Scheme-Funktionen +@translationof Scheme functions -@node Einfache Ersetzungsfunktionen -@subsection Einfache Ersetzungsfunktionen -@translationof Simple substitution functions +@cindex Scheme-Funktionen (LilyPond syntax) -Hier ist ein einfaches Beispiel: +@emph{Scheme-Funktionen} sind Scheme-Prozeduren, die Scheme-Ausdrücke +aus einer Eingabe erstellen können, die in LilyPond-Syntax geschrieben +wurde. Sie können in so gut wie allen Fällen aufgerufen werden, in +denen es erlaubt ist, @code{#} zur Angabe eines Wertes in Scheme-Syntax +einzusetzen. Während Scheme auch eigene Funktionen besitzt, handelt +% dieses kapitel von @emph{syntaktischen} Funktionen, Funktionen, die +Argumente in LilyPond-Syntax annehmen. -@lilypond[quote,verbatim,ragged-right] -padText = #(define-music-function (parser location padding) (number?) - #{ - \once \override TextScript #'padding = #$padding - #}) - -\relative c''' { - c4^"piu mosso" b a b - \padText #1.8 - c4^"piu mosso" d e f - \padText #2.6 - c4^"piu mosso" fis a g -} -@end lilypond - -Musikalische Ausdrücke können auch ersetzt werden: - -@lilypond[quote,verbatim,ragged-right] -custosNote = #(define-music-function (parser location note) - (ly:music?) - #{ - \once \override Voice.NoteHead #'stencil = - #ly:text-interface::print - \once \override Voice.NoteHead #'text = - \markup \musicglyph #"custodes.mensural.u0" - \once \override Voice.Stem #'stencil = ##f - $note - #}) - -{ c' d' e' f' \custosNote g' } -@end lilypond - -Mehrere Variablen können benutzt werden: - -@lilypond[quote,verbatim,ragged-right] -tempoPadded = #(define-music-function (parser location padding tempotext) - (number? string?) -#{ - \once \override Score.MetronomeMark #'padding = $padding - \tempo \markup { \bold $tempotext } -#}) - -\relative c'' { - \tempo \markup { "Low tempo" } - c4 d e f g1 - \tempoPadded #4.0 #"High tempo" - g4 f e d c1 -} -@end lilypond +@menu +* Definition von Scheme-Funktionen:: +* Benutzung von Scheme-Funktionen:: +* Leere Scheme-Funktionen:: +@end menu +@node Definition von Scheme-Funktionen +@subsection Definition von Scheme-Funktionen +@translationof Scheme function definitions -@node Paarige Ersetzungsfunktionen -@subsection Paarige Ersetzungsfunktionen -@translationof Paired substitution functions +@funindex define-scheme-function -Einige @code{\override}-Befehle benötigen ein Zahlenpaar -(als @code{cons}-Zelle in Scheme bezeichnet). Um beide Zahlen -einer Funktion zuzuweisen, kann entweder die Variable @code{pair?} -benutzt werden oder die @code{cons} in die musikalische Funktion -eingefügt werden. +Die übliche Form zur Definition von Scheme-Funktionen ist: -@quotation @example -manualBeam = -#(define-music-function (parser location beg-end) - (pair?) -#@{ - \once \override Beam #'positions = #$beg-end -#@}) - -\relative @{ - \manualBeam #'(3 . 6) c8 d e f -@} +function = +#(define-scheme-function + (parser location @var{Arg1} @var{Arg2} @dots{}) + (@var{Typ1?} @var{Typ2?} @dots{}) + @var{body}) @end example -@end quotation @noindent -oder - -@lilypond[quote,verbatim,ragged-right] -manualBeam = -#(define-music-function (parser location beg end) - (number? number?) -#{ - \once \override Beam #'positions = #(cons $beg $end) -#}) - -\relative { - \manualBeam #3 #6 c8 d e f -} -@end lilypond - - -@node Mathematik in Funktionen -@subsection Mathematik in Funktionen -@translationof Mathematics in functions - -Musikalische Funktionen können neben einfachen Ersetzungen -auch Scheme-Programmcode enthalten: - -@lilypond[quote,verbatim,ragged-right] -AltOn = #(define-music-function (parser location mag) (number?) - #{ \override Stem #'length = #$(* 7.0 mag) - \override NoteHead #'font-size = - #$(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) #}) - -AltOff = { - \revert Stem #'length - \revert NoteHead #'font-size -} +wobei -{ c'2 \AltOn #0.5 c'4 c' - \AltOn #1.5 c' c' \AltOff c'2 } -@end lilypond +@multitable @columnfractions .33 .66 +@item @code{parser} +@tab ganz genau das Wort @code{parser} sein muss, damit LilyPond +eine Umgebung (@code{#@{}@dots{}@code{#@}}) mit Zugriff +auf den Parser bekommt. + +@item @code{@var{ArgN}} +@tab @var{n}te Argument + +@item @code{@var{TypN?}} +@tab eine Scheme-@emph{Typenprädikat}, für welches @code{@var{argN}} +@code{#t} ausgeben muss. Manche dieser Prädikate werden vom Parser +besonders erkannt, siehe unten. Es gibt auch eine Spezialform +@code{(@emph{predicate?} @emph{default})}, um optionale Argumente +anzugeben. Wenn das eigentlich Argument fehlt, während die Funktion +aufgerufen wird, wird der Standardwert anstelle eingesetzt. Standardwerte +werden bei ihrer Definition evaluiert (gilt auch für +LilyPond-Codeabschnitte), so dass man besser einen speziellen Wert +schreibt, den man einfach erkennen kann, wenn der Wert während der +Ausführung der Position evaluiert weren soll. Wenn man das Prädikat +in Klammern setzt, aber kein Standardwert folt, wird @code{#f} +als Standard eingesetzt. Standardwerte werden weder bei der Definition +noch bei der Ausführung mit @emph{predicate?} verifiziert, sodass +man selber verantworlich für funktionsfähige Werte ist. Standardwerte, +die musikalische Ausdrücke darstellen, werden kopiert und @code{origin} +auf den Parameter @code{location} gesetzt. + +@item @code{@var{body}} +@tab Eine Folge von Scheme-Formeln, die der Reihe nach ausgewertet +werden, wobei die letzte als Ausgabewert der Scheme-Funktion eingesetzt +wird. Sie kann LilyPond-Codeabschnitte enthalten, eingeschlossen mit +Raute-Klammern (@tie{}@w{@code{#@{@dots{}#@}}}@tie{}), wie beschrieben +in @ref{LilyPond-Codeabschnitte}. Innerhalb von LilyPond-Codeabschnitten +wird mit @code{#} auf Funktionsargumente (etwa @samp{#Arg1}) verwiesen +oder ein neuer Scheme-Ausdruck mit Funktionsargumenten begonnen +(etwa @w{@samp{#(cons Arg1 Arg2)}}). Wo normale Scheme-Ausdrücke mit +@code{#} nicht funktionieren, kann man auf direkte Scheme-Ausdrücke +zurückgreifen, die mit @code{$} begonnen werden (etwa @samp{$music}). + +Wenn die Funktion eine musikalische Funktion ausgibt, bekommt sie einen +Wert von @code{origin}. zugewiesen. +@end multitable @noindent -Dieses Beispiel kann auch umformuliert werden, um musikalische Ausdrücke -zu integrieren: - -@lilypond[quote,verbatim,ragged-right] -withAlt = #(define-music-function (parser location mag music) (number? ly:music?) - #{ \override Stem #'length = #$(* 7.0 mag) - \override NoteHead #'font-size = - #$(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) - $music - \revert Stem #'length - \revert NoteHead #'font-size #}) - -{ c'2 \withAlt #0.5 {c'4 c'} - \withAlt #1.5 {c' c'} c'2 } -@end lilypond - - -@node Leere Funktionen -@subsection Leere Funktionen -@translationof Void functions - -Eine musikalische Funktion muss einen musikalischen Ausdruck -ausgeben, aber in manchen Fällen müssen Funktionen erstellt werden, -die keine Notation enthalten (wie etwa eine Funktion, mit der -man @qq{Point and Click} ausschalten kann). Um das vornehmen zu -können, wird ein @code{leere}r musikalischer Ausdruck ausgegeben. - -Das ist der Grund, warum die Form, die ausgegeben wird, -@code{(make-music ...)} heißt. Wird die Eigenschaft -@code{'void} (engl. für @qq{leer}) auf @code{#t} gesetzt, wird der -Parser angewiesen, den ausgegebenen musikalischen Ausdruck zu ignorieren. -Der maßgebliche Teil der @code{'void}-Funktion ist also die Verarbeitung, -die die Funktion vornimmt, nicht der musikalische Ausdruck, der ausgegeben -wird. +Einige Typenprädikate werden vom Parser besonders behandelt, weil +er sonst die Argumente nicht zuverlässig erkennen könnte. Im Moment +handelt es sich um @code{ly:pitch?} und @code{ly:duration?}. + +Die Eignung der Argumente für alle anderen Prädikate wird festgestellt, +indem das Prädikat aufgerufen wird, nachdem LilyPond es schon in einen +Scheme-Ausdruck umgewandelt hat. Demzufolge kann das Argument in +Scheme-Syntax angegeben werden, wenn nötig (beginnend mit @code{#} oder +als Result des Aufrufes einer Scheme-Funktion), aber LilyPond +konvertiert auch eine Reihe von LilyPond-Strukturen nach Scheme, +bevor dann tatsächlich die Prädikate überprüft werden. Bei den +letzteren handelt es sich im Moment um music (Noten), postevents, +simple strings (einfache Zeichenketten mit oder ohne Anführungszeichen) +numbers (Zahlen), markup (Beschriftung) und markup lists +(Beschriftungslisten), score (Partitur), book (Buch), bookpart +(Buchteil), Kontextdefinitions- und Ausgabedefinitionsumgebungen. + +Für einige Arten von Ausdrücken (wie die meisten Noten, die nicht +in Klammern geschrieben werden) muss LilyPond weiter nach vorne +schauen als der Ausdruck selber reicht, um das Ende des Ausdrucks +zu bestimmen. Wenn solche Ausdrücke für optionale Argumente mit +einbezogen würden, indem ihre Prädikate ausgewählt würden, könnte +LilyPond nicht mehr zurückgehen, wenn es feststellt, dass der +Ausdruck nicht zu dem Parameter passt. Darum müssen manche Formen +von Noten möglicherweise in Klammern eingeschlossen werden, damit +LilyPond sie akzeptiert. Es gibt auch einige andere Mehrdeutigkeiten, +die LilyPond durch Testen von Prädikatfunktionen eingrenzt: +ist etwa @samp{-3} die Anmerkung für einen Fingersatz oder eine +negative Zahl? Ist @code{"a" 4} im Gesangskontext eine Zeichenkette +gefolgt von einer Zahl oder ein Gesangstextereignis mit der Dauer +@code{4}? LilyPond entscheidet, indem es Prädaikate befragt. Das +heißt, dass man zu durchlässige Prädikate wie @code{scheme?} +vermeiden sollte, wenn man eine bestimmmte Verwendung beabsichtigt +und nicht nur eine Funktion für die allgemeine Verwendung schreibt. + +Eine Liste der möglichen vordefinierten Typenprädikte findet sich in +@ruser{Vordefinierte Typenprädikate}. + +@seealso + +Notationsreferenz +@ruser{Vordefinierte Typenprädikate}. + +Installierte Dateien: +@file{lily/music-scheme.cc}, +@file{scm/c++.scm}, +@file{scm/lily.scm}. + + +@node Benutzung von Scheme-Funktionen +@subsection Benutzung von Scheme-Funktionen +@translationof Scheme function usage + +Scheme-Funktionen können überall aufgerufen werden, wo ein +Scheme-Ausdruck beginnend mit @code{#} geschrieben werden kann. +Man kann eine Scheme-Funktion aufrufen, indem man ihrer Bezeichnung +@code{\} voranstellt und Argumente hinten anfügt. Wenn ein optionales +Argumentenprädikat nicht mit einem Argument übereinstimmt, lässt +LilyPond dieses und alle folgenden Argumente aus und ersetzt sie +durch ihre Standardwerte und @qq{speichert} das Argument, das nicht +gepasst hat, bis zum nächsten zwingenden Argument. Da das gespeicherte +Argument auch noch irgendwo untergebracht werden muss, werden +optionale Argumente nicht wirklich als optional angesehen, es sei denn, +sie werden von einem zwingenden Argument gefolgt. + +Es gibt eine Ausnahme: Wenn man @code{\default} anstelle eines optionalen +Arguments schreibt, wird dieses und alle folgenden Argumente ausgelassen +und durch ihre Standardwerte ersetzt. Das funktioniert auch, wenn kein +zwingendes Argument folgt, weil @code{\default} nicht gespeichert werden +muss. Die Befehle @code{mark} und @code{key} benützten diesen Trick, +um ihr Standardverhalten zur verfügung zu stellen, wenn sie +@code{\default} nachgestellt haben. + +Abgesehen von Stellen, wo ein Scheme-Wert benötigt ist, gibt es +wenige Stellen, wo @code{#}-Ausdrücke zwar für ihre (Neben-)Wirkung +akzeptiert und ausgewertet, aber ansonsten ignoriert werden. Meistens +handelt es sich dabei um Stellen, wo eine Zuweisung auch in Ordnung +wäre. + +Weil es eine schlechte Idee ist, einen Wert auszugeben, der in einigen +Kontexten misinterpretiert werden könnte, sollte man Scheme-Funktionen +nur in den Fällen benutzen, in welchen sie immer einen sinnvollen +Wert ausgeben, und leere Scheme-Funktionen an anderen stellen +einsetzen. Siehe auch @pxref{Leere Scheme-Funktionen}. + + +@node Leere Scheme-Funktionen +@subsection Leere Scheme-Funktionen +@translationof Void scheme functions + +@funindex define-void-function +@funindex \void + +Manchmal wird eine Prozedur ausgeführt, um eine Aktion zu machen und nicht, +um einen Wert auszugeben. Einige Programmiersprachen (wie C oder Scheme) +setzen Funktionen für beide Konzepte ein und verwerfen einfach den +Rückgabewert (normalerweise, indem einem Ausdruck erlaubt wird, als +Aussage zu funktionieren und das Ergebnis ignoriert wird). Das ist +klug, aber auch fehleranfällig: die meisten C-Kompilierer haben heutzutage +Warnungen für verschiedene nicht-@qq{gültige} Ausdrücke, die verworfen +werden. Viele Funktionen, die eine Aktion ausführen, werden von den +Scheme-Standards als Funktionen betrachtet, deren Wiedergabewert unspezifiert +ist. Der Scheme-Interpreter von LilyPond, Guile, hat den eindeutigen +Wert @code{*unspecified*}, der normalerweise (etwa wenn man @code{set!} +direkt auf eine Variable anwendet), aber leider nicht konsistent in +diesen Fällen ausgegeben wird. + +Indem man eine LilyPond-Funktion mit @code{define-void-function} definiert, +geht man sicher, dass dieser Spezialwert (der einzige Wert, der das +Prädikat @code{void?} erfüllt) wiedergegeben wird. @example noPointAndClick = -#(define-music-function (parser location) () - (ly:set-option 'point-and-click #f) - (make-music 'SequentialMusic 'void #t)) +#(define-void-function + (parser location) + () + (ly:set-option 'point-and-click #f)) ... -\noPointAndClick % disable point and click +\noPointAndClick % Point and Click deaktivieren @end example - -@node Funktionen ohne Argumente -@subsection Funktionen ohne Argumente -@translationof Functions without arguments - -In den meisten Fällen sollten Funktionen ohne Argumente mit einer -Variable notiert werden: +Wenn man einen Ausdruck nur wegen seiner Nebeneffekte evaluieren will +und keinen der möglicherweise ausgegebenen Werte interpretiert haben +will, kann man dem Ausdruck @code{\void} voranstellen: @example -dolce = \markup@{ \italic \bold dolce @} +\void #(hashq-set! eine-Tabelle ein-Schlüssel ein-Wert) @end example -In einigen wenigen Fällen kann es aber auch sinnvoll sein, eine -musikalische Funktion ohne Argumente zu erstellen: - -@example -displayBarNum = -#(define-music-function (parser location) () - (if (eq? #t (ly:get-option 'display-bar-numbers)) - #@{ \once \override Score.BarNumber #'break-visibility = ##f #@} - #@{#@})) -@end example - -Damit auch wirklich Taktzahlen angezeigt werden, wo die -Funktion eingesetzt wurde, muss @command{lilypond} mit -der Option - -@example -lilypond -d display-bar-numbers Dateiname.ly -@end example - -@noindent -aufgerufen werden. - - -@node Überblick über vorhandene musikalische Funktionen -@subsection Überblick über vorhandene musikalische Funktionen -@translationof Overview of available music functions - -@c fixme ; this should be move somewhere else? -Die folgenden Befehle sind musikalische Funktionen: - -@include identifiers.tely +Auf diese Weise kann man sicher sein, dass LilyPond dem ausgegebenen +Wert keine Bedeutung zuweist, unabhängig davon, wo er angetroffen wird. +Das funktioniert auch für musikalische Funktionen wie @code{\displayMusic}. +@node Musikalische Funktionen +@section Musikalische Funktionen +@translationof Music functions -@node Schnittstelle für Programmierer -@section Schnittstelle für Programmierer -@translationof Programmer interfaces +@cindex musikalische Funktionen -Dieser Abschnitt zeigt, wie LilyPond und -Scheme gemischt werden können. +@emph{Musikalische Funktionen} sind Scheme-Prozeduren, +die musikalische Ausdrücke automatisch erstellen können und dadurch die +Eingabedatei maßgeblich vereinfachen können. @menu -* Eingabevariablen und Scheme:: -* Interne Repräsentation der Musik:: +* Definition der musikalischen Funktionen:: +* Benutzung von musikalischen Funktionen:: +* Einfache Ersetzungsfunktionen:: +* Mittlere Ersetzungsfunktionen:: +* Mathematik in Funktionen:: +* Funktionen ohne Argumente:: +* Leere musikalische Funktionen:: @end menu -@node Eingabevariablen und Scheme -@subsection Eingabevariablen und Scheme -@translationof Input variables and Scheme +@node Definition der musikalischen Funktionen +@subsection Definition der musikalischen Funktionen +@translationof Music function definitions -Das Eingabeformat unterstützt die Notation von Variablen: im -folgenden Beispiel wird ein musikalischer Ausdruck einer Variable -mit der Bezeichnung @code{traLaLa} zugewiesen: +Die allgemeine Form zur Definition musikalischer Funktionen ist: @example -traLaLa = @{ c'4 d'4 @} -@end example - -Der Geltungsbereich von Variablen ist beschränkt: im folgenden -Beispiel enthält die @code{\layout}-Umgebung auch eine -@code{traLaLa}-vVariable, die unabhängig von der äußeren -@code{\traLaLa}-Variable ist: - -@example -traLaLa = @{ c'4 d'4 @} -\layout @{ traLaLa = 1.0 @} -@end example - -Grundsätzlich ist jede Eingabedatei ein Geltungsbereich, und -alle @code{\header}-, @code{\midi}- und @code{\layout}-Umgebungen -sind Geltungsbereiche, die unterhalb des globalen Geltungsbereiches -angeordnet sind. - -Sowohl Variablen als auch Geltungsbereiche sind in Form des -GUILE-Modulsystems implementiert. Ein anonymes Scheme-Modul -wird an jeden Geltunsbereich angehängt. Eine Zuweisung der form - -@example -traLaLa = @{ c'4 d'4 @} -@end example - -@noindent -wird intern in die Scheme-Definition - -@example -(define traLaLa @var{Scheme-Wert von `@code{... }'}) +function = +#(define-music-function + (parser location @var{Arg1} @var{Arg2} @dots{}) + (@var{Typ1?} @var{Typ2?} @dots{}) + @var{body}) @end example @noindent -umgewandelt. - -Das bedeutet, dass Eingabe- und Scheme-Variablen frei vermischt -werden können. Im nächsten Beispiel wird ein Notenfragment in -der Variable @code{traLaLa} gespeichert und mithilfe von Schme -dupliziert. Das Ergebnis wird in eine @code{\score}-Umgebung -mit der zweiten Variable @code{twice} integriert: - -@lilypond[verbatim] -traLaLa = { c'4 d'4 } - -%% dummy action to deal with parser lookahead -#(display "this needs to be here, sorry!") - -#(define newLa (map ly:music-deep-copy - (list traLaLa traLaLa))) -#(define twice - (make-sequential-music newLa)) - -{ \twice } -@end lilypond - -In diesem Beispiel geschieht die Zuweisung, nachdem der Parser -festgestellt hat, dass nichts interessantes mehr nach -@code{traLaLa = @{ ... @}} vorkommt. Ohne die Pseudovariable -in dem Beispiel würde die @code{newLa}-Devinition ausgeführt -werden, bevor @code{traLaLa} definiert ist, was zu einem -Syntax-Fehler führen würde. - -Das obige Beispiel zeigt, wie man musikalische Ausdrücke -von der Eingabe in den Scheme-Interpretierer @qq{exportieren} -kann. Es geht auch in die andere Richtung. Indem man einen -Scheme-Wert in die Funktion @code{ly:export} einpackt, wird -der Scheme-Wert interpretiert als ob er in LilyPond-Syntax -notiert worden wäre. Anstatt @code{\twice} zu definieren, -hätte man also auch schreiben können: - -@example -... -@{ #(ly:export (make-sequential-music (list newLa))) @} -@end example +analot zu Scheme-Funktionen, siehe @ref{Definition von Scheme-Funktionen}. +In der Mehrzahl der Fälle ist @var{body} ein LilyPond-Codeabschnitt (siehe +@ref{LilyPond-Codeabschnitte}. -Scheme-Code wird sofort ausgewertet, wenn der Parser darauf -stößt. Um Scheme-Code in einem Makro zu definieren (das dann -erst später aufgerufen werden soll), müssen leere Funktionen -benutzt werden (siehe @ref{Leere Funktionen}) oder das Folgende: +Eine Liste der möglichen Typenprädikate findet sich in +@ruser{Vordefinierte Typenprädikate}. -@example -#(define (nopc) - (ly:set-option 'point-and-click #f)) - -... -#(nopc) -@{ c'4 @} -@end example +@seealso -@knownissues +Notationsreferenz: +@ruser{Vordefinierte Typenprädikate}. -Scheme- und LilyPond-Variablen können im LilyPond-Modus mit der -@code{--safe}-Option nicht vermischt werden. +Installierte Dateien: +@file{lily/music-scheme.cc}, +@file{scm/c++.scm}, +@file{scm/lily.scm}. -@node Interne Repräsentation der Musik -@subsection Interne Repräsentation der Musik -@translationof Internal music representation +@node Benutzung von musikalischen Funktionen +@subsection Benutzung von musikalischen Funktionen +@translationof Music function usage -Wenn ein musikalischer Ausdruck ausgewertet wird, wird er in eine -Anzahl von musikalischen Scheme-Objekten konvertiert. Die Eigenschaft, die ein -musikalisches Objekt definiert, ist, dass es Zeit einnimmt. Zeit ist -eine rationale Zahl, die die Länge eines Stückes in ganzen Noten -misst. +Musikalische Funktionen können zur Zeit an verschiedenen Stellen benützt +werden. Abhängig davon, wo sie eingesetzt werden, gibt es Begrenzungen, +damit die Funktionen eindeutig interpretiert werden können. Das Resultat, +das eine musikalische Funktion wiedergibt, muss mit dem Kontext kompatibel +sein, indem sie aufgerufen wird. -Ein musikalisches Objekt hat drei Typusarten: @itemize @item -musikalische Bezeichnung: Jeder musikalische Ausdruck hat eine Bezeichnung. -Eine Note beispielsweise führt zu einem @rinternals{NoteEvent} und -@code{\simultaneous} führt zu @rinternals{SimultaneousMusic}. Eine Liste -aller möglichen Ausdrücke findet sich in der Referenz der Interna, unter -@rinternals{Music expressions}. - -@item -@q{Typ} oder Schnittstelle: Jede musikalische Bezeichnung hat mehrere -@qq{Typen} oder Schnittstellten, beispielsweise ist eine Note ein -@code{event}, ober sie ist auch ein @code{note-event}, ein -@code{rhythmic-event} und ein @code{melodic-event}. Alle diese -Notationsklassen finden sich in der Referenz der Interna unter -@rinternals{Music classes}. +Auf höchster Ebene in einer musikalischen Funktion. Keine Begrenzungen. @item -C++-Objekt: Jedes musikalische Objekt wird von einem Objekt der -C++-Klasse @code{Music} repräsentiert. -@end itemize - -Die eigentlich Information eines musikalischen Ausdrucks ist in -Eigenschaften gespeichert. Ein @rinternals{NoteEvent} hat zum -Beispiel @code{pitch}- und @code{duration}-Eigenschaften, die -die Tonhöhe und die Dauer dieser Note speichern. Eine Liste aller -verfügbaren Eigenschaften findet sich in der Referenz der Interna unter -@rinternals{Music properties}. - -Ein zusammengesetzter musikalischer Ausdruck ist ein musikalisches -Objekt, das andere Objekte in seinen Eigenschaften enthält. Eine Liste -der Objekte kann in der @code{elements}-Eigenschaft eines -musikalischen Objektes gespeichert werden, oder ein einziges -@qq{Kind}-Objekt in der @code{element}-Eigenschaft. Sa hat etwa -@rinternals{SequentialMusic} seine @qq{Kinder} in @code{elements}, -und @rinternals{GraceMusic} hat sein einziges Argument in -@code{element}. Der Hauptteil einer Wiederholung wird in der -@code{element}-Eigenschaft von @rinternals{RepeatedMusic} gespeichert, -und die Alternativen in @code{elements}. - - - -@node Komplizierte Funktionen erstellen -@section Komplizierte Funktionen erstellen -@translationof Building complicated functions - -Dieser Abschnitt zeigt, wie man Information zusammensucht, -um komplizierte musikalische Funktionen zu erstellen. - -@menu -* Musikalische Funktionen darstellen:: -* Eigenschaften von Musikobjekten:: -* Verdoppelung einer Note mit Bindebögen (Beispiel):: -* Artikulationszeichen zu Noten hinzufügen (Beispiel):: -@end menu - - -@node Musikalische Funktionen darstellen -@subsection Musikalische Funktionen darstellen -@translationof Displaying music expressions - -@cindex interne Speicherung -@cindex Musikausdrücke anzeigen -@cindex Anzeigen von Musikausdrücken - -@funindex displayMusic -@funindex \displayMusic - -Wenn man eine musikalische Funktion erstellt, ist es oft -hilfreich sich anzuschauen, wie musikalische Funktionen -intern gespeichert werden. Das kann mit der Funktion -@code{\displayMusic} erreicht werden: - -@example -@{ - \displayMusic @{ c'4\f @} -@} -@end example - -@noindent -zeigt: - -@example -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) - (make-music - 'AbsoluteDynamicEvent - 'text - "f"))))) -@end example - -Normalerweise gibt LilyPond diese Ausgabe auf der Konsole mit -allen anderen Nachrichten aus. Um die wichtigen Nachrichten -in einer Datei zu speichern, kann die Ausgabe in eine Datei -umgeleitet werden: - -@example -lilypond file.ly >display.txt -@end example - -Mit etwas Umformatierung ist die gleiche Information sehr viel -einfacher zu lesen: - -@example -(make-music 'SequentialMusic - 'elements (list (make-music 'EventChord - 'elements (list (make-music 'NoteEvent - 'duration (ly:make-duration 2 0 1 1) - 'pitch (ly:make-pitch 0 0 0)) - (make-music 'AbsoluteDynamicEvent - 'text "f"))))) -@end example - -Eine musikalische @code{@{ ... @}}-Sequenz hat die Bezeichnung -@code{SequentialMusic} und ihre inneren Ausdrücke werden als -Liste in seiner @code{'elements}-Eigenschaft gespeichert. Eine -Note ist als als ein @code{EventChord}-Ausdruck dargestellt, -der ein @code{NoteEvent}-Objekt (welches Dauer und -Tonhöhe speichert) und zusätzliche Information enthält (in -diesem Fall ein @code{AbsoluteDynamicEvent} mit einer -@code{"f"}-Text-Eigenschaft. - - -@node Eigenschaften von Musikobjekten -@subsection Eigenschaften von Musikobjekten -@translationof Music properties - -Das @code{NoteEvent}-Objekt ist das erste Objekt der -@code{'elements}-Eigenschaft von @code{someNote}. +Als ein Nach-Ereignis, explizit begonnen mit einem Richtungsindikator +(einer von @code{-}, @code{^}, @w{und @code{_}}). Wichtig dabei ist, +dass musikalische Funktionen, die das Nachereignis ausgeben, als +normale Noten akzeptiert werden. Dabei erhält man ein Resultat, das +etwa folgendem entspricht: @example -someNote = c' -\displayMusic \someNote -===> -(make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)))) +s 1*0-\fun @end example -Die @code{display-scheme-music}-Funktion ist die Funktion, die von -@code{\displayMusic} eingesetzt wird, um die Scheme-Repräsentation -eines musikalischen Ausdrucks anzuzeigen. +In diesem Fall kann man keinen @emph{offenen} musikalischen Ausdruck als +letztes Argument einsetzen, also ein Argument, das in einem musikalischen +Ausdruck schließt, der weitere Nach-Ereignisse akzeptieren kann. -@example -#(display-scheme-music (first (ly:music-property someNote 'elements))) -===> -(make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 0 0)) -@end example - -Danach wird die Tonhöhe der Note von der @code{'pitch}-Eigenschaft -des @code{NoteEvent}-Objektes gelesen: +@item +Als Element eines Akkordes. Der ausgegebene Ausdruck muss vom Typ +@code{rhythmic-event} sein, wahrscheinlich auch @code{NoteEvent}. -@example -#(display-scheme-music - (ly:music-property (first (ly:music-property someNote 'elements)) - 'pitch)) -===> -(ly:make-pitch 0 0 0) -@end example +@end itemize -Die Tonhöhe einer Note kann geändert werden, indem man diese -@code{'pitch}-Eigenschaft umdefiniert: +@noindent +Die besonderen Regeln für noch nicht abgearbeitete Argumente machen es +möglich, polymorphe Funktionen wie @code{\tweak} zu schreiben, +die auf unterschiedliche Konstruktionen angewendet werden können. -@funindex \displayLilyMusic -@funindex displayLilyMusic -@example -#(set! (ly:music-property (first (ly:music-property someNote 'elements)) - 'pitch) - (ly:make-pitch 0 1 0)) ;; Die Tonhöhen auf d' verändern. -\displayLilyMusic \someNote -===> -d' -@end example +@node Einfache Ersetzungsfunktionen +@subsection Einfache Ersetzungsfunktionen +@translationof Simple substitution functions +Einfache Ersetzungsfunktionen sind musikalische Funktionen, deren +musikalische Ausgabe-Funktion im LilyPond-Format geschrieben ist +und Funktionsargumente in der Ausgabefunktion enthält. Sie werden +beschrieben in @ruser{Beispiele der Ersetzungsfunktionen} -@node Verdoppelung einer Note mit Bindebögen (Beispiel) -@subsection Verdoppelung einer Note mit Bindebögen (Beispiel) -@translationof Doubling a note with slurs (example) -In diesem Abschnitt soll gezeigt, werden, wie man eine -Funktion erstellt, die eine Eingabe wie @code{a} -nach @code{a( a)} umdefiniert. Dazu wird zuerst die -interne Repräsentation der Musik betrachtet, die -das Endergebnis darstellt: +@node Mittlere Ersetzungsfunktionen +@subsection Mittlere Ersetzungsfunktionen +@translationof Intermediate substitution functions -@example -\displayMusic@{ a'( a') @} -===> -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)) - (make-music - 'SlurEvent - 'span-direction - -1))) - (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)) - (make-music - 'SlurEvent - 'span-direction - 1))))) -@end example +Mittlere Ersetzungsfunktionen setzen sich aus einer Mischung von +Scheme-Code und LilyPond-Code in der musikalischen Ausgabe-Funktion +zusammen. -Eine schlechte Nachricht ist, dass die -@code{SlurEvent}-Ausdrücke @qq{innerhalb} -der Noten (bzw. innerhalb der -@code{EventChord}-Ausdrücke) hinzugefügt werden müssen. +Einige @code{\override}-Befehle benötigen ein Zahlenpaar +(als @code{cons}-Zelle in Scheme bezeichnet). -Jetzt folgt eine Betrachtung der Eingabe: +Das Paar kann direkt an die musikalische Funktion +mit der Variable @code{pair?} weitergeleitet werden: @example -(make-music - 'SequentialMusic - 'elements - (list (make-music - 'EventChord - 'elements - (list (make-music - 'NoteEvent - 'duration - (ly:make-duration 2 0 1 1) - 'pitch - (ly:make-pitch 0 5 0)))))) +manualBeam = +#(define-music-function + (parser location beg-end) + (pair?) + #@{ + \once \override Beam.positions = #beg-end + #@}) + +\relative c' @{ + \manualBeam #'(3 . 6) c8 d e f +@} @end example -In der gewünschten Funktion muss also dieser Ausdruck -kopiert werden (sodass zwei Noten vorhanden sind, die -eine Sequenz bilden), dann müssen @code{SlurEvent} -zu der @code{'elements}-Eigenschaft jeder Noten hinzugefügt -werden, und schließlich muss eine @code{SequentialMusic} -mit den beiden @code{EventChords} erstellt werden. - -@example -doubleSlur = #(define-music-function (parser location note) (ly:music?) - "Return: @{ note ( note ) @}. - `note' is supposed to be an EventChord." - (let ((note2 (ly:music-deep-copy note))) - (set! (ly:music-property note 'elements) - (cons (make-music 'SlurEvent 'span-direction -1) - (ly:music-property note 'elements))) - (set! (ly:music-property note2 'elements) - (cons (make-music 'SlurEvent 'span-direction 1) - (ly:music-property note2 'elements))) - (make-music 'SequentialMusic 'elements (list note note2)))) -@end example +Anstelle dessen können auch die Zahlen, aus denen das Paar besteht, +einzeln als eigenständige Argumente weitergeleitet und der +Scheme-Code, der das Paar erstellt, in die musikalische Funktion +augenommen werden: +@lilypond[quote,verbatim,ragged-right] +manualBeam = +#(define-music-function + (parser location beg end) + (number? number?) + #{ + \once \override Beam.positions = #(cons beg end) + #}) + +\relative c' { + \manualBeam #3 #6 c8 d e f +} +@end lilypond -@node Artikulationszeichen zu Noten hinzufügen (Beispiel) -@subsection Artikulationszeichen zu Noten hinzufügen (Beispiel) -@translationof Adding articulation to notes (example) -Am einfachsten können Artikulationszeichen zu Noten -hinzugefügt werden, indem man zwei musikalische Funktionen -in einen Kontext einfügt, wie erklärt in -@ref{Kontexte erstellen}. Hier soll jetzt eine musikalische -Funktion entwickelt werden, die das vornimmt. +@node Mathematik in Funktionen +@subsection Mathematik in Funktionen +@translationof Mathematics in functions -Eine @code{$variable} innerhalb von @code{#@{...#@}} ist das -gleiche wie die normale Befehlsform @code{\variable} in -üblicher LilyPond-Notation. Es ist bekannt dass +Musikalische Funktionen können neben einfachen Ersetzungen +auch Scheme-Programmcode enthalten: -@example -@{ \music -. -> @} -@end example +@lilypond[quote,verbatim,ragged-right] +AltOn = +#(define-music-function + (parser location mag) + (number?) + #{ + \override Stem.length = #(* 7.0 mag) + \override NoteHead.font-size = + #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + #}) -@noindent -in LilyPond nicht funktioniert. Das Problem könnte vermieden -werden, indem das Artikulationszeichen an eine Pseudonote -gehängtwird: +AltOff = { + \revert Stem.length + \revert NoteHead.font-size +} -@example -@{ << \music s1*0-.-> @} -@end example +\relative c' { + c2 \AltOn #0.5 c4 c + \AltOn #1.5 c c \AltOff c2 +} +@end lilypond @noindent -aber in diesem Beispiel soll gezeigt werden, wie man das in -Scheme vornimmt. Zunächst wird die Eingabe und die gewünschte -Ausgabe examiniert: - -@example -% Eingabe -\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)))) -===== -% gewünschte Ausgabe -\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"))) -@end example +Dieses Beispiel kann auch umformuliert werden, um musikalische Ausdrücke +zu integrieren: -Dabei ist zu sehen, dass eine Note (@code{c4}) als @code{EventChord} -repräsentiert ist, mit einem @code{NoteEvent}-Ausdruck in ihrer -Elementenliste. Um eine Marcato-Artikulation hinzuzufügen, muss -ein @code{ArticulationEvent}-Ausdrcuk zu der Elementeigenschaft -des @code{EventChord}-Ausdrucks hinzugefügt werden. +@lilypond[quote,verbatim,ragged-right] +withAlt = +#(define-music-function + (parser location mag music) + (number? ly:music?) + #{ + \override Stem.length = #(* 7.0 mag) + \override NoteHead.font-size = + #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag))) + #music + \revert Stem.length + \revert NoteHead.font-size + #}) + +\relative c' { + c2 \withAlt #0.5 { c4 c } + \withAlt #1.5 { c c } c2 +} +@end lilypond -Um diese Funktion zu bauen, wird folgerndermaßen begonnen: -@example -(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)) -@end example +@node Funktionen ohne Argumente +@subsection Funktionen ohne Argumente +@translationof Functions without arguments -Die erste Zeile definiert eine Funktion in Scheme: Die Bezeichnung -der Funktion ist @code{add-marcato} und sie hat eine Variable -mit der Bezeichnung @code{event-chord}. In Scheme geht der Typ -einer Variable oft direkt aus der Bezeichnung hervor (das ist auch -eine gute Methode für andere Programmiersprachen). +In den meisten Fällen sollten Funktionen ohne Argumente mit einer +Variable notiert werden: @example -"Add a marcato..." +dolce = \markup@{ \italic \bold dolce @} @end example -@noindent -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. +In einigen wenigen Fällen kann es aber auch sinnvoll sein, eine +musikalische Funktion ohne Argumente zu erstellen: @example -(let ((result-event-chord (ly:music-deep-copy event-chord))) +displayBarNum = +#(define-music-function + (parser location) + () + (if (eq? #t (ly:get-option 'display-bar-numbers)) + #@{ \once \override Score.BarNumber.break-visibility = ##f #@} + #@{#@})) @end example -@code{let} wird benutzt, um die lokalen Variablen zu definieren. Hier -wird eine lokale Variable benutzt: @code{result-event-chord}. Sie erhält -den Wert @code{(ly:music-deep-copy event-chord)}. @code{ly:music-deep-copy} -ist eine LilyPond-spezifische Funktion, die wie alle Funktionen mit dem -Präfix @code{ly:} versehen ist. Sie wird benutzt, um eine Kopie eines -musikalischen Ausdrucks anzufertigen. Hier wird @code{event-chord} -(der Parameter der Funktion) kopiert. Die Funktion soll ja nur ein -Artikulationszeichen an einen @code{EventChord} gehängt werden, deshalb ist es besser, -den @code{EventChord}, der als Argument gegeben wurde, nicht zu -verändern, weil er woanders benutzt werden könnte. - -Jetzt gibt es @code{result-event-chord}, wobei es sich um einen -@code{NoteEventChord}-Ausdruck handelt, welcher gleichzeigt eine Kopie -von @code{event-chord} ist. Das Makro wird seiner Eigenschaftsliste -hinzugefügt: +Damit auch wirklich Taktzahlen angezeigt werden, wo die +Funktion eingesetzt wurde, muss @command{lilypond} mit +der Option @example -(set! place new-value) +lilypond -d display-bar-numbers Dateiname.ly @end example -Was in diesem Fall @qq{gesetzt} werden soll (@qq{place}) ist die -@q{elements}-Eigenschaft des @code{result-event-chord}-Ausdrucks. +@noindent +aufgerufen werden. -@example -(ly:music-property result-event-chord 'elements) -@end example -@code{ly:music-property} ist die Funktion, mit der musikalische -Eigenschaften erreicht werden können (die @code{'elements}, -@code{'duration}, @code{'pitch} usw., die in der Ausgabe von -@code{\displayMusic} weiter oben angezeigt werden). Der neue -Wert ist, was ehemals die Elemtneigenschaft war, mit einem -zusätzlichen Element: dem @code{ArticulationEvent}-Ausdruck, -der aus der Ausgabe von -@code{\displayMusic} kopiert werden kann: +@node Leere musikalische Funktionen +@subsection Leere musikalische Funktionen +@translationof Void music functions -@example -(cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements)) -@end example +Eine musikalische Funktion muss einen musikalischen Ausdruck +ausgeben. Wenn man eine Funktion nur für ihre Nebeneffekte +ausführt, sollte man @code{define-void-function} benützen. +Es kann aber auch Fälle geben, in denen man teilweise eine +musikalische Funktion erstellen will, teilweise aber nicht +(wie im vorherigen Beispiel). Indem man eine leere (@code{void}) +Funktion mit @code{#@{ #@}} ausgibt, wird das erreicht. -@code{cons} wird benutzt, um ein Element zu einer Liste hinzuzufügen, -ohne dass die originale Liste verändert wird. Das ist es, was die -Funktion tun soll: die gleiche Liste, aber mit dem neuen -@code{ArticulationEvent}-Ausdruck. Die Reihenfolge innerhalb -der Elementeeigenschaft ist hier nicht relevant. -Wenn schließlich die Marcato-Artikulation zu der entsprechenden -@code{elements}-Eigenschaft hinzuzugefügt ist, kann -@code{result-event-chord} ausgegeben werden, darum die letzte Zeile -der Funktion. +@node Ereignisfunktionen +@section Ereignisfunktionen +@translationof Event functions -Jetzt wird die @code{add-marcato}-Funktion in eine musikalische -Funktion umgewandelt: +@funindex define-event-function +@cindex Ereignisfunktionen -@example -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)) -@end example +Damit man eine musikalische Funktion anstelle eines Ereignisses benützen +kann, muss man ihr einen Richtungsindikator voranstellen. Manchmal +entspricht dies jedoch nicht der Syntax der Konstruktionen, die man ersetzen +will. Dynamikbefehle beispielsweise werden normalerweise ohne Richtungsangabe +angehängt, wie @code{c'\pp}. Das Folgende ist eine Möglichkeit, beliebige +Dynamikbefehle zu schreiben: -Eine Überprüfung, dass die Funktion richtig arbeitet, geschieht -folgendermaßen: +@lilypond[quote,verbatim,ragged-right] +dyn=#(define-event-function (parser location arg) (markup?) + (make-dynamic-script arg)) +\relative c' { c\dyn pfsss } +@end lilypond -@example -\displayMusic \addMarcato c4 -@end example +Man kann das Gleiche auch mit einer musikalischen Funktion erreichen, aber dann +muss man immer einen Richtungsindikator voranstellen, wie @code{@w{c-\dyn pfsss}}. -@node Programmierungsschnittstelle für Textbeschriftungen -@section Programmierungsschnittstelle für Textbeschriftungen -@translationof Markup programmer interface +@node Textbeschriftungsfunktionen +@section Textbeschriftungsfunktionen +@translationof Markup functions Textbeschriftungselemente sind als besondere Scheme-Funktionen -definiert, die ein Stencil-Objekt erstellen, dem eine Anzahl +definiert, die ein @code{Stencil}-Objekt erstellen, dem eine Anzahl an Argumenten übergeben wird. @menu * Beschriftungskonstruktionen in Scheme:: * Wie Beschriftungen intern funktionieren:: * Neue Definitionen von Beschriftungsbefehlen:: -* Neue Definitionen von Beschriftungsbefehlen für Listen:: +* Neue Definitionen von Beschriftungslistenbefehlen:: @end menu @@ -945,14 +600,17 @@ ist identisch mit @example -\markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} - \larger \line @{ foo bar baz @} @} +#@{ \markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} + \larger \line @{ foo bar baz @} @} #@} @end example @noindent Dieses Beispiel zeigt die hauptsächlichen Übersetzungsregeln zwischen normaler Textbeschriftungssyntax von LilyPond und der -Textbeschriftungssyntax in Scheme. +Textbeschriftungssyntax in Scheme. Es ist meistens der beste +Weg, @code{#@{ @dots{} #@}} zur Eingabe von LilyPond-Syntax zu +benützen, aber es soll auch erklärt werden, wie man das +@code{markup}-Makro einsetzt, um eine Lösung nur in Scheme zu bekommen. @quotation @multitable @columnfractions .3 .3 @@ -960,11 +618,11 @@ Textbeschriftungssyntax in Scheme. @item @code{\markup Text1} @tab @code{(markup Text1)} @item @code{\markup @{ Text1 Text2 ... @}} @tab @code{(markup Text1 Text2 ... )} -@item @code{\Befehl} @tab @code{#:Befehl} +@item @code{\Beschriftungsbefehl} @tab @code{#:Beschriftungsbefehl} @item @code{\Variable} @tab @code{Variable} @item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} @item @code{Zeichenkette} @tab @code{"Zeichenkette"} -@item @code{#scheme-arg} @tab @code{scheme-arg} +@item @code{#scheme-Arg} @tab @code{scheme-Arg} @end multitable @end quotation @@ -1025,237 +683,354 @@ wir die @code{raise-markup}-Funktion folgendermaßen aufgerufen: @var{die "Textbeispiel"-Beschriftung}) @end example -Die @code{raise-markup}-Funktion erstellt zunächt den Stencil für die +Die @code{raise-markup}-Funktion erstellt zunächst den Stencil für die @code{Textbeispiel}-Beschriftung und verschiebt dann diesen Stencil um 0.5 Notenlinienzwischenräume nach oben. Das ist ein einfaches Beispiel. Weitere, kompliziertere Beispiele finden sich nachfolgend in diesem Abschnitt und in der Datei -@file{scm/@/define@/-markup@/-commands@/.scm}. +@file{scm/define-markup-commands.scm}. @node Neue Definitionen von Beschriftungsbefehlen @subsection Neue Definitionen von Beschriftungsbefehlen @translationof New markup command definition +Dieser Abschnitt behandelt die Definition von neuen Textbeschriftungsbefehlen. + +@menu +* Syntax der Definition von Textbeschriftungsbefehlen:: +* Über Eigenschaften:: +* Ein vollständiges Bespiel:: +* Eingebaute Befehle anpassen:: +@end menu + +@node Syntax der Definition von Textbeschriftungsbefehlen +@unnumberedsubsubsec Syntax der Definition von Textbeschriftungsbefehlen +@translationof Markup command definition syntax + Neue Textbeschriftungsbefehle können mit dem @code{define-markup-command}-Scheme-Makro definiert werden. @lisp -(define-markup-command (@var{befehl-bezeichnung} @var{layout} @var{props} @var{arg1} @var{arg2} ...) - (@var{arg1-type?} @var{arg2-type?} ...) +(define-markup-command (@var{befehl-bezeichnung} @var{layout} @var{props} @var{Arg1} @var{Arg2} ...) + (@var{Arg1-typ?} @var{Arg2-typ?} ...) + [ #:properties ((@var{Eigenschaft1} @var{Standard-Wert1}) + ...) ] ..Befehlkörper..) @end lisp Die Argumente sind: @table @var -@item argi -@var{i}te Befehlsargument -@item argi-type? -eine Eigenschaft für das @var{i}te Argument -@item layout +@item @var{befehl-bezeichnung} +die Bezeichnung des Befehls + +@item @var{layout} die @q{layout}-Definition + @item props -eine Liste an alists, in der alle aktiven Eigenschaften enthalten sind +eine Liste an assoziativen Listen, in der alle aktiven Eigenschaften enthalten sind + +@item @var{argi} +das @var{i}te Befehlsargument + +@item @var{argi-type?} +eine Eigenschaft für das @var{i}te Argument @end table -Als einfaches Beispiel soll gezeigt werden, wie man einen -@code{\smallcaps}-Befehl hinzufügen kann, der die Kapitälchen -für die Schriftzeichen auswählt. Normalerweise würde man Kapitälchen -folgendermaßen auswählen: +Wenn der Befehl Eigenschaften des @code{props}-Arguments benutzt, +kann das @code{#:properties}-Schlüsselwort benutzt werden um zu +bestimmen, welche Eigenschaften mit welchen Standard-Werten benutzt +werden. -@example -\markup @{ \override #'(font-shape . caps) Text-in-Kapitälchen @} -@end example +Argumente werden nach ihrem Typ unterschieden: -@noindent -Damit wird die Kapitälchenschriftart ausgewählt, indem die -@code{font-shape}-Eigesnchaft auf @code{#'caps} gesetzt wird, -während @code{Text-in-caps} interpretiert wird. +@itemize +@item eine Textbeschriftung entspricht einem Typenprädikat @code{markup?}; +@item eine Textbeschriftungsliste entspricht einem Typenprädikat +@code{markup-list?}; +@item jedes andere Scheme-Objekt entspricht Typenprädikaten wie etwa +@code{list?}, @code{number?}, @code{boolean?}, usw. +@end itemize -Damit diese Funkion als @code{\smallcaps}-Befehl zur Verfügung -gestellt werden kann, muss eine Funktion mit @code{define-markup-command} -definiert werden. Der Befehl braucht ein Argument vom Typ @code{markup}. -Darum sollte der Beginn der Funktion lauten: +Es gibt keine Einschränkung in der Reihenfolge der Argumente (nach +den Standard-Argumenten @code{layout} und @code{props}). Textbeschriftungsfunktionen, +die als letztes Argument eine Textbeschriftung haben, haben die +Besonderheit, dass sie auf Textbeschriftungslisten angewendet werden +können, und das Resultat ist eine Textbeschriftungsliste, in der +die Textbeschriftungsfuktion (mit den angegebenen Argumenten am Anfang) +auf jedes Element der originalen Textbeschriftungsliste angewendet +wurde. -@example -(define-markup-command (smallcaps layout props argument) (markup?) -@end example +Da das Wiederholen der Argumente am Anfang bei der Anwendung einer +Textbeschriftungsfunktion auf eine Textbeschriftungsliste for allem +für Scheme-Argumente sparsam ist, kann man Leistungseinbußen vermeiden, +indem man nur Scheme-Argumente für die Argumente am Anfang einsetzt, +wenn es sich um Textbeschriftungsfunktionen handelt, die eine Textbeschriftung +als letztes Argument haben. -@noindent -Was jetzt folgt, ist der eigentliche Inhalt des Befehls: das -@code{argument} soll als Beschriftung (markup) interpretiert werden, -also: +@node Über Eigenschaften +@unnumberedsubsubsec Über Eigenschaften +@translationof On properties -@example -(interpret-markup layout @dots{} argument) -@end example +Die @code{layout}- und @code{props}-Argumente der Textbeschriftungsbefehle +bringen einen Kontext für die Interpretation der Beschriftung: +Schriftgröße, Zeilenlänge usw. -@noindent -Diese Interpretation sollte @code{'(font-shape . caps)} zu den -aktiven Eigenschaften hinzufügen, weshalb wir das Folgende anstelle -der @dots{} in dem Beispiel einfügen: +Das @code{layout}-Argument greift auf Eigenschaften zu, die in der +@code{paper}-Umgebung definiert werden, indem man die @code{ly:output-def-lookup}-Funktion +benutzt. Beispielsweise liest man die Zeilenlänge (die gleiche, die auch in +Partituren benutzt wird) aus mit: @example -(cons (list '(font-shape . caps) ) props) +(ly:output-def-lookup layout 'line-width) @end example -@noindent -Die Variable @code{props} ist eine Liste an alists, und mit @code{cons} -wird ihr eine zusätzliche Einstellung hinzugefügt. +Das @code{props}-Argument stellt einige Eigenschaften für die Textbeschriftungsbefehle +zur Verfügung. Beispielsweise wenn der Überschrifttext einer +@code{book}-Umgebung interpretiert wird, werden alle Variablen, die +in der @code{\header}-Umgebung definiert werden, automatisch zu @code{props} +hinzugefügt, sodass die Beschriftung auf Titel, Komponist usw. der +@code{book}-Umgebung zugreifen kann. Das ist auch eine Möglichkeit, das +Verhalten eines Beschriftungsbefehls zu konfigurieren: Wenn etwa ein +Befehl die Schriftgröße während der Verarbeitung einsetzt, wird die +Schriftgröße aus den @code{props} ausgelesen und nicht mit einem eigenen +@code{font-size}-Argument definiert. Beim Aufruf des Beschriftungsbefehls +kann der Wert der Schriftgröße geändert werden, womit sich auch das Verhalten +des Befehls verändert. Benutzen Sie das @code{#:properties}-Schlüsselwort +von @code{define-markup-command} um zu definieren, welche Eigenschaften aus den +@code{props}-Argumenten ausgelesen werden sollen. -Man könnte sich auch vorstellen, dass ein Rezitativ einer Oper -gesetzt werden soll, und ein Befehl wäre sehr bequem, mit dem -man die Namen der Charaktere auf eine eigene Art darstellen könnte. -Namen sollen in Kapitälchen gesetzt werden und etwas nach links und -oben verschoben werden. Man kann also einen @code{\character}-Befehl -definieren, der die nötige Verschiebung berücksichtigt und -den neuen @code{\smallcaps}-Befehl einsetzt: +Das Beispiel im nächsten Abschnitt illustriert, wie man auf Eigenschaften +in einem Beschriftungsbefehl zugreifen und sie verändern kann. -@example -#(define-markup-command (character layout props name) (string?) - "Print the character name in small caps, translated to the left and - top. Syntax: \\character #\"name\"" + +@node Ein vollständiges Bespiel +@unnumberedsubsubsec Ein vollständiges Bespiel +@translationof A complete example + +Das folgende Beispiel definiert einen Beschriftungsbefehl, der einen +doppelten Kasten um einen Text zeichnet. + +Zuerst wollen wir ein annäherndes Ergebnis mit Textbeschriftungen definieren. +Nach Stöbern in @ruser{Textbeschriftungsbefehle} finden wir den Befehl +@code{\box}: + +@lilypond[quote,verbatim,ragged-right] +\markup \box \box HELLO +@end lilypond + +Wir wollen aber etwas mehr Abstand (engl. padding) zwischen dem Text und dem Kasten. +Nach der Dokumentation von @code{\box} hat der Befehl eine +@code{box-padding}-Eigenschaft, die den Standardwert von 0.2 hat. Die +Dokumentation zeit auch, wir man den Wert verändert: + +@lilypond[quote,verbatim,ragged-right] +\markup \box \override #'(box-padding . 0.6) \box A +@end lilypond + +Auch der Abstand zwischen den zwei Kästen ist uns zu klein und soll auch +vergrößert werden: + +@lilypond[quote,verbatim,ragged-right] +\markup \override #'(box-padding . 0.4) \box + \override #'(box-padding . 0.6) \box A +@end lilypond + +Diese lange Textbeschriftung immer wieder schreiben zu müssen, ist +anstrengend. Hier kömmt ein Textbeschriftungsbefehl ins Spiel. Wir +schreiben uns alle einen @code{double-box}-Beschriftungsbefehl, der +ein Argument annimmt (den Text). Er zeichnet zwei Kästen mit genügend Abstand: + +@lisp +#(define-markup-command (double-box layout props text) (markup?) + "Draw a double box around text." (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) -@end example + #@{\markup \override #'(box-padding . 0.4) \box + \override #'(box-padding . 0.6) \box @{ #text @}#@})) +@end lisp -Hier ist eine Komplikation, die erklärt werden muss: Text über oder -unter dem Notensystem wird vertikal verschoben um in einem bestimmten -Abstand von dem System und den Noten zu sein (das wird als @qq{padding} -bezeichnet). Um sicherzugehen, dass dieser Mechanismus nicht die -vertikale Verschiebung von @code{#:translate} annulliert, wird -die leere Zeichenkette (@code{#:hspace 0}) vor den zu verschiebenden -Text gesetzt. Das @code{#:hspace 0} wird jetzt also über die Noten -gesetzt und @code{name} dann relativ zu der leeren Zeichenkette -verschoben. Im Endeffekt wird der Text nach links oben verschoben. +oder äquivalent -Das Resultat sieht folgendermaßen aus: +@lisp +#(define-markup-command (double-box layout props text) (markup?) + "Draw a double box around text." + (interpret-markup layout props + (markup #:override '(box-padding . 0.4) #:box + #:override '(box-padding . 0.6) #:box text))) +@end lisp + +@code{text} ist die Bezeichnung des Arguments dieses Befehls, +und @code{markup?} ist seine Art: hiermit wird der Befehl als +Beschriftungsbefehl identifiziert. Die @code{interpret-markup}-Funktion +wird in den meisten Beschriftungsbefehlen benutzt: sie erstellt einen +Stencil, wobei @code{layout}, @code{props} und eine Beschriftung benutzt +werden. Im zweiten Fall wird diese Beschriftung durch das +@code{markup}-Scheme-Makro erstellt, siehe auche +@ref{Beschriftungskonstruktionen in Scheme}. +Die Transformation des @code{\markup}-Ausdrucks in einen +Scheme-Beschriftungsausdruck geschieht durch Umschreiben des LilyPond-Codes +in Scheme-Code. + +Der neue Befehl kann wie folgt benutzt werden: @example -@{ - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" -@} +\markup \double-box A @end example -@lilypond[quote,ragged-right] -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" +Es wäre schön, den @code{double-box}-Befehl noch konfigurierbar zu gestalten: +in unserem Fall sind die Werte von @code{box-padding} direkt definiert und +können nicht mehr vom Benutzer verändert werden. Es wäre auch besser, wenn +der Abstand zwischen den beiden Kästen vom Abstand zwischen dem inneren Kasten +und dem Text unterschieden werden könnte. Eine neue Eigenschaft muss also +definiert werden: @code{inter-box-padding} für den Abstand zwischen den Kästen. +@code{box-padding} wird für den inneren Abstand benutzt. Der neue Befehl wird +so definiert: + +@lisp +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Draw a double box around text." (interpret-markup layout props - (make-line-markup - (map (lambda (s) - (if (= (string-length s) 0) - s - (markup #:large (string-upcase (substring s 0 1)) - #:translate (cons -0.6 0) - #:tiny (string-upcase (substring s 1))))) - (string-split str #\Space))))) - -#(define-markup-command (character layout props name) (string?) - "Print the character name in small caps, translated to the left and - top. Syntax: \\character #\"name\"" + #@{\markup \override #`(box-padding . ,inter-box-padding) \box + \override #`(box-padding . ,box-padding) \box + @{ #text @} #@})) +@end lisp + +Wiederum wäre die entsprechende Version mit dem @code{markup}-Makro +so aussehen: + +@lisp +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Draw a double box around text." (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) + (markup #:override `(box-padding . ,inter-box-padding) #:box + #:override `(box-padding . ,box-padding) #:box text))) +@end lisp -{ - c''^\markup \character #"Cleopatra" c'' c'' c'' - e'^\markup \character #"Giulio Cesare" e' e' e' -} -@end lilypond +In diesem Code wird das @code{#:properties}-Schlüsselwort benutzt, sodass +die Eigenschaften @code{inter-box-padding} und @code{box-padding} aus dem +@code{props}-Argument ausgelesen werden, und Standardwerte werden gegeben, +falls die Eigenschaften nicht definiert sein sollten. -In diesen Befehlen wurden Kapitälchen eingesetzt, aber es kann -vorkommen, dass die Schriftart keine Kapitälchen zur Verfügung -stellt. In diesem Fall können die Kapitälchen nachempfunden -werden, indem man Großbuchstaben setzt, deren Anfangsbuchstabe -etwas größer gesetzt wird: +Dann werden diese Werte benutzt, um die @code{box-padding}-Eigenschaft +zu verändert, die von beiden @code{\box}-Befehlen benutzt wird. Beachten +Sie Akzent und das Komma des @code{\override}-Arguments: hiermit kann man +einen Variablenwert in einen wörtlichen Ausdruck überführen. -@example -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps." +Jetzt kann der Befehl in Beschriftungen benutzt werden und der Abstand +der Kästen kann angepasst werden: + +@lilypond[quote,verbatim,ragged-right] +#(define-markup-command (double-box layout props text) (markup?) + #:properties ((inter-box-padding 0.4) + (box-padding 0.6)) + "Draw a double box around text." (interpret-markup layout props - (make-line-markup - (map (lambda (s) - (if (= (string-length s) 0) - s - (markup #:large (string-upcase (substring s 0 1)) - #:translate (cons -0.6 0) - #:tiny (string-upcase (substring s 1))))) - (string-split str #\Space))))) -@end example + #{\markup \override #`(box-padding . ,inter-box-padding) \box + \override #`(box-padding . ,box-padding) \box + { #text } #})) -Der @code{smallcaps}-Befehl spaltet die Argumente zuerst in -Einzelstücke auf, die von Leerzeichen getrennt sind -(@code{(string-split str #\Space)}); für jedes Einzelstück -wird dann eine Beschriftung aufgebaut, deren erster Buchstabe -vergrößert wird und als Versalbuchstabe gesetzt wird -(@code{#:large (string-upcase (substring s 0 1))}), und eine -zweite Versalbuchstaben gesetzt werden -(@code{#:tiny (string-upcase (substring s 1))}). Wenn -LilyPond ein Leerzeichen zwischen Beschriftungen einer Zeile -entdeckt, wird die zweite Beschriftung nach links verschoben -(@code{#:translate (cons -0.6 0) ...}). Dann werden die -Beschriftungen für jedes Einzelstück in eine Zeile gesetzt -@code{(make-line-markup ...)}. Schließlich wird die resultierende -Beschriftung an die @code{interpret-markup}-Funktion zusammen -mit den Argumenten @code{layout} und @code{props} weitergereicht. - -Achtung: ist gibt keinen internen Befehl @code{\smallCaps}, der -benutzt werden kann, um Text in Kapitälchen zu setzen. Siehe auch -@ref{Text markup commands}. +\markup \double-box A +\markup \override #'(inter-box-padding . 0.8) \double-box A +\markup \override #'(box-padding . 1.0) \double-box A +@end lilypond -@knownissues +@node Eingebaute Befehle anpassen +@unnumberedsubsubsec Eingebaute Befehle anpassen +@translationof Adapting builtin commands -Im Moment sind die möglichen Kombinationen von Argumenten (nach den -Standardargumenten @var{layout} und @var{props}), die mit -@code{define-markup-command} definiert werden, wie folgt -limitiert: - -@table @asis -@item (kein Argument) -@itemx @var{list} -@itemx @var{markup} -@itemx @var{markup markup} -@itemx @var{scm} -@itemx @var{scm markup} -@itemx @var{scm scm} -@itemx @var{scm scm markup} -@itemx @var{scm scm markup markup} -@itemx @var{scm markup markup} -@itemx @var{scm scm scm} -@end table +Ein guter Weg, einen neuen Beschriftungsbefehl zu schreiben, ist es, als Vorbild +einen existierenden zu nehmen. Die meisten Beschriftungsbefehle, die +LilyPond mitbringt, finden sich in der Datei +@file{scm/define-markup-commands.scm}. -@noindent -Hier stellt @var{scm} native Scheme-Datentypen dar wie -@q{number} oder @q{string}. +Man könnte beispielsweise den Befehl @code{\draw-line}, der eine Linie +zeichnet, anpassen, sodass er eine Doppellinie zeichnet. Der +Befehl @code{\draw-line} ist wie folgend definiert (Dokumentation entfernt): -Es ist beispielsweise nicht möglich, einen Beschriftungsbefehl -@code{foo} mit vier Argumenten in folgender Weise zu nutzen: +@lisp +(define-markup-command (draw-line layout props dest) + (number-pair?) + #:category graphic + #:properties ((thickness 1)) + "..documentation.." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@end lisp -@example -#(define-markup-command (foo layout props - num1 str1 num2 str2) - (number? string? number? string?) - ...) -@end example +Um einen neuen Befehl, der auf einem existierenden basiert, zu definieren, +wird die Befehlsdefinition kopiert und die Bezeichnung des Befehls +geändert. Das @code{#:category}-Schlagwort kann entfernt werden, +weil es nur zur Erstellung der LilyPond-Dokumentation eingesetzt wird +und keine Bedeutung für selbstdefinierte Befehle hat. -@noindent -Wenn es folgendermaßen eingesetzt wird: +@lisp +(define-markup-command (draw-double-line layout props dest) + (number-pair?) + #:properties ((thickness 1)) + "..documentation.." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@end lisp -@example -\markup \foo #1 #"bar" #2 #"baz" -@end example +Dann braucht man eine Eigenschaft, um den Abstand zwischen den zwei +Linien zu definieren, als @code{line-gap} bezeichnet und etwa mit +dem Standardwert 0.6: + +@lisp +(define-markup-command (draw-double-line layout props dest) + (number-pair?) + #:properties ((thickness 1) + (line-gap 0.6)) + "..documentation.." + ... +@end lisp + +Schließlich wird der Code, der die zwei Linien zeichnet, hinzugefügt. +Zwei Aufrufe an @code{make-line-stencil} werden benutzt, um beide Linien +zu zeichnen, und die beiden sich daraus ergebenden Stencils werden mit +@code{ly:stencil-add} kombiniert: + +@lilypond[quote,verbatim,ragged-right] +#(define-markup-command (my-draw-line layout props dest) + (number-pair?) + #:properties ((thickness 1) + (line-gap 0.6)) + "..documentation.." + (let* ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (dx (car dest)) + (dy (cdr dest)) + (w (/ line-gap 2.0)) + (x (cond ((= dx 0) w) + ((= dy 0) 0) + (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy)))))))) + (y (* (if (< (* dx dy) 0) 1 -1) + (cond ((= dy 0) w) + ((= dx 0) 0) + (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx)))))))))) + (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y)) + (make-line-stencil th (- x) (- y) (- dx x) (- dy y))))) + +\markup \my-draw-line #'(4 . 3) +\markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3) +@end lilypond -@cindex Scheme signature -@cindex Signatur, Scheme -@noindent -beschwert sich @command{lilypond}, dass @code{foo} wegen einer ungekannten -Scheme Signatur nicht analysiert werden kann. -@node Neue Definitionen von Beschriftungsbefehlen für Listen -@subsection Neue Definitionen von Beschriftungsbefehlen für Listen +@node Neue Definitionen von Beschriftungslistenbefehlen +@subsection Neue Definitionen von Beschriftungslistenbefehlen @translationof New markup list command definition Beschriftungslistenbefehle können mit dem Scheme-Makro @@ -1264,7 +1039,7 @@ sich ähnlich verhält wie das @code{define-markup-command}-Makro, das schon beschrieben wurde in @ref{Neue Definitionen von Beschriftungsbefehlen}. Ein Unterschied ist, dass bei diesem Listen-Makro eine ganze Liste an -Stecils ausgegeben wird. +Stencils ausgegeben wird. Im folgenden Beispiel wird ein @code{\paragraph}-Beschriftungslistenbefehl definiert, welcher eine Liste von Zeilen im Blocksatz ausgibt, von @@ -1273,13 +1048,22 @@ denen die erste Zeile eingerückt ist. Der Einzug wird aus dem @example #(define-markup-list-command (paragraph layout props args) (markup-list?) - (let ((indent (chain-assoc-get 'par-indent props 2))) - (interpret-markup-list layout props - (make-justified-lines-markup-list (cons (make-hspace-markup indent) - args))))) + #:properties ((par-indent 2)) + (interpret-markup-list layout props + #@{\markuplist \justified-lines @{ \hspace #par-indent #args @} #@})) +@end example + +Die Version nur in Scheme ist etwas komplexer: + +@example +#(define-markup-list-command (paragraph layout props args) (markup-list?) + #:properties ((par-indent 2)) + (interpret-markup-list layout props + (make-justified-lines-markup-list (cons (make-hspace-markup par-indent) + args)))) @end example -Neben den üblichen @code{layout} und @code{props}-Argumenten, nimmt der +Neben den üblichen @code{layout} und @code{props}-Argumenten nimmt der @code{paragraph}-Beschriftungslistenbefehl als Argument eine Beschriftungsliste, die @code{args} genannt wird. Das Prädikat für Beschriftungslisten ist @code{markup-list?}. @@ -1288,17 +1072,17 @@ Zuerst errechnet die Funktion die Breite des Einzugs, eine Eigenschaft mit der Bezeichnung @code{par-indent} anhand der Eigenschaftsliste @code{props}. Wenn die Eigenschaft nicht gefunden wird, ist der Standardwert @code{2}. Danach wird eine Liste von Zeilen im Blocksatz -erstellt, wobei die @code{make-justified-lines-markup-list}-Funktion -eingesetzt wird, die verwandt ist mit dem eingebauten -@code{\justified-lines}-Beschriftungslistenbefehl. Horizontaler -Platz wird zu Beginn eingefügt mit der @code{make-hspace-markup}-Funktion. -Zuletzt wird die Beschriftungsliste ausgewertet durch die -@code{interpret-markup-list}-Funktion. +erstellt, wobei der eingebaute @code{\justified-lines}-Beschriftungslistenbefehl +eingesetzt wird, der verwandt ist mit der +@code{make-justified-lines-markup-list}-Funktion. Horizontaler +Platz wird zu Beginn eingefügt mit @code{\hspace} (oder der +@code{make-hspace-markup}-Funktion). Zuletzt wird die Beschriftungsliste +ausgewertet durch die @code{interpret-markup-list}-Funktion. Dieser neue Beschriftungslistenbefehl kann wie folgt benutzt werden: @example -\markuplines @{ +\markuplist @{ \paragraph @{ Die Kunst des Notensatzes wird auch als \italic @{Notenstich@} bezeichnet. Dieser Begriff stammt aus dem traditionellen Notendruck. Noch bis vor etwa @@ -1307,7 +1091,7 @@ Dieser neue Beschriftungslistenbefehl kann wie folgt benutzt werden: @} \override-lines #'(par-indent . 4) \paragraph @{ Diese Platte wurde dann mit Druckerschwärze versehen, so dass sie - in den geschnittenen und gestempelten Vertiefungen blieb. Diese + in den geschnittenen und gestempelten Vertiefungen blieb. Diese Vertiefungen schwärzten dann ein auf die Platte gelegtes Papier. Das Gravieren wurde vollständig von Hand erledigt. @} @@ -1315,7 +1099,6 @@ Dieser neue Beschriftungslistenbefehl kann wie folgt benutzt werden: @end example - @node Kontexte für Programmierer @section Kontexte für Programmierer @translationof Contexts for programmers @@ -1344,7 +1127,7 @@ modifiziert werden. Die Syntax hierfür ist @var{function} sollte eine Scheme-Funktion sein, die ein einziges Argument braucht, welches der Kontext ist, auf den sie ausgeführt werden soll. Der folgende Code schreibt -die aktuelle Taktzahlshould in die Standardausgabe +die aktuelle Taktzahl in die Standardausgabe während der Kompilation. @example @@ -1366,7 +1149,9 @@ während der Kompilation. @funindex \applyOutput Der vielfältigste Weg, ein Objekt zu beeinflussen, ist -@code{\applyOutput}. Die Syntax lautet: +@code{\applyOutput}. Das funktioniert, indem ein musikalisches +Ereignis in den angegebenen Kontext eingefügt wird +(@rinternals{ApplyOutputEvent}). Die Syntax lautet: @example \applyOutput @var{Kontext} @var{proc} @@ -1376,8 +1161,8 @@ Der vielfältigste Weg, ein Objekt zu beeinflussen, ist wobei @var{proc} eine Scheme-Funktion ist, die drei Argumente benötigt. -Während der Interpretation wird die Funktion @var{proc} für -jedes Layoutobjekt aufgerufen, dass im Kontext @var{Kontext} +Während der Interpretation wird die Funktion @code{@var{proc}} für +jedes Layoutobjekt aufgerufen, dass im Kontext @code{@var{Kontext}} vorgefunden wird, und zwar mit folgenden Argumenten: @itemize @@ -1390,39 +1175,39 @@ Zusätzlich findet sich der Grund für das Layoutobjekt, etwa der musikalische Ausdruck oder das Objekt, das für seine Erstellung verantwortlich war, in der Objekteigenschaft @code{cause}. Für einen Notenkopf beispielsweise ist das ein -@rinternals{NoteHead}-Ereignis, und für einen Notenhals -(ein @rinternals{Stem}-Objekt) ist es ein @rinternals{NoteHead}-Objekt. +@rinternals{NoteHead}-Ereignis, und für einen Notenhals ist es +ein @rinternals{Stem}-Objekt. Hier ist eine Funktion, die mit @code{\applyOutput} benutzt -werden kann; sie macht Notenköpfe auf der Mittellinie unsichtbar: +werden kann; sie macht Notenköpfe auf und neben der Mittellinie unsichtbar: @lilypond[quote,verbatim,ragged-right] #(define (blanker grob grob-origin context) (if (and (memq 'note-head-interface (ly:grob-interfaces grob)) - (eq? (ly:grob-property grob 'staff-position) 0)) + (< (abs (ly:grob-property grob 'staff-position)) 2)) (set! (ly:grob-property grob 'transparent) #t))) -\relative { - e4 g8 \applyOutput #'Voice #blanker b d2 +\relative c' { + a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2 } @end lilypond -@node Scheme-Vorgänge als Eigenschaften -@section Scheme-Vorgänge als Eigenschaften -@translationof Scheme procedures as properties +@node Callback-Funktionen +@section Callback-Funktionen +@translationof Callback functions -Eigenschaften (wie Dicke, Richtung usw.) können mit -@code{\override} auf feste Werte gesetzt werden, etwa: +Eigenschaften (wie Dicke (@code{thickness}), Richtung (@code{direction}) +usw.) können mit @code{\override} auf feste Werte gesetzt werden, etwa: @example -\override Stem #'thickness = #2.0 +\override Stem.thickness = #2.0 @end example Eigenschaften können auch auf eine Scheme-Prozedur gesetzt werden: @lilypond[fragment,verbatim,quote,relative=2] -\override Stem #'thickness = #(lambda (grob) +\override Stem.thickness = #(lambda (grob) (if (= UP (ly:grob-property grob 'direction)) 2.0 7.0)) @@ -1430,16 +1215,16 @@ c b a g b a g b @end lilypond @noindent -In diesem Fall wird die Prozedur ausgeführt, sobal der Wert der +In diesem Fall wird die Prozedur ausgeführt, sobald der Wert der Eigenschaft während das Formatierungsprozesses angefordert wird. -Der größte Teil der Satzmaschinierie funtioniert mit derartigen +Der größte Teil der Satzmaschinierie funktioniert mit derartigen Callbacks. Eigenschaften, die üblicherweise Callbacks benutzen, sind u. A.: @table @code @item stencil - Die Druckfunktion, die eine Ausgabe des Symbols ervorruft + Die Druckfunktion, die eine Ausgabe des Symbols hervorruft @item X-offset Die Funktion, die die horizontale Position setzt @item X-extent @@ -1485,17 +1270,35 @@ für @var{proc} zur Verfügung, das äußere stellt sicher, dass das Resultat der Funktion ausgegeben wird und nicht das @code{simple-closure}-Objekt. +Aus dem Callback heraus kann man eine Beschriftung am einfachsten mit +@code{grob-interpret-markup} auswerten. Beispielsweise: + +@example +mein-callback = #(lambda (grob) + (grob-interpret-markup grob (markup "foo"))) +@end example -@node Scheme-Code anstelle von \tweak verwenden -@section Scheme-Code anstelle von @code{ weak} verwenden -@translationof Using Scheme code instead of \tweak + +@node Scheme-Code innerhalb LilyPonds +@section Scheme-Code innerhalb LilyPonds +@translationof Inline Scheme code + +TODO: das Beispiel für diesen Abschnitt ist nicht gut gewähtl: + +@example +F = -\tweak font-size #-3 -\flageolet +@end example +(beachte @samp{-}, was ein Nachereignis anzeigt) funktioniert +für den geschilderten Zweck sehr gut. Aber bis der Abschnitt +neu geschrieben wird, nehmen wir einfach an, dass wir das nicht +wissen. Der hauptsächliche Nachteil von @code{\tweak} ist seine syntaktische Inflexibilität. Folgender Code beispielsweise ergibt einen Syntaxfehler: @example -F = \tweak #'font-size #-3 -\flageolet +F = \tweak font-size #-3 -\flageolet \relative c'' @{ c4^\F c4_\F @@ -1503,10 +1306,6 @@ F = \tweak #'font-size #-3 -\flageolet @end example @noindent -Anders gesagt verhält sich @code{\tweak} nicht wie eine Artikulation -und kann auch nicht deren Syntax verwenden: man kann es nicht -mit @code{^} oder @code{_} anfügen. - Durch die Verwendung von Scheme kann dieses Problem umgangen werden. Der Weg zum Resultat wird gezeigt in @ref{Artikulationszeichen zu Noten hinzufügen (Beispiel)}, insbesondere @@ -1580,8 +1379,8 @@ wenn ja, wird @code{extra-offset} gesetzt. @end itemize Diese Funktion muss in @rinternals{Tie} (Bindebogen) installiert -werden, und der letzte Teil eines gebrochenen Bindebogens wird -nach oben verschoben. +werden, damit der letzte Teil eines gebrochenen Bindebogens +neu ausgerichtet wird. @lilypond[quote,verbatim,ragged-right] #(define (my-callback grob) @@ -1598,9 +1397,9 @@ nach oben verschoben. (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) \relative c'' { - \override Tie #'after-line-breaking = + \override Tie.after-line-breaking = #my-callback - c1 ~ \break c2 ~ c + c1 ~ \break c2 ~ 2 } @end lilypond @@ -1609,7 +1408,7 @@ Wenn man diesen Trick anwendet, sollte das neue @code{after-line-breaking} auch das alte @code{after-line-breaking}-Callback aufrufen, wenn es vorhanden ist. Wenn diese Funktion etwa mit @code{Hairpin} (Crescendo-Klammer) eingesetzt wird, sollte auch -@code{ly:hairpin::after-line-breaking} aufgerufen werden. +@code{ly:spanner::kill-zero-spanned-time} aufgerufen werden. @item @@ -1621,13 +1420,25 @@ und @code{PaperColumn}. Sie können mit der @example \overrideProperty -#"Score.NonMusicalPaperColumn" % Grob-Bezeichnung +Score.NonMusicalPaperColumn % Grob-Bezeichnung #'line-break-system-details % Eigenschaftsbezeichnung #'((next-padding . 20)) % Wert @end example Es sollte angemerkt werden, dass @code{\override}, wenn man es auf -@code{NonMusicalPaperColumn} und @code{PaperColumn} anwendet, immernoch +@code{NonMusicalPaperColumn} und @code{PaperColumn} anwendet, immer noch innerhalb der @code{\context}-Umgebung funktioniert. @end itemize + + + +@node LilyPond Scheme-Schnittstellen +@chapter LilyPond Scheme-Schnittstellen +@translationof LilyPond Scheme interfaces + +Dieses Kapitel behandelt die verschiedenen Werkzeuge, die LilyPond als +Hilfe für Scheme-Programmierer zur Verfügung stellt, um Information in +den Musik-Stream zu senden und aus ihm herauszubekommen. + +TODO: was gehört hier eigentlich hin?