| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Markup functions
Les markups sont implémentés au travers de fonctions Scheme
spécifiques qui produisent des objets Stencil comprenant un
certain nombre d’arguments.
| 2.5.1 Construction d’un markup en Scheme | ||
| 2.5.2 Fonctionnement interne des markups | ||
| 2.5.3 Définition d’une nouvelle commande de markup | ||
| 2.5.4 Définition d’une nouvelle commande de liste de markups |
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Markup construction in Scheme
Les expressions markup sont représentées en Scheme de manière
interne par la macro markup :
(markup expression) |
La commande \displayScheme permet d’obtenir la représentation en
Scheme d’une expression markup :
\displayScheme
\markup {
\column {
\line { \bold \italic "hello" \raise #0.4 "world" }
\larger \line { foo bar baz }
}
}
|
Compiler ce code renverra en console les lignes suivantes :
(markup
#:line
(#:column
(#:line
(#:bold (#:italic "hello") #:raise 0.4 "world")
#:larger
(#:line
(#:simple "foo" #:simple "bar" #:simple "baz")))))
|
L’impression du markup sera suspendue dès lors qu’apparaîtra un
‘\void \displayScheme markup’. Tout comme pour la
commande \displayMusic, le résultat de \displayScheme peut
être sauvegardé dans un fichier séparé. Voir à ce sujet
Affichage d’expressions musicales.
Vous pouvez constater les principales règles de traduction entre les
syntaxes respectives de LilyPond et de Scheme en matière de
markup. Bien que le passage en syntaxe LilyPond grâce à
#{ … #} apporte de la souplesse, nous allons voir comment
utiliser la macro markup en Scheme exclusivement.
LilyPond Scheme \markup markup1(markup markup1)\markup { markup1 markup2… }(markup markup1 markup2… )\commande-markup#:commande-markup\variablevariable\center-column { … }#:center-column ( … )chaîne"chaîne"#argument-schemeargument-scheme
L’intégralité du langage Scheme est accessible à l’intérieur même de la
macro markup. Vous pouvez ainsi appeler des fonctions à partir
de markup pour manipuler des chaînes de caractères, ce qui est
particulièrement pratique lorsque vous créez votre propre commande de
markup – voir
Définition d’une nouvelle commande de markup.
L’argument markup-list des commandes #:line,
#:center ou #:column ne saurait être une variable ni le
résultat de l’appel à une fonction.
(markup #:line (fonction-qui-retourne-des-markups)) |
n’est pas valide. Il vaut mieux, en pareil cas, utiliser les fonctions
make-line-markup, make-center-markup ou
make-column-markup :
(markup (make-line-markup (fonction-qui-retourne-des-markups))) |
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof How markups work internally
Dans un markup tel que
\raise #0.5 "text example" |
\raise représente en fait la fonction raise-markup.
L’expression markup est enregistrée sous la forme
(list raise-markup 0.5 (list simple-markup "text example")) |
Lorsque ce markup est converti en objets imprimables (stencils),
la fonction raise-markup est appelée ainsi :
(apply raise-markup
\layout objet
liste des alists de propriété
0.5
le markup "text example")
|
La fonction raise-markup commence par créer le stencil pour la
chaîne text example, puis remonte ce stencil d’un demi espace de
portée. Il s’agit là d’un exemple relativement simple, et nous en
aborderons de plus complexes au fil des paragraphes suivants ;
d’autres exemples se trouvent directement dans le fichier
‘scm/define-markup-commands.scm’.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof New markup command definition
Nous allons étudier dans ce qui suit la manière de définir une nouvelle commande de markup.
| Syntaxe d’une commande markup | ||
| Attribution de propriétés | ||
| Exemple commenté | ||
| Adaptation d’une commande incorporée |
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Markup command definition syntax
Une commande de markup personnalisée se définit à l’aide de la
macro Scheme define-markup-command, placée en tête de fichier.
(define-markup-command (nom-commande layout props arg1 arg2…)
(arg1-type? arg2-type?…)
[ #:properties ((propriété1 valeur-par-défaut1)
…) ]
…corps de la commande…)
|
Quelques commentaires sur les arguments :
nom-commandele nom que vous attribuez à votre commande de markup.
layoutla définition du « layout » – son formatage.
propsune liste de listes associatives, comprenant toutes les propriétés actives.
argile ième argument de la commande.
argi-type?un type de prédicat pour le ième argument.
Si la commande utilise des propriétés à partir des arguments
props, le mot-clé #:properties permet de spécifier ces
différentes propriétés ainsi que leur valeur par défaut.
Les arguments se distinguent selon leur type :
markup? ;
markup-list? ;
list?, number?, boolean?, etc.
Il n’existe aucune restriction quant à l’ordre des arguments fournis à
la suite des arguments layout et props. Néanmoins, les
fonctions markup qui ont en dernier argument un markup ont
ceci de particulier qu’elles peuvent s’appliquer à des listes de
markups ; ceci résultera en une liste de markups où
tous les éléments de la liste originelle se verront appliquer cette
fonction markup avec ses arguments de tête.
La réplication des arguments de tête dans le but d’appliquer une fonction markup à une liste de markups est économique, principalement lorsqu’il s’agit d’arguments Scheme. Vous éviterez ainsi d’éventuelles pertes de performance en utilisant des arguments Scheme en tant qu’arguments principaux d’une fonction markup dont le dernier argument est un markup.
Les commandes de markup ont un cycle de vie relativement
complexe. Le corps de la définition d’une commande de markup est
chargé de convertir les arguments de la commande en expression stencil
qui sera alors renvoyée. Bien souvent, ceci s’accomplit par un appel à
la fonction interpret-markup, en lui passant les arguments
layout et props. Ces arguments ne seront en principe connus
que bien plus tardivement dans le processus typographique. Lors de
l’expansion d’une expression LilyPond \markup ou d’une macro
Scheme markup, les expressions markup auront déjà vu leurs
composants assemblés en expressions markup. L’évaluation et le
contrôle du type des arguments à une commande de markup
n’interviennent qu’au moment de l’interprétation de \markup ou
markup.
Seule l’application de interpret-markup sur une expression
markup réalisera effectivement la conversion des expressions
markup en stencil, au travers de l’exécution du corps des
fonctions markup.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof On properties
Les arguments layout et props d’une commande de
markup fournissent un contexte à l’interprétation du
markup : taille de fonte, longueur de ligne, etc.
L’argument layout permet d’accéder aux propriétés définies dans
les blocs \paper, grâce à la fonction
ly:output-def-lookup. Par exemple, la longueur de ligne,
identique à celle de la partition, est lue au travers de
(ly:output-def-lookup layout 'line-width) |
L’argument props rend certaines propriétés accessibles aux
commandes de markup. Il en va ainsi lors de l’interprétation
d’un markup de titre d’ouvrage : toutes les variables
définies dans le bloc \header sont automatiquement ajoutées aux
props, de telle sorte que le markup de titrage de
l’ouvrage pourra accéder aux différents champs titre, compositeur, etc.
Ceci permet aussi de configurer le comportement d’une commande de
markup : la taille des fontes, par exemple, est lue à
partir de props plutôt que grâce à un argument font-size.
La fonction appelant une commande de markup peut altérer la
valeur de la propriété taille des fontes et donc en modifier le
comportement. L’utilisation du mot-clé #:properties, attaché à
define-markup-command, permet de spécifier les propriétés devant
être lues parmi les arguments props.
L’exemple proposé à la rubrique suivante illustre comment, au sein d’une commande de markup, accéder aux différentes propriétés et les modifier.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof A complete example
Nous allons, dans cet exemple, nous attacher à encadrer du texte avec un double liseré.
Commençons par construire quelque chose d’approximatif à l’aide d’un
simple markup. La lecture de
(notation)Commandes pour markup section ‘Commandes pour markup’ dans Manuel de notation nous
indique la commande \box, qui semble ici appropriée.
\markup \box \box HELLO
Dans un souci d’esthétique, nous aimerions que le texte et les
encadrements ne soient pas autant accolés. Selon la documentation de
\box, cette commande utilise la propriété box-padding,
fixée par défaut à 0,2. Cette même documentation nous indique
aussi comment la modifier :
\markup \box \override #'(box-padding . 0.6) \box A
L’espacement des deux liserés est cependant toujours trop réduit ; modifions le à son tour :
\markup \override #'(box-padding . 0.4) \box \override #'(box-padding . 0.6) \box A
Vous conviendrez que recopier une telle définition de markup
deviendra vite fastidieux. C’est pourquoi nous écrivons la commande de
markup double-box qui prendra un seul argument – le
texte. Cette commande se chargera de dessiner les encadrements, en
tenant compte des espacements.
#(define-markup-command (double-box layout props text) (markup?)
"Dessine un double encadrement autour du texte."
(interpret-markup layout props
#{\markup \override #'(box-padding . 0.4) \box
\override #'(box-padding . 0.6) \box { #text }#}))
|
ou bien son équivalent
#(define-markup-command (double-box layout props text) (markup?)
"Dessine un double encadrement autour du texte."
(interpret-markup layout props
(markup #:override '(box-padding . 0.4) #:box
#:override '(box-padding . 0.6) #:box text)))
|
text est le nom de l’argument de notre commande, et
markup? son type – l’argument sera identifié comme étant un
markup. La fonction interpret-markup, utilisée dans la
plupart des commandes de markup, construira un stencil à partir
de layout, props et un markup. Dans la seconde
variante, ce markup sera construit à l’aide de la macro Scheme
markup – voir Construction d’un markup en Scheme. La
transformation d’une expression \markup en expression Scheme est
des plus triviales.
Notre commande personnalisée s’utilise ainsi :
\markup \double-box A |
Il serait intéressant de rendre cette commande double-box plus
souple : les valeurs de box-padding sont figées et ne
peuvent être modifiées à l’envie. Pareillement, il serait bien de
distinguer l’espacement entre les encadrements de l’espacement entre le
texte et ses encadrements. Nous allons donc introduire une propriété
supplémentaire, que nous appellerons inter-box-padding, chargée
de gérer l’espacement des encadrements ; box-padding ne
servira alors que pour l’espacement intérieur. Voici le code adapté à
ces évolutions :
#(define-markup-command (double-box layout props text) (markup?)
#:properties ((inter-box-padding 0.4)
(box-padding 0.6))
"Dessine un double encadrement autour du texte."
(interpret-markup layout props
#{\markup \override #`(box-padding . ,inter-box-padding) \box
\override #`(box-padding . ,box-padding) \box
{ #text } #}))
|
Ainsi que son équivalent à partir de la macro markup :
#(define-markup-command (double-box layout props text) (markup?)
#:properties ((inter-box-padding 0.4)
(box-padding 0.6))
"Dessine un double encadrement autour du texte."
(interpret-markup layout props
(markup #:override `(box-padding . ,inter-box-padding) #:box
#:override `(box-padding . ,box-padding) #:box text)))
|
C’est ici le mot-clé #:properties qui permet de lire les
propriétés inter-box-padding et box-padding à partir de
l’argumenet props ; on leur a d’ailleurs fourni des valeurs
par défaut au cas où elles ne seraient pas définies.
Ces valeurs permettront alors d’adapter les propriétés de
box-padding utilisées par les deux commandes \box. Vous
aurez remarqué, dans l’argument \override, la présence de
l’apostrophe inversée (`) et de la virgule ; elles vous
permettent d’insérer une valeur variable au sein d’une expression
littérale.
Notre commande est maintenant prête à servir dans un markup, et les encadrements sont repositionnables.
#(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
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Adapting builtin commands
Le meilleur moyen de construire ses propres commandes de markup consiste à prendre exemple sur les commandes déjà incorporées. La plupart des commandes de markup fournies avec LilyPond sont répertoriées dans le fichier ‘scm/define-markup-commands.scm’.
Nous pourrions, par exemple, envisager d’adapter la commande
\draw-line pour dessiner plutôt une ligne double. Voici comment
est définie la commande \draw-line, expurgée de sa
documentation :
(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)))
|
Avant de définir notre propre commande basée sur l’une de celles
fournies par LilyPond, commençons par en recopier la définition, puis
attribuons lui un autre nom. Le mot-clé #:category peut être
supprimé sans risque ; il ne sert que lors de la génération de la
documentation et n’est d’aucune utilité pour une commande personnalisée.
(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)))
|
Nous ajoutons ensuite une propriété pour gérer l’écart entre les deux
lignes, que nous appelons line-gap, et lui attribuons une valeur
par défaut de 6 dixièmes :
(define-markup-command (draw-double-line layout props dest)
(number-pair?)
#:properties ((thickness 1)
(line-gap 0.6))
"…documentation…"
…
|
Nous ajoutons enfin le code qui dessinera nos deux lignes. Deux appels
à make-line-stencil permettrons de dessiner les lignes dont nous
regrouperons les stencils à l’aide de ly:stencil-add :
#(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)
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof New markup list command definition
Une commande traitant une liste de markups se définit à l’aide de
la macro Scheme define-markup-list-command, de manière analogue à
la macro define-markup-command abordée à la rubrique
Définition d’une nouvelle commande de markup, à ceci près que
cette dernière renvoie un seul stencil, non une liste de stencils.
La fonction interpret-markup-list, à l’instar de la fonction
interpret-markup, permet de convertir une liste de markups
en liste de stencils.
Dans l’exemple suivant, nous définissons \paragraph, une commande
de liste de markups, qui renverra une liste de lignes justifiées
dont la première sera indentée. La largeur de l’alinéa sera récupérée
par l’argument props.
#(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 } #}))
|
La version purement Scheme est un peu plus complexe :
#(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))))
|
En dehors des habituels arguments layout et props, la
commande de liste de markups paragraph prend en argument
une liste de markups appelée args. Le prédicat des listes
de markups est markup-list?.
Pour commencer, la fonction récupère la taille de l’alinéa, propriété
ici dénommée par-indent, à partir de la liste de propriétés
props. En cas d’absence, la valeur par défaut sera
de 2. Ensuite est créée une liste de lignes justifiées
grâce à la commande prédéfinie \justified-lines, liée à la
fonction make-justified-lines-markup-list. Un espace horizontal
est ajouté en tête, grâce à \hspace ou à la fonction
make-hspace-markup. Enfin, la liste de markups est
interprétée par la fonction interpret-markup-list.
Voici comment utiliser cette nouvelle commande de liste de markups :
\markuplist {
\paragraph {
The art of music typography is called \italic {(plate) engraving.}
The term derives from the traditional process of music printing.
Just a few decades ago, sheet music was made by cutting and stamping
the music into a zinc or pewter plate in mirror image.
}
\override-lines #'(par-indent . 4) \paragraph {
The plate would be inked, the depressions caused by the cutting
and stamping would hold ink. An image was formed by pressing paper
to the plate. The stamping and cutting was completely done by
hand.
}
}
|
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] |
Ce document a été généré le le 13 juillet 2020 par gub en utilisant texi2html 1.82.
Autres langues : English, deutsch, español.
À propos de la sélection automatique de la langue.