@c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*-
@ignore
- Translation of GIT committish: 3f4496001441e0b1b27d7bc5395c4520f4f2088c
+ Translation of GIT committish: d46572826e777ed3e9fa4656535a6e9000f2ed9e
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.13.36"
+@c \version "2.19.2"
-@c Translators: Valentin Villenave
-@c Translation checkers: Gilles Thibault, Jean-Charles Malahieude
+@c Translators: Valentin Villenave, Jean-Charles Malahieude
+@c Translation checkers: Gilles Thibault
-
-@node Interfaces pour les programmeurs
-@chapter Interfaces pour les programmeurs
+@node Interfaces pour programmeurs
+@chapter Interfaces pour programmeurs
@translationof Interfaces for programmers
-@untranslated
-
+Scheme permet de réaliser des affinages très pointus. Si vous ne
+connaissez rien de Scheme, vous en aurez un aperçu au travers de notre
+@ref{Tutoriel Scheme}.
@menu
+* Blocs de code LilyPond::
+* Fonctions Scheme::
* Fonctions musicales::
-* Interfaces de programmation::
-* Construction de fonctions complexes::
-* Interface de programmation des marqueurs de texte::
+* Fonctions événementielles::
+* Fonctions pour markups::
* Contextes pour programmeurs::
-* Utilisation de procédures Scheme en tant que propriétés::
-* Utilisation de code Scheme au lieu de \"tweak\"::
+* 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
+
+@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
+@section Fonctions Scheme
+@translationof Scheme functions
+
+@cindex Scheme, fonctions (syntaxe LilyPond)
+
+Les @emph{fonctions Scheme} sont des procédures Scheme chargées de créer
+des expressions Scheme à partir de code rédigé selon la syntaxe de
+LilyPond. Elles peuvent être appelées en de nombreux endroits, à l'aide
+d'un @code{#}, où spécifier une valeur en syntaxe Scheme est autorisé.
+Bien que Scheme dispose de fonctions en propre, nous nous intéresserons,
+au fil des paragraphes qui suivent, aux fonctions @emph{syntaxiques},
+autrement dit des fonctions qui reçoivent des arguments libellés dans la
+syntaxe de LilyPond.
+
+@menu
+* Définition de fonctions Scheme::
+* Utilisation de fonctions Scheme::
+* Fonctions Scheme fantômes::
+@end menu
+
+@node Définition de fonctions Scheme
+@subsection Définition de fonctions Scheme
+@translationof Scheme function definitions
+
+@funindex define-scheme-function
+
+D'une manière générale, une fonction Scheme se définit ainsi :
+
+@example
+fonction =
+#(define-scheme-function
+ (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 formes d'expression, comme la plupart du temps où la
+musique n'est pas bornée par des accolades, où LilyPond doit lire
+au-delà de cette même expression afin d'en déterminer la fin. Si une
+telle expression devait, après évaluation du prédicat, faire l'objet
+d'un argument optionnel, LilyPond n'aurait aucun moyen, à partir du
+moment où il aura décidé que l'expression ne correspond pas au
+paramètre, de « revenir en arrière ». C'est la raison pour laquelle
+certaines formes musicales devraient être bornées par des accolades pour
+que LilyPond puisse les reconnaître efficacement. Il existe d'autres
+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 pourraient ne pas être cohérents avec 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
+
+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
+
+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
@section Fonctions musicales
@translationof Music functions
-@untranslated
+@cindex musicale, fonction
+Les @emph{fonctions musicales} sont des procédures Scheme capables de
+créer automatiquement des expressions musicales ; elles permettent
+de grandement simplifier un fichier source.
@menu
-* Aperçu des fonctions musicales::
+* Définition de fonctions musicales::
+* Utilisation de fonctions musicales::
* Fonctions de substitution simple::
-* Fonctions de substitution par paire::
+* Fonctions de substitution intermédiaires::
* De l'usage des mathématiques dans les fonctions::
-* Fonctions fantômes::
* Fonctions dépourvues d'argument::
-* Liste des fonctions musicales prédéfinies::
+* Fonctions musicales fantômes::
@end menu
-@node Aperçu des fonctions musicales
-@subsection Aperçu des fonctions musicales
-@translationof Overview of music functions
-@untranslated
+@node Définition de fonctions musicales
+@subsection Définition de fonctions musicales
+@translationof Music function definitions
+
+@cindex fonction musicale, définition
+
+@funindex define-music-function
+
+Une fonction musicale se définit ainsi :
+
+@example
+fonction =
+#(define-music-function
+ (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
+
+Une fonction musicale peut prendre place en différents endroits.
+Certaines restrictions s'appliqueront selon l'endroit où elle est
+utilisée, de telle sorte que l'analyse syntaxique soit sans ambiguïté.
+Le résultat renvoyé par une fonction musicale doit être compatible avec
+le contexte dans lequel elle est appelée.
+
+@itemize
+@item
+Dans une expression musicale de haut niveau@tie{}: aucune restriction.
+
+@item
+En tant que post-événement, explicitement introduit par un indicateur de
+positionnement -- à savoir @code{-}, @code{^}, ou@tie{}@code{_}.
+
+Dans ce cas particulier, vous ne pouvez utiliser une expression musicale
+@emph{ouverte} en tant que dernier argument -- argument qui se
+composerait d'une expression musicale susceptible d'accepter des
+postévénements additionnels.
+
+@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
+Les règles spécifiques en matière d'arguments de fin rendent possible
+l'écriture de fonctions polymorphes telles que @code{\tweak}, qui
+peuvent s'appliquer à différentes constructions.
@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
+
+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
-@node Fonctions de substitution par paire
-@subsection Fonctions de substitution par paire
-@translationof Paired substitution functions
+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.
-@untranslated
+@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
+}
-@node Fonctions fantômes
-@subsection Fonctions fantômes
-@translationof Void functions
+\relative c' {
+ c2 \AltOn #0.5 c4 c
+ \AltOn #1.5 c c \AltOff c2
+}
+@end lilypond
-@untranslated
+@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
-@node Liste des fonctions musicales prédéfinies
-@subsection Liste des fonctions musicales prédéfinies
-@translationof Overview of available music functions
+Il peut, dans certains cas particuliers, s'avérer utile de créer une
+fonction sans argument comme ici,
-@untranslated
+@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
-@include identifiers.tely
-@node Interfaces de programmation
-@section Interfaces de programmation
-@translationof Programmer interfaces
+@example
+lilypond -d display-bar-numbers MONFICHIER.ly
+@end example
-@untranslated
+@node Fonctions musicales fantômes
+@subsection Fonctions musicales fantômes
+@translationof Void music functions
-@menu
-* Variables d'entrée et Scheme::
-* Représentation interne de la musique::
-@end menu
+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 Variables d'entrée et Scheme
-@subsection Variables d'entrée et Scheme
-@translationof Input variables and Scheme
-@untranslated
+@node Fonctions événementielles
+@section Fonctions événementielles
+@translationof Event functions
+@funindex define-event-function
+@cindex événementielle, fonction
-@node Représentation interne de la musique
-@subsection Représentation interne de la musique
-@translationof Internal music representation
+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 Construction de fonctions complexes
-@section Construction de fonctions complexes
-@translationof Building complicated functions
-@untranslated
+@node Fonctions pour markups
+@section Fonctions pour @emph{markups}
+@translationof Markup functions
+Les @emph{markups} sont implémentés au travers de fonctions Scheme
+spécifiques qui produisent des objets @code{Stencil} comprenant un
+certain nombre d'arguments.
@menu
-* Affichage d'expressions musicales::
-* Propriétés de la musique::
-* Exemple : redoubler une note avec liaison::
-* Exemple : ajouter une articulation à plusieurs notes::
+* Construction d'un markup en Scheme::
+* Fonctionnement interne des markups::
+* Définition d'une nouvelle commande de markup::
+* Définition d'une nouvelle commande de liste de markups::
@end menu
-@node Affichage d'expressions musicales
-@subsection Affichage d'expressions musicales
-@translationof Displaying music expressions
-@untranslated
+@node Construction d'un markup en Scheme
+@subsection Construction d'un @emph{markup} en Scheme
+@translationof Markup construction in Scheme
+
+@cindex définition d'une commande markup
+
+@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} :
-@node Propriétés de la musique
-@subsection Propriétés de la musique
-@translationof Music properties
+@example
+\displayScheme
+\markup @{
+ \column @{
+ \line @{ \bold \italic "hello" \raise #0.4 "world" @}
+ \larger \line @{ foo bar baz @}
+ @}
+@}
+@end example
-@untranslated
+@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
-@node Exemple : redoubler une note avec liaison
-@subsection Exemple : redoubler une note avec liaison
-@translationof Doubling a note with slurs (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}.
-@untranslated
+@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} :
-@node Exemple : ajouter une articulation à plusieurs notes
-@subsection Exemple : ajouter une articulation à plusieurs notes
-@translationof Adding articulation to notes (example)
+@lisp
+(markup (make-line-markup (fonction-qui-retourne-des-markups)))
+@end lisp
-@untranslated
+@node Fonctionnement interne des markups
+@subsection Fonctionnement interne des @emph{markups}
+@translationof How markups work internally
-@node Interface de programmation des marqueurs de texte
-@section Interface de programmation des marqueurs de texte
-@translationof Markup programmer interface
+Dans un @emph{markup} tel que
-@untranslated
+@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
+
+Nous allons étudier dans ce qui suit la manière de définir une nouvelle
+commande de @emph{markup}.
@menu
-* Construction Scheme d'un marqueur::
-* Fonctionnement interne des marqueurs::
-* Définition d'une nouvelle commande de marqueur::
-* Définition d'une nouvelle commande de liste de marqueurs::
+* Syntaxe d'une commande markup::
+* Attribution de propriétés::
+* Exemple commenté::
+* Adaptation d'une commande incorporée::
@end menu
-@node Construction Scheme d'un marqueur
-@subsection Construction Scheme d'un marqueur
-@translationof Markup construction in Scheme
-@untranslated
+@node Syntaxe d'une commande markup
+@unnumberedsubsubsec Syntaxe d'une commande @emph{markup}
+@translationof Markup command definition syntax
+
+Une commande de @emph{markup} personnalisée se définit à l'aide de la
+macro Scheme @code{define-markup-command}, placée en tête de fichier.
+
+@lisp
+(define-markup-command (@var{nom-commande} @var{layout} @var{props} @var{arg1} @var{arg2}@dots{})
+ (@var{arg1-type?} @var{arg2-type?}@dots{})
+ [ #:properties ((@var{propriété1} @var{valeur-par-défaut1})
+ @dots{}) ]
+ @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
+
+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
-@node Fonctionnement interne des marqueurs
-@subsection Fonctionnement interne des marqueurs
-@translationof How markups work internally
+@example
+(ly:output-def-lookup layout 'line-width)
+@end example
-@untranslated
+L'argument @code{props} rend certaines propriétés accessibles aux
+commandes de @emph{markup}. Il en va ainsi lors de l'interprétation
+d'un @emph{markup} de titre d'ouvrage : toutes les variables
+définies dans le bloc @code{\header} sont automatiquement ajoutées aux
+@code{props}, de telle sorte que le @emph{markup} de titrage de
+l'ouvrage pourra accéder aux différents champs titre, compositeur etc.
+Ceci permet aussi de configurer le comportement d'une commande de
+@emph{markup} : la taille des fontes, par exemple, est lue à
+partir de @code{props} plutôt que grâce à un argument @code{font-size}.
+La fonction appelant une commande de @emph{markup} peut altérer la
+valeur de la propriété taille des fontes et donc en modifier le
+comportement. L'utilisation du mot-clé @code{#:properties}, attaché à
+@code{define-markup-command}, permet de spécifier les propriétés devant
+être lues parmi les arguments @code{props}.
+
+L'exemple proposé à la rubrique suivante illustre comment, au sein d'une
+commande de @emph{markup}, accéder aux différentes propriétés et les
+modifier.
+
+
+@node Exemple commenté
+@unnumberedsubsubsec Exemple commenté
+@translationof A complete example
+
+Nous allons, dans cet exemple, nous attacher à encadrer du texte avec un
+double liseré.
+
+Commençons par construire quelque chose d'approximatif à l'aide d'un
+simple @emph{markup}. La lecture de @ruser{Commandes pour markup} nous
+indique la commande @code{\box}, qui semble ici appropriée.
+@lilypond[quote,verbatim,ragged-right]
+\markup \box \box HELLO
+@end lilypond
-@node Définition d'une nouvelle commande de marqueur
-@subsection Définition d'une nouvelle commande de marqueur
-@translationof New markup command definition
+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
-@untranslated
+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
+
+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 marqueurs
-@subsection Définition d'une nouvelle commande de liste de marqueurs
+@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}@tie{}:
+@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::
@end menu
+
@node Évaluation d'un contexte
@subsection Évaluation d'un contexte
@translationof Context evaluation
-@untranslated
+@cindex appel de code durant l'interprétation
+@funindex \applyContext
+
+Un contexte peut être modifié, au moment même de son interprétation, par
+du code Scheme. La syntaxe consacrée en pareil cas est
+@example
+\applyContext @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. Les lignes de code qui suivent auront
+pour effet d'afficher à l'écran, en cours de compilation, le numéro de
+mesure en cours.
+
+@example
+\applyContext
+ #(lambda (x)
+ (format #t "\nNous en sommes à la mesure ~a.\n"
+ (ly:context-property x 'currentBarNumber)))
+@end example
@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
-@untranslated
+@cindex appel de code sur des objets de mise en forme
+@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
+à la syntaxe
+@example
+\applyOutput @var{Contexte} @var{procédure}
+@end example
-@node Utilisation de procédures Scheme en tant que propriétés
-@section Utilisation de procédures Scheme en tant que propriétés
-@translationof Scheme procedures as properties
+@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
-@untranslated
+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.
-@menu
-* Utilisation de code Scheme au lieu de \"tweak\"::
-* Retouches complexes::
-@end menu
+@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} 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
+
+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
+
+Dans le cas où la routine doit faire appel à plusieurs arguments, le
+@emph{grob} en cours peut s'insérer à l'aide d'un @emph{grob} enchâssé.
+Voici, à titre d'illustration, un réglage pour
+@code{AccidentalSuggestion} :
+
+@example
+`(X-offset .
+ ,(ly:make-simple-closure
+ `(,+
+ ,(ly:make-simple-closure
+ (list ly:self-alignment-interface::centered-on-x-parent))
+ ,(ly:make-simple-closure
+ (list ly:self-alignment-interface::x-aligned-on-self)))))
+@end example
+
+@noindent
+Ici, aussi bien @code{ly:self-alignment-interface::x-aligned-on-self}
+que @code{ly:self-alignment-interface::centered-on-x-parent} font appel
+à l'argument @emph{grob}. La fonction @code{+} a pour effet
+d'additionner les résultats. L'ensemble est inclus dans un
+@code{ly:make-simple-closure} de telle sorte que l'addition s'exécute de
+façon correcte
+
+Dans les faits, l'utilisation d'une unique procédure en tant que valeur
+d'une propriété revient à écrire
+
+@example
+(ly:make-simple-closure (ly:make-simple-closure (list @var{proc})))
+@end example
+
+@noindent
+Le @code{ly:make-simple-closure} intérieur fournit le @emph{grob} en
+argument à la procédure @var{proc}, l'extérieur s'assure que le résultat
+de la fonction sera bien renvoyé, non pas l'objet @code{simple-closure}.
+
+Au sein d'un @emph{callback}, le meilleur moyen d'évaluer un
+@emph{markup} consiste à utiliser la fonction
+@code{grob-interpret-markup}, comme ici :
-@node Utilisation de code Scheme au lieu de \"tweak\"
-@section Utilisation de code Scheme au lieu de @code{\tweak}
-@translationof Using Scheme code instead of tweak
+@example
+my-callback = #(lambda (grob)
+ (grob-interpret-markup grob (markup "foo")))
+@end example
+
+
+@node Code Scheme intégré
+@section Code Scheme intégré
+@translationof 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{Exemple : ajouter une articulation à plusieurs notes}, en
+@ref{Ajout d'articulation à des notes (exemple)}, en
particulier quant à l'emploi de @code{\displayMusic}.
@example
Certains réglages sont plus délicats que d'autres.
-@itemize @bullet
-
-
+@itemize
@item
-L'un d'entre eux est l'apparence des objets dits @qq{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}.
-
+L'un d'entre eux est l'apparence des objets dits @qq{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 @q{spanner}. Pour ne modifier que la partie
-précédant ou suivant le changement de ligne, il faut intervenir
+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é
Dans l'exemple suivant, on définit une nouvelle opération nommée
@code{my-callback}. Cette opération
-@itemize @bullet
+@itemize
@item
détermine si l'objet a été divisé à l'occasion d'un changement de ligne
@item
-si oui, recherche les différents morceaux de l'objet
+dans l'affirmative, recherche les différents morceaux de l'objet
@item
vérifie si l'objet considéré est bien la deuxième moitié d'un objet
divisé
@item
-si oui, applique un espacement supplémentaire (@code{extra-offset}).
+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),
@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))
+ (let* (
+ ;; l'objet a-t-il été divisé ?
+ (orig (ly:grob-original grob))
- ; si oui, rechercher les morceaux frères (siblings)
- (siblings (if (ly:grob? orig)
- (ly:spanner-broken-into orig) '() )))
+ ;; si oui, rechercher les morceaux 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)))))
+ (if (and (>= (length siblings) 2)
+ (eq? (car (last-pair siblings)) grob))
+ (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
+ c1 ~ \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 appeler également
-@code{ly:spanner::kill-zero-spanned-time}.
+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
+@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@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 cependant que la commande @code{\override} peut tout de même être
+Notez toutefois que la commande @code{\override} peut tout de même être
appliquée à @code{NonMusicalPaperColumn} et @code{PaperColumn} dans un
bloc @code{\context}.
@end itemize
+
+
+@node Interfaces LilyPond Scheme
+@chapter Interfaces LilyPond Scheme
+@translationof LilyPond Scheme interfaces
+
+Ce chapitre aborde les différents outils fournis par LilyPond à
+l'intention des programmeurs en Scheme désireux d'obtenir des
+informations à partir et autour des fluxs de musique.
+
+TODO -- figure out what goes in here and how to organize it