From: Jean-Charles Malahieude Date: Tue, 6 Mar 2012 16:14:41 +0000 (+0100) Subject: Doc-fr: enable Extending X-Git-Tag: release/2.15.33-1~2^2 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=ab45be2f0dd1b5eece042934682039ec4e99b271;p=lilypond.git Doc-fr: enable Extending * master file * Scheme tutorial (first delivery) * programming interface (re-enable old material & update skeleton) --- diff --git a/Documentation/fr/extending.tely b/Documentation/fr/extending.tely new file mode 100644 index 0000000000..346c0e6e2d --- /dev/null +++ b/Documentation/fr/extending.tely @@ -0,0 +1,78 @@ +\input texinfo @c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*- +@ignore + Translation of GIT committish: 3c62ac104645533873bba800f7b0f371089f535a + + 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 + +@setfilename lilypond-extending.info +@settitle GNU LilyPond -- Extension des fonctionnalités +@documentencoding UTF-8 +@documentlanguage fr +@afourpaper + +@c Translators: Jean-Charles Malahieude + +@macro manualIntro +Ce document constitue fournit les informations de base pour étendre les +fonctionnalités de LilyPond@tie{}version @version{}. +@end macro + +@c `Extending' was born 2003-04-23 with git commit c08f6e8... +@macro copyrightDeclare +Copyright @copyright{} 2003--2012 by par les auteurs. +@end macro + +@set FDL +@include macros.itexi + + +@c don't remove this comment. +@ignore +@omfcreator Han-Wen Nienhuys, Jan Nieuwenhuizen and Graham Percival +@omfdescription Programming extensions for the LilyPond music engraving system +@omftype program usage +@omfcategory Applications|Publishing +@omflanguage English +@end ignore + + +@lilyTitlePage{Extension des fonctionnalités} + + +@c TOC -- non-tex +@ifnottex + +@menu +* Tutoriel Scheme:: Programmation dans LilyPond. +* Interfaces pour programmeurs:: Comment dialoguer avec scheme. +* Interfaces LilyPond Scheme:: Obtention d'information dans la musique et autour + +Appendices + +* GNU Free Documentation License:: Licence de ce document. +* Index de LilyPond:: +@end menu + +@docMain +@end ifnottex + + +@contents + +@allowcodebreaks false + +@include extending/scheme-tutorial.itely +@include extending/programming-interface.itely + +@include fdl.itexi + +@node Index de LilyPond +@appendix Index de LilyPond +@translationof LilyPond index + +@printindex cp + +@bye diff --git a/Documentation/fr/extending/programming-interface.itely b/Documentation/fr/extending/programming-interface.itely index 13901180e5..53767027b2 100644 --- a/Documentation/fr/extending/programming-interface.itely +++ b/Documentation/fr/extending/programming-interface.itely @@ -1,209 +1,240 @@ @c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*- @ignore - Translation of GIT committish: c299f84d574ac9b97ab7ffbb640b5c3a1cdca5cc + Translation of GIT committish: 3c62ac104645533873bba800f7b0f371089f535a 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 \version "2.15.18" -@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 - +Advanced tweaks may be performed by using Scheme. If you are +not familiar with Scheme, you may wish to read our +@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 Fonctions musicales -@section Fonctions musicales -@translationof Music functions +@node Blocs de code Lilypond +@section Blocs de code Lilypond +@translationof Lilypond code blocks + +@untranslated + + +@node Fonctions Scheme +@section Fonctions Scheme +@translationof Scheme functions + +@cindex Scheme, fonctions (syntaxe LilyPond) @untranslated @menu -* Aperçu des fonctions musicales:: -* Fonctions de substitution simple:: -* Fonctions de substitution par paire:: -* De l'usage des mathématiques dans les fonctions:: -* Fonctions fantômes:: -* Fonctions dépourvues d'argument:: -* Liste des fonctions musicales prédéfinies:: +* Définition de fonctions Scheme:: +* Utilisation de fonctions Scheme:: +* Fonctions Scheme fantômes:: @end menu -@node Aperçu des fonctions musicales -@subsection Aperçu des fonctions musicales -@translationof Overview of music functions +@node Définition de fonctions Scheme +@subsection Définition de fonctions Scheme +@translationof Scheme function definitions + +@funindex define-scheme-function @untranslated -@node Fonctions de substitution simple -@subsection Fonctions de substitution simple -@translationof Simple substitution functions +@node Utilisation de fonctions Scheme +@subsection Utilisation de fonctions Scheme +@translationof Scheme function usage @untranslated -@node Fonctions de substitution par paire -@subsection Fonctions de substitution par paire -@translationof Paired substitution functions +@node Fonctions Scheme fantômes +@subsection Fonctions Scheme fantômes +@translationof Void scheme functions +@funindex define-void-function +@funindex \void @untranslated -@node De l'usage des mathématiques dans les fonctions -@subsection De l'usage des mathématiques dans les fonctions -@translationof Mathematics in functions +@node Fonctions musicales +@section Fonctions musicales +@translationof Music functions + +@cindex musicale, fonction @untranslated +@menu +* Définition de fonctions musicales:: +* Utilisation de fonctions musicales:: +* Fonctions de substitution simple:: +* Fonctions de substitution intermédiaires:: +* De l'usage des mathématiques dans les fonctions:: +* Fonctions dépourvues d'argument:: +* Fonctions musicales fantômes:: +@end menu + -@node Fonctions musicales fantômes -@subsection Fonctions musicales fantômes -@translationof Void music functions +@node Définition de fonctions musicales +@subsection Définition de fonctions musicales +@translationof Music function definitions + +@cindex defining music functions +@funindex define-music-function @untranslated -@node Fonctions dépourvues d'argument -@subsection Fonctions dépourvues d'argument -@translationof Functions without arguments +@node Utilisation de fonctions musicales +@subsection Utilisation de fonctions musicales +@translationof Music function usage @untranslated -@node Liste des fonctions musicales prédéfinies -@subsection Liste des fonctions musicales prédéfinies -@translationof Overview of available music functions +@node Fonctions de substitution simple +@subsection Fonctions de substitution simple +@translationof Simple substitution functions @untranslated -@include identifiers.tely -@node Interfaces de programmation -@section Interfaces de programmation -@translationof Programmer interfaces +@node Fonctions de substitution intermédiaires +@subsection Fonctions de substitution intermédiaires +@translationof Intermediate substitution functions @untranslated -@menu -* Variables d'entrée et Scheme:: -* Représentation interne de la musique:: -@end menu - -@node Variables d'entrée et Scheme -@subsection Variables d'entrée et Scheme -@translationof Input variables and Scheme +@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 -@node Représentation interne de la musique -@subsection Représentation interne de la musique -@translationof Internal music representation +@node Fonctions dépourvues d'argument +@subsection Fonctions dépourvues d'argument +@translationof Functions without arguments @untranslated -@node Construction de fonctions complexes -@section Construction de fonctions complexes -@translationof Building complicated functions +@node Fonctions musicales fantômes +@subsection Fonctions musicales fantômes +@translationof Void music functions @untranslated -@menu -* Affichage d'expressions musicales:: -* Propriétés de la musique:: -* Exemple : redoubler une note avec liaison:: -* Exemple : ajouter une articulation à plusieurs notes:: -@end menu +@node Fonctions événementielles +@section Fonctions événementielles +@translationof Event functions -@node Affichage d'expressions musicales -@subsection Affichage d'expressions musicales -@translationof Displaying music expressions +@funindex define-event-function +@cindex event functions @untranslated -@node Propriétés de la musique -@subsection Propriétés de la musique -@translationof Music properties +@node Fonctions pour markups +@section Fonctions pour @emph{markups} +@translationof Markup functions @untranslated +@menu +* Construction d'un markup en Scheme:: +* Fonctionnement interne des markups:: +* Définition d'une nouvelle commande de markup:: +* Définition d'une nouvelle commande de liste de markups:: +@end menu -@node Exemple : redoubler une note avec liaison -@subsection Exemple : redoubler une note avec liaison -@translationof Doubling a note with slurs (example) + +@node Construction d'un markup en Scheme +@subsection Construction d'un @emph{markup} en Scheme +@translationof Markup construction in Scheme + +@cindex defining markup commands @untranslated -@node Exemple : ajouter une articulation à plusieurs notes -@subsection Exemple : ajouter une articulation à plusieurs notes -@translationof Adding articulation to notes (example) +@node Fonctionnement interne des markups +@subsection Fonctionnement interne des @emph{markups} +@translationof How markups work internally @untranslated -@node Interface de programmation des marqueurs de texte -@section Interface de programmation des marqueurs de texte -@translationof Markup programmer interface +@node Définition d'une nouvelle commande de markup +@subsection Définition d'une nouvelle commande de @emph{markup} +@translationof New markup command definition @untranslated - @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 + +@node Syntaxe d'une commande markup +@unnumberedsubsubsec Syntaxe d'une commande @emph{markup} +@translationof Markup command definition syntax @untranslated -@node Fonctionnement interne des marqueurs -@subsection Fonctionnement interne des marqueurs -@translationof How markups work internally +@node Attribution de propriétés +@unnumberedsubsubsec Attribution de propriétés +@translationof On properties @untranslated -@node Définition d'une nouvelle commande de marqueur -@subsection Définition d'une nouvelle commande de marqueur -@translationof New markup command definition +@node Exemple commenté +@unnumberedsubsubsec Exemple commenté +@translationof A complete example @untranslated -@node Définition d'une nouvelle commande de liste de marqueurs -@subsection Définition d'une nouvelle commande de liste de marqueurs +@node Adaptation d'une commande incorporée +@unnumberedsubsubsec Adaptation d'une commande incorporée +@translationof Adapting builtin commands + +@untranslated + + +@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 @@ -214,17 +245,19 @@ @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 +@cindex calling code during interpreting +@funindex \applyContext + @untranslated @@ -232,24 +265,31 @@ @subsection Application d'une fonction à tous les objets de mise en forme @translationof Running a function on all layout objects + +@cindex calling code on layout objects +@funindex \applyOutput + @untranslated -@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 +@node Fonctions de rappel +@section Fonctions de rappel +@translationof Callback functions @untranslated -@menu -* Utilisation de code Scheme au lieu de \"tweak\":: -* Retouches complexes:: -@end menu +@node Code Scheme intégré +@section Code Scheme intégré +@translationof Inline Scheme code -@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 +TODO: the example for this section is ill-chosen since +@example +F = -\tweak #'font-size #-3 -\flageolet +@end example +(note the @samp{-} marking it as a post event) will actually work fine +for the stated purpose. Until this section gets a rewrite, let's +pretend we don't know. L'inconvénient principal de la commande @code{\tweak} est la rigidité de sa syntaxe. Par exemple, le code suivant produit une erreur. @@ -269,7 +309,7 @@ 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 +341,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 +364,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 +384,59 @@ 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@tie{}: @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 + +@untranslated + diff --git a/Documentation/fr/extending/scheme-tutorial.itely b/Documentation/fr/extending/scheme-tutorial.itely new file mode 100644 index 0000000000..7e43a19623 --- /dev/null +++ b/Documentation/fr/extending/scheme-tutorial.itely @@ -0,0 +1,1649 @@ +@c -*- coding: utf-8; mode: texinfo; documentlanguage: fr -*- + +@ignore + Translation of GIT committish: 3c62ac104645533873bba800f7b0f371089f535a + + When revising a translation, copy the HEAD committish of the + version that you are working on. For details, see the Contributors' + Guide, node Updating translation committishes.. +@end ignore + +@c \version "2.15.20" + +@c Translators: Jean-Charles Malahieude + +@node Tutoriel Scheme +@chapter Tutoriel Scheme + +@cindex Scheme +@cindex GUILE +@cindex Scheme, in-line code +@cindex accessing Scheme +@cindex evaluating Scheme +@cindex LISP + +LilyPond recourt abondamment au langage de programmation Scheme, tant au +niveau de la syntaxe de saisie que des mécanismes internes chargés de +combiner les différents modules du logiciel. Les lignes qui suivent +constituent un bref aperçu de la manière de saisir des données en +Scheme. Si vous désirez en apprendre plus sur Scheme, n'hésitez pas à +vous rendre sur @uref{http://@/www@/.schemers@/.org}. + +Le Scheme utilisé par LilyPond repose sur l'implémentation GNU +Guile@tie{}; celle-ci se base sur le standard Scheme @qq{R5RS}. Si +votre but est d'apprendre Scheme au travers de LilyPond, sachez que +l'utilisation d'une autre implémentation ou d'un autre standard pourrait +être source de désagrément. Vous trouverez plus d'information sur +guile à la page @uref{http://www.gnu.org/software/guile/}@tie{}; le +standard Scheme @qq{R5RS} est quant à lui disponible à la page +@uref{http://www.schemers.org/Documents/Standards/R5RS/}. + +@menu +* Introduction à Scheme:: +* Scheme et LilyPond:: +* Construction de fonctions complexes:: +@end menu + + +@node Introduction à Scheme +@section Introduction à Scheme +@translationof Introduction to Scheme + +Nous commencerons par nous intéresser à Scheme et à son fonctionnement, +grâce à l'interpréteur GUILE. Une fois plus à l'aise avec Scheme, nous +verrons comment ce langage peut s'intégrer à un fichier LilyPond. + +@menu +* Le bac à sable de Scheme:: +* Scheme et les variables:: +* Types de données Scheme simples:: +* Types de données Scheme composites:: +* Scheme et les calculs:: +* Scheme et les procédures:: +* Scheme et les conditions:: +@end menu + + +@node Le bac à sable de Scheme +@subsection Le bac à sable de Scheme +@translationof Scheme sandbox + +L'installation de LilyPond comprend l'implémentation Guile de Scheme. +La plupart des systèmes disposent d'un @qq{bac à sable} Scheme pour +effectuer des tests@tie{}; vous y accéderez en tapant @qq{guile} dans +un terminal. Certains systèmes, notamment Windows, nécessitent d'avoir +auparavant créé la variable d'environnement @code{GUILE_LOAD_PATH} qui +devra pointer vers le répertoire @code{../usr/share/guile/1.8} de +l'installation de LilyPond -- pour connaître le chemin complet d'accès à +ce répertoire, consultez @rlearning{Autres sources de documentation}. +Les utilisateurs de Windows peuvent aussi prendre l'option @qq{Exécuter} +à partir du menu @qq{Démarrer} puis taper @qq{guile}. + +Néanmoins, tous les paquetages de LilyPond disposent d'un bac à sable +Scheme, accessible par la commande@tie{}: +@example +lilypond scheme-sandbox +@end example + +@noindent +Une fois le bac à sable actif, vous obtiendrez l'invite@tie{}: +@lisp +guile> +@end lisp + +Vous pouvez dès à présent saisir des expressions Scheme pour vous +exercer. Si vous souhaitez pourvoir utiliser la bibliothèque GNU +@code{readline}, qui offre une ligne de commande plus élaborée, +consultez les informations contenues dans le fichier +@file{ly/scheme-sandbox.ly}. La bibliothèque @var{readline}, dans la +mesure où elle est habituellement activée dans vos sessions Guile, +devrait être effective y compris dans le bac à sable. + + +@node Scheme et les variables +@subsection Scheme et les variables +@translationof Scheme variables + +Une variable Scheme peut contenir n'importe quelle valeur valide en +Scheme, y compris une procédure Scheme. + +Une variable Scheme se crée avec la fonction @code{define}@tie{}: + +@lisp +guile> (define a 2) +guile> +@end lisp + +L'évaluation d'une variable Scheme se réalise en saisissant le nom de +cette variable à l'invite de Guile@tie{}: + +@lisp +guile> a +2 +guile> +@end lisp + +Une variable Scheme s'affiche à l'écran à l'aide de la fonction +@code{display}@tie{}: + +@lisp +guile> (display a) +2guile> +@end lisp + +@noindent +Vous aurez remarqué que la valeur @code{2} et l'invite @code{guile} +apparaissent sur une même ligne. On peut améliorer la présentation à +l'aide de la procédure @code{newline} ou bien en affichant un caractère +@qq{retour chariot}. + +@lisp +guile> (display a)(newline) +2 +guile> (display a)(display "\n") +2 +guile> +@end lisp + +Après avoir créé une variable, vous pouvez en modifier la valeur grâce à +un @code{set!}@tie{}: + +@lisp +guile> (set! a 12345) +guile> a +12345 +guile> +@end lisp + +Vous quitterez proprement le bac à sable à l'aide de l'instruction +@code{quit}@tie{}: + +@lisp +guile> (quit) +@end lisp + + +@node Types de données Scheme simples +@subsection Types de données Scheme simples +@translationof Scheme simple data types + +L'un des concepts de base de tout langage est la saisie de données, +qu'il s'agisse de nombres, de chaînes de caractères, de listes etc. +Voici les différents types de données Scheme simples utilisées +couramment dans LilyPond. + +@table @asis +@item Booléens +Les valeurs booléennes sont vrai ou faux. En Scheme, ce sera @code{#t} +pour vrai, et @code{#f} pour faux. +@funindex ##t +@funindex ##f + +@item Nombres +Les nombres se saisissent le plus communément@tie{}: @code{1} est le +nombre (entier) un, alors que @w{@code{-1.5}} est un nombre à virgule +flottante (un nombre non entier). + +@item Chaînes +Les chaînes de caractères sont bornées par des guillemets +informatiques@tie{}: + +@example +"ceci est une chaîne" +@end example + +Une chaîne peut s'étendre su plusieurs lignes@tie{}: + +@example +"ceci +est +une chaîne" +@end example + +@noindent +auquel cas les retours à la ligne seront inclus dans la chaîne. + +Un caractère de retour à la ligne peut s'ajouter dans la chaîne, sous la +forme d'un @code{\n}. + +@example +"ceci\nest une\nchaîne multiligne" +@end example + +Guillemets et obliques inverses dans une chaîne doivent être précédés +d'une oblique inverse. La chaîne @code{\a dit "b"} se saisit donc + +@example +"\\a dit \"b\"" +@end example + +@end table + +Il existe bien d'autres types de donnée Scheme, dont nous ne parlerons +pas ici. Vous en trouverez une liste exhaustive dans le guide de +référence de Guile, à la page +@uref{http://www.gnu.org/software/guile/manual/html_node/Simple-Data-Types.html}. + + +@node Types de données Scheme composites +@subsection Types de données Scheme composites +@translationof Scheme compound data types + +Scheme prend aussi en charge des types de données composites. LilyPond +utilise beaucoup les paires, listes, listes associatives et tables de +hachage. + +@subheading Paires + +Le type de donnée composite fondamental est la paire (@code{pair}). +Comme son nom l'indique, il s'agit de lier deux valeurs, à l'aide de +l'opérateur @code{cons}. + +@lisp +guile> (cons 4 5) +(4 . 5) +guile> +@end lisp + +Vous aurez noté que la paire s'affiche sous la forme de deux éléments +bornés par des parenthèses et séparés par une espace, un point +(@code{.}) et une autre espace. Le point n'est en aucune manière un +séparateur décimal@tie{}; il s'agit de l'indicateur d'une paire. + +Vous pouvez aussi saisir littéralement les valeurs d'une paire, en la +faisant précéder d'une apostrophe. + +@lisp +guile> '(4 . 5) +(4 . 5) +guile> +@end lisp + +Les deux éléments d'une paire peuvent être constitués de n'importe +quelle valeur Scheme valide@tie{}: + +@lisp +guile> (cons #t #f) +(#t . #f) +guile> '("blah-blah" . 3.1415926535) +("blah-blah" . 3.1415926535) +guile> +@end lisp + +Les premier et second éléments de la paire sont accessibles à l'aide des +procédures Scheme @code{car} et @code{cdr}. + +@lisp +guile> (define mypair (cons 123 "hello there") +... ) +guile> (car mypair) +123 +guile> (cdr mypair) +"hello there" +guile> +@end lisp + +@noindent + +Note : @code{cdr} se prononce @qq{couldeur}, comme l'indiquent Sussman et +Abelson -- voir +@uref{http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-14.html#footnote_Temp_133}. + + +@subheading Listes + +Autre structure de donnée commune en Scheme@tie{}: la liste +(@emph{list}). Une liste se définit comme étant vide (représentée par +@code{'()}) ou une paire dont le @code{cdr} est une liste. + +Il existe plusieurs méthodes pour créer une liste, la plus courante +étant l'utilisation de la procédure @code{list}@tie{}: + +@lisp +guile> (list 1 2 3 "abc" 17.5) +(1 2 3 "abc" 17.5) +@end lisp + +Comme vous le remarquez, une liste s'affiche sous la forme d'une suite +d'éléments séparés par une espace, bornée par des parenthèses. +Contrairement à une paire, il n'y a pas de point entre les éléments. + +Vous pouvez aussi saisir directement une liste en entourant ses éléments +par des parenthèses à la suite d'une apostrophe@tie{}: + +@lisp +guile> '(17 23 "foo" "bar" "bazzle") +(17 23 "foo" "bar" "bazzle") +@end lisp + +Les listes ont une importance considérable en Scheme. Certains vont +d'ailleurs jusqu'à considérer Scheme comme un dialecte du lisp, où +@qq{lisp} serait une abréviation de @qq{List Processing}. Il est vrai +que toute expression Scheme est une liste. + + +@subheading Listes associatives (alists) + +Il existe un type particulier de liste@tie{}: la @emph{liste +associative} -- ou @emph{alist}. Une @emph{alist} permet de stocker des +données dans le but de les réutiliser. + +Une liste associative est une liste dont les éléments sont des paires. +Le @code{car} de chacun des éléments constitue une clé (@emph{key}) et +chaque @code{cdr} une valeur (@emph{value}). La procédure Scheme +@code{assoc} permet de retrouver une entrée de la liste +associative@tie{}; son @code{cdr} en fournira la valeur@tie{}: + +@lisp +guile> (define mon-alist '((1 . "A") (2 . "B") (3 . "C"))) +guile> mon-alist +((1 . "A") (2 . "B") (3 . "C")) +guile> (assoc 2 mon-alist) +(2 . "B") +guile> (cdr (assoc 2 mon-alist)) +"B" +guile> +@end lisp + +LilyPond recourt abondamment aux @emph{alists} pour stocker des +propriétés ou autres données. + + +@subheading Tables de hachage + +Il s'agit d'une structure de données à laquelle LilyPond fait parfois +appel. Une table de hachage (@emph{hash table}) peut se comparer à une +matrice ou un tableau dont l'index peut être n'importe quel type de +valeur Scheme et ne se limitant pas à des nombres entiers. + +Les tables de hachage sont un moyen plus efficace que les listes +associatives lorsqu'il s'agit d'enregistrer de nombreuses données qui ne +changeront que peu fréquemment. + +La syntaxe permettant de créer une table de hachage peut paraître +complexe, mais vous en trouverez de nombreux exemples dans les sources +de LilyPond. + +@lisp +guile> (define h (make-hash-table 10)) +guile> h +# +guile> (hashq-set! h 'cle1 "valeur1") +"valeur1" +guile> (hashq-set! h 'key2 "valeur2") +"valeur2" +guile> (hashq-set! h 3 "valeur3") +"valeur3" +@end lisp + +La procédure @code{hashq-ref} permet de récupérer une valeur dans la +table de hachage. + +@lisp +guile> (hashq-ref h 3) +"valeur3" +guile> (hashq-ref h 'cle2) +"valeur2" +guile> +@end lisp + +La procédure @code{hashq-get-handle} permet de retrouver à la fois une +clé et sa valeur. Cette procédure a l'avantage de renvoyer @code{#f} +lorsque la clé n'existe pas. + +@lisp +guile> (hashq-get-handle h 'cle1) +(cle1 . "valeur1") +guile> (hashq-get-handle h 'zut) +#f +guile> +@end lisp + +@node Scheme et les calculs +@subsection Scheme et les calculs +@translationof Calculations in Scheme + +@ignore +We have been using lists all along. A calculation, like @code{(+ 1 2)} +is also a list (containing the symbol @code{+} and the numbers 1 +and@tie{}2). Normally lists are interpreted as calculations, and the +Scheme interpreter substitutes the outcome of the calculation. To enter a +list, we stop the evaluation. This is done by quoting the list with a +quote @code{'} symbol. So, for calculations do not use a quote. + +Inside a quoted list or pair, there is no need to quote anymore. The +following is a pair of symbols, a list of symbols and a list of lists +respectively, + +@example +#'(stem . head) +#'(staff clef key-signature) +#'((1) (2)) +@end example +@end ignore + +Scheme permet aussi d'effectuer des calculs. Il utilise alors un +@emph{préfixe}. Additionner 1 et@tie{}2 s'écrira @w{@code{(+ 1 2)}} et +non @math{1+2} comme on aurait pu s'y attendre. + +@lisp +guile> (+ 1 2) +3 +@end lisp + +Les calculs peuvent s'imbriquer@tie{}; le résultat d'une fonction peut +servir pour un autre calcul. + +@lisp +guile> (+ 1 (* 3 4)) +13 +@end lisp + +Ces calculs sont un exemple d'évaluation@tie{}: une expression telle que +@w{@code{(* 3 4)}} est remplacée par sa valeur, soit @code{12}. + +En matière de calcul, Scheme fait la différence entre des nombres entiers +ou non. Les calculs sur des nombres entiers seront exacts, alors que +s'il s'agit de nombres non entiers, les calculs tiendront compte de la +précision mentionnée@tie{}: + +@lisp +guile> (/ 7 3) +7/3 +guile> (/ 7.0 3.0) +2.33333333333333 +@end lisp + +Lorsque l'interpréteur Scheme rencontre une expression sous forme de +liste, le premier élément de cette liste est considéré en tant que +procédure qui prendra en argument le restant de la liste. C'est la +raison pour laquelle, en Scheme, tous les opérateurs sont en préfixe. + +Le fait que le premier élément d'une expression Scheme sous forme de +liste ne soit pas un opérateur ou une procédure déclenchera une +erreur de la part de l'interpréteur@tie{}: + +@lisp +guile> (1 2 3) + +Backtrace: +In current input: + 52: 0* [1 2 3] + +:52:1: In expression (1 2 3): +:52:1: Wrong type to apply: 1 +ABORT: (misc-error) +guile> +@end lisp + +Vous pouvez constater que l'interpréteur a tenté de considérer @code{1} +comme étant un opérateur ou une procédure, ce qu'il n'a pu réaliser. Il +a donc renvoyé l'erreur @qq{Wrong type to apply: 1} (@emph{Application +d'un type erroné@tie{}: 1}). + +C'est pourquoi il est impératif, pour créer une liste, soit d'utiliser +l'opérateur consacré (@code{list}), soit de faire précéder la liste +d'une apostrophe, de telle sorte que l'interpréteur ne tente pas de +l'évaluer. + +@lisp +guile> (list 1 2 3) +(1 2 3) +guile> '(1 2 3) +(1 2 3) +guile> +@end lisp + +Vous pourrez être confronté à cette erreur lorsque vous intégrerez +Scheme à LilyPond. + +@ignore +The same assignment can be done in completely in Scheme as well, + +@example +#(define twentyFour (* 2 twelve)) +@end example + +@c this next section is confusing -- need to rewrite + +The @emph{name} of a variable is also an expression, similar to a +number or a string. It is entered as + +@example +#'twentyFour +@end example + +@funindex #'symbol +@cindex quoting in Scheme + +The quote mark @code{'} prevents the Scheme interpreter from substituting +@code{24} for the @code{twentyFour}. Instead, we get the name +@code{twentyFour}. +@end ignore + + +@node Scheme et les procédures +@subsection Scheme et les procédures +@translationof Scheme procedures + +Une procédure Scheme est une expression Scheme qui renverra une valeur +issue de son exécution. Les procédures Scheme sont capables de +manipuler des variables qui ne sont pas définies en leur sein. + + +@subheading Définition de procédures + +En Scheme, on définit une procédure à l'aide de l'instruction +@code{define}@tie{}: + +@example +(define (nom-fonction argument1 argument2 ... argumentn) + expression-scheme-qui-donnera-une-valeur-en-retour) +@end example + +Nous pourrions, par exemple, définir une procédure calculant la moyenne +de deux nombres@tie{}: + +@lisp +guile> (define (moyenne x y) (/ (+ x y) 2)) +guile> moyenne +# +@end lisp + +Une fois la procédure définie, on l'appelle en la faisant suivre, dans +une liste, des arguments qui doivent l'accompagner. Calculons +maintenant la moyenne de 3 et 12@tie{}: + +@lisp +guile> (moyenne 3 12) +15/2 +@end lisp + + +@subheading Prédicats + +Une procédure Scheme chargée de retourner une valeur booléenne s'appelle +un @qq{prédicat} (@emph{predicate}). Par convention, plutôt que par +nécessité, le nom d'un prédicat se termine par un point +d'interrogation@tie{}: + +@lisp +guile> (define (moins-de-dix? x) (< x 10)) +guile> (moins-de-dix? 9) +#t +guile> (moins-de-dix? 15) +#f +@end lisp + + +@subheading Valeurs de retour + +Une procédure Scheme doit toujours renvoyer une valeur de retour, en +l'occurrence la valeur de la dernière expression exécutée par cette +procédure. La valeur de retour sera une valeur Scheme valide, y compris +une structure de donnée complexe ou une procédure. + +On peut avoir besoin de regrouper plusieurs expressions Scheme dans une +même procédure. Deux méthodes permettent de combiner des expressions +multiples. La première consiste à utiliser la procédure @code{begin}, +qui permet l'évaluation de plusieurs expressions et renvoie la valeur de +la dernière expression. + +@lisp +guile> (begin (+ 1 2) (- 5 8) (* 2 2)) +4 +@end lisp + +Une deuxième méthode consiste à combiner les expressions dans un bloc +@code{let}. Ceci aura pour effet de créer une série de liens, puis +d'évaluer en séquence les expressions susceptibles d'inclure ces +liens. La valeur renvoyée par un bloc @emph{let} est la valeur de +retour de la dernière clause de ce bloc@tie{}: + +@lisp +guile> (let ((x 2) (y 3) (z 4)) (display (+ x y)) (display (- z 4)) +... (+ (* x y) (/ z x))) +508 +@end lisp + + +@node Scheme et les conditions +@subsection Scheme et les conditions +@translationof Scheme conditionals + +@subheading if + +Scheme dispose d'une procédure @code{if}@tie{}: + +@example +(if expression-test expression-affirmative expression-négative) +@end example + +@var{expression-test} est une expression qui renverra une valeur +booléenne. Dans le cas où @var{expression-test} retourne @code{#t}, la +procédure @code{if} renvoie la valeur de @var{expression-affirmative}, +et celle de @var{expression-négative} dans le cas contraire. + +@lisp +guile> (define a 3) +guile> (define b 5) +guile> (if (> a b) "a est plus grand que b" "a n'est pas plus grand que b") +"a n'est pas plus grand que b" +@end lisp + + +@subheading cond + +Une autre manière d'introduire une condition en Scheme est d'utiliser +l'instruction @code{cond}@tie{}: + +@example +(cond (expression-test-1 expression-résultat-séquence-1) + (expression-test-2 expression-résultat-séquence-2) + ... + (expression-test-n expression-résultat-séquence-n)) +@end example + +Comme par exemple ici@tie{}: + +@lisp +guile> (define a 6) +guile> (define b 8) +guile> (cond ((< a b) "a est plus petit que b") +... ((= a b) "a égale b") +... ((> a b) "a est plus grand que b")) +"a est plus petit que b" +@end lisp + + +@node Scheme et LilyPond +@section Scheme et LilyPond +@translationof Scheme in LilyPond + +@menu +* Syntaxe Scheme dans LilyPond:: +* Variables LilyPond:: +* Saisie de variables et Scheme:: +* Propriétés des objets:: +* Variables LilyPond composites:: +* Représentation interne de la musique:: +@end menu + +@node Syntaxe Scheme dans LilyPond +@subsection Syntaxe Scheme dans LilyPond +@translationof LilyPond Scheme syntax + +@funindex $ +@funindex # + +L'installation de LilyPond comprenant l'interpréteur Guile, les fichiers +source LilyPond peuvent contenir du Scheme. Vous disposez de plusieurs +méthodes pour inclure du Scheme dans vos fichiers LilyPond. + +La méthode la plus simple consiste à insérer un @emph{hash} (le caractère +@code{#}, improprement appelé dièse) avant l'expression Scheme. + +Rappelons-nous qu'un fichier source LilyPond est structuré en jetons et +expressions, tout comme le langage humain est structuré en mots et +phrases. LilyPond dispose d'un analyseur lexical (appelé @emph{lexer}) +qui sait identifier les jetons -- nombres, chaînes, éléments Scheme, +hauteurs etc. -- ainsi que d'un analyseur syntaxique (appelé +@emph{parser}) -- voir l'annexe @ruser{Grammaire de LilyPond}. Dès lors +que le programme sait quelle règle grammaticale particulière doit +s'appliquer, il exécute les consignes qui lui sont associées. + +Le recours à un @emph{hash} pour mettre en exergue du Scheme est tout à +fait approprié. Dès qu'il rencontre un @code{#}, l'analyseur lexical +passe le relais au lecteur Scheme qui va alors déchiffrer l'intégralité +de l'expression Scheme -- ce peut être un identificateur, une expression +bornée par des parenthèses ou bien d'autres choses encore. Une fois +cette expression lue, elle est enregistrée en tant que valeur d'un +élément grammatical @code{SCM_TOKEN}. Puisque l'analyseur syntaxique +sait comment traiter ce jeton, il charge Guile d'évaluer l'expression +Scheme. Dans la mesure où le @emph{parser} requiert une lecture en +avance de la part du @emph{lexer} pour prendre une décision, cette +distinction entre lecture et évaluation -- @emph{lexer} et @emph{parser} +-- révèle toute sa pertinence lorsqu'il s'agit d'exécuter conjointement +des expressions LilyPond et des expressions Scheme. C'est la raison +pour laquelle nous vous recommandons, dans toute la mesure du possible, +d'utiliser un signe @emph{hash} lorsque vous faites appel à Scheme. + +Une autre manière de faire appel à l'interpréteur Scheme à partir de +LilyPond consiste à introduire une expression Scheme par un caractère +dollar au lieu d'un caractère dièse -- un@tie{}@code{$} au lieu +d'un@tie{}@code{#}. En pareil cas, LilyPond évalue le code dès sa +lecture par l'analyseur lexical, vérifie le type d'expression Scheme qui +en résulte et détermine un type de jeton (l'un des @code{xxx_IDENTIFIER} +de la grammaire) qui lui corresponde, puis en fait une copie qui servira +à traiter la valeur de ce jeton. Lorsque la valeur de l'expression est +@emph{void}, autrement dit une valeur Guile @code{*unspecified*} +(pour @emph{non spécifiée}), aucune information n'est transmise à +l'analyseur grammatical. + +C'est, en réalité, la manière dont LilyPond opère lorsque vous rappelez +une variable ou une fonction par son nom -- au travers d'un @code{\nom} +--, à la seule différence que sa finalité est déterminée par l'analyseur +lexical de LilyPond sans consultation du lecteur Scheme@tie{}; le nom de +la variable rappelée doit donc être en corrélation avec le mode LilyPond +actif à ce moment là. + +L'immédiateté de l'opérateur @code{$} peut entraîner des effets +indésirables dont nous reparlerons à la rubrique +@ref{Saisie de variables et Scheme}@tie{}; aussi est-il préférable +d'utiliser un @code{#} dès que l'analyseur grammatical le supporte. + +Examinons à présent du vrai code Scheme. Nous pouvons définir des +procédures Scheme au milieu d'un fichier source LilyPond@tie{}: + +@example +#(define (moyenne a b c) (/ (+ a b c) 3)) +@end example + +Pour mémoire, vous noterez que les commentaires LilyPond (@code{%} ou +@code{%@{ %@}}) ne peuvent s'utiliser dans du code Scheme, même si +celui-ci se trouve au sein d'un fichier LilyPond. Ceci tient au fait +que l'expression Scheme est lue par l'interpréteur Guile, et en aucune +façon par l'analyseur lexical de LilyPond. Voici comment introduire des +commentaires dans votre code Scheme@tie{}: + +@example +; ceci n'est qu'une simple ligne de commentaire + +#! + Ceci constitue un bloc de commentaire (non imbricable) + dans le style Guile. + En fait, les Schemeurs les utilisent très rarement, + et vous n'en trouverez jamais dans le code source + de LilyPond. +!# +@end example + +Dans la suite de notre propos, nous partons du principe que les données +sont incluses dans un fichier musical, aussi toutes les expressions +Scheme seront introduites par un@code{#}. + +Toutes les expressions Scheme de haut niveau incluses dans un fichier +LilyPond peuvent se combiner en une expression Scheme unique à l'aide de +la clause @code{begin}@tie{}: + +@example +#(begin + (define foo 0) + (define bar 1)) +@end example + + +@node Variables LilyPond +@subsection Variables LilyPond +@translationof LilyPond variables + +Les variables LilyPond sont enregistrées en interne sous la forme de +variables Scheme. Ainsi, + +@example +douze = 12 +@end example + +@noindent +est équivalant à + +@example +#(define douze 12) +@end example + +Ceci a pour conséquence que toute variable LilyPond peut être utilisée +dans une expression Scheme. Par exemple, nous pourrions dire + +@example +vingtQuatre = #(* 2 douze) +@end example + +@noindent +ce qui aurait pour conséquence que le nombre 24 sera stocké dans la +variable LilyPond (et Scheme) @code{vingtQuatre}. + +La façon habituelle de faire référence à une variable LilyPond consiste +à la rappeler à l'aide d'une oblique inverse -- autrement dit saisir +@code{\vingtQuatre}. Dans la mesure où ceci, pour la plupart des types +internes de LilyPond y compris les expressions musicales, aura pour +effet d'en recopier la valeur, les fonctions musicales n'ont pas pour +habitude de créer une copie du matériau qu'elles vont modifier. De +fait, une expression musicale introduite par @code{#} de devrait pas +contenir de matériau inexistant auparavant ou bien littéralement +recopié, mais plutôt une référence explicite. + + +@node Saisie de variables et Scheme +@subsection Saisie de variables et Scheme +@translationof Input variables and Scheme + +Le format de saisie prend en charge la notion de variable -- ou +identificateur. Dans l'exemple suivant, une expression musicale se voit +attribuer un identificateur qui portera le nom de @code{traLaLa}. + +@example +traLaLa = @{ c'4 d'4 @} +@end example + +@noindent + +Une variable a aussi une portée. Dans l'exemple suivant, le bloc +@code{\layout} contient une variable @code{traLaLa} tout à fait +indépendante de l'autre @code{\traLaLa}. + +@example +traLaLa = @{ c'4 d'4 @} +\layout @{ traLaLa = 1.0 @} +@end example + +Dans les faits, chaque fichier a un domaine de compétence, et les +différents blocs @code{\header}, @code{\midi} et @code{\layout} ont leur +propre champ de compétence, imbriqué dans ce domaine principal. + +Variables et champs de compétence sont implémentés par le système de +modules de Guile. Un module anonyme Scheme est attaché à chacun de ces +domaines. Une assertion telle que + +@example +traLaLa = @{ c'4 d'4 @} +@end example + +@noindent +est convertie, en interne, en une définition Scheme@tie{}: + +@example +(define traLaLa @var{valeur Scheme de `@code{... }'}) +@end example + +Cela signifie que variables LilyPond et variables Scheme peuvent tout à +fait se mélanger. Dans l'exemple suivant, un fragment musical est +stocké dans la variable @code{traLaLa} puis dupliqué à l'aide de Scheme. +Le résultat est alors importé dans un bloc @code{\score} au moyen d'une +seconde variable @code{twice}. + +@lilypond[verbatim] +traLaLa = { c'4 d'4 } + +#(define newLa (map ly:music-deep-copy + (list traLaLa traLaLa))) +#(define twice + (make-sequential-music newLa)) + +{ \twice } +@end lilypond + +@c Due to parser lookahead + +Cet exemple est particulièrement intéressant. L'assignation +n'interviendra qu'une fois que l'analyseur grammatical aura l'assurance +que rien du type de @code{\addlyrics} ne suit@tie{}; il doit donc +vérifier ce qui vient après. Le @emph{parser} lit le @code{#} et +l'expression Scheme qui le suit @strong{sans} l'évaluer, de telle sorte +qu'il peut procéder à l'assignation, et @strong{ensuite} exécuter le +code Scheme sans problème. + +Cet exemple illustre la manière @qq{d'exporter} une expression musicale +à partir des saisies et à destination de l'interpréteur Scheme. +L'inverse est aussi réalisable@tie{}: en la plaçant derrière +un@tie{}@code{$}, une valeur Scheme sera interprétée comme si elle avait +été saisie en syntaxe LilyPond. Au lieu de définir @code{\twice}, nous +aurions tout aussi bien pu écrire + +@example +... +@{ $(make-sequential-music (list newLa)) @} +@end example + +Vous pouvez utiliser @code{$} suivi d'une expression Scheme partout où +vous auriez utilisé @code{\@var{nom}}, dès lors que vous aurez assigné à +cette expression Scheme le nom de variable @var{nom}. La substitution +intervenant au niveau de l'analyseur lexical (le @emph{lexer}), LilyPond +ne saurait faire la différence. + +Cette manière de procéder comporte cependant un inconvénient au niveau +de la temporisation. Si nous avions défini @code{newLa} avec un +@code{$} plutôt qu'un@tie{#}, la définition Scheme suivante aurait +échoué du fait que @code{traLaLa} n'était pas encore définie. Pour plus +d'information quant au problème de synchronisation, voir la rubrique +@ref{Syntaxe Scheme dans LilyPond}. + +En tout état de cause, le @emph{parser} évalue le code Scheme en +dernier. S'il ne doit être exécuté que plus tard, consultez la rubrique +@ref{Fonctions Scheme fantômes}, ou stockez le dans une macro comme +ici@tie{}: + +@example +#(define (nopc) + (ly:set-option 'point-and-click #f)) + +... +#(nopc) +@{ c'4 @} +@end example + +@knownissues +L'imbrication de variables Scheme et LilyPond n'est pas possible +avec l'option @option{--safe}. + + +@node Propriétés des objets +@subsection Propriétés des objets +@translationof Object properties + +Les propriétés des objets sont stockées dans LilyPond sous la forme +d'enchaînements de listes associatives, autrement dit des listes de +listes associatives. Une propriété se détermine par l'ajout de valeurs +en début de liste de cette propriété. Les caractéristiques d'une +propriété s'ajustent donc à la lecture des différentes valeurs des +listes associatives. + +La modification d'une valeur pour une propriété donnée requiert +l'assignation d'une valeur de la liste associative, tant pour la clé que +la valeur associée. Voici comment procéder selon la syntaxe de +LilyPond@tie{}: + +@example +\override Stem #'thickness = #2.6 +@end example + +Cette instruction ajuste l'apparence des hampes. Une entrée +@w{@code{'(thickness . 2.6)}} de la @emph{alist} est ajoutée à la liste +de la propriété de l'objet @code{Stem}. @code{thickness} devant +s'exprimer en unité d'épaisseur de ligne, les hampes auront donc une +épaisseur de 2,6@tie{}ligne de portée, et à peu près le double de leur +épaisseur normale. Afin de faire la distinction entre les variables que +vous définissez au fil de vos fichiers -- tel le @code{vingtQuatre} que +nous avons vu plus haut -- et les variables internes des objets, nous +parlerons de @qq{propriétés} pour ces dernières, et de @qq{variables} +pour les autres. Ainsi, l'objet hampe possède une propriété +@code{thickness}, alors que @code{vingtQuatre} est une variable. + +@cindex propriétés ou variables +@cindex variables ou propriétés + +@c todo -- here we're getting interesting. We're now introducing +@c LilyPond variable types. I think this deserves a section all +@c its own + + +@node Variables LilyPond composites +@subsection Variables LilyPond composites +@translationof LilyPond compound variables + +@subheading Décalages (@emph{offsets}) + +Les décalages (@emph{offset}) sur deux axes (coordonnées X et Y) sont +stockés sous forme de @emph{paires}. Le @code{car} de l'offset +correspond à l'abscisse (coordonnée X) et le @code{cdr} à l'ordonnée +(coordonnée Y). + +@example +\override TextScript #'extra-offset = #'(1 . 2) +@end example + +Cette clause affecte la paire @code{(1 . 2)} à la propriété +@code{extra-offset} de l'objet @code{TextScript}. Ces nombres sont +exprimés en espace de portée. La commande aura donc pour effet de +déplacer l'objet d'un espace de portée vers la droite, et de deux +espaces vers le haut. + +Les procédures permettant de manipuler les offsets sont regroupées dans +le fichier @file{scm/lily-library.scm}. + + +@subheading Fractions + +Les fractions, tel que LilyPond les utilise, sont aussi stockées sous +forme de @emph{paire}. Alors que Scheme est tout à fait capable de +représenter des nombres rationnels, vous conviendrez que, musicalement +parlant, @samp{2/4} et @samp{1/2} ne se valent pas@tie{}; nous devrons +donc pouvoir les distinguer. Dans le même ordre d'idée, LilyPond ne +connaît pas les @qq{fractions} négatives. Pour ces raisons, @code{2/4} +en LilyPond correspond à @code{(2 . 4)} en Scheme, et @code{#2/4} en +LilyPond correspond à @code{1/2} en Scheme. + + +@subheading Étendues (@emph{extents}) + +Les paires permettent aussi de stocker des intervalles qui représentent +un ensemble de nombres compris entre un minimum (le @code{car}) et un +maximum (le @code{cdr}). Ces intervalles stockent l'étendue, tant au +niveau horizontal (X) que vertical (Y) des objets imprimables. En +matière d'étendue sur les X, le @code{car} correspond à la coordonnée de +l'extrémité gauche, et le @code{cdr} à la coordonnée de l'extrémité +droite. En matière d'étendue sur les Y, le @code{car} correspond à la +coordonnée de l'extrémité basse, et le @code{cdr} à la coordonnée de +l'extrémité haute. + +Les procédures permettant de manipuler les offsets sont regroupées dans +le fichier @file{scm/lily-library.scm}. Nous vous recommandons +l'utilisation de ces procédures dans toute la mesure du possible afin +d'assurer la cohérence du code. + + +@subheading Propriété en @emph{alists} + +Les propriétés en @emph{alists} sont des structures de données +particulières à LilyPond. Il s'agit de listes associatives dont les +clés sont des propriétés et les valeurs des expressions Scheme +fournissant la valeur requise pour cette propriété. + +Les propriétés LilyPond sont des symboles Scheme, à l'instar de +@code{'thickness}. + + +@subheading Chaînes d'@emph{alist} + +Une chaîne d'@emph{alist} est une liste contenant les listes +associatives d'une propriété. + +L'intégralité du jeu de propriétés qui doivent s'appliquer à un objet +graphique est en fait stocké en tant que chaîne d'@emph{alist}. Afin +d'obtenir la valeur d'une propriété particulière qu'un objet graphique +devrait avoir, on examinera chacune des listes associatives de la +chaîne, à la recherche d'une entrée contenant la clé de cette propriété. +Est renvoyée la première entrée d'@emph{alist} trouvée, sa valeur étant +la valeur de la propriété. + +L'obtention des valeurs de propriété des objets graphiques se réalise en +principe à l'aide de la procédure Scheme @code{chain-assoc-get}. + + +@node Représentation interne de la musique +@subsection Représentation interne de la musique +@translationof Internal music representation + +Dans les entrailles du programme, la musique se présente comme une liste +Scheme. Cette liste comporte les différents éléments qui affecteront la +sortie imprimable. L'analyse grammaticale (l'opération @emph{parsing}) +est le processus chargé de convertir la musique représentée par le code +LilyPond en présentation interne Scheme. + +L'analyse d'une expression musicale se traduit par un jeu d'objets +musicaux en Scheme. Une objet musical est déterminé par le temps qu'il +occupe, que l'on appelle @emph{durée}. Les durées s'expriment par des +nombres rationnels représentant la longueur d'un objet musical par +rapport à la ronde. + +Un objet musical dispose de trois types@tie{}: +@itemize +@item +un nom de musique@tie{}: Toute expression musicale a un nom. Par +exemple, une note amène à un @rinternals{NoteEvent}, un +@code{\simultaneous} à un @rinternals{SimultaneousMusic}. Une liste +exhaustive des différentes expressions est disponible dans la référence +des propriétés internes, à la rubrique @rinternals{Music expressions}. + +@item +un @qq{type} ou interface@tie{}: Tout nom de musique dispose de +plusieurs types ou interfaces. Ainsi, une note est tout à la fois un +@code{event}, un @code{note-event}, un @code{rhythmic-event} et un +@code{melodic-event}. Les différentes classes musicales sont +répertoriées à la rubrique @rinternals{Music classes} de la référence +des propriétés internes. + +@item +un objet C++@tie{}: Tout objet musical est représenté par un objet de la +classe C++ @code{Music}. +@end itemize + +L'information réelle d'une expression musicale est enregistrée sous +forme de propriétés. Par exemple, un @rinternals{NoteEvent} dispose des +propriétés @code{pitch} et @code{duration}, respectivement chargées de +stocker la hauteur et la durée de cette note. Les différentes +propriétés sont répertoriées à la rubrique +@rinternalsnamed{Music properties,Music properties} +de la référence des propriétés internes. + +Une expression composite est un objet musical dont les propriétés +contiennent d'autres objets musicaux. S'il s'agit d'une liste d'objets, +elle sera stockée dans la propriété @code{elements} d'un objet +musical@tie{}; s'il n'y a qu'un seul objet @qq{enfant}, il sera stocké +dans la propriété @code{element}. Ainsi, par exemple, les enfants de +@rinternals{SequentialMusic} iront dans @code{elements}, alors que +l'argument unique de @rinternals{GraceMusic} ira dans @code{element}. +De même, le corps d'une répétition ira dans la propriété @code{element} +d'un @rinternals{RepeatedMusic}, les alternatives quant à elles dans la +propriété @code{elements}. + + +@node Construction de fonctions complexes +@section Construction de fonctions complexes +@translationof Building complicated functions + +Nous allons voir dans cette partie les moyens dont vous disposez pour +obtenir les informations qui vous permettront de créer vos propres +fonctions musicales complexes. + +@menu +* Affichage d'expressions musicales:: +* Propriétés musicales:: +* Doublement d'une note avec liaison (exemple):: +* Ajout d'articulation à des notes (exemple):: +@end menu + + +@node Affichage d'expressions musicales +@subsection Affichage d'expressions musicales +@translationof Displaying music expressions + +@cindex stockage interne +@cindex expression musicale, affichage +@cindex représentation interne, affichage +@cindex displayMusic +@funindex \displayMusic + +Lorsque l'on veut écrire une fonction musicale, il est intéressant +d'examiner comment une expression musicale est représentée en interne. +Vous disposez à cet effet de la fonction musicale @code{\displayMusic}. + +@example +@{ + \displayMusic @{ c'4\f @} +@} +@end example + +@noindent +affichera + +@example +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'NoteEvent + 'articulations + (list (make-music + 'AbsoluteDynamicEvent + 'text + "f")) + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)))) +@end example + +Par défaut, LilyPond affichera ces messages sur la console, parmi toutes +les autres informations. Vous pouvez, afin de les isoler et de garder +le résultat des commandes @code{\display@{TRUC@}}, rediriger la sortie +vers un fichier@tie{}: + +@example +lilypond file.ly >display.txt +@end example + +Un peu de Scheme combiné à notre code LilyPond, et les seules +informations qui nous intéressent se retrouveront directement dans un +fichier indépendant@tie{}: + +@example +@{ + $(with-output-to-file "display.txt" + (lambda () #@{ \displayMusic @{ c'4\f @} #@})) +@} +@end example + +L'information sera encore plus lisible après un peu de mise en +forme@tie{}: + +@example +(make-music 'SequentialMusic + 'elements (list + (make-music 'NoteEvent + 'articulations (list + (make-music 'AbsoluteDynamicEvent + 'text + "f")) + 'duration (ly:make-duration 2 0 1 1) + 'pitch (ly:make-pitch 0 0 0)))) +@end example + +Une séquence musicale @code{@{ ... @}} se voit attribuer le nom de +@code{SequentialMusic}, et les expressions qu'elle contient sont +enregistrées en tant que liste dans sa propriété @code{'elements}. Une +note est représentée par un objet @code{NoteEvent} -- contenant les +propriétés de durée et hauteur -- ainsi que l'information qui lui est +attachée -- en l'occurrence un @code{AbsoluteDynamicEvent} ayant une +propriété @code{text} de valeur @code{"f"} -- et stockée dans sa +propriété @code{articulations}. + +@funindex{\void} +La fonction @code{\displayMusic} renvoie la musique qu'elle +affiche@tie{}; celle-ci sera donc aussi interprétée. L'insertion d'une +commande @code{\void} avant le @code{\displayMusic} permet de +s'affranchir de la phase d'interprétation. + + +@node Propriétés musicales +@subsection Propriétés musicales +@translationof Music properties + +Nous abordons ici les propriétés @emph{music}, et non pas les propriétés +@emph{context} ou @emph{layout}. + +Partons de cet exemple simple@tie{}: + +@example +someNote = c' +\displayMusic \someNote +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) +@end example + +L'objet @code{NoteEvent} est la représentation brute de @code{someNote}. +Voyons ce qui se passe lorsque nous plaçons ce @notation{c'} dans une +construction d'accord@tie{}: + +@example +someNote = +\displayMusic \someNote +===> +(make-music + 'EventChord + 'elements + (list (make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)))) +@end example + +L'objet @code{NoteEvent} est maintenant le premier objet de la propriété +@code{'elements} de @code{someNote}. + +@code{\displayMusic} utilise la fonction @code{display-scheme-music} +pour afficher la représentation en Scheme d'une expression musicale@tie{}: + +@example +#(display-scheme-music (first (ly:music-property someNote 'elements))) +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 0 0)) +@end example + +La hauteur de la note est accessible au travers de la propriété +@code{'pitch} de l'objet @code{NoteEvent}@tie{}: + +@example +#(display-scheme-music + (ly:music-property (first (ly:music-property someNote 'elements)) + 'pitch)) +===> +(ly:make-pitch 0 0 0) +@end example + +La hauteur de la note se modifie en définissant sa propriété +@code{'pitch}@tie{}: + +@funindex \displayLilyMusic + +@example +#(set! (ly:music-property (first (ly:music-property someNote 'elements)) + 'pitch) + (ly:make-pitch 0 1 0)) ;; set the pitch to d'. +\displayLilyMusic \someNote +===> +d' +@end example + + +@node Doublement d'une note avec liaison (exemple) +@subsection Doublement d'une note avec liaison (exemple) +@translationof Doubling a note with slurs (example) + +Supposons que nous ayons besoin de créer une fonction transformant une +saisie @code{a} en @w{@code{@{ a( a) @}}}. Commençons par examiner +comment le résultat est représenté en interne. + +@example +\displayMusic@{ a'( a') @} +===> +(make-music + 'SequentialMusic + 'elements + (list (make-music + 'NoteEvent + 'articulations + (list (make-music + 'SlurEvent + 'span-direction + -1)) + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)) + (make-music + 'NoteEvent + 'articulations + (list (make-music + 'SlurEvent + 'span-direction + 1)) + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)))) +@end example + +Mauvaise nouvelle@tie{}! Les expressions @code{SlurEvent} doivent +s'ajouter @qq{à l'intérieur} de la note -- dans sa propriété +@code{articulations}. + +Examinons à présent la saisie@tie{}: + +@example +\displayMusic a' +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch 0 5 0)))) +@end example + +Nous aurons donc besoin, dans notre fonction, de cloner cette expression +-- de telle sorte que les deux notes constituent la séquence -- puis +d'ajouter un @code{SlurEvent} à la propriété @code{'articulations} de +chacune d'elles, et enfin réaliser un @code{SequentialMusic} de ces deux +@code{EventChords}. En tenant compte du fait que, dans le cadre d'un +ajout, une propriété non définie est lue @code{'()} (une liste vide), +aucune vérification n'est requise avant d'introduire un nouvel élément +en tête de la propriété @code{articulations}. + +@example +doubleSlur = #(define-music-function (parser location note) (ly:music?) + "Renvoie : @{ note ( note ) @}. + `note' est censé être une note unique." + (let ((note2 (ly:music-deep-copy note))) + (set! (ly:music-property note 'articulations) + (cons (make-music 'SlurEvent 'span-direction -1) + (ly:music-property note 'articulations))) + (set! (ly:music-property note2 'articulations) + (cons (make-music 'SlurEvent 'span-direction 1) + (ly:music-property note2 'articulations))) + (make-music 'SequentialMusic 'elements (list note note2)))) +@end example + + +@node Ajout d'articulation à des notes (exemple) +@subsection Ajout d'articulation à des notes (exemple) +@translationof Adding articulation to notes (example) + +Le moyen d'ajouter une articulation à des notes consiste à fusionner +deux expressions musicales en un même contexte, comme nous l'avons vu à +la rubrique @ruser{Création d'un contexte}. L'option de réaliser +nous-mêmes une fonction musicale à cette fin nous offre l'avantage de +pouvoir alors ajouter une articulation, telle qu'une instruction de +doigté, individuellement à l'une des notes d'un accord, ce qui est +impossible dans le cadre d'une simple fusion de musique indépendante. + +Un @code{$variable} au milieu de la notation @code{#@{...#@}} se +comporte exactement comme un banal @code{\variable} en notation LilyPond +traditionnelle. Nous savons déjà que + +@example +@{ \musique -. -> @} +@end example + +@noindent +n'est pas admis par LilyPond. Nous pourrions tout à fait contourner ce +problème en attachant l'articulation à une @qq{fausse} note, + +@example +@{ << \musique s1*0-.-> @} +@end example + +@noindent +mais, pour les besoins de la démonstration, nous allons voir comment +réaliser ceci en Scheme. Commençons par examiner une saisie simple et +le résultat auquel nous désirons aboutir@tie{}: + +@example +% saisie +\displayMusic c4 +===> +(make-music + 'NoteEvent + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)))) +===== +% résultat attendu +\displayMusic c4-> +===> +(make-music + 'NoteEvent + 'articulations + (list (make-music + 'ArticulationEvent + 'articulation-type + "accent")) + 'duration + (ly:make-duration 2 0 1 1) + 'pitch + (ly:make-pitch -1 0 0)) +@end example + +Nous voyons qu'une note (@code{c4}) est représentée par une expression +@code{NoteEvent}. Si nous souhaitons ajouter une articulation +@notation{accent}, nous devrons ajouter une expression +@code{ArticulationEvent} à la propriété @code{articulations} de +l'expression @code{NoteEvent}. + +Construisons notre fonction en commençant par + +@example +(define (ajoute-accent note-event) + "Ajoute un accent (ArticulationEvent) aux articulations de `note-event', + qui est censé être une expression NoteEvent." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) +@end example + +La première ligne est la manière de définir une fonction en +Scheme@tie{}: la fonction Scheme a pour nom @code{ajoute-accent} et elle +comporte une variable appelée @code{note-event}. En Scheme, le type +d'une variable se déduit la plupart de temps de par son nom -- c'est +d'ailleurs une excellente pratique que l'on retrouve dans de nombreux +autres langages. + +@example +"Ajoute un accent..." +@end example + +@noindent +décrit ce que fait la fonction. Bien que ceci ne soit pas primordial, +tout comme des noms de variable évidents, tâchons néanmoins de prendre +de bonnes habitudes dès nos premiers pas. + +Vous pouvez vous demander pourquoi nous modifions directement +l'événement note plutôt que d'en manipuler une copie -- on pourrait +utiliser @code{ly:music-deep-copy} à cette fin. La raison en est qu'il +existe un contrat tacite@tie{}: les fonctions musicales sont autorisées +à modifier leurs arguments -- ils sont générés en partant de zéro (comme +les notes que vous saisissez) ou déjà recopiés (faire référence à une +variable musicale avec @samp{\name} ou à de la musique issue +d'expressions Scheme @samp{$(@dots{})} aboutit à une copie). Dans la +mesure où surmultiplier les copies serait contre productif, la valeur de +retour d'une fonction musicale n'est @strong{pas} recopiée. Afin de +respecter ce contrat, n'utilisez pas un même argument à plusieurs +reprises, et n'oubliez pas que le retourner compte pour une utilisation. + +Dans un exemple précédent, nous avons construit de la musique en +répétant un certain argument musical. Dans ce cas là, l'une des +répétitions se devait d'être une copie. Dans le cas contraire, +certaines bizarreries auraient pu survenir. Par exemple, la présence +d'un @code{\relative} ou d'un @code{\transpose}, après plusieurs +répétitions du même élément, entraînerait des @qq{relativisations} ou +transpositions en cascade. Si nous les assignons à une variable +musicale, l'enchaînement est rompu puisque la référence à @samp{\nom} +créera une nouvelle copie sans toutefois prendre en considération +l'identité des éléments répétés. + +Cette fonction n'étant pas une fonction musicale à part entière, elle +peut s'utiliser dans d'autres fonctions musicales. Il est donc sensé de +respecter le même contrat que pour les fonctions musicales@tie{}: +l'entrée peut être modifiée pour arriver à une sortie, et il est de la +responsabilité de l'appelant d'effectuer des copies s'il a réellement +besoin de l'argument dans son état originel. Vous constaterez, à la +lecture des fonctions propres à LilyPond, comme @code{music-map}, que ce +principe est toujours respecté. + +Revenons à nos moutons@dots{} Nous disposons maintenant d'un +@code{note-event} que nous pouvons modifier, non pas grâce à un +@code{ly:music-deep-copy}, mais plutôt en raison de notre précédente +réflexion. Nous ajoutons @notation{l'accent} à la liste de ses +propriétés @code{'articulations}. + +@example +(set! emplacement nouvelle-valeur) +@end example + +L'emplacement est ce que nous voulons ici définir. Il s'agit de la +propriété @code{'articulations} de l'expression @code{note-event}. + +@example +(ly:music-property note-event 'articulations) +@end example + +La fonction @code{ly:music-property} permet d'accéder aux propriétés +musicales -- les @code{'articulations}, @code{'duration}, @code{'pitch} +etc. que @code{\displayMusic} nous a indiquées. La nouvelle valeur sera +l'ancienne propriété @code{'articulations}, augmentée d'un +élément@tie{}: l'expression @code{ArticulationEvent}, que nous +recopions à partir des informations de @code{\displayMusic}. + +@example +(cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property result-event-chord 'articulations)) +@end example + +@code{cons} permet d'ajouter un élément en tête de liste sans pour +autant modifier la liste originale. C'est exactement ce que nous +recherchons@tie{}: la même liste qu'auparavant, plus la nouvelle +expression @code{ArticulationEvent}. L'ordre au sein de la propriété +@code{'articulations} n'a ici aucune importance. + +Enfin, après avoir ajouté l'articulation @notation{accent} à sa +propriété @code{articulations}, nous pouvons renvoyer le +@code{note-event}, ce que réalise la dernière ligne de notre fonction. + +Nous pouvons à présent transformer la fonction @code{ajoute-accent} en +fonction musicale, à l'aide d'un peu d'enrobage syntaxique et mention du +type de son unique argument @qq{réel}. + +@example +ajouteAccent = #(define-music-function (parser location note-event) + (ly:music?) + "Ajoute un accent (ArticulationEvent) aux articulations de `note-event', + qui est censé être une expression NoteEvent." + (set! (ly:music-property note-event 'articulations) + (cons (make-music 'ArticulationEvent + 'articulation-type "accent") + (ly:music-property note-event 'articulations))) + note-event) +@end example + +Par acquis de conscience, vérifions que tout ceci fonctione@tie{}: + +@example +\displayMusic \ajouteAccent c4 +@end example + + + + + +@ignore +@menu +* Tweaking with Scheme:: +@end menu + +@c @nod e Tweaking with Scheme +@c @sectio n Tweaking with Scheme + +We have seen how LilyPond output can be heavily modified using +commands like +@code{\override TextScript #'extra-offset = ( 1 . -1)}. But +we have even more power if we use Scheme. For a full explanation +of this, see the @ref{Scheme tutorial}, and +@ref{Interfaces for programmers}. + +We can use Scheme to simply @code{\override} commands, + +TODO Find a simple example +@c This isn't a valid example with skylining +@c It works fine without padText -td +@end ignore + +@ignore +@lilypond[quote,verbatim,ragged-right] +padText = #(define-music-function (parser location padding) (number?) +#{ + \once \override TextScript #'padding = #padding +#}) + +\relative c''' { + c4^"piu mosso" b a b + \padText #1.8 + c4^"piu mosso" d e f + \padText #2.6 + c4^"piu mosso" fis a g +} +@end lilypond +@end ignore + +@ignore +We can use it to create new commands: + +@c Check this is a valid example with skylining +@c It is - 'padding still works + + +@lilypond[quote,verbatim,ragged-right] +tempoPadded = #(define-music-function (parser location padding tempotext) + (number? string?) +#{ + \once \override Score.MetronomeMark #'padding = $padding + \tempo \markup { \bold #tempotext } +#}) + +\relative c'' { + \tempo \markup { "Low tempo" } + c4 d e f g1 + \tempoPadded #4.0 #"High tempo" + g4 f e d c1 +} +@end lilypond + + +Even music expressions can be passed in: + +@lilypond[quote,verbatim,ragged-right] +pattern = #(define-music-function (parser location x y) (ly:music? ly:music?) +#{ + $x e8 a b $y b a e +#}) + +\relative c''{ + \pattern c8 c8\f + \pattern {d16 dis} { ais16-> b\p } +} +@end lilypond +@end ignore