1.3.1 Première approche (exemple) (GNU LilyPond – Extension des fonctionnalités)

#### 1.3.1 Première approche (exemple)

1. La problématique

   Partant du code suivant, l’indication « espressivo » (les deux petits soufflets) devrait être plus large, mais pas gagner en hauteur.

   >     { f'\espressivo }

2. Les solutions envisageables
   1. créer un nouveau stencil
   2. redimensionner le stencil par défaut sur l’axe des X
3. Réflexions sur le point précédent

   La solution A est réalisable, mais demandera plus d’effort de codage. Quant à la solution B, bien que moins exigeante, elle a le désavantage de ne pas donner de résultats acceptables dans tous les cas – mais on ne le saura pas avant d’avoir essayé.

   ⇒ opter pour la solution B.

4. Codage
   - Si l’on veut manipuler le stencil par défaut, il faut s’informer à son sujet.

     L’indication d’espressivo est un objet graphique `Script`. En consultant la référence des propriétés internes, on lit

         ‘stencil’ (stencil):
              ‘ly:script-interface::print’

     Voyons voir si tout cela marche. Pour être assurés d’affecter le bon grob, nous utiliserons des couleurs. Il existe une fonction prédéfinie à cet effet – voir Scheme functions.

         -- Fonction: stencil-with-color stencil couleur
             Renvoie une version modifiée du stencil donné, teint
             dans la couleur donnée. Voir ‘normalize-color’ pour
             les formats de couleur possibles.

         -- Fonction: normalize-color couleur
             Convertit une couleur donnée dans l'un des formats pris en
             charge en une liste de 4 nombres : R, G, B, A. Les formats
             possibles sont : une liste de 4 nombres ; une liste de 3
             nombres (transparence par défaut à 1.0) ; une chaîne CSS
             (nom de couleur, ou “#RRGGBB”, “#RRGGBBAA”, “#RGB” ou
             “#RGBA”).

     Utilisant un nom de couleur (‘`red`’), nous obtenons le code suivant :

     >     colorDefaultStencil =
     >     \once \override Script.stencil =
     >       % `lambda` starts a procedure; its argument is `grob`.
     >       #(lambda (grob)
     >          ;; With `let`, local variables are defined.
     >          (let ((stil (ly:script-interface::print grob)))
     >            ;; The procedure returns the colored default stencil.
     >            (stencil-with-color stil red)))

     >     { \colorDefaultStencil f'\espressivo }

     Parfait, cela fonctionne.

   - Ce type d’opération – prendre un stencil ou une propriété par défaut et en retourner une version modifiée – est très courante, et LilyPond dispose d’une fonction dédiée à cet effet : `grob-transformer`.

         -- Function: grob-transformer property func
             Create an override value good for applying FUNC to either
             pure or unpure values.  FUNC is called with the
             respective grob as first argument and the default value
             (after resolving all callbacks) as the second.

     Laissons-nous tenter. Les concepts de pur ou impur seront vus plus avant, dans Conteneurs requalifiants ; ignorons-les pour l’instant.

     >     colorDefaultStencil =
     >     \once \override Script.stencil =
     >       #(grob-transformer 'stencil
     >          (lambda (grob orig)
     >            (stencil-with-color orig red)))

     >     { \colorDefaultStencil f'\espressivo }

     Excellent !

   - Pour obtenir un stencil redimensionné, il faut utiliser

         -- Function: ly:stencil-scale stil x y
             Scale stencil STIL using the horizontal and vertical
             scaling factors X and optional Y (defaulting to X).
             Negative values flip or mirror STIL without changing its
             origin; this may result in collisions unless it is
             repositioned.

     à partir du même chapitre de la référence des propriétés internes.

     Résultat :

     >     scaleColorDefaultStencil =
     >     \once \override Script.stencil =
     >       #(grob-transformer 'stencil
     >          (lambda (grob orig)
     >            (stencil-with-color
     >             (ly:stencil-scale
     >              orig
     >              ;; 1 is the neutral element with ly:stencil-scale,
     >              ;; i.e., scaling with '1 1' (for x- and y-axis)
     >              ;; returns a visibly unchanged stencil.
     >              2 1)
     >             red)))

     >     { \scaleColorDefaultStencil f'\espressivo }

     Mis à part la couleur, cela ressemble fort à ce que l’on voulait.

   - Certains problèmes subsistent cependant, comme le montre l’exemple suivant :

         { \scaleColorDefaultStencil f'_\espressivo ^\fermata }

     - − Le point d’orgue est redimensionné lui aussi.
     - − Devoir taper la commande avant les notes et `\espressivo` après ces notes n’est pas pratique.

     Solution aux deux inconvénients : utilisons `\tweak` !

     >     {
     >       f'-\tweak stencil
     >           #(grob-transformer 'stencil
     >              (lambda (grob orig)
     >                (stencil-with-color
     >                 (ly:stencil-scale orig 2 1)
     >                 red)))
     >           _\espressivo
     >         ^\fermata
     >     }

     Cela fait ce qui est demandé, mais autant de saisie n’est pas la panacée ; pourquoi ne pas définir une variable que l’on utiliserait dans le tweak ? Après un peu de copier coller, nous obtenons

     >     #(define longer-script
     >        (grob-transformer 'stencil
     >          (lambda (grob orig)
     >            (stencil-with-color
     >             (ly:stencil-scale orig 2 1)
     >             red))))

     >     {
     >       f'-\tweak stencil #longer-script _\espressivo
     >         ^\fermata
     >     }

     Cela fonctionne correctement, bien que les valeurs soient codées en dur et que taper `-\tweak stencil #longer-script` sans arrêt soit rébarbatif.

     Pour régler cela, commençons par introduire des variables dans `longer-script` pour les valeurs de redimensionnement x et y.

         #(define (longer-script x y)
            (grob-transformer 'stencil
              (lambda (grob orig)
                (stencil-with-color
                 (ly:stencil-scale orig x y)
                 red))))

     Ensuite, et pour réduire la frappe, nous définissons une fonction événementielle – voir Fonctions événementielles. Les éléments du premier groupe entre parenthèses – `(x-val y-val)` – sont les variables de la fonction, et les éléments du second groupe entre parenthèses sont les types respectifs de variable (on cherche deux fois un nombre – voir Types de prédicat prédéfinis pour les possibilités de test).

         scaleEspr =
         #(define-event-function (x-val y-val) (number? number?)
           #{
             \tweak stencil #(longer-script x-val y-val)
             \espressivo
           #})

         { f'_\scaleEspr 2 1
              ^\fermata }

     Cela fonctionne à merveille ! Notez l’utilisation de `#{ … #}` : dans cette construction Scheme, il est tout à fait possible d’utiliser la syntaxe de LilyPond, et les arguments de la fonction, tel que x-val, sont correctement expansés – voir Blocs de code LilyPond.

5. Le code finalisé

   Pour terminer, faisons un peu de ménage.

   - − Nous souhaitons redimensionner uniquement dans l’horizontalité ; nous pouvons donc forcer le redimensionnement vertical dans la fonction événementielle.
   - − Supprimons la couleur.

   Ceci nous amène au code suivant.

   >     #(define (longer-script x y)
   >        (grob-transformer 'stencil
   >          (lambda (grob orig)
   >            (ly:stencil-scale orig x y))))

   >     longEspressivo =
   >     #(define-event-function (x-val) (number?)
   >       #{
   >         \tweak stencil #(longer-script x-val 1)
   >         \espressivo
   >       #})

   >     { f'^\longEspressivo #2 _\fermata }

   Voilà !

   Le principal bénéfice à l’utilisation de `grob-transformer` réside dans le fait que nul n’est besoin de connaître le nom exact de la fonction de stencil. Dans l’exemple qui suit, nous pivotons une liaison et une ligature de 90 degrés – que les fonction de stencil s’appellent respectivement `ly:slur::print` et `ly:beam::print` n’est d’aucun intérêt en l’occurrence.

   >     #(define rotate-90
   >        (grob-transformer 'stencil
   >          (lambda (grob orig)
   >            (ly:stencil-rotate orig 90 0 0))))

   >     { f'8( g')
   >       f'8-\tweak stencil #rotate-90 ( g')
   >       f'8[ g']
   >       f'8-\tweak stencil #rotate-90 [ g'] }

#### GNU LilyPond – Extension des fonctionnalités v2.26.0 (stable-branch).

- 1 Tutoriel Scheme
  - 1.1 Introduction à Scheme
    - 1.1.1 Le bac à sable de Scheme
    - 1.1.2 Scheme et les variables
    - 1.1.3 Types de données Scheme simples
    - 1.1.4 Types de données Scheme composites
      - Paires
      - Listes
      - Listes associatives (alists)
      - Tables de hachage
    - 1.1.5 Scheme et les calculs
    - 1.1.6 Scheme et les procédures
      - Définition de procédures
      - Prédicats
      - Valeurs de retour
    - 1.1.7 Scheme et les conditions
      - if
      - cond
  - 1.2 Scheme et LilyPond
    - 1.2.1 Syntaxe Scheme dans LilyPond
    - 1.2.2 Variables LilyPond
    - 1.2.3 Débogage de code Scheme
    - 1.2.4 Saisie de variables et Scheme
    - 1.2.5 Import de code Scheme dans LilyPond
    - 1.2.6 Propriétés des objets
    - 1.2.7 Variables LilyPond composites
      - Décalages (offsets)
      - Fractions
      - Étendues (extents)
      - Propriété en alist
      - Chaînes d’alist
    - 1.2.8 Le modèle de boîte de LilyPond
    - 1.2.9 Représentation interne de la musique
  - 1.3 Construction de fonctions complexes
    - 1.3.1 Première approche (exemple)
    - 1.3.2 Affichage d’expressions musicales
    - 1.3.3 Propriétés musicales
    - 1.3.4 Doublement d’une note avec liaison (exemple)
    - 1.3.5 Ajout d’articulation à des notes (exemple)
- 2 Interfaces pour programmeurs
  - 2.1 Blocs de code LilyPond
  - 2.2 Fonctions Scheme
    - 2.2.1 Définition de fonctions Scheme
    - 2.2.2 Utilisation de fonctions Scheme
    - 2.2.3 Fonctions Scheme fantômes
  - 2.3 Fonctions musicales
    - 2.3.1 Définition de fonctions musicales
    - 2.3.2 Utilisation de fonctions musicales
    - 2.3.3 Fonctions de substitution simple
    - 2.3.4 Fonctions de substitution intermédiaires
    - 2.3.5 De l’usage des mathématiques dans les fonctions
    - 2.3.6 Fonctions dépourvues d’argument
    - 2.3.7 Fonctions musicales fantômes
  - 2.4 Fonctions événementielles
  - 2.5 Fonctions pour markups
    - 2.5.1 Construction d’un markup en Scheme
    - 2.5.2 Fonctionnement interne des markups
    - 2.5.3 Définition d’une nouvelle commande de markup
      - Syntaxe d’une commande markup
      - Attribution de propriétés
      - Exemple commenté
      - Adaptation d’une commande incorporée
      - Conversion de markups en chaînes
    - 2.5.4 Définition d’une nouvelle commande de liste de markups
  - 2.6 Contextes pour programmeurs
    - 2.6.1 Évaluation d’un contexte
    - 2.6.2 Application d’une fonction à tous les objets de mise en forme
  - 2.7 Fonctions de rappel
  - 2.8 Conteneurs requalifiants
  - 2.9 Retouches complexes
- 3 Interfaces LilyPond Scheme
- Appendix A GNU Free Documentation License
- Appendix B Index