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

@ignore
   Translation of GIT committish: c2ea1fa2792532a1a123f08504fc8677defb7a96

   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 for programmers
@chapter Interfaces pour programmeurs

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{Scheme tutorial}.


@node LilyPond code blocks
@section Blocs de code LilyPond

@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 @samp{$} ou @samp{#}.

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 @samp{#}) mais en tant que variables LilyPond (préfixées par
un @samp{\}).

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 Scheme functions
@section Fonctions Scheme

@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 @samp{#}, 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.


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

@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ù

@indentedblock
@table @code
@item @var{argN}
@var{n}-ième argument.

@item @var{typeN?}
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 @var{corps}
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{LilyPond code blocks}. Au sein d'un bloc de code LilyPond, un
@samp{#} permet de référencer des arguments de la fonction -- tel
@code{#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 @samp{#} ne vous
permet pas de parvenir à vos fins, vous pourriez devoir revenir à une
expression Scheme « immédiate » à l'aide d'un @samp{$}, comme
@code{$music}.

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

@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 @samp{#} 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 @rnotationnamed{Predefined type predicates,
Types de prédicats prédéfinis}.

@morerefs
Manuel de notation :
@rnotationnamed{Predefined type predicates, 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 Scheme function usage
@subsection Utilisation de fonctions Scheme

Vous pouvez appeler une fonction Scheme pratiquement partout où une
expression Scheme derrière un @samp{#} peut prendre place. Vous appelez
une fonction Scheme à partir de LilyPond en faisant précéder son nom
d'un @samp{\}, 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 @samp{#} 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{Void Scheme functions} -- dans le cas contraire.

Pour des raisons de commodité, il est possible de faire appel à des
fonctions Scheme directement en Scheme, court-circuitant 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 traité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 omis sans plus d'indication
lorsque l'appel est fait au sein même de Scheme.


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

@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 Music functions
@section Fonctions musicales

@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.


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

@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{Scheme function definitions,
fonctions Scheme}.  La plupart du temps, le @var{corps} sera constitué
d'un @ref{LilyPond code blocks, bloc de code LilyPond}.

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

@morerefs
Manuel de notation :
@rnotationnamed{Predefined type predicates, 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 Music function usage
@subsection Utilisation de fonctions musicales

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

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 Simple substitution functions
@subsection Fonctions de substitution simple

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 @rnotationnamed{Substitution function examples, Exemples de
fonction de substitution}.


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

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éapparaîtra 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 Mathematics in functions
@subsection De l'usage des mathématiques dans les fonctions

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 Functions without arguments
@subsection Fonctions dépourvues d'argument

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 Void music functions
@subsection Fonctions musicales fantômes

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 Event functions
@section Fonctions événementielles

@funindex define-event-function
@cindex @'evé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 Markup functions
@section Fonctions pour @emph{markups}

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.


@node Markup construction in Scheme
@subsection Construction d'un @emph{markup} en 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 ("foo" "bar" "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{Displaying music expressions}.

@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 {@code{\markup @{ markup1 markup2 @dots{} @}}} {@code{(markup markup1 markup2 @dots{})}}
@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
@end indentedblock

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{New markup command definition}.

@knownissues
L'argument @var{markup-list} des commandes @code{#:line},
@code{#:center-column} 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-column-markup} ou
@code{make-column-markup} :

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


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

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 New markup command definition
@subsection Définition d'une nouvelle commande de @emph{markup}

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


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

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 On properties
@unnumberedsubsubsec Attribution de propriétés

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 A complete example
@unnumberedsubsubsec Exemple commenté

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 @rnotationnamed{Text markup commands,
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

@noindent
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{Markup construction in 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'argument @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 Adapting builtin commands
@unnumberedsubsubsec Adaptation d'une commande incorporée

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 Converting markups to strings
@unnumberedsubsubsec Conversion de @emph{markups} en chaînes

@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éta-donné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 New markup list command definition
@subsection Définition d'une nouvelle commande de liste de @emph{markups}

@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{New markup command definition}, à 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


@need 1500
@node Contexts for programmers
@section Contextes pour programmeurs


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

@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 Running a function on all layout objects
@subsection Application d'une fonction à tous les objets de mise en forme

@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 pour 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 Callback functions
@section Fonctions de rappel

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{Adding articulation to notes (example)}, 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 Unpure-pure containers
@section Conteneurs requalifiants

@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 Difficult tweaks
@section Retouches complexes

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 @minus{}
@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 LilyPond Scheme interfaces
@chapter Interfaces LilyPond Scheme

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
