X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Documentation%2Ffr%2Fextending%2Fprogramming-interface.itely;h=d27cc4162265b9e26838fb0cefe2667ad3a75ba7;hb=32a34dcef0c0041c6d62677487a380b5c8b85712;hp=a66da00d6c6e37d2a1462ca06e76d0b4894b0b4f;hpb=f41973ff763d5972a85995b6d40c864281ec6714;p=lilypond.git diff --git a/Documentation/fr/extending/programming-interface.itely b/Documentation/fr/extending/programming-interface.itely index a66da00d6c..d27cc41622 100644 --- a/Documentation/fr/extending/programming-interface.itely +++ b/Documentation/fr/extending/programming-interface.itely @@ -1,255 +1,1289 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*- - @ignore - Translation of GIT committish: 3f4496001441e0b1b27d7bc5395c4520f4f2088c + Translation of GIT committish: 952705bbbb000581a13836e6a733df04511e93c5 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.14.0" - -@c Translators: Valentin Villenave -@c Translation checkers: Gilles Thibault, Jean-Charles Malahieude +@c \version "2.16.0" +@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 + +Les blocs de code LilyPond ressemblent à +@example + #@{ @var{du code LilyPond} #@} +@end example +Ils peuvent s'utiliser partout où vous pouvez écrire du code Scheme. +Le lecteur Scheme est en fait quelque peu adapté pour accepter des blocs +de code LilyPond ; il est capable de traiter des expressions Scheme +intégrées débutant par @code{$} ou @code{#}. + +Le lecteur Scheme extrait le bloc de code LilyPond et déclenche un appel +à l'analyseur grammatical de LilyPond (le @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. + +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{@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}. Certains de ces prédicats, comme nous le +verrons plus loin, bénéficient d'un traitement particulier de la part du +@emph{parser}. De même existe 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 +de 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 @qq{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 +Certains types de prédicat font l'objet d'un traitement spécial de la +part de l'analyseur grammatical, dans la mesure où il n'a aucun autre +moyen de reconnaître efficacement les arguments. Il s'agit, à l'heure +actuelle, de @code{ly:pitch?} et @code{ly:duration?}. + +Pour tous les autres prédicats, 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 @qq{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 +après consultation du prédicat. Pour toutes ces raisons, nous vous +enjoignons à éviter d'utiliser des prédicats permissifs tel que +@code{scheme?}, dès que vous voulez les utiliser dans un but particulier +plutôt que dans une fonction de portée générale. + +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)) +... +\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{_}. Notez +bien que le renvoi d'un post-événement est valide lorsque la fonction +musicale est appelée comme de la musique normale ; ceci amène à un +résultat ressemblant à +@example +s 1*0-\fonction +@end example + +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?} : -@node Fonctions de substitution par paire -@subsection Fonctions de substitution par paire -@translationof Paired substitution functions +@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 : -@untranslated +@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 @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 + +La macro @code{markup} construit en Scheme des expressions @emph{markup} +tout en disposant d'une syntaxe proche de celle de LilyPond. Par exemple, +@example +(markup #:column (#:line (#:bold #:italic "hello" #:raise 0.4 "world") + #:larger #:line ("foo" "bar" "baz"))) +@end example + +@noindent +est équivalent à +@example +#@{ \markup \column @{ \line @{ \bold \italic "hello" \raise #0.4 "world" @} + \larger \line @{ foo bar baz @} @} #@} +@end example +@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 ... @}} @tab + @code{(markup markup1 markup2 ... )} +@item @code{\commande-markup} @tab @code{#:commande-markup} +@item @code{\variable} @tab @code{variable} +@item @code{\center-column @{ ... @}} @tab @code{#:center-column ( ... )} +@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 -@node Propriétés de la musique -@subsection Propriétés de la musique -@translationof Music properties +@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 Exemple : redoubler une note avec liaison -@subsection Exemple : redoubler une note avec liaison -@translationof Doubling a note with slurs (example) +@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 -@node Exemple : ajouter une articulation à plusieurs notes -@subsection Exemple : ajouter une articulation à plusieurs notes -@translationof Adding articulation to notes (example) +@noindent +@code{\raise} représente en fait la fonction @code{raise-markup}. +L'expression @emph{markup} est enregistrée sous la forme -@untranslated +@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 : -@node Interface de programmation des marqueurs de texte -@section Interface de programmation des marqueurs de texte -@translationof Markup programmer interface +@example +(apply raise-markup + @var{\layout objet} + @var{liste des alists de propriété} + 0.5 + @var{le @emph{markup} "text example"}) +@end example -@untranslated +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} ...) + (@var{arg1-type?} @var{arg2-type?} ...) + [ #:properties ((@var{propriété1} @var{valeur-par-défaut1}) + ...) ] + ..corps de la commande..) +@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. -@node Fonctionnement interne des marqueurs -@subsection Fonctionnement interne des marqueurs -@translationof How markups work internally +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}. -@untranslated +@node Attribution de propriétés +@unnumberedsubsubsec Attribution de propriétés +@translationof On properties -@node Définition d'une nouvelle commande de marqueur -@subsection Définition d'une nouvelle commande de marqueur -@translationof New markup command definition +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. -@untranslated +L'argument @code{layout} permet d'accéder aux propriétés définies dans +les blocs @code{\paper}, grâce à la fonction +@code{ly:output-def-lookup}. Par exemple, la longueur de ligne, +identique à celle de la partition, est lue au travers de + +@example +(ly:output-def-lookup layout 'line-width) +@end example + +L'argument @code{props} rend certaines propriétés accessibles aux +commandes de @emph{markup}. Il en va ainsi lors de l'interprétation +d'un @emph{markup} de titre d'ouvrage : toutes les variables +définies dans le bloc @code{\header} sont automatiquement ajoutées aux +@code{props}, de telle sorte que le @emph{markup} de titrage de +l'ouvrage pourra accéder aux différents champs titre, compositeur etc. +Ceci permet aussi de configurer le comportement d'une commande de +@emph{markup} : la taille des fontes, par exemple, est lue à +partir de @code{props} plutôt que grâce à un argument @code{font-size}. +La fonction appelant une commande de @emph{markup} peut altérer la +valeur de la propriété taille des fontes et donc en modifier le +comportement. L'utilisation du mot-clé @code{#:properties}, attaché à +@code{define-markup-command}, permet de spécifier les propriétés devant +être lues parmi les arguments @code{props}. + +L'exemple proposé à la rubrique suivante illustre comment, au sein d'une +commande de @emph{markup}, accéder aux différentes propriétés et les +modifier. + + +@node Exemple commenté +@unnumberedsubsubsec Exemple commenté +@translationof A complete example + +Nous allons, dans cet exemple, nous attacher à encadrer du texte avec un +double liseré. + +Commençons par construire quelque chose d'approximatif à l'aide d'un +simple @emph{markup}. La lecture de @ruser{Commandes pour markup} nous +indique la commande @code{\box}, qui semble ici appropriée. + +@lilypond[quote,verbatim,ragged-right] +\markup \box \box HELLO +@end lilypond +Dans un souci d'esthétique, nous aimerions que le texte et les +encadrements ne soient pas autant accolés. Selon la documentation de +@code{\box}, cette commande utilise la propriété @code{box-padding}, +fixée par défaut à 0,2. Cette même documentation nous indique +aussi comment la modifier : -@node Définition d'une nouvelle commande de liste de marqueurs -@subsection Définition d'une nouvelle commande de liste de marqueurs +@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 + +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)) + "..documentation.." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@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)) + "..documentation.." + (let ((th (* (ly:output-def-lookup layout 'line-thickness) + thickness)) + (x (car dest)) + (y (cdr dest))) + (make-line-stencil th 0 0 x y))) +@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)) + "..documentation.." + ... +@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 +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. + +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. + +@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 + + +@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}). + +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 : + +@example +my-callback = #(lambda (grob) + (grob-interpret-markup grob (markup "foo"))) +@end example -@menu -* Utilisation de code Scheme au lieu de \"tweak\":: -* Retouches complexes:: -@end menu -@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 +@node Code Scheme intégré +@section Code Scheme intégré +@translationof Inline Scheme code + +À REVOIR : l'exemple de cette rubrique n'est pas des plus judicieux puisque +@example +F = -\tweak #'font-size #-3 -\flageolet +@end example +(notez le @samp{-} qui qualifie d'événement postérieur) fonctionne +correctement dans ce cas d'espèce. 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. @@ -264,12 +1298,12 @@ F = \tweak #'font-size #-3 -\flageolet @noindent En d'autres termes, @code{\tweak} ne se comporte pas comme une -articulation@tie{}: il ne peut notamment pas être accolé avec les +articulation : 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 @@ -301,22 +1335,20 @@ finale de @samp{m} lui-même. 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é @@ -326,16 +1358,17 @@ systèmes différents. 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), @@ -345,49 +1378,62 @@ rehaussé. @c KEEP LY @lilypond[quote,verbatim,ragged-right] #(define (my-callback grob) - (let* ( - ; l'objet a-t-il été divisé ? - (orig (ly:grob-original grob)) + (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 = #my-callback - c1 ~ \break c2 ~ c + c1 ~ \break + c2 ~ c } @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 +#'((next-padding . 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