From: Till Paala Date: Thu, 28 Jan 2010 08:55:20 +0000 (+0200) Subject: Doc-de: create extending.tely X-Git-Tag: release/2.13.12-1~3^2~4^2~5 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=016ba6fb07e70572c8171eb73090a3f24aeb9eea;p=lilypond.git Doc-de: create extending.tely --- diff --git a/Documentation/de/extending.tely b/Documentation/de/extending.tely new file mode 100644 index 0000000000..c69b2e1d1b --- /dev/null +++ b/Documentation/de/extending.tely @@ -0,0 +1,77 @@ +\input texinfo @c -*- coding: utf-8; mode: texinfo; -*- +@ignore + Translation of GIT committish: 354f8ea159bb5216202e5815685fca8bd7e6919c + + 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 + +@setfilename lilypond-extending.info +@settitle Extending LilyPond +@documentencoding UTF-8 +@documentlanguage de +@afourpaper + +@c Translators: Till Paala + +@macro manualIntro +Diese Datei erklärt, wie man die Funktionalität von +LilyPond Version @version{} erweitern kann. +@end macro + +@c `Extending' was born 2003-04-23 with git commit c08f6e8... +@macro copyrightDeclare +Copyright @copyright{} 2003--2009 bei den Autoren. +@end macro + +@set FDL +@include macros.itexi + + +@c don't remove this comment. +@ignore +@omfcreator Han-Wen Nienhuys, Jan Nieuwenhuizen and Graham Percival +@omfdescription Programming extensions for the LilyPond music engraving system +@omftype program usage +@omfcategory Applications|Publishing +@omflanguage German +@end ignore + + +@lilyTitlePage{Extending} + + +@c TOC -- non-tex +@ifnottex + +@menu +* Scheme-Übung:: Programmieren innerhalb von LilyPond. +* Schnittstellen für Programmierer:: Wie man mit Scheme kommunizieren kann. +* LilyPond Scheme interfaces:: Information in die Noten senden und aus den Noten erhalten. + +Anhänge + +* GNU Free Documentation License:: Die Lizenz dieses Dokuments. +* LilyPond-Index:: +@end menu + +@docMain +@end ifnottex + + +@contents + + +@include extending/scheme-tutorial.itely +@include extending/programming-interface.itely + +@include fdl.itexi + +@node LilyPond-Index +@appendix LilyPond-Index +@translationof LilyPond index + +@printindex cp + +@bye diff --git a/Documentation/de/extending/programming-interface.itely b/Documentation/de/extending/programming-interface.itely new file mode 100644 index 0000000000..a2cc7683f4 --- /dev/null +++ b/Documentation/de/extending/programming-interface.itely @@ -0,0 +1,1633 @@ +@c -*- coding: utf-8; mode: texinfo; -*- + +@ignore + Translation of GIT committish: 7b70644b95f383b4281e9ffa146d315d2ada11d3 + + 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 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 +@rlearning{Scheme-Übung}. + +@menu +* Musikalische Funktionen:: +* Schnittstelle für Programmierer:: +* Komplizierte Funktionen erstellen:: +* Programmierungsschnittstelle für Textbeschriftungen:: +* Kontexte für Programmierer:: +* Scheme-Vorgänge als Eigenschaften:: +* Scheme-Code anstelle von \tweak verwenden:: +* 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 + +Es ist einfach, eine Funktion zu erstellen, die Variablen +im LilyPond-Code ersetzt. Die allgemeine Form derartiger +Funktionen ist + +@example +function = +#(define-music-function (parser location @var{var1} @var{var2}...@var{vari}... ) + (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) + #@{ + @emph{...Noten...} + #@}) +@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 + +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. + +@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 + +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 Einfache Ersetzungsfunktionen +@subsection Einfache Ersetzungsfunktionen +@translationof Simple substitution functions + +Hier ist ein einfaches Beispiel: + +@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 + + +@node Paarige Ersetzungsfunktionen +@subsection Paarige Ersetzungsfunktionen +@translationof Paired substitution functions + +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. + +@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 +@} +@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 +} + +{ c'2 \AltOn #0.5 c'4 c' + \AltOn #1.5 c' c' \AltOff c'2 } +@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 #}) + +{ 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. + +@example +noPointAndClick = +#(define-music-function (parser location) () + (ly:set-option 'point-and-click #f) + (make-music 'SequentialMusic 'void #t)) +... +\noPointAndClick % disable point and click +@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: + +@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 Ü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 + + + +@node Schnittstelle für Programmierer +@section Schnittstelle für Programmierer +@translationof Programmer interfaces + +Dieser Abschnitt zeigt, wie LilyPond und +Scheme gemischt werden können. + +@menu +* Eingabevariablen und Scheme:: +* Interne Repräsentation der Musik:: +@end menu + + +@node Eingabevariablen und Scheme +@subsection Eingabevariablen und Scheme +@translationof Input variables and Scheme + +Das Eingabeformat unterstützt die Notation von Variablen: im +folgenden Beispiel wird ein musikalischer Ausdruck einer Variable +mit der Bezeichnung @code{traLaLa} zugewiesen: + +@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{... }'}) +@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 + +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: + +@example +#(define (nopc) + (ly:set-option 'point-and-click #f)) + +... +#(nopc) +@{ c'4 @} +@end example + +@knownissues + +Scheme- und LilyPond-Variablen können im LilyPond-Modus mit der +@code{--safe}-Option nicht vermischt werden. + + +@node Interne Repräsentation der Musik +@subsection Interne Repräsentation der Musik +@translationof Internal music representation + +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. + +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}. + +@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}. + +@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)))) +@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. + +@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: + +@example +#(display-scheme-music + (ly:music-property (first (ly:music-property someNote 'elements)) + 'pitch)) +===> +(ly:make-pitch 0 0 0) +@end example + +Die Tonhöhe einer Note kann geändert werden, indem man diese +@code{'pitch}-Eigenschaft umdefiniert: + +@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 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: + +@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 + +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. + +Jetzt folgt eine Betrachtung der Eingabe: + +@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)))))) +@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 + + +@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. + +Eine @code{$variable} innerhalb von @code{#@{...#@}} ist das +gleiche wie die normale Befehlsform @code{\variable} in +üblicher LilyPond-Notation. Es ist bekannt dass + +@example +@{ \music -. -> @} +@end example + +@noindent +in LilyPond nicht funktioniert. Das Problem könnte vermieden +werden, indem das Artikulationszeichen an eine Pseudonote +gehängtwird: + +@example +@{ << \music s1*0-.-> @} +@end example + +@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 + +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. + +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 + +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). + +@example +"Add a marcato..." +@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. + +@example +(let ((result-event-chord (ly:music-deep-copy event-chord))) +@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: + +@example +(set! place new-value) +@end example + +Was in diesem Fall @qq{gesetzt} werden soll (@qq{place}) ist die +@q{elements}-Eigenschaft des @code{result-event-chord}-Ausdrucks. + +@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: + +@example +(cons (make-music 'ArticulationEvent + 'articulation-type "marcato") + (ly:music-property result-event-chord 'elements)) +@end example + +@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. + +Jetzt wird die @code{add-marcato}-Funktion in eine musikalische +Funktion umgewandelt: + +@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 + +Eine Überprüfung, dass die Funktion richtig arbeitet, geschieht +folgendermaßen: + +@example +\displayMusic \addMarcato c4 +@end example + + +@node Programmierungsschnittstelle für Textbeschriftungen +@section Programmierungsschnittstelle für Textbeschriftungen +@translationof Markup programmer interface + +Textbeschriftungselemente sind als besondere Scheme-Funktionen +definiert, die ein 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:: +@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{\Befehl} @tab @code{#:Befehl} +@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ächt 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 + +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?} ...) + ..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 +die @q{layout}-Definition +@item props +eine Liste an alists, in der alle aktiven Eigenschaften enthalten sind +@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: + +@example +\markup @{ \override #'(font-shape . caps) Text-in-Kapitälchen @} +@end example + +@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. + +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: + +@example +(define-markup-command (smallcaps layout props argument) (markup?) +@end example + +@noindent + +Was jetzt folgt, ist der eigentliche Inhalt des Befehls: das +@code{argument} soll als Beschriftung (markup) interpretiert werden, +also: + +@example +(interpret-markup layout @dots{} argument) +@end example + +@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: + +@example +(cons (list '(font-shape . caps) ) props) +@end example + +@noindent +Die Variable @code{props} ist eine Liste an alists, und mit @code{cons} +wird ihr eine zusätzliche Einstellung hinzugefügt. + +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: + +@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\"" + (interpret-markup layout props + (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) +@end example + +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. + +Das Resultat sieht folgendermaßen aus: + +@example +@{ + c''^\markup \character #"Cleopatra" + e'^\markup \character #"Giulio Cesare" +@} +@end example + +@lilypond[quote,ragged-right] +#(define-markup-command (smallcaps layout props str) (string?) + "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" + (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\"" + (interpret-markup layout props + (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) + +{ + c''^\markup \character #"Cleopatra" c'' c'' c'' + e'^\markup \character #"Giulio Cesare" e' e' e' +} +@end lilypond + +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: + +@example +#(define-markup-command (smallcaps layout props str) (string?) + "Print the string argument in small caps." + (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 + +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}. + +@knownissues + +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 + +@noindent +Hier stellt @var{scm} native Scheme-Datentypen dar wie +@q{number} oder @q{string}. + +Es ist beispielsweise nicht möglich, einen Beschriftungsbefehl +@code{foo} mit vier Argumenten in folgender Weise zu nutzen: + +@example +#(define-markup-command (foo layout props + num1 str1 num2 str2) + (number? string? number? string?) + ...) +@end example + +@noindent +Wenn es folgendermaßen eingesetzt wird: + +@example +\markup \foo #1 #"bar" #2 #"baz" +@end example + +@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 +@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 +Stecils 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 +\markuplines @{ + \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 Taktzahlshould 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}. 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 @var{proc} für +jedes Layoutobjekt aufgerufen, dass im Kontext @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 +(ein @rinternals{Stem}-Objekt) ist es ein @rinternals{NoteHead}-Objekt. + +Hier ist eine Funktion, die mit @code{\applyOutput} benutzt +werden kann; sie macht Notenköpfe auf 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)) + (set! (ly:grob-property grob 'transparent) #t))) + +\relative { + e4 g8 \applyOutput #'Voice #blanker b d2 +} +@end lilypond + + +@node Scheme-Vorgänge als Eigenschaften +@section Scheme-Vorgänge als Eigenschaften +@translationof Scheme procedures as properties + +Eigenschaften (wie Dicke, Richtung 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, sobal der Wert der +Eigenschaft während das Formatierungsprozesses angefordert wird. + +Der größte Teil der Satzmaschinierie funtioniert mit derartigen +Callbacks. Eigenschaften, die üblicherweise Callbacks +benutzen, sind u. A.: + +@table @code +@item stencil + Die Druckfunktion, die eine Ausgabe des Symbols ervorruft +@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. + + +@node Scheme-Code anstelle von \tweak verwenden +@section Scheme-Code anstelle von @code{ weak} verwenden +@translationof Using Scheme code instead of \tweak + +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, und der letzte Teil eines gebrochenen Bindebogens wird +nach oben verschoben. + +@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:hairpin::after-line-breaking} 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, immernoch +innerhalb der @code{\context}-Umgebung funktioniert. + +@end itemize diff --git a/Documentation/de/extending/scheme-tutorial.itely b/Documentation/de/extending/scheme-tutorial.itely new file mode 100644 index 0000000000..ba1599fb88 --- /dev/null +++ b/Documentation/de/extending/scheme-tutorial.itely @@ -0,0 +1,350 @@ +@c -*- coding: utf-8; mode: texinfo; documentlanguage: de -*- + +@ignore + Translation of GIT committish: 5cf864d550e7148412d594cf336841791bff6f76 + + 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" + +@node Scheme-Übung +@appendix Scheme-Übung +@translationof Scheme tutorial + +@funindex # +@cindex Scheme +@cindex GUILE +@cindex Scheme, in einer LilyPond-Datei +@cindex LISP + +LilyPond verwendet die Scheme-Programmiersprache sowohl als Teil +der Eingabesyntax als auch als internen Mechanismus, um Programmmodule +zusammenzufügen. Dieser Abschnitt ist ein sehr kurzer Überblick über +die Dateneingabe mit Scheme. Wenn Sie mehr über Scheme wissen wollen, +gehen Sie zu @uref{http://@/www@/.schemers@/.org}. + +LilyPond benutzt die GNU Guile-Implementation von Scheme, die auf dem +@qq{R5RS}-Standard von Scheme basiert. Wenn Sie Scheme lernen wollen, +um es innerhalb von LilyPond zu benutzen, wird es nicht empfohlen, +mit einer anderen Implementation (die sich auf einen anderen +Standard bezieht) zu arbeiten. Information zu Guile findet sich +unter @uref{http://www.gnu.org/software/guile/}. Der +@qq{R5RS}-Standard von Scheme befindet sich unter der Adresse +@uref{http://www.schemers.org/Documents/Standards/R5RS/}. + +Die LilyPond-Installation enthält gleichzeitig auch die +Guile-Implemenation von Scheme. Auf den meisten Systemen kann +man in einer Scheme-sandbox experimentieren, indem man ein +Kommandozeilen-Fenster öffnet und @code{guile} auffruft. Unter +einigen Systemen, insbesondere unter Windows, muss man evtl. +die Umgebungsvariable @code{GUILE_LOAD_PATH} auf das Verzeichnis +@code{../usr/shr/guile/1.8} innerhalb des LilyPond-Installationsverzeichnisses +setzen (der vollständige Pfad ist erklärt in @ref{Other sources of information}). +Alternativ können Windows-Benutzer auch einfach @qq{Ausführen} im +Startmenü wählen und @code{guile} schreiben. + +Das Grundlegendste an einer Sprache sind Daten: Zahlen, Zeichen, +Zeichenketten, Listen usw. Hier ist eine Liste der Datentypen, die für +LilyPond-Eingabedateien relevant sind. + +@table @asis +@item Boolesche Variablen +Werte einer Booleschen Variable sind Wahr oder Falsch. Die Scheme-Entsprechung +für Wahr ist @code{#t} und für Falsch @code{#f}. +@funindex ##t +@funindex ##f + +@item Zahlen +Zahlen werden wie üblich eingegeben, @code{1} ist die (ganze) +Zahl Eins, während @code{-1.5} ist eine Gleitkommazahl (also +eine nicht-ganze). + +@item Zeichenketten +Zeichenketten werden in doppelte Anführungszeichen gesetzt: + +@example +"Das ist eine Zeichenkette" +@end example + +Zeichenketten können über mehrere Zeilen reichen: + +@example +"Das +ist +eine Zeichenkette" +@end example + +Anführungszeichen und neue Zeilen können auch mit sogenannten +Fluchtsequenzen eingefügt werden. Die Zeichenkette +@code{a sagt "b"} wird wie folgt eingegeben: + +@example +"a sagt \"b\"" +@end example + +Neue Zeilen und Backslashe werden mit @code{\n} bzw. @code{\\} +eingegeben. +@end table + +In einer Notationsdatei werden kleine Scheme-Abschnitte mit der +Raute (@code{#}) eingeleitet. Die vorigen Beispiele heißen also in +LilyPond: + +@example +##t ##f +#1 #-1.5 +#"Das ist eine Zeichenkette" +#"Das +ist +eine Zeichenkette" +@end example + +LilyPond-Kommentare (@code{%} oder @code{%@{ %@}}) können innerhalb +von Scheme-Code nicht benutzt werden. Kommentare in Guile Scheme +werden wie folgt notiert: + +@example +; Einzeiliges Kommentar + +#! + Guile-Stil Blockkommentar (nicht schachtelbar) + Diese Kommentare werden von Scheme-Programmierern + selten benutzt und nie im Quellcode + von LilyPond +!# ++@end example + +Merere aufeinander folgende Scheme-Ausdrücke in einer Notationsdatei +können kombiniert werden, wenn man @code{begin} einsetzt. Das +erlaubt es, die Anzahl an Rauten auf eins zu begrenzen. + +@example +#(begin + (define foo 0) + (define bar 1)) +@end example + +Wenn @code{#} von einer öffnenden Klammer, @code{(}, gefolgt wird, wie +in dem Beispiel oben, bleibt der Parser im Scheme-Modus bis eine +passende schließende Klammer, @code{)}, gefunden wird, sodass keine +weiteren @code{#}-Zeichen benötigt werden, um einen Scheme-Abschnitt +anzuzeigen. + +Für den Rest dieses Abschnitts nehmen wir an, dass die Daten immer in +einer LilyPond-Datei stehen, darum wird immer die Raute verwendet. + +Scheme kann verwendet werden, um Berechnungen durchzuführen. Es +verwendet eine @emph{Präfix}-Syntax. Um 1 und@tie{}2 zu addieren, muss +man @code{(+ 1 2)} schreiben, und nicht @math{1+2}, wie in traditioneller +Mathematik. + +@lisp +#(+ 1 2) + @result{} #3 +@end lisp + +Der Pfeil @result{} zeigt an, dass das Ergebnis der Auswertung von +@code{(+ 1 2)} @code{3}@tie{}ist. Berechnungen können geschachtelt +werden und das Ergebnis einer Berechnung kann für eine neue +Berechnung eingesetzt werden. + +@lisp +#(+ 1 (* 3 4)) + @result{} #(+ 1 12) + @result{} #13 +@end lisp + +Diese Berechnungen sind Beispiele von Auswertungen. Ein Ausdruck +wie @code{(* 3 4)} wird durch seinen Wert @code{12} ersetzt. Ähnlich +verhält es sich mit Variablen. Nachdem eine Variable definiert ist: + +@example +zwoefl = #12 +@end example + +@noindent +kann man sie in Ausdrücken weiterverwenden: + +@example +vierundzwanzig = #(* 2 zwoelf) +@end example + +@noindent +Die 24 wird in der Variablen @code{vierundzwanzig} gespeichert. +Die gleiche Zuweisung kann auch vollständig in Scheme geschrieben +werden: + +@example +#(define vierundzwanzig (* 2 zwoelf)) +@end example + +Der @emph{Name} einer Variable ist auch ein Ausdruck, genauso wie +eine Zahl oder eine Zeichenkette. Er wird wie folgt eingegeben: + +@example +#'vierundzwanzig +@end example + +@funindex #'symbol +@cindex Zitieren in Scheme + +Das Apostroph @code{'} verhindert, dass bei der Scheme-Auswertung + @code{vierundzwanzig} durch @code{24} ersetzt wird. Anstatt dessen erhalten + wir die Bezeichnung @code{vierundzwanzig}. + +Diese Syntax wird sehr oft verwendet, weil es manche +Einstellungsveränderungen erfordern, dass Scheme-Werte einer +internen Variable zugewiesen werden, wie etwa + +@example +\override Stem #'thickness = #2.6 +@end example + +Diese Anweisung verändert die Erscheinung der Notenhälse. Der Wert +@code{2.6} wird der Variable @code{thickness} (Dicke) eines +@code{Stem}-(Hals)-Objektes gleichgesetzt. +@code{thickness} wird relativ zu den Notenlinien errechnet, in diesem +Fall sind die Hälse also 2,6 mal so dick wie die Notenlinien. Dadurch +werden Hälse fast zweimal so dick dargestellt, wie sie normalerweise sind. +Um zwischen Variablen zu unterscheiden, die in den Quelldateien direkt +definiert werden (wie @code{vierundzwanzig} weiter oben), und zwischen denen, +die für interne Objekte zuständig sind, werden hier die ersteren +@qq{Bezeichner} genannt, die letzteren dagegen @qq{Eigenschaften}. +Das Hals-Objekt hat also eine @code{thickness}-Eigenschaft, während +@code{vierundzwanzig} ein Bezeichner ist. + +@cindex Eigenschaften versus Bezeichner +@cindex Bezeichner versus Eigenschaften + +Sowohl zweidimensionale Abstände (X- und Y-Koordinaten) als auch +Größen von Objekten (Intervalle mit linker und rechter Begrenzung) werden +als @code{pairs} (Paare) eingegeben. Ein Paar@footnote{In der +Scheme-Terminologie wird ein Paar @code{cons} genannt und seine +zwei Elemente @code{car} und @code{cdr}.} wird als @code{(erster . zweiter)} +eingegeben und sie müssen mit dem Apostroph eingeleitet werden, genauso +wie Symbole: + +@example +\override TextScript #'extra-offset = #'(1 . 2) +@end example + +Hierdurch wird das Paar (1, 2) mit der Eigenschaft @code{extra-offset} +des TextScript-Objektes verknüpft. Diese Zahlen werden in +Systembreiten gemessen, so dass der Befehl das Objekt eine Systembreite +nach rechts verschiebt und zwei Breiten nach oben. + +Die zwei Elemente eines Paares können von beliebigem Inhalt sein, etwa + +@example +#'(1 . 2) +#'(#t . #f) +#'("blah-blah" . 3.14159265) +@end example + +Eine Liste wird eingegeben, indem die Elemente der Liste in Klammern +geschrieben werden, mit einem Apostroph davor. Beispielsweise: + +@example +#'(1 2 3) +#'(1 2 "string" #f) +@end example + +Die ganze Zeit wurde hier schon Listen benutzt. Eine Berechnung, +wie @code{(+ 1 2)}, ist auch eine Liste (welche das Symbol @code{+} +und die Nummern 1 und@tie{}2 enthält. Normalerweise werden Listen +als Berechnungen interpretiert und der Scheme-Interpreter ersetzt +die Liste mit dem Ergebnis der Berechnung. Um eine Liste an sich +einzugeben, muss die Auswertung angehalten werden. Das geschieht, +indem der Liste ein Apostroph vorangestellt wird. Für Berechnungen +kann man also den Apostroph nicht verwenden. + +Innerhalb einer zitierten Liste (also mit Apostroph) muss man keine +Anführungszeichen mehr setzen. Im Folgenden ein Symbolpaar, eine +Symbolliste und eine Liste von Listen: + +@example +#'(stem . head) +#'(staff clef key-signature) +#'((1) (2)) +@end example + + + +@menu +* Optimierungen mit Scheme:: +@end menu + +@node Optimierungen mit Scheme +@appendixsec Optimierungen mit Scheme +@translationof Tweaking with Scheme + +Wir haben gesehen wie LilyPond-Eingabe massiv beeinflusst +werden kann, indem Befehle wie etwa +@code{\override TextScript #'extra-offset = ( 1 . -1)} +benutzt werden. Aber es wurde gezeigt, dass Scheme noch +mächtiger ist. Eine bessere Erklärung findet sich in der@ref{Scheme-Übung} und in +@ruser{Schnittstellen für Programmierer}. + +Scheme kann auch in einfachen @code{\override}-Befehlen +benutzt werden: + +TODO Find a simple example +@c This isn't a valid example with skylining +@c It works fine without padText -td + +@ignore +@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 +@end ignore + +Es kann auch benutzt werden, um Befehle zu erstellen: + +@c Check this is a valid example with skylining +@c It is - 'padding still works + +@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 + +Sogar ganze Musikausdrücke können eingefügt werden: + +@lilypond[quote,verbatim,ragged-right] +pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) +#{ + $x e8 a b $y b a e +#}) + +\relative c''{ + \pattern c8 c8\f + \pattern {d16 dis} { ais16-> b\p } +} +@end lilypond + + diff --git a/Documentation/de/learning/scheme-tutorial.itely b/Documentation/de/learning/scheme-tutorial.itely deleted file mode 100644 index ba1599fb88..0000000000 --- a/Documentation/de/learning/scheme-tutorial.itely +++ /dev/null @@ -1,350 +0,0 @@ -@c -*- coding: utf-8; mode: texinfo; documentlanguage: de -*- - -@ignore - Translation of GIT committish: 5cf864d550e7148412d594cf336841791bff6f76 - - 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" - -@node Scheme-Übung -@appendix Scheme-Übung -@translationof Scheme tutorial - -@funindex # -@cindex Scheme -@cindex GUILE -@cindex Scheme, in einer LilyPond-Datei -@cindex LISP - -LilyPond verwendet die Scheme-Programmiersprache sowohl als Teil -der Eingabesyntax als auch als internen Mechanismus, um Programmmodule -zusammenzufügen. Dieser Abschnitt ist ein sehr kurzer Überblick über -die Dateneingabe mit Scheme. Wenn Sie mehr über Scheme wissen wollen, -gehen Sie zu @uref{http://@/www@/.schemers@/.org}. - -LilyPond benutzt die GNU Guile-Implementation von Scheme, die auf dem -@qq{R5RS}-Standard von Scheme basiert. Wenn Sie Scheme lernen wollen, -um es innerhalb von LilyPond zu benutzen, wird es nicht empfohlen, -mit einer anderen Implementation (die sich auf einen anderen -Standard bezieht) zu arbeiten. Information zu Guile findet sich -unter @uref{http://www.gnu.org/software/guile/}. Der -@qq{R5RS}-Standard von Scheme befindet sich unter der Adresse -@uref{http://www.schemers.org/Documents/Standards/R5RS/}. - -Die LilyPond-Installation enthält gleichzeitig auch die -Guile-Implemenation von Scheme. Auf den meisten Systemen kann -man in einer Scheme-sandbox experimentieren, indem man ein -Kommandozeilen-Fenster öffnet und @code{guile} auffruft. Unter -einigen Systemen, insbesondere unter Windows, muss man evtl. -die Umgebungsvariable @code{GUILE_LOAD_PATH} auf das Verzeichnis -@code{../usr/shr/guile/1.8} innerhalb des LilyPond-Installationsverzeichnisses -setzen (der vollständige Pfad ist erklärt in @ref{Other sources of information}). -Alternativ können Windows-Benutzer auch einfach @qq{Ausführen} im -Startmenü wählen und @code{guile} schreiben. - -Das Grundlegendste an einer Sprache sind Daten: Zahlen, Zeichen, -Zeichenketten, Listen usw. Hier ist eine Liste der Datentypen, die für -LilyPond-Eingabedateien relevant sind. - -@table @asis -@item Boolesche Variablen -Werte einer Booleschen Variable sind Wahr oder Falsch. Die Scheme-Entsprechung -für Wahr ist @code{#t} und für Falsch @code{#f}. -@funindex ##t -@funindex ##f - -@item Zahlen -Zahlen werden wie üblich eingegeben, @code{1} ist die (ganze) -Zahl Eins, während @code{-1.5} ist eine Gleitkommazahl (also -eine nicht-ganze). - -@item Zeichenketten -Zeichenketten werden in doppelte Anführungszeichen gesetzt: - -@example -"Das ist eine Zeichenkette" -@end example - -Zeichenketten können über mehrere Zeilen reichen: - -@example -"Das -ist -eine Zeichenkette" -@end example - -Anführungszeichen und neue Zeilen können auch mit sogenannten -Fluchtsequenzen eingefügt werden. Die Zeichenkette -@code{a sagt "b"} wird wie folgt eingegeben: - -@example -"a sagt \"b\"" -@end example - -Neue Zeilen und Backslashe werden mit @code{\n} bzw. @code{\\} -eingegeben. -@end table - -In einer Notationsdatei werden kleine Scheme-Abschnitte mit der -Raute (@code{#}) eingeleitet. Die vorigen Beispiele heißen also in -LilyPond: - -@example -##t ##f -#1 #-1.5 -#"Das ist eine Zeichenkette" -#"Das -ist -eine Zeichenkette" -@end example - -LilyPond-Kommentare (@code{%} oder @code{%@{ %@}}) können innerhalb -von Scheme-Code nicht benutzt werden. Kommentare in Guile Scheme -werden wie folgt notiert: - -@example -; Einzeiliges Kommentar - -#! - Guile-Stil Blockkommentar (nicht schachtelbar) - Diese Kommentare werden von Scheme-Programmierern - selten benutzt und nie im Quellcode - von LilyPond -!# -+@end example - -Merere aufeinander folgende Scheme-Ausdrücke in einer Notationsdatei -können kombiniert werden, wenn man @code{begin} einsetzt. Das -erlaubt es, die Anzahl an Rauten auf eins zu begrenzen. - -@example -#(begin - (define foo 0) - (define bar 1)) -@end example - -Wenn @code{#} von einer öffnenden Klammer, @code{(}, gefolgt wird, wie -in dem Beispiel oben, bleibt der Parser im Scheme-Modus bis eine -passende schließende Klammer, @code{)}, gefunden wird, sodass keine -weiteren @code{#}-Zeichen benötigt werden, um einen Scheme-Abschnitt -anzuzeigen. - -Für den Rest dieses Abschnitts nehmen wir an, dass die Daten immer in -einer LilyPond-Datei stehen, darum wird immer die Raute verwendet. - -Scheme kann verwendet werden, um Berechnungen durchzuführen. Es -verwendet eine @emph{Präfix}-Syntax. Um 1 und@tie{}2 zu addieren, muss -man @code{(+ 1 2)} schreiben, und nicht @math{1+2}, wie in traditioneller -Mathematik. - -@lisp -#(+ 1 2) - @result{} #3 -@end lisp - -Der Pfeil @result{} zeigt an, dass das Ergebnis der Auswertung von -@code{(+ 1 2)} @code{3}@tie{}ist. Berechnungen können geschachtelt -werden und das Ergebnis einer Berechnung kann für eine neue -Berechnung eingesetzt werden. - -@lisp -#(+ 1 (* 3 4)) - @result{} #(+ 1 12) - @result{} #13 -@end lisp - -Diese Berechnungen sind Beispiele von Auswertungen. Ein Ausdruck -wie @code{(* 3 4)} wird durch seinen Wert @code{12} ersetzt. Ähnlich -verhält es sich mit Variablen. Nachdem eine Variable definiert ist: - -@example -zwoefl = #12 -@end example - -@noindent -kann man sie in Ausdrücken weiterverwenden: - -@example -vierundzwanzig = #(* 2 zwoelf) -@end example - -@noindent -Die 24 wird in der Variablen @code{vierundzwanzig} gespeichert. -Die gleiche Zuweisung kann auch vollständig in Scheme geschrieben -werden: - -@example -#(define vierundzwanzig (* 2 zwoelf)) -@end example - -Der @emph{Name} einer Variable ist auch ein Ausdruck, genauso wie -eine Zahl oder eine Zeichenkette. Er wird wie folgt eingegeben: - -@example -#'vierundzwanzig -@end example - -@funindex #'symbol -@cindex Zitieren in Scheme - -Das Apostroph @code{'} verhindert, dass bei der Scheme-Auswertung - @code{vierundzwanzig} durch @code{24} ersetzt wird. Anstatt dessen erhalten - wir die Bezeichnung @code{vierundzwanzig}. - -Diese Syntax wird sehr oft verwendet, weil es manche -Einstellungsveränderungen erfordern, dass Scheme-Werte einer -internen Variable zugewiesen werden, wie etwa - -@example -\override Stem #'thickness = #2.6 -@end example - -Diese Anweisung verändert die Erscheinung der Notenhälse. Der Wert -@code{2.6} wird der Variable @code{thickness} (Dicke) eines -@code{Stem}-(Hals)-Objektes gleichgesetzt. -@code{thickness} wird relativ zu den Notenlinien errechnet, in diesem -Fall sind die Hälse also 2,6 mal so dick wie die Notenlinien. Dadurch -werden Hälse fast zweimal so dick dargestellt, wie sie normalerweise sind. -Um zwischen Variablen zu unterscheiden, die in den Quelldateien direkt -definiert werden (wie @code{vierundzwanzig} weiter oben), und zwischen denen, -die für interne Objekte zuständig sind, werden hier die ersteren -@qq{Bezeichner} genannt, die letzteren dagegen @qq{Eigenschaften}. -Das Hals-Objekt hat also eine @code{thickness}-Eigenschaft, während -@code{vierundzwanzig} ein Bezeichner ist. - -@cindex Eigenschaften versus Bezeichner -@cindex Bezeichner versus Eigenschaften - -Sowohl zweidimensionale Abstände (X- und Y-Koordinaten) als auch -Größen von Objekten (Intervalle mit linker und rechter Begrenzung) werden -als @code{pairs} (Paare) eingegeben. Ein Paar@footnote{In der -Scheme-Terminologie wird ein Paar @code{cons} genannt und seine -zwei Elemente @code{car} und @code{cdr}.} wird als @code{(erster . zweiter)} -eingegeben und sie müssen mit dem Apostroph eingeleitet werden, genauso -wie Symbole: - -@example -\override TextScript #'extra-offset = #'(1 . 2) -@end example - -Hierdurch wird das Paar (1, 2) mit der Eigenschaft @code{extra-offset} -des TextScript-Objektes verknüpft. Diese Zahlen werden in -Systembreiten gemessen, so dass der Befehl das Objekt eine Systembreite -nach rechts verschiebt und zwei Breiten nach oben. - -Die zwei Elemente eines Paares können von beliebigem Inhalt sein, etwa - -@example -#'(1 . 2) -#'(#t . #f) -#'("blah-blah" . 3.14159265) -@end example - -Eine Liste wird eingegeben, indem die Elemente der Liste in Klammern -geschrieben werden, mit einem Apostroph davor. Beispielsweise: - -@example -#'(1 2 3) -#'(1 2 "string" #f) -@end example - -Die ganze Zeit wurde hier schon Listen benutzt. Eine Berechnung, -wie @code{(+ 1 2)}, ist auch eine Liste (welche das Symbol @code{+} -und die Nummern 1 und@tie{}2 enthält. Normalerweise werden Listen -als Berechnungen interpretiert und der Scheme-Interpreter ersetzt -die Liste mit dem Ergebnis der Berechnung. Um eine Liste an sich -einzugeben, muss die Auswertung angehalten werden. Das geschieht, -indem der Liste ein Apostroph vorangestellt wird. Für Berechnungen -kann man also den Apostroph nicht verwenden. - -Innerhalb einer zitierten Liste (also mit Apostroph) muss man keine -Anführungszeichen mehr setzen. Im Folgenden ein Symbolpaar, eine -Symbolliste und eine Liste von Listen: - -@example -#'(stem . head) -#'(staff clef key-signature) -#'((1) (2)) -@end example - - - -@menu -* Optimierungen mit Scheme:: -@end menu - -@node Optimierungen mit Scheme -@appendixsec Optimierungen mit Scheme -@translationof Tweaking with Scheme - -Wir haben gesehen wie LilyPond-Eingabe massiv beeinflusst -werden kann, indem Befehle wie etwa -@code{\override TextScript #'extra-offset = ( 1 . -1)} -benutzt werden. Aber es wurde gezeigt, dass Scheme noch -mächtiger ist. Eine bessere Erklärung findet sich in der@ref{Scheme-Übung} und in -@ruser{Schnittstellen für Programmierer}. - -Scheme kann auch in einfachen @code{\override}-Befehlen -benutzt werden: - -TODO Find a simple example -@c This isn't a valid example with skylining -@c It works fine without padText -td - -@ignore -@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 -@end ignore - -Es kann auch benutzt werden, um Befehle zu erstellen: - -@c Check this is a valid example with skylining -@c It is - 'padding still works - -@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 - -Sogar ganze Musikausdrücke können eingefügt werden: - -@lilypond[quote,verbatim,ragged-right] -pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) -#{ - $x e8 a b $y b a e -#}) - -\relative c''{ - \pattern c8 c8\f - \pattern {d16 dis} { ais16-> b\p } -} -@end lilypond - - diff --git a/Documentation/de/notation.tely b/Documentation/de/notation.tely index 8a455c1e27..fc43361fa5 100644 --- a/Documentation/de/notation.tely +++ b/Documentation/de/notation.tely @@ -241,7 +241,8 @@ Anhänge @include notation/spacing.itely @include notation/changing-defaults.itely -@include notation/programming-interface.itely +@c @include notation/programming-interface.itely +@c moved to extending.tely @include notation/notation-appendices.itely diff --git a/Documentation/de/notation/programming-interface.itely b/Documentation/de/notation/programming-interface.itely deleted file mode 100644 index a2cc7683f4..0000000000 --- a/Documentation/de/notation/programming-interface.itely +++ /dev/null @@ -1,1633 +0,0 @@ -@c -*- coding: utf-8; mode: texinfo; -*- - -@ignore - Translation of GIT committish: 7b70644b95f383b4281e9ffa146d315d2ada11d3 - - 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 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 -@rlearning{Scheme-Übung}. - -@menu -* Musikalische Funktionen:: -* Schnittstelle für Programmierer:: -* Komplizierte Funktionen erstellen:: -* Programmierungsschnittstelle für Textbeschriftungen:: -* Kontexte für Programmierer:: -* Scheme-Vorgänge als Eigenschaften:: -* Scheme-Code anstelle von \tweak verwenden:: -* 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 - -Es ist einfach, eine Funktion zu erstellen, die Variablen -im LilyPond-Code ersetzt. Die allgemeine Form derartiger -Funktionen ist - -@example -function = -#(define-music-function (parser location @var{var1} @var{var2}...@var{vari}... ) - (@var{var1-type?} @var{var2-type?}...@var{vari-type?}...) - #@{ - @emph{...Noten...} - #@}) -@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 - -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. - -@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 - -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 Einfache Ersetzungsfunktionen -@subsection Einfache Ersetzungsfunktionen -@translationof Simple substitution functions - -Hier ist ein einfaches Beispiel: - -@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 - - -@node Paarige Ersetzungsfunktionen -@subsection Paarige Ersetzungsfunktionen -@translationof Paired substitution functions - -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. - -@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 -@} -@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 -} - -{ c'2 \AltOn #0.5 c'4 c' - \AltOn #1.5 c' c' \AltOff c'2 } -@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 #}) - -{ 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. - -@example -noPointAndClick = -#(define-music-function (parser location) () - (ly:set-option 'point-and-click #f) - (make-music 'SequentialMusic 'void #t)) -... -\noPointAndClick % disable point and click -@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: - -@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 Ü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 - - - -@node Schnittstelle für Programmierer -@section Schnittstelle für Programmierer -@translationof Programmer interfaces - -Dieser Abschnitt zeigt, wie LilyPond und -Scheme gemischt werden können. - -@menu -* Eingabevariablen und Scheme:: -* Interne Repräsentation der Musik:: -@end menu - - -@node Eingabevariablen und Scheme -@subsection Eingabevariablen und Scheme -@translationof Input variables and Scheme - -Das Eingabeformat unterstützt die Notation von Variablen: im -folgenden Beispiel wird ein musikalischer Ausdruck einer Variable -mit der Bezeichnung @code{traLaLa} zugewiesen: - -@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{... }'}) -@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 - -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: - -@example -#(define (nopc) - (ly:set-option 'point-and-click #f)) - -... -#(nopc) -@{ c'4 @} -@end example - -@knownissues - -Scheme- und LilyPond-Variablen können im LilyPond-Modus mit der -@code{--safe}-Option nicht vermischt werden. - - -@node Interne Repräsentation der Musik -@subsection Interne Repräsentation der Musik -@translationof Internal music representation - -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. - -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}. - -@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}. - -@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)))) -@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. - -@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: - -@example -#(display-scheme-music - (ly:music-property (first (ly:music-property someNote 'elements)) - 'pitch)) -===> -(ly:make-pitch 0 0 0) -@end example - -Die Tonhöhe einer Note kann geändert werden, indem man diese -@code{'pitch}-Eigenschaft umdefiniert: - -@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 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: - -@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 - -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. - -Jetzt folgt eine Betrachtung der Eingabe: - -@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)))))) -@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 - - -@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. - -Eine @code{$variable} innerhalb von @code{#@{...#@}} ist das -gleiche wie die normale Befehlsform @code{\variable} in -üblicher LilyPond-Notation. Es ist bekannt dass - -@example -@{ \music -. -> @} -@end example - -@noindent -in LilyPond nicht funktioniert. Das Problem könnte vermieden -werden, indem das Artikulationszeichen an eine Pseudonote -gehängtwird: - -@example -@{ << \music s1*0-.-> @} -@end example - -@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 - -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. - -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 - -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). - -@example -"Add a marcato..." -@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. - -@example -(let ((result-event-chord (ly:music-deep-copy event-chord))) -@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: - -@example -(set! place new-value) -@end example - -Was in diesem Fall @qq{gesetzt} werden soll (@qq{place}) ist die -@q{elements}-Eigenschaft des @code{result-event-chord}-Ausdrucks. - -@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: - -@example -(cons (make-music 'ArticulationEvent - 'articulation-type "marcato") - (ly:music-property result-event-chord 'elements)) -@end example - -@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. - -Jetzt wird die @code{add-marcato}-Funktion in eine musikalische -Funktion umgewandelt: - -@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 - -Eine Überprüfung, dass die Funktion richtig arbeitet, geschieht -folgendermaßen: - -@example -\displayMusic \addMarcato c4 -@end example - - -@node Programmierungsschnittstelle für Textbeschriftungen -@section Programmierungsschnittstelle für Textbeschriftungen -@translationof Markup programmer interface - -Textbeschriftungselemente sind als besondere Scheme-Funktionen -definiert, die ein 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:: -@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{\Befehl} @tab @code{#:Befehl} -@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ächt 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 - -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?} ...) - ..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 -die @q{layout}-Definition -@item props -eine Liste an alists, in der alle aktiven Eigenschaften enthalten sind -@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: - -@example -\markup @{ \override #'(font-shape . caps) Text-in-Kapitälchen @} -@end example - -@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. - -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: - -@example -(define-markup-command (smallcaps layout props argument) (markup?) -@end example - -@noindent - -Was jetzt folgt, ist der eigentliche Inhalt des Befehls: das -@code{argument} soll als Beschriftung (markup) interpretiert werden, -also: - -@example -(interpret-markup layout @dots{} argument) -@end example - -@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: - -@example -(cons (list '(font-shape . caps) ) props) -@end example - -@noindent -Die Variable @code{props} ist eine Liste an alists, und mit @code{cons} -wird ihr eine zusätzliche Einstellung hinzugefügt. - -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: - -@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\"" - (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) -@end example - -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. - -Das Resultat sieht folgendermaßen aus: - -@example -@{ - c''^\markup \character #"Cleopatra" - e'^\markup \character #"Giulio Cesare" -@} -@end example - -@lilypond[quote,ragged-right] -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps. Syntax: \\smallcaps #\"string\"" - (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\"" - (interpret-markup layout props - (markup #:hspace 0 #:translate (cons -3 1) #:smallcaps name))) - -{ - c''^\markup \character #"Cleopatra" c'' c'' c'' - e'^\markup \character #"Giulio Cesare" e' e' e' -} -@end lilypond - -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: - -@example -#(define-markup-command (smallcaps layout props str) (string?) - "Print the string argument in small caps." - (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 - -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}. - -@knownissues - -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 - -@noindent -Hier stellt @var{scm} native Scheme-Datentypen dar wie -@q{number} oder @q{string}. - -Es ist beispielsweise nicht möglich, einen Beschriftungsbefehl -@code{foo} mit vier Argumenten in folgender Weise zu nutzen: - -@example -#(define-markup-command (foo layout props - num1 str1 num2 str2) - (number? string? number? string?) - ...) -@end example - -@noindent -Wenn es folgendermaßen eingesetzt wird: - -@example -\markup \foo #1 #"bar" #2 #"baz" -@end example - -@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 -@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 -Stecils 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 -\markuplines @{ - \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 Taktzahlshould 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}. 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 @var{proc} für -jedes Layoutobjekt aufgerufen, dass im Kontext @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 -(ein @rinternals{Stem}-Objekt) ist es ein @rinternals{NoteHead}-Objekt. - -Hier ist eine Funktion, die mit @code{\applyOutput} benutzt -werden kann; sie macht Notenköpfe auf 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)) - (set! (ly:grob-property grob 'transparent) #t))) - -\relative { - e4 g8 \applyOutput #'Voice #blanker b d2 -} -@end lilypond - - -@node Scheme-Vorgänge als Eigenschaften -@section Scheme-Vorgänge als Eigenschaften -@translationof Scheme procedures as properties - -Eigenschaften (wie Dicke, Richtung 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, sobal der Wert der -Eigenschaft während das Formatierungsprozesses angefordert wird. - -Der größte Teil der Satzmaschinierie funtioniert mit derartigen -Callbacks. Eigenschaften, die üblicherweise Callbacks -benutzen, sind u. A.: - -@table @code -@item stencil - Die Druckfunktion, die eine Ausgabe des Symbols ervorruft -@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. - - -@node Scheme-Code anstelle von \tweak verwenden -@section Scheme-Code anstelle von @code{ weak} verwenden -@translationof Using Scheme code instead of \tweak - -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, und der letzte Teil eines gebrochenen Bindebogens wird -nach oben verschoben. - -@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:hairpin::after-line-breaking} 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, immernoch -innerhalb der @code{\context}-Umgebung funktioniert. - -@end itemize