@c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*-
@ignore
- Translation of GIT committish: 3c62ac104645533873bba800f7b0f371089f535a
+ Translation of GIT committish: e3c6bd65c8db492728d2f1f3a791bcf6bde056e4
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.15.18"
+@c \version "2.19.12"
@c Translators: Valentin Villenave, Jean-Charles Malahieude
@c Translation checkers: Gilles Thibault
@chapter Interfaces pour programmeurs
@translationof Interfaces for programmers
-Advanced tweaks may be performed by using Scheme. If you are
-not familiar with Scheme, you may wish to read our
+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::
+* Blocs de code LilyPond::
* Fonctions Scheme::
* Fonctions musicales::
* Fonctions événementielles::
* Fonctions pour markups::
* Contextes pour programmeurs::
* Fonctions de rappel::
-* Code Scheme intégré::
* Retouches complexes::
@end menu
-@node Blocs de code Lilypond
-@section Blocs de code Lilypond
-@translationof Lilypond code blocks
-@untranslated
+@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 (parser location) ()
+ #{ ^"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{#}.
+
+@cindex parser (fonction argument)
+@cindex location
+
+Le lecteur Scheme extrait le bloc de code LilyPond et déclenche un appel
+à l'analyseur grammatical de LilyPond (le @code{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{\}).
+
+Lorsque l'emplacement (@code{location} -- voir @ref{Fonctions Scheme})
+fait référence à un endroit valide dans la source -- ce qui est en
+général le cas au sein de fonctions musicales ou Scheme --, 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
@cindex Scheme, fonctions (syntaxe LilyPond)
-@untranslated
-
+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::
@funindex define-scheme-function
-@untranslated
+D'une manière générale, une fonction Scheme se définit ainsi :
+
+@example
+fonction =
+#(define-scheme-function
+ (parser location @var{arg1} @var{arg2}@dots{})
+ (@var{type1?} @var{type2?}@dots{})
+ @var{corps})
+@end example
+
+@noindent
+où
+
+@multitable @columnfractions .33 .66
+@item @code{parser}
+@tab doit être littéralement @code{parser}, de telle sorte que
+l'analyseur grammatical puisse accéder aux blocs de code LilyPond
+(@code{#@{}@dots{}@code{#@}}).
+
+@item @code{location}
+@tab doit être littéralement @code{location}, de telle sorte que soit
+accessible l'emplacement de l'objet dans la source, aux fins de
+transmettre aux messages d'erreur les fichier et numéro de ligne.
+
+@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} vers le paramètre @code{location}.
+
+@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à converti 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@tie{}? 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 type d'argument plus spécifiques.
+
+Les différents types des prédicat propres à LilyPond sont recensés à
+l'annexe @ruser{Types de prédicats prédéfinis}.
+
+@seealso
+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}.
@node Utilisation de fonctions Scheme
@subsection Utilisation de fonctions Scheme
@translationof Scheme function usage
-@untranslated
+Vous pouvez appeler une fonction Scheme pratiquement partout où une
+expression Scheme derrière un @code{#} peut prendre place. Vous appelez
+une fonction Scheme 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 @qq{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.
@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
-@untranslated
+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
+ (parser location)
+ ()
+ (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
@cindex musicale, fonction
-@untranslated
+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::
@subsection Définition de fonctions musicales
@translationof Music function definitions
-@cindex defining music functions
+@cindex fonction musicale, définition
+
@funindex define-music-function
-@untranslated
+Une fonction musicale se définit ainsi :
+
+@example
+fonction =
+#(define-music-function
+ (parser location @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 @code{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}.
+
+@seealso
+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}.
@node Utilisation de fonctions musicales
@subsection Utilisation de fonctions musicales
@translationof Music function usage
-@untranslated
+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
-@untranslated
+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
-@untranslated
+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 @qq{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
+ (parser location 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
+ (parser location 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érogatoins 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 une 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 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 (parser location 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
-@untranslated
+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
+ (parser location 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' {
+ c2 \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
+ (parser location 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' {
+ c2 \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
-@untranslated
+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
+ (parser location)
+ ()
+ (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
-@untranslated
+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
@translationof Event functions
@funindex define-event-function
-@cindex event functions
+@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 :
-@untranslated
+@lilypond[quote,verbatim,ragged-right]
+dyn=#(define-event-function (parser location arg) (markup?)
+ (make-dynamic-script arg))
+\relative c' { 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
-@untranslated
+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::
@subsection Construction d'un @emph{markup} en Scheme
@translationof Markup construction in Scheme
-@cindex defining markup commands
+@cindex définition d'une commande markup
+
+@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.
+
+@quotation
+@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
+@end quotation
+
+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} :
-@untranslated
+@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
-@untranslated
+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 (list simple-markup "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
-@untranslated
+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::
@unnumberedsubsubsec Syntaxe d'une commande @emph{markup}
@translationof Markup command definition syntax
-@untranslated
+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{}) ]
+ @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 @qq{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?}@tie{};
+@item une liste de @emph{markups}, correspondant au type de prédicat
+@code{markup-list?}@tie{};
+@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{macro}, 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
-@untranslated
+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
-@untranslated
+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
+
+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@tie{}: 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}@tie{}; 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
-@untranslated
+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 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
-@untranslated
+@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é @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
-@untranslated
@menu
* Évaluation d'un contexte::
* Application d'une fonction à tous les objets de mise en forme::
@subsection Évaluation d'un contexte
@translationof Context evaluation
-@cindex calling code during interpreting
+@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
-@untranslated
+@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@tie{}\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 g' {
+ \time 3/4
+ g8[ 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@tie{}\override} et pour un @code{\revert} :
+
+@lilypond[quote,verbatim]
+desaturate =
+#(define-music-function
+ (parser location 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 g' {
+ \override NoteHead.color = #darkblue
+ \override Stem.color = #darkblue
+ \override Beam.color = #darkblue
+ g8 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 calling code on layout objects
+@cindex appel de code sur des objets de mise en forme
@funindex \applyOutput
-@untranslated
+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
+à la syntaxe
+@example
+\applyOutput @var{Contexte} @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 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 et 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 @qq{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 (and (memq 'note-head-interface (ly:grob-interfaces grob))
+ (< (abs (ly:grob-property grob 'staff-position)) 2))
+ (set! (ly:grob-property grob 'transparent) #t)))
+
+\relative c' {
+ a'4 e8 <<\applyOutput #'Voice #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 #@var{procédure}
+\applyOutput #'Staff #@var{procédure}
+@end example
@node Fonctions de rappel
@section Fonctions de rappel
@translationof Callback functions
-@untranslated
+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@tie{}:
+
+@example
+\override Stem.thickness = #2.0
+@end example
+
+Une procédure Scheme peut aussi se charger de modifier des
+propriétés@tie{}:
+
+@lilypond[fragment,verbatim,quote,relative=2]
+\override Stem.thickness = #(lambda (grob)
+ (if (= UP (ly:grob-property grob 'direction))
+ 2.0
+ 7.0))
+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 c'' @{
+ \override Flag.X-offset = #(lambda (flag)
+ (let ((default (ly:flag::calc-x-offset flag)))
+ (* default 4.0)))
+ c4. d8 a4. g8
+@}
+@end example
-@node Code Scheme intégré
-@section Code Scheme intégré
-@translationof Inline Scheme code
+Au sein d'un @emph{callback}, le meilleur moyen d'évaluer un
+@emph{markup} consiste à utiliser la fonction
+@code{grob-interpret-markup}, comme ici :
-TODO: the example for this section is ill-chosen since
@example
-F = -\tweak #'font-size #-3 -\flageolet
+my-callback = #(lambda (grob)
+ (grob-interpret-markup grob (markup "foo")))
@end example
-(note the @samp{-} marking it as a post event) will actually work fine
-for the stated purpose. Until this section gets a rewrite, let's
-pretend we don't know.
+
+
+@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.
+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
+F = \tweak font-size #-3 -\flageolet
\relative c'' @{
c4^\F c4_\F
@end example
@noindent
-En d'autres termes, @code{\tweak} ne se comporte pas comme une
-articulation@tie{}: il ne peut notamment pas être accolé avec les
-symboles @samp{^} ou @samp{_}.
-
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
@code{set!}. Le dernier élément, dans ce bloc @code{let}, est la valeur
finale de @samp{m} lui-même.
+@end ignore
+
@node Retouches complexes
@section Retouches complexes
(ly:grob-set-property! grob 'extra-offset '(-2 . 5)))))
\relative c'' {
- \override Tie #'after-line-breaking =
+ \override Tie.after-line-breaking =
#my-callback
c1 ~ \break
- c2 ~ c
+ c2 ~ 2
}
@end lilypond
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@tie{}:
+@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 . 20)) % Valeur
+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
@chapter Interfaces LilyPond Scheme
@translationof LilyPond Scheme interfaces
-@untranslated
+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