@c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*-

@ignore
   Translation of GIT committish: a5cf37bc53f57635bf984ecc2d1c5a067573b87c

   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.23.6"

@c Translators: Valentin Villenave, Jean-Charles Malahieude
@c Translation checkers: Gilles Thibault


@node Interfaces pour programmeurs
@chapter Interfaces pour programmeurs
@translationof Interfaces for programmers

Scheme permet de réaliser des affinages très pointus.  Si vous ne
connaissez rien de Scheme, vous en aurez un aperçu au travers de notre
@ref{Tutoriel Scheme}.

@menu
* Blocs de code LilyPond::
* Fonctions Scheme::
* Fonctions musicales::
* Fonctions événementielles::
* Fonctions pour markups::
* Contextes pour programmeurs::
* Fonctions de rappel::
* Conteneurs requalifiants::
* Retouches complexes::
@end menu


@node Blocs de code LilyPond
@section Blocs de code LilyPond
@translationof LilyPond code blocks

@cindex code, blocs LilyPond
@cindex LilyPond, bloc de code

@funindex #@{ ... #@}
@funindex $
@funindex #

L'utilisation de Scheme pour créer des expressions musicales peut
s'avérer ardue, principalement à cause des imbrications et de la
longueur du code Scheme qui en résulte.  Dans le cas de tâches
simples, on peut toutefois contourner une partie du problème en
utilisant des blocs de code LilyPond, ce qui autorise la syntaxe
habituelle de LilyPond au sein même de Scheme.

Les blocs de code LilyPond ressemblent à

@example
  #@{ @var{du code LilyPond} #@}
@end example

En voici un exemple basique :

@lilypond[verbatim,quote]
ritpp = #(define-event-function () ()
  #{ ^"rit." \pp #}
)

{ c'4 e'4\ritpp g'2 }
@end lilypond

Les blocs de code LilyPond peuvent s'utiliser partout où vous pouvez
écrire du code Scheme.  Le lecteur Scheme est en fait quelque peu adapté
pour accepter des blocs de code LilyPond ; il est capable de traiter des
expressions Scheme intégrées débutant par @code{$} ou @code{#}.

Le lecteur Scheme extrait le bloc de code LilyPond et déclenche un appel
à l'analyseur grammatical de LilyPond (le @emph{parser}) qui réalise en
temps réel l'interprétation de ce bloc de code LilyPond.  Toute
expression Scheme imbriquée est exécutée dans l'environnement lexical du
bloc de code LilyPond, de telle sorte que vous avez accès aux variables
locales et aux paramètres de la fonction au moment même où le bloc de
code LilyPond est écrit.  Les variables définies dans d'autres modules
Scheme, tels ceux contenant les blocs @code{\header} ou @code{\layout},
ne sont pas accessibles en tant que variables Scheme (préfixées par
un @code{#}) mais en tant que variables LilyPond (préfixées par
un @code{\}).

Toute la musique générée au sein de ce bloc de code voit son
@code{origine} établie à cet @emph{emplacement}.

Un bloc de code LilyPond peut contenir tout ce que vous pourriez mettre
à droite de l'assignation.  Par ailleurs, un bloc LilyPond vide
correspond à une expression fantôme, et un bloc LilyPond de multiples
événements musicaux sera transformé en une expression de musique
séquentielle.


@node Fonctions Scheme
@section Fonctions Scheme
@translationof Scheme functions

@cindex Scheme, fonctions (syntaxe LilyPond)

Les @emph{fonctions Scheme} sont des procédures Scheme chargées de créer
des expressions Scheme à partir de code rédigé selon la syntaxe de
LilyPond.  Elles peuvent être appelées en de nombreux endroits, à l'aide
d'un @code{#}, où spécifier une valeur en syntaxe Scheme est autorisé.
Bien que Scheme dispose de fonctions en propre, nous nous intéresserons,
au fil des paragraphes qui suivent, aux fonctions @emph{syntaxiques},
autrement dit des fonctions qui reçoivent des arguments libellés dans la
syntaxe de LilyPond.

@menu
* Définition de fonctions Scheme::
* Utilisation de fonctions Scheme::
* Fonctions Scheme fantômes::
@end menu


@node Définition de fonctions Scheme
@subsection Définition de fonctions Scheme
@translationof Scheme function definitions

@funindex define-scheme-function

D'une manière générale, une fonction Scheme se définit ainsi :

@example
fonction =
#(define-scheme-function
     (@var{arg1} @var{arg2}@dots{})
     (@var{type1?} @var{type2?}@dots{})
   @var{corps})
@end example

@noindent
où

@multitable @columnfractions .33 .66
@item @code{@var{argN}}
@tab @var{n}-ième argument.

@item @code{@var{typeN?}}
@tab un @emph{type de prédicat} Scheme pour lequel @code{@var{argN}}
devra retourner @code{#t}.  Il existe aussi une forme spécifique --
@code{(@emph{prédicat?} @emph{default})} -- qui permet de fournir des
argument optionnels.  En l'absence d'argument réel au moment de l'appel
à la fonction, c'est la valeur par défaut qui lui sera substituée.  Les
valeurs par défaut sont évaluées dès l'apparition de la définition, y
compris dans le cas de blocs de code LilyPond ; vous devrez donc,
si ces valeurs par défaut ne peuvent être déterminées que plus tard,
mentionner une valeur spéciale que vous reconnaîtrez facilement.
Lorsque vous mentionnez un prédicat entre parenthèses sans toutefois
fournir sa valeur par défaut, celle-ci sera considérée comme
étant @code{#f}.  Les valeurs par défaut d'un @code{prédicat?} ne sont
vérifiées ni au moment de la définition, ni à l'exécution ; il est
de votre ressort de gérer les valeurs que vous spécifiez.  Une valeur
par défaut constituée d'une expression musicale est recopiée dès la
définition de @code{origin} à l'emplacement courant du code.

@item @code{@var{corps}}
@tab une séquence de formules Scheme évaluées dans l'ordre, la dernière
servant de valeur de retour de la fonction. Il peut contenir des blocs
de code LilyPond, enchâssés dans des accolades et @emph{hashes} --
@w{@code{#@{@dots{}#@}}} -- comme indiqué à la rubrique
@ref{Blocs de code LilyPond}.  Au sein d'un bloc de code LilyPond, un
@code{#} permet de référencer des arguments de la fonction -- tel
@samp{#arg1} -- ou d'ouvrir une expression Scheme contenant les
arguments de la fonction -- par exemple @w{@samp{#(cons arg1 arg2)}}.
Dans le cas où une expression Scheme introduite par @code{#} ne vous
permet pas de parvenir à vos fins, vous pourriez devoir revenir à une
expression Scheme « immédiate » à l'aide d'un @code{$}, comme
@samp{$music}.

Lorsque votre fonction retourne une expression musicale, lui est
attribuée la valeur @code{origin}.
@end multitable

@noindent
La recevabilité des arguments est déterminée par un appel effectif au
prédicat après que LilyPond les a déjà convertis en expression Scheme.
Par voie de conséquence, l'argument peut tout à fait se libeller en
syntaxe Scheme -- introduite par un @code{#} ou en tant que résultat
d'un appel à une fonction Scheme.  Par ailleurs, LilyPond convertira en
Scheme un certain nombre de constructions purement LilyPond avant même
d'en avoir vérifié le prédicat.  C'est notamment le cas de la musique,
des @emph{postévénements}, des chaînes simples (avec ou sans
guillemets), des nombres, des @emph{markups} et listes de
@emph{markups}, ainsi que des blocs @emph{score}, @emph{book},
@emph{bookpart}, ou qui définissent un contexte ou un format de sortie.

Il existe certaines situations pour lesquelles LilyPond lèvera toute
ambiguïté grâce aux fonctions de prédicat : un @samp{-3} est-il un
@emph{postévénement} de type doigté ou un nombre négatif ?  Un
@code{"a" 4} en mode paroles est-il une chaîne suivie d'un nombre ou
bien un événement syllabe de durée @code{4} ?  LilyPond répondra à ces
questions par des interprétations successives du prédicat de l'argument,
dans un ordre défini de sorte à minimiser les interprétations erronées
et le besoin de lecture en avance.

Un prédicat qui accepte par exemple aussi bien une expression musicale
qu'une hauteur considèrera @code{c''} comme étant une hauteur plutôt
qu'une expression musicale.  Les durées ou @emph{postévénements} qui
viennent juste après viendront modifier cette interprétation.  C'est la
raison pour laquelle il vaut mieux éviter des prédicats par trop
permissifs tel que @code{Scheme?} lorsque l'application fait plutôt
appel à des types d'argument plus spécifiques.

Les différents types de prédicat propres à LilyPond sont recensés à
l'annexe @ruser{Types de prédicats prédéfinis}.

@morerefs
Manuel de notation :
@ruser{Types de prédicats prédéfinis}.

Fichiers d'initialisation :
@file{lily/music-scheme.cc},
@file{scm/c++.scm},
@file{scm/lily.scm}.
@endmorerefs


@node Utilisation de fonctions Scheme
@subsection Utilisation de fonctions Scheme
@translationof Scheme function usage

Vous pouvez appeler une fonction Scheme pratiquement partout où une
expression Scheme derrière un @code{#} peut prendre place.  Vous appelez
une fonction Scheme à partir de LilyPond en faisant précéder son nom
d'un @code{\}, et en le faisant suivre de ses arguments.  Lorsqu'un
prédicat d'argument optionnel ne correspond pas à un argument, LilyPond
l'ignore ainsi que tous les arguments optionnels qui suivent, les
remplaçant par leur valeur par défaut, et « sauvegarde » en tant que
prochain argument obligatoire l'argument qui ne correspondait pas.  Dans
la mesure où l'argument sauvegardé doit servir, les argument optionnels
ne sont en fait pas considérés comme optionnels, sauf à être suivis d'un
argument obligatoire.

Une exception cependant à cette règle : le fait de donner un
@code{\default} en tant qu'argument optionnel aura pour résultat que cet
argument et tous les autres arguments optionnels qui suivent seront
ignorés et remplacés par leur valeur par défaut.  Il en va de même
lorsqu'aucun argument obligatoire ne suit, du fait que @code{\default}
ne requiert pas de sauvegarde.  C'est d'ailleurs ainsi que fonctionnent
les commandes @code{mark} et @code{key}, qui retrouvent leur
comportement par défaut lorsque vous les faites suivre d'un
@code{\default}.

En plus de là où une expression Scheme est requise, il y a quelques
endroits où des expressions @code{#} sont acceptées et évaluées
uniquement pour leurs effets annexes.  Il s'agit, dans la plupart des
cas, d'endroits où une affectation serait tout à fait envisageable.

Dans la mesure où il n'est pas bon de renvoyer une valeur qui pourrait
être mal interprétée dans certains contextes, nous vous enjoignons à
utiliser des fonctions Scheme normales uniquement dans les cas où vous
renvoyez toujours une valeur utile, et une fonction fantôme -- voir
@ref{Fonctions Scheme fantômes} -- dans le cas contraire.

Pour des raisons de commodité, il est possible de faire appel à des
fonctions Scheme directement en Scheme, courcircuitant ainsi l'analyseur
de LilyPond.  Leur nom s'utilise comme n'importe quel nom de fonction.
Le contrôle de typologie des arguments et l'omission des arguments
optionnels seront traîtés de la même manière que lorsque l'appel est
fait à partir de LilyPond, la valeur Scheme @code{*unspecified*} ayant
le rôle du mot réservé @code{\default} pour omettre explicitement les
arguments optionnels. Les arguments optionnels en fin de liste
d'arguments peuvent être omsi sans plus d'indication lorsque l'appel est
fait au sein même de Scheme.


@node Fonctions Scheme fantômes
@subsection Fonctions Scheme fantômes
@translationof Void scheme functions

@cindex @emph{void}, fonction
@cindex fantôme, fonction

@funindex define-void-function
@funindex \void

Il arrive qu'une procédure soit exécutée pour réaliser une action, non
pour renvoyer une valeur.  Certains langages de programmation, tels
le C et Scheme, utilisent des fonctions dans les deux cas et se
débarrassent tout bonnement de la valeur renvoyée ; en règle
générale, il suffit que l'expression fasse office de déclaration, et
d'ignorer le résultat.  C'est futé, mais pas sans risque d'erreur :
la plupart des compilateurs C actuels déclenchent un avertissement si
l'on se débarrasse de certaines expressions non @emph{void}.  Pour de
nombreuses fonctions réalisant une action, les standards Scheme
déclarent que la valeur de retour est indéfinie.  L'interpréteur Guile
qu'utilise le Scheme de LilyPond dispose d'une valeur unique
@code{*unspecified*} qu'il retourne alors, en règle générale -- notamment
lorsqu'on utilise @code{set!} directement sur une variable -- mais
malheureusement pas toujours.

Une fonction LilyPond définie à l'aide de la clause
@code{define-void-function} vous apporte l'assurance que c'est cette
valeur spéciale -- la seule valeur qui satisfasse au prédicat
@code{void?} -- qui sera retournée.

@example
noPointAndClick =
#(define-void-function
     ()
     ()
   (ly:set-option 'point-and-click #f))
@dots{}
\noPointAndClick   % desactive le "pointer-cliquer"
@end example

L'utilisation d'un préfixe @code{\void} permet ainsi d'évaluer une
expression pour ses effets annexes sans interprétation d'une quelconque
valeur de retour :

@example
\void #(hashq-set! une-table une-clé une-valeur)
@end example

Vous serez alors assuré que LilyPond ne tentera pas d'affecter un sens à
la valeur de retour, à quelque endroit qu'elle ressorte.  Ceci est aussi
opérationnel dans le cadre de fonctions musicales telles que
@code{\displayMusic}.


@node Fonctions musicales
@section Fonctions musicales
@translationof Music functions

@cindex musicale, fonction

Les @emph{fonctions musicales} sont des procédures Scheme capables de
créer automatiquement des expressions musicales ; elles permettent
de grandement simplifier un fichier source.

@menu
* Définition de fonctions musicales::
* Utilisation de fonctions musicales::
* Fonctions de substitution simple::
* Fonctions de substitution intermédiaires::
* De l'usage des mathématiques dans les fonctions::
* Fonctions dépourvues d'argument::
* Fonctions musicales fantômes::
@end menu


@node Définition de fonctions musicales
@subsection Définition de fonctions musicales
@translationof Music function definitions

@cindex fonction musicale, définition

@funindex define-music-function

Une fonction musicale se définit ainsi :

@example
fonction =
#(define-music-function
     (@var{arg1} @var{arg2}@dots{})
     (@var{type1?} @var{type2?}@dots{})
   @var{corps})
@end example

@noindent
de manière similaire aux @ref{Définition de fonctions Scheme, fonctions
Scheme}.  La plupart du temps, le @var{corps} sera constitué d'un
@ref{Blocs de code LilyPond, bloc de code LilyPond}.

Les différents types des prédicat sont recensés à l'annexe
@ruser{Types de prédicats prédéfinis}.

@morerefs
Manuel de notation :
@ruser{Types de prédicats prédéfinis}.

Fichiers d'initialisation :
@file{lily/music-scheme.cc},
@file{scm/c++.scm},
@file{scm/lily.scm}.
@endmorerefs


@node Utilisation de fonctions musicales
@subsection Utilisation de fonctions musicales
@translationof Music function usage

En ce qui concerne la gestion des listes d'argments, les fonctions
musicales ne diffèrent en rien des fonction Scheme -- voir
@ref{Utilisation de fonctions Scheme}.

Une « fonction musicale » doit impérativement renvoyer une expression
répondant au prédicat @code{ly:music?}.  Ceci a pour conséquence
d'autoriser l'appel à une fonction musicale en tant qu'argument de type
@code{ly:music?} dans le cadre de l'appel à une autre fonction musicale.

Certaines restrictions s'appliqueront selon le contexte où une fonction
musicale est utilisée, de telle sorte que l'analyse syntaxique soit sans
ambiguïté.

@itemize
@item
Dans une expression musicale de haut niveau, aucun postévénement n'est
toléré.

@item
Lorsqu'une fonction musicale -- contrairement à une fonction
événementielle -- renvoie une expression de type postévénement, LilyPond
requiert son introduction par un indicateur de positionnement -- à
savoir @code{-}, @code{^} ou @code{_} -- de telle sorte que le
postévénement produit par l'appel à cette fonction s'intègre
correctement dans l'expression environnante.

@item
En tant que partie d'un accord, l'expression musicale renvoyée doit
être du type @code{rhythmic-event}, et plus particulièrement un
@code{NoteEvent}.
@end itemize

@noindent
Des fonctions « polymorphes » telles que @code{\tweak} peuvent
s'appliquer aux postévénements, constituants d'accord et expressions de
haut niveau.


@node Fonctions de substitution simple
@subsection Fonctions de substitution simple
@translationof Simple substitution functions

Une fonction de substitution simple renvoie une expression musicale
écrite au format LilyPond et contient des arguments au format de
l'expression résultante.  Vous en trouverez une description détaillée à
la rubrique @ruser{Exemples de fonction de substitution}.


@node Fonctions de substitution intermédiaires
@subsection Fonctions de substitution intermédiaires
@translationof Intermediate substitution functions

Une fonction de substitution intermédiaire est une fonction dont
l'expression musicale résultante mélangera du code Scheme au code
LilyPond.

Certaines commandes @code{\override} nécessitent un argument
supplémentaire constitué d'une paire de nombres, appelée @emph{cons
cell} en Scheme -- que l'on pourrait traduire par « construction de
cellule ».

Cette paire peut se mentionner directement dans la fonction musicale à
l'aide d'une variable @code{pair?} :

@example
manualBeam =
#(define-music-function
     (beg-end)
     (pair?)
   #@{
     \once \override Beam.positions = #beg-end
   #@})

\relative c' @{
  \manualBeam #'(3 . 6) c8 d e f
@}
@end example

Autre manière de procéder, les nombres formant la paire sont transmis
comme arguments séparés ; le code Scheme chargé de créer la paire
pourra alors être inclus dans l'expression musicale :

@lilypond[quote,verbatim,ragged-right]
manualBeam =
#(define-music-function
     (beg end)
     (number? number?)
   #{
     \once \override Beam.positions = #(cons beg end)
   #})

\relative c' {
  \manualBeam #3 #6 c8 d e f
}
@end lilypond

@funindex \temporary
@cindex temporaire, dérogation (override)
@cindex dérogation temporaire (override)
@cindex propriétés, retour à la valeur précédente

L'entretien des propriétés peut se voir comme un empilement par
propriété par objet par contexte.  Les fonctions musicales peuvent
nécessiter des dérogations pour une ou plusieurs propriétés pour la
durée de la fonction, puis de revenir aux valeurs précédentes avant de
quitter.  Néanmoins, une dérogation normale va retirer de la pile -- ou
dépiler -- et supprimer le sommet de la pile de la propriété avant
d'y ajouter quoi que ce soit -- ou empiler -- ; la valeur précédente de
la propriété est de fait perdue.  Lorsque la valeur antérieure doit être
préservée, l'instruction @code{\override} devra être préfixée d'un
@code{\temporary}, comme ceci :

@example
\temporary \override @dots{}
@end example

L'utilisation d'un @code{\temporary} a pour effet d'effacer la propriété
@code{pop-first} (@emph{commence par dépiler} normalement activée) de la
dérogation ; la valeur antérieure ne sera alors pas supprimée de la pile
de la propriété avant d'y empiler la nouvelle valeur.  Lorsqu'un
@code{\revert} viendra par la suite supprimer la valeur dérogatoire
temporaire, réapparaitra la valeur antérieure.

En d'autres termes, un @code{\revert} qui suit un @code{\temporary
\override} pour la même propriété n'apporte rien.  Ce principe est aussi
valable pour un couple @code{\temporary} et @code{\undo} sur la même
musique contenant des dérogations.

Voici un exemple de fonction musicale utilisant cette fonctionnalité.
La présence du @code{\temporary} permet de s'assurer qu'en sortant de la
fonction, les propriétés @code{cross-staff} et @code{style} retrouveront
les valeurs qu'elles avaient avant que ne soit appelée la fonction
@code{crossStaff}.  En l'absence de @code{\temporary}, ces propriétés
auraient retrouvé leurs valeurs par défaut à la sortie de la fonction.

@example
crossStaff =
#(define-music-function (notes) (ly:music?)
  (_i "Create cross-staff stems")
  #@{
  \temporary \override Stem.cross-staff = #cross-staff-connect
  \temporary \override Flag.style = #'no-flag
  #notes
  \revert Stem.cross-staff
  \revert Flag.style
#@})
@end example


@node De l'usage des mathématiques dans les fonctions
@subsection De l'usage des mathématiques dans les fonctions
@translationof Mathematics in functions

Une fonction musicale peut requérir, en plus d'une simple substitution,
une part de programmation en Scheme.

@lilypond[quote,verbatim,ragged-right]
AltOn =
#(define-music-function
     (mag)
     (number?)
   #{
     \override Stem.length = #(* 7.0 mag)
     \override NoteHead.font-size =
       #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
   #})

AltOff = {
  \revert Stem.length
  \revert NoteHead.font-size
}

\relative {
  c'2 \AltOn #0.5 c4 c
  \AltOn #1.5 c c \AltOff c2
}
@end lilypond

@noindent
Cette fonction pourrait tout à fait être réécrite de telle sorte qu'elle
s'applique à une expression musicale :

@lilypond[quote,verbatim,ragged-right]
withAlt =
#(define-music-function
     (mag music)
     (number? ly:music?)
   #{
     \override Stem.length = #(* 7.0 mag)
     \override NoteHead.font-size =
       #(inexact->exact (* (/ 6.0 (log 2.0)) (log mag)))
     #music
     \revert Stem.length
     \revert NoteHead.font-size
   #})

\relative {
  c'2 \withAlt #0.5 { c4 c }
  \withAlt #1.5 { c c } c2
}
@end lilypond


@node Fonctions dépourvues d'argument
@subsection Fonctions dépourvues d'argument
@translationof Functions without arguments

Dans la plupart des cas, une fonction dépourvue d'argument devrait
être créée à l'aide d'une variable :

@example
dolce = \markup@{ \italic \bold dolce @}
@end example

Il peut, dans certains cas particuliers, s'avérer utile de créer une
fonction sans argument comme ici,

@example
displayBarNum =
#(define-music-function
     ()
     ()
   (if (eq? #t (ly:get-option 'display-bar-numbers))
       #@{ \once \override Score.BarNumber.break-visibility = ##f #@}
       #@{#@}))
@end example

@noindent
de manière à pouvoir afficher les numéros de mesure grâce à un appel à
cette fonction.  En pareil cas, vous devrez invoquer @command{lilypond}
en respectant la syntaxe

@example
lilypond -d display-bar-numbers MONFICHIER.ly
@end example


@node Fonctions musicales fantômes
@subsection Fonctions musicales fantômes
@translationof Void music functions

Une fonction musicale doit renvoyer une expression musicale.  Toutefois,
une fonction musicale peut n'être exécutée que dans le but d'en retenir
les effets annexes ; vous devrez alors utiliser une procédure
@code{define-void-function}.  Il peut cependant arriver que vous ayez
besoin d'une fonction qui, selon le cas, produise ou non (comme dans
l'exemple de la rubrique précédente) une expression musicale.
L'utilisation d'un @code{#@{ #@}} vous permettra de renvoyer une
expression musicale @code{void}.


@node Fonctions événementielles
@section Fonctions événementielles
@translationof Event functions

@funindex define-event-function
@cindex événementielle, fonction

L'utilisation d'une fonction musicale pour placer un événement requiert
l'insertion d'un indicateur de position, ce qui peut ne pas correspondre
à la syntaxe de la construction à remplacer.  C'est par exemple le cas
lorsque vous voulez écrire une commande de nuance, instruction qui
ne comporte habituellement pas d'indicateur de positionnement, comme
dans @code{c'\pp}.  Voici de quoi vous permettre de mentionner n'importe
quelle nuance :

@lilypond[quote,verbatim,ragged-right]
dyn=#(define-event-function (arg) (markup?)
         (make-dynamic-script arg))
\relative { c'\dyn pfsss }
@end lilypond

Vous pourriez obtenir le même résultat avec une fonction musicale, à
ceci près que chaque appel à la fonction devra être précédé d'un
indicateur de positionnement, comme @code{c-\dyn pfsss}.


@node Fonctions pour markups
@section Fonctions pour @emph{markups}
@translationof Markup functions

Les @emph{markups} sont implémentés au travers de fonctions Scheme
spécifiques qui produisent des objets @code{Stencil} comprenant un
certain nombre d'arguments.

@menu
* Construction d'un markup en Scheme::
* Fonctionnement interne des markups::
* Définition d'une nouvelle commande de markup::
* Définition d'une nouvelle commande de liste de markups::
@end menu


@node Construction d'un markup en Scheme
@subsection Construction d'un @emph{markup} en Scheme
@translationof Markup construction in Scheme

@cindex définition d'une commande markup
@cindex markup, définition d'une commande

@funindex \displayScheme

Les expressions @emph{markup} sont représentées en Scheme de manière
interne par la macro @code{markup} :

@example
(markup @var{expression})
@end example

La commande @code{\displayScheme} permet d'obtenir la représentation en
Scheme d'une expression @emph{markup} :

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

@noindent
Compiler ce code renverra en console les lignes suivantes :

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

L'impression du @emph{markup} sera suspendue dès lors qu'apparaîtra un
@w{@samp{\void \displayScheme @var{markup}}}.  Tout comme pour la
commande @code{\displayMusic}, le résultat de @code{\displayScheme} peut
être sauvegardé dans un fichier séparé.  Voir à ce sujet
@ref{Affichage d'expressions musicales}.

@noindent
Vous pouvez constater les principales règles de traduction entre les
syntaxes respectives de LilyPond et de Scheme en matière de
@emph{markup}.  Bien que le passage en syntaxe LilyPond grâce à
@code{#@{ @dots{} #@}} apporte de la souplesse, nous allons voir comment
utiliser la macro @code{markup} en Scheme exclusivement.

@indentedBlock
@multitable @columnfractions .3 .3
@item @b{LilyPond} @tab @b{Scheme}
@item @code{\markup markup1} @tab @code{(markup markup1)}
@item @code{\markup @{ markup1 markup2@dots{} @}} @tab
        @code{(markup markup1 markup2@dots{} )}
@item @code{\commande-markup} @tab @code{#:commande-markup}
@item @code{\variable} @tab @code{variable}
@item @code{\center-column @{ @dots{} @}} @tab
        @code{#:center-column ( @dots{} )}
@item @code{chaîne} @tab @code{"chaîne"}
@item @code{#argument-scheme} @tab @code{argument-scheme}
@end multitable
@endIndentedBlock

L'intégralité du langage Scheme est accessible à l'intérieur même de la
macro @code{markup}.  Vous pouvez ainsi appeler des fonctions à partir
de @code{markup} pour manipuler des chaînes de caractères, ce qui est
particulièrement pratique lorsque vous créez votre propre commande de
@emph{markup} -- voir
@ref{Définition d'une nouvelle commande de markup}.

@knownissues
L'argument @var{markup-list} des commandes @code{#:line},
@code{#:center} ou @code{#:column} ne saurait être une variable ni le
résultat de l'appel à une fonction.

@lisp
(markup #:line (fonction-qui-retourne-des-markups))
@end lisp

@noindent
n'est pas valide.  Il vaut mieux, en pareil cas, utiliser les fonctions
@code{make-line-markup}, @code{make-center-markup} ou
@code{make-column-markup} :

@lisp
(markup (make-line-markup (fonction-qui-retourne-des-markups)))
@end lisp


@node Fonctionnement interne des markups
@subsection Fonctionnement interne des @emph{markups}
@translationof How markups work internally

Dans un @emph{markup} tel que

@example
\raise #0.5 "text example"
@end example

@noindent
@code{\raise} représente en fait la fonction @code{raise-markup}.
L'expression @emph{markup} est enregistrée sous la forme

@example
(list raise-markup 0.5 "text example")
@end example

Lorsque ce @emph{markup} est converti en objets imprimables (stencils),
la fonction @code{raise-markup} est appelée ainsi :

@example
(apply raise-markup
       @var{\layout objet}
       @var{liste des alists de propriété}
       0.5
       @var{le @emph{markup} "text example"})
@end example

La fonction @code{raise-markup} commence par créer le stencil pour la
chaîne @code{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
@file{scm/define-markup-commands.scm}.


@node Définition d'une nouvelle commande de markup
@subsection Définition d'une nouvelle commande de @emph{markup}
@translationof New markup command definition

Nous allons étudier dans ce qui suit la manière de définir une nouvelle
commande de @emph{markup}.

@menu
* Syntaxe d'une commande markup::
* Attribution de propriétés::
* Exemple commenté::
* Adaptation d'une commande incorporée::
* Conversion de markups en chaînes::
@end menu


@node Syntaxe d'une commande markup
@unnumberedsubsubsec Syntaxe d'une commande @emph{markup}
@translationof Markup command definition syntax

Une commande de @emph{markup} personnalisée se définit à l'aide de la
macro Scheme @code{define-markup-command}, placée en tête de fichier.

@lisp
(define-markup-command (@var{nom-commande} @var{layout} @var{props} @var{arg1} @var{arg2}@dots{})
    (@var{arg1-type?} @var{arg2-type?}@dots{})
    [ #:properties ((@var{propriété1} @var{valeur-par-défaut1})
                    @dots{}) ]
    [ #:as-string @var{expression} ]
  @dots{}corps de la commande@dots{})
@end lisp

Quelques commentaires sur les arguments :

@table @code
@item @var{nom-commande}
le nom que vous attribuez à votre commande de @emph{markup}.
@item layout
la définition du « layout » -- son formatage.
@item props
une liste de listes associatives, comprenant toutes les propriétés actives.
@item @var{argi}
le @var{ième} argument de la commande.
@item @var{argi-type?}
un type de prédicat pour le @var{ième} argument.
@end table

Si la commande utilise des propriétés à partir des arguments
@code{props}, le mot-clé @code{#: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 :
@itemize
@item un @emph{markup}, correspondant au type de prédicat
@code{markup?} ;
@item une liste de @emph{markups}, correspondant au type de prédicat
@code{markup-list?} ;
@item tout autre objet Scheme, correspondant au types de prédicat tels
que @code{list?}, @code{number?}, @code{boolean?}, etc.
@end itemize

Il n'existe aucune restriction quant à l'ordre des arguments fournis à
la suite des arguments @code{layout} et @code{props}.  Néanmoins, les
fonctions @emph{markup} qui ont en dernier argument un @emph{markup} ont
ceci de particulier qu'elles peuvent s'appliquer à des listes de
@emph{markups} ; ceci résultera en une liste de @emph{markups} où
tous les éléments de la liste originelle se verront appliquer cette
fonction @emph{markup} avec ses arguments de tête.

La réplication des arguments de tête dans le but d'appliquer une
fonction @emph{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 @emph{markup} dont
le dernier argument est un @emph{markup}.

@cindex markup macro
@cindex macro de markup
@funindex \markup
@funindex interpret-markup

Les commandes de @emph{markup} ont un cycle de vie relativement
complexe.  Le corps de la définition d'une commande de @emph{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 @code{interpret-markup}, en lui passant les arguments
@var{layout} et @var{props}.  Ces arguments ne seront en principe connus
que bien plus tardivement dans le processus typographique.  Lors de
l'expansion d'une expression LilyPond @code{\markup} ou d'une macro
Scheme @code{markup}, les expressions @emph{markup} auront déjà vu leurs
composants assemblés en expressions @emph{markup}.  L'évaluation et le
contrôle du type des arguments à une commande de @emph{markup}
n'interviennent qu'au moment de l'interprétation de @code{\markup} ou
@code{markup}.

Seule l'application de @code{interpret-markup} sur une expression
@emph{markup} réalisera effectivement la conversion des expressions
@emph{markup} en stencil, au travers de l'exécution du corps des
fonctions @emph{markup}.


@node Attribution de propriétés
@unnumberedsubsubsec Attribution de propriétés
@translationof On properties

Les arguments @code{layout} et @code{props} d'une commande de
@emph{markup} fournissent un contexte à l'interprétation du
@emph{markup} : taille de fonte, longueur de ligne, etc.

L'argument @code{layout} permet d'accéder aux propriétés définies dans
les blocs @code{\paper}, grâce à la fonction
@code{ly:output-def-lookup}.  Par exemple, la longueur de ligne,
identique à celle de la partition, est lue au travers de

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

L'argument @code{props} rend certaines propriétés accessibles aux
commandes de @emph{markup}.  Il en va ainsi lors de l'interprétation
d'un @emph{markup} de titre d'ouvrage : toutes les variables
définies dans le bloc @code{\header} sont automatiquement ajoutées aux
@code{props}, de telle sorte que le @emph{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
@emph{markup} : la taille des fontes, par exemple, est lue à
partir de @code{props} plutôt que grâce à un argument @code{font-size}.
La fonction appelant une commande de @emph{markup} peut altérer la
valeur de la propriété taille des fontes et donc en modifier le
comportement.  L'utilisation du mot-clé @code{#:properties}, attaché à
@code{define-markup-command}, permet de spécifier les propriétés devant
être lues parmi les arguments @code{props}.

L'exemple proposé à la rubrique suivante illustre comment, au sein d'une
commande de @emph{markup}, accéder aux différentes propriétés et les
modifier.


@node Exemple commenté
@unnumberedsubsubsec Exemple commenté
@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 @emph{markup}.  La lecture de @ruser{Commandes pour markup} nous
indique la commande @code{\box}, qui semble ici appropriée.

@lilypond[quote,verbatim,ragged-right]
\markup \box \box HELLO
@end lilypond

Dans un souci d'esthétique, nous aimerions que le texte et les
encadrements ne soient pas autant accolés.  Selon la documentation de
@code{\box}, cette commande utilise la propriété @code{box-padding},
fixée par défaut à 0,2.  Cette même documentation nous indique
aussi comment la modifier :

@lilypond[quote,verbatim,ragged-right]
\markup \box \override #'(box-padding . 0.6) \box A
@end lilypond

L'espacement des deux liserés est cependant toujours trop réduit ;
modifions le à son tour :

@lilypond[quote,verbatim,ragged-right]
\markup \override #'(box-padding . 0.4) \box
     \override #'(box-padding . 0.6) \box A
@end lilypond

Vous conviendrez que recopier une telle définition de @emph{markup}
deviendra vite fastidieux.  C'est pourquoi nous écrivons la commande de
@emph{markup} @code{double-box} qui prendra un seul argument -- le
texte.  Cette commande se chargera de dessiner les encadrements, en
tenant compte des espacements.

@lisp
#(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 @}#@}))
@end lisp

@noindent
ou bien son équivalent

@lisp
#(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)))
@end lisp

@code{text} est le nom de l'argument de notre commande, et
@code{markup?} son type -- l'argument sera identifié comme étant un
@emph{markup}.  La fonction @code{interpret-markup}, utilisée dans la
plupart des commandes de @emph{markup}, construira un stencil à partir
de @code{layout}, @code{props} et un @emph{markup}.  Dans la seconde
variante, ce @emph{markup} sera construit à l'aide de la macro Scheme
@code{markup} -- voir @ref{Construction d'un markup en Scheme}.  La
transformation d'une expression @code{\markup} en expression Scheme est
des plus triviales.

Notre commande personnalisée s'utilise ainsi :

@example
\markup \double-box A
@end example

Il serait intéressant de rendre cette commande @code{double-box} plus
souple :  les valeurs de @code{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 @code{inter-box-padding}, chargée
de gérer l'espacement des encadrements ; @code{box-padding} ne
servira alors que pour l'espacement intérieur.  Voici le code adapté à
ces évolutions :

@lisp
#(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 @} #@}))
@end lisp

Ainsi que son équivalent à partir de la macro @emph{markup} :

@lisp
#(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)))
@end lisp

C'est ici le mot-clé @code{#:properties} qui permet de lire les
propriétés @code{inter-box-padding} et @code{box-padding} à partir de
l'argumenet @code{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
@code{box-padding} utilisées par les deux commandes @code{\box}.  Vous
aurez remarqué, dans l'argument @code{\override}, la présence de
l'apostrophe inversée (@code{`}) 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 @emph{markup}, et
les encadrements sont repositionnables.

@lilypond[quote,verbatim,ragged-right]
#(define-markup-command (double-box layout props text) (markup?)
  #:properties ((inter-box-padding 0.4)
                (box-padding 0.6))
  "Draw a double box around text."
  (interpret-markup layout props
    #{\markup \override #`(box-padding . ,inter-box-padding) \box
              \override #`(box-padding . ,box-padding) \box
              { #text } #}))

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


@node Adaptation d'une commande incorporée
@unnumberedsubsubsec Adaptation d'une commande incorporée
@translationof Adapting builtin commands

Le meilleur moyen de construire ses propres commandes de @emph{markup}
consiste à prendre exemple sur les commandes déjà incorporées.  La
plupart des commandes de @emph{markup} fournies avec LilyPond sont
répertoriées dans le fichier @file{scm/define-markup-commands.scm}.

Nous pourrions, par exemple, envisager d'adapter la commande
@code{\draw-line} pour dessiner plutôt une ligne double.  Voici comment
est définie la commande @code{\draw-line}, expurgée de sa
documentation :

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

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é @code{#: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.

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

Nous ajoutons ensuite une propriété pour gérer l'écart entre les deux
lignes, que nous appelons @code{line-gap}, et lui attribuons une valeur
par défaut de 6 dixièmes :

@lisp
(define-markup-command (draw-double-line layout props dest)
  (number-pair?)
  #:properties ((thickness 1)
                (line-gap 0.6))
  "@dots{}documentation@dots{}"
  @dots{}
@end lisp

Nous ajoutons enfin le code qui dessinera nos deux lignes.  Deux appels
à @code{make-line-stencil} permettrons de dessiner les lignes dont nous
regrouperons les stencils à l'aide de @code{ly:stencil-add} :

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

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


@node Conversion de markups en chaînes
@unnumberedsubsubsec Conversion de @emph{markups} en chaînes
@translationof Converting markups to strings

@cindex @emph{markup}, conversion en chaîne
@funindex markup->string

Les @emph{markups} sont parfois convertis en chaînes littérales, ce qui
est le cas pour générer une métadonnée PDF basée sur le champ d'entête
@code{title} ou pour convertir des paroles en MIDI. Cette conversion
n'est pas parfaite, mais elle est aussi fidèle que possible. La fonction
dévolue à cette opération est @code{markup->string}.

@lilypond[verbatim,quote]
composerName = \markup \box "Arnold Schönberg"

\markup \composerName

\markup \typewriter #(markup->string composerName)
@end lilypond

Dans le cas de commandes de @emph{markup} personnalisées, le
comportement par défaut consiste à convertir dans un premier temps tous
les @emph{markups} ou les arguments de la liste de @emph{markups}, puis
à joindre les résultats par des espaces.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   (interpret-markup layout props
    #{
      \markup \fill-line { \box #authorA and \box #authorB }
    #}))

defaultBehavior = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \defaultBehavior

\markup \typewriter #(markup->string defaultBehavior)
@end lilypond

@code{markup->string} peut aussi recevoir les argument nommés
@code{#:layout @var{layout}} et @code{#:props @var{props}}, avec la même
signification que lorsqu'ils apparaissent dans la définition d'une
commande de @emph{markup}. Ils sont toutefois optionnels dans la mesure
où ils peuvent ne pas toujours être pourvus -- cas typique de l'argument
@code{layout} pour convertir en MIDI.

Afin de définir une conversion différente du comportement par
défaut dans une commande pour @emph{markup} personnalisée, on peut
fournir le paramètre @code{#:as-string} à
@code{define-markup-command}. Il attend une expression, évaluée
par @code{markup->string}, afin de produire la chaîne.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   #:as-string (format #f "~a and ~a"
                       (markup->string authorA #:layout layout #:props props)
                       (markup->string authorB #:layout layout #:props props))
   (interpret-markup layout props
    #{
      \markup \fill-line { \box #authorA and \box #authorB }
    #}))

customized = \markup \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \customized

\markup \typewriter #(markup->string customized)
@end lilypond

Au sein de l'expression sont disponibles les mêmes variables que dans le
corps de la commande de @emph{markup}, à savoir les argument de la
commande, ainsi que @code{layout} et @code{props}, et les éventuelles
propriétés.

@lilypond[verbatim,quote]
#(define-markup-command (authors-and layout props authorA authorB)
                        (markup? markup?)
   #:properties ((author-separator " and "))
   #:as-string (format #f "~a~a~a"
                       (markup->string authorA #:layout layout #:props props)
                       (markup->string author-separator #:layout layout #:props props)
                       (markup->string authorB #:layout layout #:props props))
   (interpret-markup layout props
    #{
      \markup { \box #authorA #author-separator \box #authorB }
    #}))

customized = \markup \override #'(author-separator . ", ")
                     \authors-and "Bertolt Brecht" "Kurt Weill"

\markup \customized

\markup \typewriter #(markup->string customized)
@end lilypond

La plupart du temps, il suffira au gestionnaire personnalisé d'un appel
récursif à @code{markup->string} sur certains arguments, comme illustré
ci-dessus. Néanmoins, on peut toujours recourir directement à
@code{layout} et @code{props} comme si l'on était dans le corps
principal. Une attention particulière doit être portée au fait que, dès
lors que @code{#:layout} n'est pas passé à @code{markup->string},
l'argument @code{layout} égale @code{#f}. L'argument @code{props} est
par défaut une liste vide.


@node Définition d'une nouvelle commande de liste de markups
@subsection Définition d'une nouvelle commande de liste de @emph{markups}
@translationof New markup list command definition

@cindex liste de markup, définition de commande
@funindex define-markup-list-command
@funindex interpret-markup-list

Une commande traitant une liste de @emph{markups} se définit à l'aide de
la macro Scheme @code{define-markup-list-command}, de manière analogue à
la macro @code{define-markup-command} abordée à la rubrique
@ref{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 @code{interpret-markup-list}, à l'instar de la fonction
@code{interpret-markup}, permet de convertir une liste de @emph{markups}
en liste de stencils.

Dans l'exemple suivant, nous définissons @code{\paragraph}, une commande
de liste de @emph{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 @code{props}.

@example
#(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 @} #@}))
@end example

La version purement Scheme est un peu plus complexe :
@example
#(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))))
@end example

En dehors des habituels arguments @code{layout} et @code{props}, la
commande de liste de @emph{markups} @code{paragraph} prend en argument
une liste de @emph{markups} appelée @code{args}.  Le prédicat des listes
de @emph{markups} est @code{markup-list?}.

Pour commencer, la fonction récupère la taille de l'alinéa, propriété
ici dénommée @code{par-indent}, à partir de la liste de propriétés
@code{props}.  En cas d'absence, la valeur par défaut sera
de @code{2}.  Ensuite est créée une liste de lignes justifiées
grâce à la commande prédéfinie @code{\justified-lines}, liée à la
fonction @code{make-justified-lines-markup-list}.  Un espace horizontal
est ajouté en tête, grâce à @code{\hspace} ou à la fonction
@code{make-hspace-markup}.  Enfin, la liste de @emph{markups} est
interprétée par la fonction @code{interpret-markup-list}.

Voici comment utiliser cette nouvelle commande de liste de
@emph{markups} :

@example
\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.
  @}
@}
@end example


@node Contextes pour programmeurs
@section Contextes pour programmeurs
@translationof Contexts for programmers

@menu
* Évaluation d'un contexte::
* Application d'une fonction à tous les objets de mise en forme::
@end menu


@node Évaluation d'un contexte
@subsection Évaluation d'un contexte
@translationof Context evaluation

@cindex appel de code durant l'interprétation
@funindex \applyContext
@funindex make-apply-context
@funindex ly:context-property
@funindex ly:context-set-property!
@funindex ly:context-grob-definition
@funindex ly:assoc-get
@funindex ly:context-pushpop-property

Un contexte peut être modifié, au moment même de son interprétation, par
du code Scheme.  La syntaxe consacrée au sein d'un bloc LilyPond est

@example
\applyContext @var{fonction}
@end example

@noindent
et, dans le cadre d'un code Scheme :

@example
(make-apply-context @var{fonction})
@end example

@code{@var{fonction}} est constitué d'une fonction Scheme comportant un
unique argument : le contexte au sein duquel la commande
@code{\applyContext} est appelée.  Cette fonction peut accéder aussi
bien aux propriétés de @emph{grob} (y compris modifiées par
@code{\override} ou @code{\set}) qu'aux propriétés de contexte.  Toute
action entreprise par la fonction et qui dépendrait de l'état du
contexte sera limitée à l'état de ce contexte @b{au moment de l'appel à
la fonction}.  Par ailleurs, les adaptations résultant d'un appel à
@code{\applyContext} seront effectives jusqu'à ce qu'elles soient à
nouveau directement modifiées ou bien annulées, quand bien même les
conditions initiales dont elles dépendent auraient changé.

Voici quelques fonctions Scheme utiles avec @code{\applyContext} :

@table @code
@item ly:context-property
recherche la valeur d'une propriété de contexte,

@item ly:context-set-property!
détermine une propriété de contexte,

@item ly:context-grob-definition
@itemx ly:assoc-get
recherche la valeur d'une propriété de @emph{grob},

@item ly:context-pushpop-property
réalise un @code{\temporary \override} ou un @code{\revert} sur une
propriété de @emph{grob}.
@end table

L'exemple suivant recherche la valeur en cours de @code{fontSize} puis
la double :

@lilypond[quote,verbatim]
doubleFontSize =
\applyContext
  #(lambda (context)
     (let ((fontSize (ly:context-property context 'fontSize)))
       (ly:context-set-property! context 'fontSize (+ fontSize 6))))

{
  \set fontSize = -3
  b'4
  \doubleFontSize
  b'
}
@end lilypond

L'exemple suivant recherche la couleur des objets @code{NoteHead},
@code{Stem} et @code{Beam}, puis diminue pour chacun d'eux le degré de
saturation.

@lilypond[quote,verbatim]
desaturate =
\applyContext
  #(lambda (context)
     (define (desaturate-grob grob)
       (let* ((grob-def (ly:context-grob-definition context grob))
              (color (ly:assoc-get 'color grob-def black))
              (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
         (ly:context-pushpop-property context grob 'color new-color)))
     (for-each desaturate-grob '(NoteHead Stem Beam)))

\relative {
  \time 3/4
  g'8[ g] \desaturate g[ g] \desaturate g[ g]
 \override NoteHead.color = #darkred
  \override Stem.color = #darkred
  \override Beam.color = #darkred
  g[ g] \desaturate g[ g] \desaturate g[ g]
}
@end lilypond

Ceci pourrait tout à fait s'implémenter sous la forme d'une fonction
musicale, afin d'en réduire les effets à un seul bloc de musique.  Notez
comment @code{ly:context-pushpop-property} est utilisé à la fois pour un
@code{\temporary \override} et pour un @code{\revert} :

@lilypond[quote,verbatim]
desaturate =
#(define-music-function
   (music) (ly:music?)
   #{
     \applyContext
     #(lambda (context)
        (define (desaturate-grob grob)
          (let* ((grob-def (ly:context-grob-definition context grob))
                 (color (ly:assoc-get 'color grob-def black))
                 (new-color (map (lambda (x) (min 1 (/ (1+ x) 2))) color)))
            (ly:context-pushpop-property context grob 'color new-color)))
        (for-each desaturate-grob '(NoteHead Stem Beam)))
     #music
     \applyContext
     #(lambda (context)
        (define (revert-color grob)
          (ly:context-pushpop-property context grob 'color))
        (for-each revert-color '(NoteHead Stem Beam)))
   #})

\relative {
  \override NoteHead.color = #darkblue
  \override Stem.color = #darkblue
  \override Beam.color = #darkblue
  g'8 a b c
  \desaturate { d c b a }
  g b d b g2
}
@end lilypond


@node Application d'une fonction à tous les objets de mise en forme
@subsection Application d'une fonction à tous les objets de mise en forme
@translationof Running a function on all layout objects

@cindex appel de code sur des objets de mise en forme
@cindex objets de mise en forme, appel de code
@funindex \applyOutput

La manière la plus souple d'affiner un objet consiste à utiliser la
commande @code{\applyOutput}.  Celle-ci va insérer un événement
(@rinternals{ApplyOutputEvent}) dans le contexte spécifié.  Elle répond
aussi bien à la syntaxe
@example
\applyOutput @var{Contexte} @var{procédure}
@end example
@noindent
que
@example
\applyOutput @var{Contexte}.@var{Grob} @var{procédure}
@end example

@noindent
où @code{@var{procédure}} est une fonction Scheme à trois arguments.

Lors de l'interprétation de cette commande, la fonction
@code{@var{procédure}} est appelée pout tout objet de rendu (nommé
@var{Grob} si celui-ci est spécifié) appartenant au contexte
@code{@var{Contexte}} à cet instant précis, avec les arguments
suivants :
@itemize
@item l'objet de rendu en lui-même,
@item le contexte au sein duquel cet objet est créé,
@item le contexte dans lequel @code{\applyOutput} est effectué.
@end itemize

De plus, ce qui est à l'origine de l'objet de rendu -- l'expression
musicale ou l'objet qui l'a générée -- se retrouve en tant que propriété
d'objet @code{cause}.  Il s'agit, pour une tête de note, d'un événement
@rinternals{NoteHead}, et d'un objet @rinternals{Stem} pour une hampe.

Voici une fonction utilisable avec la commande
@code{\applyOutput} : elle « blanchit » la tête des notes se trouvant
sur la ligne médiane ou bien directement à son contact.

@lilypond[quote,verbatim,ragged-right]
#(define (blanker grob grob-origin context)
   (if (< (abs (ly:grob-property grob 'staff-position)) 2)
       (set! (ly:grob-property grob 'transparent) #t)))

\relative {
  a'4 e8 <<\applyOutput Voice.NoteHead #blanker a c d>> b2
}
@end lilypond

La @var{procédure} sera interprétée au niveau @code{Score} (partition)
ou @code{Staff} (portée) dès lors que vous utiliserez l'une des syntaxes

@example
\applyOutput Score@dots{}
\applyOutput Staff@dots{}
@end example


@node Fonctions de rappel
@section Fonctions de rappel
@translationof Callback functions

Certaines propriétés, entre autres @code{thickness} ou @code{direction},
peuvent voir leur valeur figée à l'aide d'un @code{\override} comme
ici :

@example
\override Stem.thickness = #2.0
@end example

Une procédure Scheme peut aussi se charger de modifier des propriétés :

@lilypond[fragment,verbatim,quote]
\override Stem.thickness = #(lambda (grob)
    (if (= UP (ly:grob-property grob 'direction))
        2.0
        7.0))
\relative { c'' b a g b a g b }
@end lilypond

@noindent
Dans ce cas, la procédure est exécutée dès que la valeur de la propriété
est nécessaire au processus de mise en forme.

La majeure partie du procédé typographique consiste en la réalisation de
tels rappels (@emph{callbacks} en anglais).  Entre autres propriétés
utilisant particulièrement des rappels, nous mentionnerons

@table @code
@item stencil
  Routine d'impression, construisant le dessin du symbole
@item X-offset
  Routine effectuant le positionnement horizontal
@item X-extent
  Routine calculant la largeur d'un objet
@end table

La procédure prend un unique argument, en l'occurrence l'objet graphique
(le @emph{grob}).

Cette procédure, grâce à un appel à la fonction de rappel dévolue à
cette propriété -- mentionnée dans la référence des propriétés internes
et dans le fichier @file{define-grobs.scm} --, pourra accéder à la
valeur usuelle de la propriété :

@example
\relative @{
  \override Flag.X-offset = #(lambda (flag)
    (let ((default (ly:flag::calc-x-offset flag)))
      (* default 4.0)))
  c''4. d8 a4. g8
@}
@end example

La valeur par défaut est aussi accessible à l'aide de la fonction
@code{grob-transformer} :

@lilypond[verbatim,quote]
\relative {
  \override Flag.X-offset = #(grob-transformer 'X-offset
    (lambda (flag default) (* default 4.0)))
  c''4. d8 a4. g8
}
@end lilypond

Au sein d'un @emph{callback}, le meilleur moyen d'évaluer un
@emph{markup} consiste à utiliser la fonction
@code{grob-interpret-markup}, comme ici :

@example
my-callback = #(lambda (grob)
                 (grob-interpret-markup grob (markup "foo")))
@end example


@ignore
@n ode Code Scheme intégré
@s ection Code Scheme intégré
@t ranslationof Inline Scheme code

À REVOIR : depuis la rédaction de cette section, LilyPond en est
arrivé à un point tel que trouver un exemple @emph{simple} où l'on se
retrouve obligé d'en venir à utiliser du code Scheme devient chose
ardue.

En attendant un remaniement de cette section, faisons comme si nous
l'ignorions.

L'inconvénient principal de la commande @code{\tweak} est la rigidité de
sa syntaxe.  Par exemple, le code suivant produit une erreur de syntaxe
(du moins, c'était le cas auparavant).

@example
F = \tweak font-size #-3 -\flageolet

\relative @{
  c''4^\F c4_\F
@}
@end example

@noindent
C'est en se servant du langage Scheme que l'on peut résoudre ce
problème.  Dans cet exemple, on a recours aux méthodes décrites dans
@ref{Ajout d'articulation à des notes (exemple)}, en
particulier quant à l'emploi de @code{\displayMusic}.

@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''4^\F c4_\F
@}
@end example

@noindent
Ici les propriétés @code{tweak} de l'objet flageolet nommé @samp{m}
(créé au moyen de @code{make-music}) sont extraites par
@code{ly:music-property}, une nouvelle valeur de la taille de fonte
est ajoutée à la liste de ses propriétés (grâce à la fonction Scheme
@code{acons}), et le résultat de cette opération est renvoyé par
@code{set!}.  Le dernier élément, dans ce bloc @code{let}, est la valeur
finale de @samp{m} lui-même.

@end ignore


@node Conteneurs requalifiants
@section Conteneurs requalifiants
@translationof Unpure-pure containers

@c See issue #3512.
@warning{Bien que cette rubrique reflète la situation actuelle,
l'exemple qui suit est discutable et ne met rien en évidence.}

@cindex Scheme, @emph{pure container}
@cindex Scheme, @emph{unpure container}
@cindex @emph{pure containers}, Scheme
@cindex @emph{unpure containers}, Scheme
@cindex espacement horizontal, affinage

Les conteneurs requalifiants permettent de faciliter le calcul des
espacements en cas de modification du @emph{Y-axis} -- plus
particulièrement les composantes @code{Y-offset} et @code{Y-extent} -- à
l'aide d'une fonction Scheme en lieu et place de valeurs.

L'envergure verticale (@code{Y-extent}) de certains objets dépend de la
propriété @code{stencil} ; jouer sur leur stencil requiert alors une
intervention supplémentaire au niveau du @code{Y-extent} à l'aide d'un
conteneur transitoire.  Lorsqu'une fonction affecte un @code{Y-offset} ou
un @code{Y-extent}, cela déclenche la détermination des sauts de ligne
de manière anticipée dans la séquence des traitements.  Il en résulte
que cette opération n'est en fait pas exécutée ; elle renvoie
habituellement @samp{0} ou @samp{'(0 . 0)}, ce qui peut engendrer des
collisions.  Une fonction « pure » évitera d'avorter la construction
des propriétés ou objets, qui de ce fait verront leurs arguments liés à
la verticalité (@code{Y-axis}) correctement évalués.

Il existe actuellement une trentaine de fonctions que l'on peut
qualifier de « pures ».  Le recours à un conteneur transitoire permet
de requalifier une fonction de telle sorte qu'elle soit reconnue comme
« pure » et soit donc évaluée @strong{avant} détermination des sauts de
ligne -- l'espacement horizontal sera de fait ajusté en temps et en heure.
La fonction « impure » sera ensuite évaluée @strong{après} le
positionnement des sauts de ligne.

@warning{Il n'est pas toujours facile d'avoir l'assurance qu'une
fonction soit qualifiée de « pure » ; aussi nous vous recommandons
d'éviter d'utiliser les objets @code{Beam} ou @code{VerticalAlignment}
lorsque vous désirez en créer une.}

Un conteneur requalifiant se construit selon la syntaxe

@example
(ly:make-unpure-pure-container f0 f1)
@end example

@noindent
où @code{f0} est une fonction prenant @var{n} arguments (@var{n_>=_1}),
le premier devant être l'objet en question ; il s'agit de la fonction
dont le résultat sera réutilisé.  @var{f1} est la fonction qui sera
qualifiée de « pure ».  Elle prend @var{n_+_2} arguments, le premier
devant être lui aussi l'objet en question, et les second et troisième
étant respectivement les « point de départ » (@var{start}) et « point
d'arrivée » (@var{end}).

@var{start} et @var{end} sont dans tous les cas des valeurs fictives qui
trouveront leur utilité dans le cas d'objets de type @code{Spanner},
tels les soufflets (@code{Hairpin}) ou barres de ligature (@code{Beam}),
en retournant les différentes estimations de hauteur basées sur leurs
début et fin d'extension.

Viennent ensuite les autres arguments de la fonction initiale @code{f0}
-- autrement dit aucun si @var{n_=_1}.

Les résultats de la deuxième fonction (@code{f1}) permettent une
approximation des valeurs qui seront ensuite utilisées par la fonction
initiale aux fins d'ajustement lors des phases ultérieures d'espacement.

@c TODO: The following example supposedly showing a collision no longer
@c 'works' since 2.18.x. Another example of a collision is needed.
@c Issue #3512

@lilypond[verbatim,quote,ragged-right]
#(define (square-line-circle-space grob)
(let* ((pitch (ly:event-property (ly:grob-property grob 'cause)
                                 'pitch))
      (notename (ly:pitch-notename pitch)))
 (if (= 0 (modulo notename 2))
     (make-circle-stencil 0.5 0.0 #t)
     (make-filled-box-stencil '(0 . 1.0)
                              '(-0.5 . 0.5)))))

squareLineCircleSpace = {
  \override NoteHead.stencil = #square-line-circle-space
}

smartSquareLineCircleSpace = {
  \squareLineCircleSpace
  \override NoteHead.Y-extent =
   #(ly:make-unpure-pure-container
      ly:grob::stencil-height
      (lambda (grob start end) (ly:grob::stencil-height grob)))
}

\new Voice \with { \remove Stem_engraver }
\relative c'' {
  \squareLineCircleSpace
  cis4 ces disis d
  \smartSquareLineCircleSpace
  cis4 ces disis d
}
@end lilypond

@noindent
La première mesure de l'exemple ci-dessus ne fait pas appel à un
conteneur requalifiant ; le moteur d'espacement n'a donc aucune
connaissance de la largeur des têtes de note et ne peut empêcher
qu'elles chevauchent les altérations.  Dans la deuxième mesure, par
contre, le recours à un conteneur requalifiant informe le moteur
d'espacement de la largeur des têtes de note ; les collisions sont alors
évitées du fait de l'espace réservé à chacune des têtes.

Lorsqu'il s'agit de calculs simples, les fonctions, tant pour la partie
« pure » que pour la partie « impure », peuvent être identiques au
détail près du nombre d'arguments utilisés ou du domaine d'intervention.
Ce cas de figure étant relativement répandu,
@code{ly:make-unpure-pure-container} construira d'elle même cette
deuxième lorsqu'il ne sera fait appel qu'à une seule fonction en
argument.

@warning{Le fait de qualifier une fonction de « pure » alors qu'elle ne
l'est pas peut générer des résultats imprévisibles.}


@node Retouches complexes
@section Retouches complexes
@translationof Difficult tweaks

Certains réglages sont plus délicats que d'autres.

@itemize
@item
L'un d'entre eux est l'apparence des objets dits « extenseurs »
(@emph{spanner}), qui s'étendent horizontalement, tels que les liaisons.
Si, en principe, un seul de ces objets est créé à la fois et peut donc
être modifié de façon habituelle, lorsque ces objets doivent enjamber un
changement de ligne, ils sont dupliqués au début du ou des systèmes
suivants.  Comme ces objets sont des clones de l'objet d'origine, ils en
héritent toutes les propriétés, y compris les éventuelles commandes
@code{\override}.

En d'autres termes, une commande @code{\override} affecte toujours les
deux extrémités d'un objet @emph{spanner}.  Pour ne modifier que la
partie précédant ou suivant le changement de ligne, il faut intervenir
directement dans le processus de mise en page.
La fonction de rappel @code{after-line-breaking} contient toute
l'opération Scheme effectuée lorsque les sauts de lignes ont été
déterminés, et que des objets graphiques ont été divisés sur des
systèmes différents.

Dans l'exemple suivant, on définit une nouvelle opération nommée
@code{my-callback}.  Cette opération

@itemize
@item
détermine si l'objet a été divisé à l'occasion d'un changement de ligne
@item
dans l'affirmative, recherche les différents tronçons de l'objet
@item
vérifie si l'objet considéré est bien la deuxième moitié d'un objet
divisé
@item
dans l'affirmative, applique un espacement supplémentaire
(@code{extra-offset}).
@end itemize

On ajoute cette procédure à l'objet @rinternals{Tie} (liaison de tenue),
de façon à ce que le deuxième tronçon d'une liaison divisée soit
rehaussé.

@c KEEP LY
@lilypond[quote,verbatim,ragged-right]
#(define (my-callback grob)
   (let* (
          ;; l'objet a-t-il été divisé ?
          (orig (ly:grob-original grob))

          ;; si oui, rechercher les tronçons frères (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 {
  \override Tie.after-line-breaking =
  #my-callback
  c''1 ~ \break
  c2 ~ 2
}
@end lilypond

@noindent
Lorsque cette astuce va être appliquée, notre nouvelle fonction de
rappel @code{after-line-breaking} devra également appeler celle
d'origine (@code{after-line-breaking}), si elle existe.  Ainsi, pour
l'utiliser dans le cas d'un crescendo (objet @code{Hairpin}), il faudra
également appeler @code{ly:spanner::kill-zero-spanned-time}.


@item
Pour des raisons d'ordre technique, certains objets ne peuvent être
modifiés par @code{\override}.  Parmi ceux-là, les objets
@code{NonMusicalPaperColumn} et @code{PaperColumn}.  La commande
@code{\overrideProperty} sert à les modifier, de façon similaire à
@code{\once \override}, mais avec une syntaxe différente :

@example
\overrideProperty
Score.NonMusicalPaperColumn      % Nom de l'objet
  . line-break-system-details    % Nom de la propriété
  . next-padding                 % Nom de la sous-propriété (optionnel)
  . #20                          % Valeur
@end example

Notez toutefois que la commande @code{\override} peut tout de même être
appliquée à @code{NonMusicalPaperColumn} et @code{PaperColumn} dans un
bloc @code{\context}.

@end itemize


@node Interfaces LilyPond Scheme
@chapter Interfaces LilyPond Scheme
@translationof LilyPond Scheme interfaces

Ce chapitre aborde les différents outils fournis par LilyPond à
l'intention des programmeurs en Scheme désireux d'obtenir des
informations à partir et autour des fluxs de musique.

TODO -- figure out what goes in here and how to organize it
