[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

2.5 Textbeschriftungsfunktionen

@translationof Markup functions

Textbeschriftungselemente sind als besondere Scheme-Funktionen definiert, die ein Stencil-Objekt erstellen, dem eine Anzahl an Argumenten übergeben wird.


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

2.5.1 Beschriftungskonstruktionen in Scheme

@translationof Markup construction in Scheme

Das markup-(Textbeschriftungs)Makro erstellt Textbeschriftungs-Ausdrücke in Scheme, wobei eine LilyPond-artige Syntax benutzt wird. Beispielsweise ist

 
(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world")
                  #:larger #:line ("foo" "bar" "baz")))

identisch mit

 
#{ \markup \column { \line { \bold \italic "hello" \raise #0.4 "world" }
                  \larger \line { foo bar baz } } #}

Dieses Beispiel zeigt die hauptsächlichen Übersetzungsregeln zwischen normaler Textbeschriftungssyntax von LilyPond und der Textbeschriftungssyntax in Scheme. Es ist meistens der beste Weg, #{ … #} zur Eingabe von LilyPond-Syntax zu benützen, aber es soll auch erklärt werden, wie man das markup-Makro einsetzt, um eine Lösung nur in Scheme zu bekommen.

LilyPondScheme
\markup Text1(markup Text1)
\markup { Text1 Text2 ... }(markup Text1 Text2 ... )
\Beschriftungsbefehl#:Beschriftungsbefehl
\VariableVariable
\center-column { ... }#:center-column ( ... )
Zeichenkette"Zeichenkette"
#scheme-Argscheme-Arg

Die gesamte Scheme-Sprache ist innerhalb des markup-Makros zugänglich. Man kann also beispielsweise Funktionen innerhalb eines markup aufrufen, um Zeichenketten zu manipulieren. Das ist nützlich, wenn neue Beschriftungsbefehle definiert werden sollen (siehe auch Neue Definitionen von Beschriftungsbefehlen).

Bekannte Probleme und Warnungen

Das Beschriftungslistenargument von Befehlen wie #:line, #:center und #:column kann keine Variable oder das Resultat eines Funktionsaufrufen sein.

 
(markup #:line (Funktion-die-Textbeschriftung-ausgibt))

ist ungültig. Man sollte anstatt dessen die Funktionen make-line-markup, make-center-markup oder make-column-markup benutzen:

 
(markup (make-line-markup (Funktion-die-Textbeschriftung-ausgibt)))

[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

2.5.2 Wie Beschriftungen intern funktionieren

@translationof How markups work internally

In einer Textbeschriftung wie

 
\raise #0.5 "Textbeispiel"

ist \raise unter der Haube durch die raise-markup-Funktion repräsentiert. Der Beschriftungsausdruck wird gespeichert als

 
(list raise-markup 0.5 (list simple-markup "Textbeispiel"))

Wenn die Beschriftung in druckbare Objekte (Stencils) umgewandelt ist, wir die raise-markup-Funktion folgendermaßen aufgerufen:

 
(apply raise-markup
       \layout object
       Liste der Eigenschafts-alists
       0.5
       die "Textbeispiel"-Beschriftung)

Die raise-markup-Funktion erstellt zunächst den Stencil für die 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 ‘scm/define-markup-commands.scm’.


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

2.5.3 Neue Definitionen von Beschriftungsbefehlen

@translationof New markup command definition

Dieser Abschnitt behandelt die Definition von neuen Textbeschriftungsbefehlen.


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

Syntax der Definition von Textbeschriftungsbefehlen

@translationof Markup command definition syntax

Neue Textbeschriftungsbefehle können mit dem define-markup-command-Scheme-Makro definiert werden.

 
(define-markup-command (befehl-bezeichnung layout props Arg1 Arg2 ...)
            (Arg1-typ? Arg2-typ? ...)
    [ #:properties ((Eigenschaft1 Standard-Wert1)
                    ...) ]
  ..Befehlkörper..)

Die Argumente sind:

befehl-bezeichnung

die Bezeichnung des Befehls

layout

die ‚layout‘-Definition

props

eine Liste an assoziativen Listen, in der alle aktiven Eigenschaften enthalten sind

argi

das ite Befehlsargument

argi-type?

eine Eigenschaft für das ite Argument

Wenn der Befehl Eigenschaften des props-Arguments benutzt, kann das #:properties-Schlüsselwort benutzt werden um zu bestimmen, welche Eigenschaften mit welchen Standard-Werten benutzt werden.

Argumente werden nach ihrem Typ unterschieden:

Es gibt keine Einschränkung in der Reihenfolge der Argumente (nach den Standard-Argumenten layout und props). Textbeschriftungsfunktionen, die als letztes Argument eine Textbeschriftung haben, haben die Besonderheit, dass sie auf Textbeschriftungslisten angewendet werden können, und das Resultat ist eine Textbeschriftungsliste, in der die Textbeschriftungsfuktion (mit den angegebenen Argumenten am Anfang) auf jedes Element der originalen Textbeschriftungsliste angewendet wurde.

Da das Wiederholen der Argumente am Anfang bei der Anwendung einer Textbeschriftungsfunktion auf eine Textbeschriftungsliste for allem für Scheme-Argumente sparsam ist, kann man Leistungseinbußen vermeiden, indem man nur Scheme-Argumente für die Argumente am Anfang einsetzt, wenn es sich um Textbeschriftungsfunktionen handelt, die eine Textbeschriftung als letztes Argument haben.


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

Über Eigenschaften

@translationof On properties

Die layout- und props-Argumente der Textbeschriftungsbefehle bringen einen Kontext für die Interpretation der Beschriftung: Schriftgröße, Zeilenlänge usw.

Das layout-Argument greift auf Eigenschaften zu, die in der paper-Umgebung definiert werden, indem man die ly:output-def-lookup-Funktion benutzt. Beispielsweise liest man die Zeilenlänge (die gleiche, die auch in Partituren benutzt wird) aus mit:

 
(ly:output-def-lookup layout 'line-width)

Das props-Argument stellt einige Eigenschaften für die Textbeschriftungsbefehle zur Verfügung. Beispielsweise wenn der Überschrifttext einer book-Umgebung interpretiert wird, werden alle Variablen, die in der \header-Umgebung definiert werden, automatisch zu props hinzugefügt, sodass die Beschriftung auf Titel, Komponist usw. der book-Umgebung zugreifen kann. Das ist auch eine Möglichkeit, das Verhalten eines Beschriftungsbefehls zu konfigurieren: Wenn etwa ein Befehl die Schriftgröße während der Verarbeitung einsetzt, wird die Schriftgröße aus den props ausgelesen und nicht mit einem eigenen font-size-Argument definiert. Beim Aufruf des Beschriftungsbefehls kann der Wert der Schriftgröße geändert werden, womit sich auch das Verhalten des Befehls verändert. Benutzen Sie das #:properties-Schlüsselwort von define-markup-command um zu definieren, welche Eigenschaften aus den props-Argumenten ausgelesen werden sollen.

Das Beispiel im nächsten Abschnitt illustriert, wie man auf Eigenschaften in einem Beschriftungsbefehl zugreifen und sie verändern kann.


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

Ein vollständiges Bespiel

@translationof A complete example

Das folgende Beispiel definiert einen Beschriftungsbefehl, der einen doppelten Kasten um einen Text zeichnet.

Zuerst wollen wir ein annäherndes Ergebnis mit Textbeschriftungen definieren. Nach Stöbern in (notation)Textbeschriftungsbefehle in Abschnitt ‘Textbeschriftungsbefehle’ in Notationsreferenz finden wir den Befehl \box:

 
\markup \box \box HELLO

[image of music]

Wir wollen aber etwas mehr Abstand (engl. padding) zwischen dem Text und dem Kasten. Nach der Dokumentation von \box hat der Befehl eine box-padding-Eigenschaft, die den Standardwert von 0.2 hat. Die Dokumentation zeit auch, wir man den Wert verändert:

 
\markup \box \override #'(box-padding . 0.6) \box A

[image of music]

Auch der Abstand zwischen den zwei Kästen ist uns zu klein und soll auch vergrößert werden:

 
\markup \override #'(box-padding . 0.4) \box
    \override #'(box-padding . 0.6) \box A

[image of music]

Diese lange Textbeschriftung immer wieder schreiben zu müssen, ist anstrengend. Hier kömmt ein Textbeschriftungsbefehl ins Spiel. Wir schreiben uns alle einen double-box-Beschriftungsbefehl, der ein Argument annimmt (den Text). Er zeichnet zwei Kästen mit genügend Abstand:

 
#(define-markup-command (double-box layout props text) (markup?)
  "Draw a double box around text."
  (interpret-markup layout props
    #{\markup \override #'(box-padding . 0.4) \box
            \override #'(box-padding . 0.6) \box { #text }#}))

oder äquivalent

 
#(define-markup-command (double-box layout props text) (markup?)
  "Draw a double box around text."
  (interpret-markup layout props
    (markup #:override '(box-padding . 0.4) #:box
            #:override '(box-padding . 0.6) #:box text)))

text ist die Bezeichnung des Arguments dieses Befehls, und markup? ist seine Art: hiermit wird der Befehl als Beschriftungsbefehl identifiziert. Die interpret-markup-Funktion wird in den meisten Beschriftungsbefehlen benutzt: sie erstellt einen Stencil, wobei layout, props und eine Beschriftung benutzt werden. Im zweiten Fall wird diese Beschriftung durch das markup-Scheme-Makro erstellt, siehe auche Beschriftungskonstruktionen in Scheme. Die Transformation des \markup-Ausdrucks in einen Scheme-Beschriftungsausdruck geschieht durch Umschreiben des LilyPond-Codes in Scheme-Code.

Der neue Befehl kann wie folgt benutzt werden:

 
\markup \double-box A

Es wäre schön, den double-box-Befehl noch konfigurierbar zu gestalten: in unserem Fall sind die Werte von box-padding direkt definiert und können nicht mehr vom Benutzer verändert werden. Es wäre auch besser, wenn der Abstand zwischen den beiden Kästen vom Abstand zwischen dem inneren Kasten und dem Text unterschieden werden könnte. Eine neue Eigenschaft muss also definiert werden: inter-box-padding für den Abstand zwischen den Kästen. box-padding wird für den inneren Abstand benutzt. Der neue Befehl wird so definiert:

 
#(define-markup-command (double-box layout props text) (markup?)
  #:properties ((inter-box-padding 0.4)
                (box-padding 0.6))
  "Draw a double box around text."
  (interpret-markup layout props
    #{\markup \override #`(box-padding . ,inter-box-padding) \box
               \override #`(box-padding . ,box-padding) \box
               { #text } #}))

Wiederum wäre die entsprechende Version mit dem markup-Makro so aussehen:

 
#(define-markup-command (double-box layout props text) (markup?)
  #:properties ((inter-box-padding 0.4)
                (box-padding 0.6))
  "Draw a double box around text."
  (interpret-markup layout props
    (markup #:override `(box-padding . ,inter-box-padding) #:box
            #:override `(box-padding . ,box-padding) #:box text)))

In diesem Code wird das #:properties-Schlüsselwort benutzt, sodass die Eigenschaften inter-box-padding und box-padding aus dem props-Argument ausgelesen werden, und Standardwerte werden gegeben, falls die Eigenschaften nicht definiert sein sollten.

Dann werden diese Werte benutzt, um die box-padding-Eigenschaft zu verändert, die von beiden \box-Befehlen benutzt wird. Beachten Sie Akzent und das Komma des \override-Arguments: hiermit kann man einen Variablenwert in einen wörtlichen Ausdruck überführen.

Jetzt kann der Befehl in Beschriftungen benutzt werden und der Abstand der Kästen kann angepasst werden:

 
#(define-markup-command (double-box layout props text) (markup?)
  #:properties ((inter-box-padding 0.4)
                (box-padding 0.6))
  "Draw a double box around text."
  (interpret-markup layout props
    #{\markup \override #`(box-padding . ,inter-box-padding) \box
              \override #`(box-padding . ,box-padding) \box
              { #text } #}))

\markup \double-box A
\markup \override #'(inter-box-padding . 0.8) \double-box A
\markup \override #'(box-padding . 1.0) \double-box A

[image of music]


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

Eingebaute Befehle anpassen

@translationof Adapting builtin commands

Ein guter Weg, einen neuen Beschriftungsbefehl zu schreiben, ist es, als Vorbild einen existierenden zu nehmen. Die meisten Beschriftungsbefehle, die LilyPond mitbringt, finden sich in der Datei ‘scm/define-markup-commands.scm’.

Man könnte beispielsweise den Befehl \draw-line, der eine Linie zeichnet, anpassen, sodass er eine Doppellinie zeichnet. Der Befehl \draw-line ist wie folgend definiert (Dokumentation entfernt):

 
(define-markup-command (draw-line layout props dest)
  (number-pair?)
  #:category graphic
  #:properties ((thickness 1))
  "..documentation.."
  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
               thickness))
        (x (car dest))
        (y (cdr dest)))
    (make-line-stencil th 0 0 x y)))

Um einen neuen Befehl, der auf einem existierenden basiert, zu definieren, wird die Befehlsdefinition kopiert und die Bezeichnung des Befehls geändert. Das #:category-Schlagwort kann entfernt werden, weil es nur zur Erstellung der LilyPond-Dokumentation eingesetzt wird und keine Bedeutung für selbstdefinierte Befehle hat.

 
(define-markup-command (draw-double-line layout props dest)
  (number-pair?)
  #:properties ((thickness 1))
  "..documentation.."
  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
               thickness))
        (x (car dest))
        (y (cdr dest)))
    (make-line-stencil th 0 0 x y)))

Dann braucht man eine Eigenschaft, um den Abstand zwischen den zwei Linien zu definieren, als line-gap bezeichnet und etwa mit dem Standardwert 0.6:

 
(define-markup-command (draw-double-line layout props dest)
  (number-pair?)
  #:properties ((thickness 1)
                (line-gap 0.6))
  "..documentation.."
  ...

Schließlich wird der Code, der die zwei Linien zeichnet, hinzugefügt. Zwei Aufrufe an make-line-stencil werden benutzt, um beide Linien zu zeichnen, und die beiden sich daraus ergebenden Stencils werden mit ly:stencil-add kombiniert:

 
#(define-markup-command (my-draw-line layout props dest)
  (number-pair?)
  #:properties ((thickness 1)
                (line-gap 0.6))
  "..documentation.."
  (let* ((th (* (ly:output-def-lookup layout 'line-thickness)
                thickness))
         (dx (car dest))
         (dy (cdr dest))
         (w (/ line-gap 2.0))
         (x (cond ((= dx 0) w)
                  ((= dy 0) 0)
                  (else (/ w (sqrt (+ 1 (* (/ dx dy) (/ dx dy))))))))
         (y (* (if (< (* dx dy) 0) 1 -1)
               (cond ((= dy 0) w)
                     ((= dx 0) 0)
                     (else (/ w (sqrt (+ 1 (* (/ dy dx) (/ dy dx))))))))))
     (ly:stencil-add (make-line-stencil th x y (+ dx x) (+ dy y))
                     (make-line-stencil th (- x) (- y) (- dx x) (- dy y)))))

\markup \my-draw-line #'(4 . 3)
\markup \override #'(line-gap . 1.2) \my-draw-line #'(4 . 3)

[image of music]


[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]         [Anfang] [Inhalt] [Index] [ ? ]

2.5.4 Neue Definitionen von Beschriftungslistenbefehlen

@translationof New markup list command definition

Beschriftungslistenbefehle können mit dem Scheme-Makro define-markup-list-command definiert werden, welches sich ähnlich verhält wie das define-markup-command-Makro, das schon beschrieben wurde in Neue Definitionen von Beschriftungsbefehlen. Ein Unterschied ist, dass bei diesem Listen-Makro eine ganze Liste an Stencils ausgegeben wird.

Im folgenden Beispiel wird ein \paragraph-Beschriftungslistenbefehl definiert, welcher eine Liste von Zeilen im Blocksatz ausgibt, von denen die erste Zeile eingerückt ist. Der Einzug wird aus dem props-Argument entnommen.

 
#(define-markup-list-command (paragraph layout props args) (markup-list?)
   #:properties ((par-indent 2))
   (interpret-markup-list layout props
     #{\markuplist \justified-lines { \hspace #par-indent #args } #}))

Die Version nur in Scheme ist etwas komplexer:

 
#(define-markup-list-command (paragraph layout props args) (markup-list?)
   #:properties ((par-indent 2))
   (interpret-markup-list layout props
     (make-justified-lines-markup-list (cons (make-hspace-markup par-indent)
                                             args))))

Neben den üblichen layout und props-Argumenten nimmt der paragraph-Beschriftungslistenbefehl als Argument eine Beschriftungsliste, die args genannt wird. Das Prädikat für Beschriftungslisten ist markup-list?.

Zuerst errechnet die Funktion die Breite des Einzugs, eine Eigenschaft mit der Bezeichnung par-indent anhand der Eigenschaftsliste props. Wenn die Eigenschaft nicht gefunden wird, ist der Standardwert 2. Danach wird eine Liste von Zeilen im Blocksatz erstellt, wobei der eingebaute \justified-lines-Beschriftungslistenbefehl eingesetzt wird, der verwandt ist mit der make-justified-lines-markup-list-Funktion. Horizontaler Platz wird zu Beginn eingefügt mit \hspace (oder der make-hspace-markup-Funktion). Zuletzt wird die Beschriftungsliste ausgewertet durch die interpret-markup-list-Funktion.

Dieser neue Beschriftungslistenbefehl kann wie folgt benutzt werden:

 
\markuplist {
  \paragraph {
    Die Kunst des Notensatzes wird auch als \italic {Notenstich} bezeichnet. Dieser
    Begriff stammt aus dem traditionellen Notendruck. Noch bis vor etwa
    20 Jahren wurden Noten erstellt, indem man sie in eine Zink- oder
    Zinnplatte schnitt oder mit Stempeln schlug.
  }
  \override-lines #'(par-indent . 4) \paragraph {
    Diese Platte wurde dann mit Druckerschwärze versehen, so dass sie
    in den geschnittenen und gestempelten Vertiefungen blieb. Diese
    Vertiefungen schwärzten dann ein auf die Platte gelegtes Papier.
    Das Gravieren wurde vollständig von Hand erledigt.
  }
}

[ < ] [ > ]   [ << ] [ Nach oben ] [ >> ]

Dieses Dokument wurde erzeugt von gub am 13. Juli 2020 durch texi2html 1.82.

Andere Sprachen: English, español, français.
Über die automatische Sprachauswahl.