B.4.3 Neue Definitionen von Beschriftungsbefehlen
Neue Textbeschriftungsbefehle können mit dem
define-markup-command
-Scheme-Makro definiert werden.
(define-markup-command (befehl-bezeichnung layout props arg1 arg2 ...) (arg1-type? arg2-type? ...) ..Befehlkörper..) |
Die Argumente sind:
- argi
ite Befehlsargument
- argi-type?
eine Eigenschaft für das ite Argument
- layout
die ‚layout‘-Definition
- props
eine Liste an alists, in der alle aktiven Eigenschaften enthalten sind
Als einfaches Beispiel soll gezeigt werden, wie man einen
\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:
\markup { \override #'(font-shape . caps) Text-in-Kapitälchen }
Damit wird die Kapitälchenschriftart ausgewählt, indem die
font-shape
-Eigesnchaft auf #'caps
gesetzt wird,
während Text-in-caps
interpretiert wird.
Damit diese Funkion als \smallcaps
-Befehl zur Verfügung
gestellt werden kann, muss eine Funktion mit define-markup-command
definiert werden. Der Befehl braucht ein Argument vom Typ markup
.
Darum sollte der Beginn der Funktion lauten:
(define-markup-command (smallcaps layout props argument) (markup?)
Was jetzt folgt, ist der eigentliche Inhalt des Befehls: das
argument
soll als Beschriftung (markup) interpretiert werden,
also:
(interpret-markup layout … argument)
Diese Interpretation sollte '(font-shape . caps)
zu den
aktiven Eigenschaften hinzufügen, weshalb wir das Folgende anstelle
der … in dem Beispiel einfügen:
(cons (list '(font-shape . caps) ) props)
Die Variable props
ist eine Liste an alists, und mit 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 \character
-Befehl
definieren, der die nötige Verschiebung berücksichtigt und
den neuen \smallcaps
-Befehl einsetzt:
#(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)))
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 „padding“
bezeichnet). Um sicherzugehen, dass dieser Mechanismus nicht die
vertikale Verschiebung von #:translate
annulliert, wird
die leere Zeichenkette (#:hspace 0
) vor den zu verschiebenden
Text gesetzt. Das #:hspace 0
wird jetzt also über die Noten
gesetzt und name
dann relativ zu der leeren Zeichenkette
verschoben. Im Endeffekt wird der Text nach links oben verschoben.
Das Resultat sieht folgendermaßen aus:
{ c''^\markup \character #"Cleopatra" e'^\markup \character #"Giulio Cesare" }
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:
#(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)))))
Der smallcaps
-Befehl spaltet die Argumente zuerst in
Einzelstücke auf, die von Leerzeichen getrennt sind
((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
(#:large (string-upcase (substring s 0 1))
), und eine
zweite Versalbuchstaben gesetzt werden
(#:tiny (string-upcase (substring s 1))
). Wenn
LilyPond ein Leerzeichen zwischen Beschriftungen einer Zeile
entdeckt, wird die zweite Beschriftung nach links verschoben
(#:translate (cons -0.6 0) ...
). Dann werden die
Beschriftungen für jedes Einzelstück in eine Zeile gesetzt
(make-line-markup ...)
. Schließlich wird die resultierende
Beschriftung an die interpret-markup
-Funktion zusammen
mit den Argumenten layout
und props
weitergereicht.
Achtung: ist gibt keinen internen Befehl \smallCaps
, der
benutzt werden kann, um Text in Kapitälchen zu setzen. Siehe auch
@ref{Text markup commands}.
Bekannte Probleme und Warnungen
Im Moment sind die möglichen Kombinationen von Argumenten (nach den
Standardargumenten layout und props), die mit
define-markup-command
definiert werden, wie folgt
limitiert:
- (kein Argument)
- list
- markup
- markup markup
- scm
- scm markup
- scm scm
- scm scm markup
- scm scm markup markup
- scm markup markup
- scm scm scm
Hier stellt scm native Scheme-Datentypen dar wie ‚number‘ oder ‚string‘.
Es ist beispielsweise nicht möglich, einen Beschriftungsbefehl
foo
mit vier Argumenten in folgender Weise zu nutzen:
#(define-markup-command (foo layout props num1 str1 num2 str2) (number? string? number? string?) ...)
Wenn es folgendermaßen eingesetzt wird:
\markup \foo #1 #"bar" #2 #"baz"
beschwert sich lilypond
, dass foo
wegen einer ungekannten
Scheme Signatur nicht analysiert werden kann.