| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Scheme in LilyPond
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof LilyPond Scheme syntax
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 hash (le
caractère #, 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é lexer) qui sait identifier les jetons – nombres, chaînes, éléments Scheme, hauteurs, etc. – ainsi que d’un analyseur syntaxique (appelé parser) – voir (contributor)LilyPond grammar section ‘Grammaire de LilyPond’ dans Guide du contributeur. 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 hash pour mettre en exergue du Scheme est tout à
fait approprié. Dès qu’il rencontre un #, 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 SCM_TOKEN. Puisque l’analyseur syntaxique
sait comment traiter ce jeton, il charge Guile d’évaluer l’expression
Scheme. Dans la mesure où le parser requiert une lecture en
avance de la part du lexer pour prendre une décision, cette
distinction entre lecture et évaluation – lexer et 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 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 $ au lieu
d’un #. 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 xxx_IDENTIFIER de
la grammaire) qui lui correspond, puis en fait une copie qui servira à
traiter la valeur de ce jeton. Lorsque la valeur de l’expression est
void, autrement dit une valeur Guile *unspecified* (pour
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 \nom
–, à la seule différence que sa finalité est déterminée par l’analyseur
lexical de LilyPond sans consultation du lecteur Scheme ; 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 $ peut entraîner des effets
indésirables dont nous reparlerons à la rubrique
Saisie de variables et Scheme ; aussi est-il préférable
d’utiliser un # dès que l’analyseur grammatical le supporte.
Dans le cadre d’une expression musicale, une expression qui aura été
créée à l’aide d’un # sera interprétée comme étant de la musique.
Elle ne sera cependant pas recopiée avant utilisation. Si la structure
qui l’abrite devait être réutilisée, un appel expicite à
ly:music-deep-copy pourrait être requis.
Les opérateurs $@ et #@ agissent comme des « colleurs de
liste » : leur fonction consiste à insérer tous les éléments d’une liste
dans le contexte environnant.
Examinons à présent du vrai code Scheme. Nous pouvons définir des procédures Scheme au milieu d’un fichier source LilyPond :
#(define (moyenne a b c) (/ (+ a b c) 3)) |
Pour mémoire, vous noterez que les commentaires LilyPond (% ou
%{…%}) 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 :
; 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. !# |
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 #.
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 begin :
#(begin (define foo 0) (define bar 1)) |
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof LilyPond variables
Les variables LilyPond sont enregistrées en interne sous la forme de variables Scheme. Ainsi,
douze = 12 |
est équivalant à
#(define douze 12) |
Ceci a pour conséquence que toute variable LilyPond peut être utilisée dans une expression Scheme. Par exemple, nous pourrions dire
vingtQuatre = #(* 2 douze) |
ce qui aurait pour conséquence que le nombre 24 sera stocké dans
la variable LilyPond (et Scheme) vingtQuatre.
Scheme autorise la modification d’expressions complexes au fil de l’eau,
ce que réalise LilyPond dans le cadre des fonctions musicales.
Toutefois, lorsqu’une expression musicale est stockée dans une variable
plutôt que saisie au fur et à mesure, on s’attend, alors qu’elle est
passée à une fonction musicale, à ce que sa valeur originale ne soit en
rien modifiée. C’est la raison pour laquelle faire référence à une
variable à l’aide d’une oblique inverse – autrement dit saisir
\vingtQuatre – aura pour effet que LilyPond créera une copie de
la valeur musicale de cette variable aux fins de l’utiliser au sein de
l’expression musicale au lieu d’utiliser directement la valeur de cette
variable.
Par voie de conséquence, une expression musicale introduite par #
ne devrait pas contenir de matériau inexistant auparavant ou bien
littéralement recopié, mais plutôt une référence explicite.
Manuel d’extension : Syntaxe Scheme dans LilyPond.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@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 traLaLa.
traLaLa = { c'4 d'4 }
|
Une variable a aussi une portée. Dans l’exemple suivant, le bloc
\layout contient une variable traLaLa tout à fait
indépendante de l’autre \traLaLa.
traLaLa = { c'4 d'4 }
\layout { traLaLa = 1.0 }
|
Dans les faits, chaque fichier a un domaine de compétence, et les
différents blocs \header, \midi et \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
traLaLa = { c'4 d'4 }
|
est convertie, en interne, en une définition Scheme :
(define traLaLa valeur Scheme de ` |
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 traLaLa puis dupliqué à l’aide de Scheme.
Le résultat est alors importé dans un bloc \score au moyen d’une
seconde variable twice.
traLaLa = { c'4 d'4 }
#(define newLa (map ly:music-deep-copy
(list traLaLa traLaLa)))
#(define twice
(make-sequential-music newLa))
\twice
|
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 \addlyrics ne suit ; il doit donc
vérifier ce qui vient après. Le parser lit le # et
l’expression Scheme qui le suit sans l’évaluer, de telle sorte
qu’il peut procéder à l’assignation, et ensuite exécuter le
code Scheme sans problème.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Importing Scheme in LilyPond
L’exemple précédent illustre la manière « d’exporter » une expression
musicale à partir des saisies et à destination de l’interpréteur Scheme.
L’inverse est aussi réalisable : en la plaçant derrière un $, une
valeur Scheme sera interprétée comme si elle avait été saisie en
syntaxe LilyPond. Au lieu de définir \twice, nous aurions tout
aussi bien pu écrire
… $(make-sequential-music (list newLa)) |
Vous pouvez utiliser $ suivi d’une expression Scheme partout où
vous auriez utilisé \nom, dès lors que vous aurez assigné à
cette expression Scheme le nom de variable nom. La substitution
intervenant au niveau de l’analyseur lexical (le 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 newLa avec un
$ plutôt qu’un #, la définition Scheme suivante aurait
échoué du fait que traLaLa n’était pas encore défini. Pour plus
d’information quant au problème de synchronisation, voir la rubrique
Syntaxe Scheme dans LilyPond.
Une autre façon de procéder serait de recourir aux « colleurs de liste »
$@ et #@ dont la fonction est d’insérer les éléments
d’une liste dans le contexte environnant. Grâce à ces opérateurs, la
dernière partie de notre fonction pourrait s’écrire ainsi :
…
{ #@newLa }
|
Ici, chaque élément de la liste stockée dans newLa est pris à
son tour et inséré dans la liste, tout comme si nous avions écrit
{ #(premier newLa) #(deuxième newLa) }
|
Dans ces deux dernières formes, le code Scheme est évalué alors même que le code initial est en cours de traitement, que ce soit par le lexer ou par le parser. Si le code Scheme ne doit être exécuté que plus tard, consultez la rubrique Fonctions Scheme fantômes, ou stockez le dans une procédure comme ici :
#(define (nopc)
(ly:set-option 'point-and-click #f))
…
#(nopc)
{ c'4 }
|
L’imbrication de variables Scheme et LilyPond n’est pas possible avec l’option ‘--safe’.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@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 pour la valeur associée. Voici comment procéder selon la syntaxe de LilyPond :
\override Stem.thickness = #2.6 |
Cette instruction ajuste l’apparence des hampes. Une entrée
'(thickness . 2.6) de la alist est ajoutée à la liste
de la propriété de l’objet Stem. thickness devant
s’exprimer en unité d’épaisseur de ligne, les hampes auront donc une
épaisseur de 2,6 lignes 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 vingtQuatre que
nous avons vu plus haut – et les variables internes des objets, nous
parlerons de « propriétés » pour ces dernières, et de « variables »
pour les autres. Ainsi, l’objet hampe possède une propriété
thickness, alors que vingtQuatre est une variable.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof LilyPond compound variables
| Décalages (offsets) | ||
| Fractions | ||
| Étendues (extents) | ||
| Propriété en alist | ||
| Chaînes d’alist |
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Offsets
Les décalages (offset) sur deux axes (coordonnées X et Y) sont
stockés sous forme de paires. Le car de l’offset
correspond à l’abscisse (coordonnée X) et le cdr à l’ordonnée
(coordonnée Y).
\override TextScript.extra-offset = #'(1 . 2) |
Cette clause affecte la paire (1 . 2) à la propriété
extra-offset de l’objet 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 ‘scm/lily-library.scm’.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Fractions
Les fractions, telles que LilyPond les utilise, sont aussi stockées sous
forme de paire. Alors que Scheme est tout à fait capable de
représenter des nombres rationnels, vous conviendrez que, musicalement
parlant, ‘2/4’ et ‘1/2’ ne se valent pas ; nous devrons
donc pouvoir les distinguer. Dans le même ordre d’idée, LilyPond ne
connaît pas les « fractions » négatives. Pour ces raisons, 2/4
en LilyPond correspond à (2 . 4) en Scheme, et #2/4 en
LilyPond correspond à 1/2 en Scheme.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Extents
Les paires permettent aussi de stocker des intervalles qui représentent
un ensemble de nombres compris entre un minimum (le car) et un
maximum (le 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 car correspond à la coordonnée de
l’extrémité gauche, et le cdr à la coordonnée de l’extrémité
droite. En matière d’étendue sur les Y, le car correspond à la
coordonnée de l’extrémité basse, et le cdr à la coordonnée de
l’extrémité haute.
Les procédures permettant de manipuler les offsets sont regroupées dans le fichier ‘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.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Property alists
Les propriétés en alist 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
'thickness.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@translationof Alist chains
Une chaîne d’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’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’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 chain-assoc-get.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] | [Racine] | [Table des matières] | [Index] | [ ? ] |
@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 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 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 :
\simultaneous à un
(internals)SimultaneousMusic section ‘SimultaneousMusic’ dans Référence des propriétés internes. Une liste exhaustive des différentes
expressions est disponible dans la référence des propriétés internes, à
la rubrique
(internals)Music expressions section ‘Music expressions’ dans Référence des propriétés internes.
event, un note-event, un rhythmic-event et un
melodic-event. Les différentes classes musicales sont
répertoriées à la rubrique
(internals)Music classes section ‘Music classes’ dans Référence des propriétés internes de la référence
des propriétés internes.
Music.
L’information réelle d’une expression musicale est enregistrée sous
forme de propriétés. Par exemple, un
(internals)NoteEvent section ‘NoteEvent’ dans Référence des propriétés internes dispose des
propriétés pitch et 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
(internals)Music properties section ‘Music properties’ dans Référence des propriétés internes
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é elements d’un objet
musical ; s’il n’y a qu’un seul objet « enfant », il sera stocké
dans la propriété element. Ainsi, par exemple, les enfants de
(internals)SequentialMusic section ‘SequentialMusic’ dans Référence des propriétés internes iront dans elements, alors que
l’argument unique de
(internals)GraceMusic section ‘GraceMusic’ dans Référence des propriétés internes ira dans element.
De même, le corps d’une répétition ira dans la propriété element
d’un
(internals)RepeatedMusic section ‘RepeatedMusic’ dans Référence des propriétés internes, les alternatives quant à elles dans la
propriété elements.
| [ < ] | [ > ] | [ << ] | [Plus haut] | [ >> ] |
Ce document a été généré le le 13 juillet 2020 par gub en utilisant texi2html 1.82.
Autres langues : English, deutsch, español.
À propos de la sélection automatique de la langue.