@c -*- coding: utf-8; mode: texinfo; -*- @ignore Translation of GIT committish: 8cbb38db1591ab95a178643e7bf41db018aa22c0 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.15.17" @c Translators: Till Paala @node Schnittstellen für Programmierer @chapter Schnittstellen für Programmierer @translationof Interfaces for programmers Fortgeschrittene Anpassungen können mithilfe der Programmiersprache Scheme vorgenommen werden. Wenn Sie Scheme nicht kennen, gibt es eine grundlegende Einleitung in LilyPonds @ref{Scheme-Übung}. @menu * Musikalische Funktionen:: * Textbeschriftungsfunktionen:: * Kontexte für Programmierer:: * 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. @emph{Musikalische Funktionen} sind Scheme-Prozeduren, die musikalische Ausdrücke automatisch erstellen können und dadurch die Eingabedatei maßgeblich vereinfachen können. @menu * Syntax der musikalischen Funktionen:: * Einfache Ersetzungsfunktionen:: * Mittlere Ersetzungsfunktionen:: * Mathematik in Funktionen:: * Funktionen ohne Argumente:: * Leere Funktionen:: @end menu @node Syntax der musikalischen Funktionen @subsection Syntax der musikalischen Funktionen @translationof Music function definitions Die allgemeine Form von musikalischen Funktionen ist: @example function = #(define-music-function (parser location @var{Arg1} @var{Arg2} @dots{}) (@var{Typ1?} @var{Typ2?} @dots{}) @var{Noten}) @end example @noindent wobei @multitable @columnfractions .33 .66 @item @var{ArgN} @tab das @var{n}te Argument @item @var{TypN?} @tab ein Scheme-Typenprädikat (engl. type predicate), für welches @code{@var{ArgN}} @code{#t} ausgeben muss. Einige dieser Prädikate werden durch den Parser gesondert erkannt, sodass die entsprechenden Werte als LilyPond-Syntx gelesen werden und nicht als Scheme-Syntax. Diese Prädikate sind gegenwärtig @code{ly:music?}, @code{markup?}, @code{ly:pitch?} und @code{ly:duration?}. Nicht alle Kombinationen sind erlaubt: man kann z. B. nicht eine Dauer nach den Noten suchen, denn Noten können @emph{optional} mit einer Dauer enden. Wenn Sie wirklich einige dieser Elemente als Scheme- und nicht als LilyPond-Ausdruck einsetzen wollen, können Sie sie in einen Aufruf von @code{ly:export} einfügen. @item @var{...Noten...} @tab ein musikalischer Ausdruck, optional in Scheme geschrieben, mit allem LilyPond-Code in Raute/geschweifte Klammer eingeschlossen (@tie{}@w{@code{#@{@dots{}#@}}}@tie{}). Innerhalb der LilyPond-Codeumgebungen wird @code{$} eingesetzt, um auf Funktionsargumente zu verweisen (etwa @samp{$Arg1}), oder ein neuer Scheme-Ausdruck muss begonnen werden, der die Funktionsargumente enthält (etwa @w{@samp{$(cons Arg1 Arg2)}}). @end multitable Eine Liste der möglichen Typenprädikate findet sich in @ruser{Vordefinierte Typenprädikate}. Durch den Benutzer definierte Typenprädikate sind auch erlaubt. @seealso Notationsreferenz: @ruser{Vordefinierte Typenprädikate}. Installierte Dateien: @file{lily/music-scheme.cc}, @file{scm/c++.scm}, @file{scm/lily.scm}. @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 Mittlere Ersetzungsfunktionen @subsection Mittlere Ersetzungsfunktionen @translationof Intermediate substitution functions Mittlere Ersetzungsfunktionen setzen sich aus einer Mischung von Scheme-Code und LilyPond-Code in der musikalischen Ausgabe-Funktion zusammen. Einige @code{\override}-Befehle benötigen ein Zahlenpaar (als @code{cons}-Zelle in Scheme bezeichnet). Das Paar kann direkt an die musikalische Funktion mit der Variable @code{pair?} weitergeleitet werden: @example 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 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 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 } \relative c' { c2 \AltOn #0.5 c4 c \AltOn #1.5 c c \AltOff c2 } @end lilypond @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 #}) \relative c' { c2 \withAlt #0.5 { c4 c } \withAlt #1.5 { c c } c2 } @end lilypond @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: @example dolce = \markup@{ \italic \bold dolce @} @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 Leere Funktionen @subsection Leere Funktionen @translationof Void music functions Eine musikalische Funktion muss einen musikalischen Ausdruck ausgeben, aber in manchen Fällen müssen Funktionen erstellt werden, die keine Noten 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, @w{@code{(make-music @dots{})}} 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. @example noPointAndClick = #(define-music-function (parser location) () (ly:set-option 'point-and-click #f) (make-music 'SequentialMusic 'void #t)) ... \noPointAndClick % Point and Click ausschalten @end example @node Textbeschriftungsfunktionen @section Textbeschriftungsfunktionen @translationof Markup functions Textbeschriftungselemente sind als besondere Scheme-Funktionen 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 Beschriftungslistenbefehlen:: @end menu @node Beschriftungskonstruktionen in Scheme @subsection Beschriftungskonstruktionen in Scheme @translationof Markup construction in Scheme @cindex Textbeschriftungsbefehle, definieren @cindex Textbeschriftung, eigene Befehle @cindex eigene Befehle, Textbeschriftung @cindex markup, eigene Befehle @cindex Befehle definieren, Textbeschriftung Das @code{markup}-(Textbeschriftungs)Makro erstellt Textbeschriftungs-Ausdrücke in Scheme, wobei eine LilyPond-artige Syntax benutzt wird. Beispielsweise ist @example (markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") #:larger #:line ("foo" "bar" "baz"))) @end example @noindent identisch mit @example \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. @quotation @multitable @columnfractions .3 .3 @item @b{LilyPond} @tab @b{Scheme} @item @code{\markup Text1} @tab @code{(markup Text1)} @item @code{\markup @{ Text1 Text2 ... @}} @tab @code{(markup Text1 Text2 ... )} @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} @end multitable @end quotation Die gesamte Scheme-Sprache ist innerhalb des @code{markup}-Makros zugänglich. Man kann also beispielsweise Funktionen innerhalb eines @code{markup} aufrufen, um Zeichenketten zu manipulieren. Das ist nützlich, wenn neue Beschriftungsbefehle definiert werden sollen (siehe auch @ref{Neue Definitionen von Beschriftungsbefehlen}). @knownissues Das Beschriftungslistenargument von Befehlen wie @code{#:line}, @code{#:center} und @code{#:column} kann keine Variable oder das Resultat eines Funktionsaufrufen sein. @lisp (markup #:line (Funktion-die-Textbeschriftung-ausgibt)) @end lisp @noindent ist ungültig. Man sollte anstatt dessen die Funktionen @code{make-line-markup}, @code{make-center-markup} oder @code{make-column-markup} benutzen: @lisp (markup (make-line-markup (Funktion-die-Textbeschriftung-ausgibt))) @end lisp @node Wie Beschriftungen intern funktionieren @subsection Wie Beschriftungen intern funktionieren @translationof How markups work internally In einer Textbeschriftung wie @example \raise #0.5 "Textbeispiel" @end example @noindent ist @code{\raise} unter der Haube durch die @code{raise-markup}-Funktion repräsentiert. Der Beschriftungsausdruck wird gespeichert als @example (list raise-markup 0.5 (list simple-markup "Textbeispiel")) @end example Wenn die Beschriftung in druckbare Objekte (Stencils) umgewandelt ist, wir die @code{raise-markup}-Funktion folgendermaßen aufgerufen: @example (apply raise-markup @var{\layout object} @var{Liste der Eigenschafts-alists} 0.5 @var{die "Textbeispiel"-Beschriftung}) @end example 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}. @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-typ?} @var{Arg2-typ?} ...) [ #:properties ((@var{Eigenschaft1} @var{Standard-Wert1}) ...) ] ..Befehlkörper..) @end lisp Die Argumente sind: @table @var @item @var{befehl-bezeichnung} die Bezeichnung des Befehls @item @var{layout} die @q{layout}-Definition @item props 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 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. Argumente werden nach ihrem Typ unterschieden: @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 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. 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. @node Über Eigenschaften @unnumberedsubsubsec Über Eigenschaften @translationof On properties Die @code{layout}- und @code{props}-Argumente der Textbeschriftungsbefehle bringen einen Kontext für die Interpretation der Beschriftung: Schriftgröße, Zeilenlänge usw. 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 (ly:output-def-lookup layout 'line-width) @end example 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. Das Beispiel im nächsten Abschnitt illustriert, wie man auf Eigenschaften in einem Beschriftungsbefehl zugreifen und sie verändern kann. @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 #: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. In unserem 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 \markup \double-box A @end example 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 (markup #:override `(box-padding . ,inter-box-padding) #:box #:override `(box-padding . ,box-padding) #:box text))) @end lisp 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. 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. 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 (markup #:override `(box-padding . ,inter-box-padding) #:box #:override `(box-padding . ,box-padding) #:box text))) \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 @node Eingebaute Befehle anpassen @unnumberedsubsubsec Eingebaute Befehle anpassen @translationof Adapting builtin commands 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}. 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): @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 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. @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 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 @node Neue Definitionen von Beschriftungslistenbefehlen @subsection Neue Definitionen von Beschriftungslistenbefehlen @translationof New markup list command definition Beschriftungslistenbefehle können mit dem Scheme-Makro @code{define-markup-list-command} definiert werden, welches 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 Stencils ausgegeben wird. Im folgenden Beispiel wird ein @code{\paragraph}-Beschriftungslistenbefehl definiert, welcher eine Liste von Zeilen im Blocksatz ausgibt, von denen die erste Zeile eingerückt ist. Der Einzug wird aus dem @code{props}-Argument entnommen. @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))))) @end example 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?}. 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. Dieser neue Beschriftungslistenbefehl kann wie folgt benutzt werden: @example \markuplist @{ \paragraph @{ Die Kunst des Notensatzes wird auch als \italic @{Notenstich@} bezeichnet. Dieser Begriff stammt aus dem traditionellen Notendruck. Noch bis vor etwa 20 Jahren wurden Noten erstellt, indem man sie in eine Zink- oder Zinnplatte schnitt oder mit Stempeln schlug. @} \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 Vertiefungen schwärzten dann ein auf die Platte gelegtes Papier. Das Gravieren wurde vollständig von Hand erledigt. @} @} @end example @node Kontexte für Programmierer @section Kontexte für Programmierer @translationof Contexts for programmers @menu * Kontextauswertung:: * Eine Funktion auf alle Layout-Objekte anwenden:: @end menu @node Kontextauswertung @subsection Kontextauswertung @translationof Context evaluation @cindex Aufrufen von Code während der Interpretation @cindex On-the-fly Code ausführen @funindex \applyContext Kontexte können während ihrer Interpretation mit Scheme-Code modifiziert werden. Die Syntax hierfür ist @example \applyContext @var{function} @end example @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 Taktzahl in die Standardausgabe während der Kompilation. @example \applyContext #(lambda (x) (format #t "\nWe were called in barnumber ~a.\n" (ly:context-property x 'currentBarNumber))) @end example @node Eine Funktion auf alle Layout-Objekte anwenden @subsection Eine Funktion auf alle Layout-Objekte anwenden @translationof Running a function on all layout objects @cindex Aufruf von Code für Layoutobjekte @funindex \applyOutput Der vielfältigste Weg, ein Objekt zu beeinflussen, ist @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} @end example @noindent wobei @var{proc} eine Scheme-Funktion ist, die drei Argumente benötigt. 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 @item dem Layoutobjekt @item dem Kontext, in dem das Objekt erstellt wurde @item dem Kontext, in welchem @code{\applyOutput} bearbeitet wird. @end itemize 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 ist es ein @rinternals{Stem}-Objekt. Hier ist eine Funktion, die mit @code{\applyOutput} benutzt 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)) (< (abs (ly:grob-property grob 'staff-position)) 2)) (set! (ly:grob-property grob 'transparent) #t))) \relative c' { a'4 e8 <<\applyOutput #'Voice #blanker a c d>> b2 } @end lilypond @node Callback-Funktionen @section Callback-Funktionen @translationof Callback functions 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 @end example Eigenschaften können auch auf eine Scheme-Prozedur gesetzt werden: @lilypond[fragment,verbatim,quote,relative=2] \override Stem #'thickness = #(lambda (grob) (if (= UP (ly:grob-property grob 'direction)) 2.0 7.0)) c b a g b a g b @end lilypond @noindent 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 funktioniert mit derartigen Callbacks. Eigenschaften, die üblicherweise Callbacks benutzen, sind u. A.: @table @code @item stencil Die Druckfunktion, die eine Ausgabe des Symbols hervorruft @item X-offset Die Funktion, die die horizontale Position setzt @item X-extent Die Funktion, die die Breite eines Objekts errechnet @end table Die Funktionen brauchen immer ein einziges Argument, das der Grob ist. Wenn Funktionen mit mehreren Argumenten aufgerufen werden müssen, kann der aktuelle Grob mit einer Grob-Einschließung eingefügt werden. Hier eine Einstellung aus @code{AccidentalSuggestion}: @example (X-offset . ,(ly:make-simple-closure `(,+ ,(ly:make-simple-closure (list ly:self-alignment-interface::centered-on-x-parent)) ,(ly:make-simple-closure (list ly:self-alignment-interface::x-aligned-on-self))))) @end example @noindent In diesem Beispiel werden sowohl @code{ly:self-alignment-interface::x-aligned-on-self} als auch @code{ly:self-alignment-interface::centered-on-x-parent} mit dem Grob als Argument aufgerufen. Die Resultate werden mit der @code{+}-Funktion addiert. Um sicherzugehen, dass die Addition richtig ausgeführt wird, wird das ganze Konstrukt in @code{ly:make-simple-closure} eingeschlossen. In der Tat ist die Benutzung einer einzelnen Funktion als Eigenschaftswert äquivalent zu @example (ly:make-simple-closure (ly:make-simple-closure (list @var{proc}))) @end example @noindent Das innere @code{ly:make-simple-closure} stellt den Grob als Argument 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 innerhalb LilyPonds @section Scheme-Code innerhalb LilyPonds @translationof Inline Scheme code 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 \relative c'' @{ c4^\F c4_\F @} @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 wie @code{\displayMusic} benutzt wird, hilft hier weiter. @example F = #(let ((m (make-music 'ArticulationEvent 'articulation-type "flageolet"))) (set! (ly:music-property m 'tweaks) (acons 'font-size -3 (ly:music-property m 'tweaks))) m) \relative c'' @{ c4^\F c4_\F @} @end example @noindent In diesem Beispiel werden die @code{tweaks}-Eigenschaften des Flageolet-Objekts @code{m} (mit @code{make-music} erstellt) werden mit @code{ly:music-property} ausgelesen, ein neues Schlüssel-Wert-Paar, um die Schriftgröße zu ändern, wird der Eigenschaftenliste mithilfe der @code{acons}-Schemefunktion vorangestellt, und das Resultat wird schließlich mit @code{set!} zurückgeschrieben. Das letzte Element des @code{let}-Blocks ist der Wiedergabewert, @code{m}. @node Schwierige Korrekturen @section Schwierige Korrekturen @translationof Difficult tweaks Hier finden sich einige Klassen an schwierigeren Anpassungen. @itemize @item Ein Typ der schwierigen Anpassungen ist die Erscheinung von Strecker-Objekten wie Binde- oder Legatobögen. Zunächst wird nur eins dieser Objekte erstellt, und sie können mit dem normalen Mechanismus verändert werden. In einigen Fällen reichen die Strecker jedoch über Zeilenumbrüche. Wenn das geschieht, werden diese Objekte geklont. Ein eigenes Objekt wird für jedes System erstellt, in dem es sich befindet. Sie sind Klone des originalen Objektes und erben alle Eigenschaften, auch @code{\override}-Befehle. Anders gesagt wirkt sich ein @code{\override} immer auf alle Stücke eines geteilten Streckers aus. Um nur einen Teil eines Streckers bei einem Zeilenumbruch zu verändern, ist es notwendig, in den Formatierungsprozess einzugreifen. Das Callback @code{after-line-breaking} enthält die Schemefunktion, die aufgerufen wird, nachdem Zeilenumbrüche errechnet worden sind und die Layout-Objekte über die unterschiedlichen Systeme verteilt wurden. Im folgenden Beispiel wird die Funktion @code{my-callback} definiert. Diese Funktion @itemize @item bestimmt, ob das Objekt durch Zeilenumbrüche geteilt ist, @item wenn ja, ruft sie alle geteilten Objekte auf, @item testet, ob es sich um das letzte der geteilten Objekte handelt, @item wenn ja, wird @code{extra-offset} gesetzt. @end itemize Diese Funktion muss in @rinternals{Tie} (Bindebogen) installiert werden, damit der letzte Teil eines gebrochenen Bindebogens neu ausgerichtet wird. @lilypond[quote,verbatim,ragged-right] #(define (my-callback grob) (let* ( ; have we been split? (orig (ly:grob-original grob)) ; if yes, get the split pieces (our siblings) (siblings (if (ly:grob? orig) (ly:spanner-broken-into orig) '() ))) (if (and (>= (length siblings) 2) (eq? (car (last-pair siblings)) grob)) (ly:grob-set-property! grob 'extra-offset '(-2 . 5))))) \relative c'' { \override Tie #'after-line-breaking = #my-callback c1 ~ \break c2 ~ c } @end lilypond @noindent 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:spanner::kill-zero-spanned-time} aufgerufen werden. @item Manche Objekte können aus technischen Gründen nicht mit @code{\override} verändert werden. Beispiele hiervon sind @code{NonMusicalPaperColumn} und @code{PaperColumn}. Sie können mit der @code{\overrideProperty}-Funktion geändert werden, die ähnlich wie @code{\once \override} funktioniert, aber eine andere Syntax einsetzt. @example \overrideProperty #"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, 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?