Subject: [LilyPond] Lier une variable par référence plutôt que par valeur en scheme

From: Emmanuel Franquemagne via LilyPond <[email-masked]>
Date: Tue, 28 Oct 2025 11:58:13 +0000

Bonjour,

Je continue mon cheminement pour automatiser les partitions en fonction des instruments et des clefs.
Grâce à des posts passes, j'ai pu définir une fonction qui génère un \book de façon paramétrique, en indiquant le niveau de transposition que je souhaite. Voici ce que ça donne:

[details="Générateur scheme de \book"]
```
bookRenderingBuilder = 
  #(define-void-function (highKey lowKey printKey targetPitch targetAlteration)
    (string? string? string? integer? number?)
    (print-book-with-defaults
     #{
      \book {
        \bookOutputSuffix #(string-join (list printKey defaultInstrumentKey))
        \header {
          instrument = #(string-concatenate (list "Instruments en " printKey))
        }
         \score {
          <<
            \structurePart
            \chordsPart
            \transpose #(ly:make-pitch 0 0) #(ly:make-pitch 0 targetPitch targetAlteration) \choirPart
          \layout { }
        }
      }
    #}))
```
[/details]
L'appel s'effectue comme suit:
`\bookRenderingBuilder "treble" "treble_8" "Sib" -1 #FLAT`
Question optionnelle intermédiaire: est-ce que vous repérez des mauvaises pratiques dans ce que j'ai fait?
Il faudra que je puisse trouver un mécanisme qui unifie les 3 derniers paramètres, puisqu'on peut déduire `-1 #FLAT` de `"Sib"`

Ma question concerne plus particulièrement les 2 premiers paramètres, qui définissent une clef par défaut pour les partitions "voix aiguës" et une clef pour les "voix graves".
La définition dans la déclaration des parties est celle qui suit:
[details="exemple sur une partie de chœur"]
```
choirPart = \new ChoirStaff <<
  \new Staff 
  <<
    \clef #defaultHighKey     % <= Positionnement de la clef pour les voix hautes
    \new Voice = "soprano" { \voiceOne \soprano }
    \new Voice = "alto" { \voiceTwo \alto }
  \new Lyrics \with {
    \override VerticalAxisGroup.staff-affinity = #CENTER
  } \lyricsto "soprano" \verseOne
  \new Staff \with 
  <<
    \clef #defaultLowKey     % <= Positionnement de la clef pour les voix basses
    \new Voice = "tenor" { \voiceOne \tenor }
    \new Voice = "bass" { \voiceTwo \bass }
```
[/details]

Mon problème est que si je fais 2 appels successifs, ex:
```
\bookRenderingBuilder "treble" "treble_8" "Ut" -1 #FLAT

#(define defaultHighKey "treble")
#(define defaultLowKey "bass")

\bookRenderingBuilder "alto" "alto_8" "Sib" 0 #NATURAL
```
, alors la transposition fonctionne bien, mais les clefs ne changent pas puisqu'elles ont déjà été interprétées au moment de la déclaration.
*(Note: je précise que pour le moment je n'utilise pas les 2 paramètres de clef dans l'appel, j'essaye déjà que ça marche en direct).*

Ma question est donc: est-il possible de faire un passage "par référence" plutôt que "par valeur" lorsqu'on définit une expression lilypond+scheme ?
Et si ce n'est pas possible (mon intuition me dicte que c'est bien le cas), alors comment faire? Est-ce qu'il faut mettre un "template" de clef (ex `@@HIGH_KEY@@`) qu'on remplace lors de l'instanciation (du style `s/@@HIGH_KEY@@/#defaultHighKey/g`)? 
Est-il possible de "reparser" ou "recompiler" une variable?
Y a-t-il une autre bonne pratique correspondant à ce besoin?

Et j'en profite pour reformuler ici une demande qui avait été faite dans un post précédent: est-ce qu'il existe un moyen de se former de façon plus poussée sur la programmation Lilypond+Scheme? J'ai bien compris que la puissance de l'association des 2 est monumentale, mais plonger dans les arcanes de la chose, même lorsqu'on a un passé d'informaticien, n'est vraiment pas évident.

Merci beaucoup, bonne journée à tous.
Emmanuel

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/1).

Pour créer un nouveau sujet, écrivez à [[email-masked]](mailto:[email-masked]) ou visitez la [page d'accueil de lilypond.community](https://lilypond.community).

---

From: Ben via LilyPond <[email-masked]>
Date: Tue, 28 Oct 2025 13:30:03 +0000

Bonjour Emmanuel, Il existe une documentation complète du Scheme sur leur site officiel, il existe même une ébauche en français faite par Jean sur l'intégration de Scheme et Lilypond sur le site de lilypond, mais c'est tout. Autrement dit, pour y parvenir il vaudrait mieux directement devenir développeur occasionnel de lilypond, afin de pratiquer régulièrement et de pouvoir maintenir le code sur la durée.   Si  votre seul objectif est d'avoir un générateur conditionnel de book, il me paraît plus simple de le faire avec un script système. On peut d'ailleurs envoyer une variable lilypond via la ligne de commande lilypond et ensuite faire une condition en scheme dans le code lilypond. Au plaisir, Ben
-------- Message d'origine --------De : Emmanuel Franquemagne via LilyPond <[email-masked]> Date : 28.10.25  12:58  (GMT+01:00) À : [email-masked] Objet : [LilyPond] Lier une variable par référence plutôt que par valeur en scheme 

  

        

          Emmanuel Franquemagne
            franquemagnee
        
        Octobre 28

  Bonjour,

Générateur scheme de \book (cliquer pour plus de détails)
L'appel s'effectue comme suit:
\bookRenderingBuilder "treble" "treble_8" "Sib" -1 #FLAT
Question optionnelle intermédiaire: est-ce que vous repérez des mauvaises pratiques dans ce que j'ai fait?
Il faudra que je puisse trouver un mécanisme qui unifie les 3 derniers paramètres, puisqu'on peut déduire -1 #FLAT de "Sib"
Ma question concerne plus particulièrement les 2 premiers paramètres, qui définissent une clef par défaut pour les partitions "voix aiguës" et une clef pour les "voix graves".
La définition dans la déclaration des parties est celle qui suit:

exemple sur une partie de chœur (cliquer pour plus de détails)
Mon problème est que si je fais 2 appels successifs, ex:
\bookRenderingBuilder "treble" "treble_8" "Ut" -1 #FLAT

, alors la transposition fonctionne bien, mais les clefs ne changent pas puisqu'elles ont déjà été interprétées au moment de la déclaration.
(Note: je précise que pour le moment je n'utilise pas les 2 paramètres de clef dans l'appel, j'essaye déjà que ça marche en direct).
Ma question est donc: est-il possible de faire un passage "par référence" plutôt que "par valeur" lorsqu'on définit une expression lilypond+scheme ?
Et si ce n'est pas possible (mon intuition me dicte que c'est bien le cas), alors comment faire? Est-ce qu'il faut mettre un "template" de clef (ex @@HIGH_KEY@@) qu'on remplace lors de l'instanciation (du style s/@@HIGH_KEY@@/#defaultHighKey/g)?
Est-il possible de "reparser" ou "recompiler" une variable?
Y a-t-il une autre bonne pratique correspondant à ce besoin?
Et j'en profite pour reformuler ici une demande qui avait été faite dans un post précédent: est-ce qu'il existe un moyen de se former de façon plus poussée sur la programmation Lilypond+Scheme? J'ai bien compris que la puissance de l'association des 2 est monumentale, mais plonger dans les arcanes de la chose, même lorsqu'on a un passé d'informaticien, n'est vraiment pas évident.
Merci beaucoup, bonne journée à tous.
Emmanuel

Pour poster dans ce sujet, visitez la page du sujet.
Pour créer un nouveau sujet, écrivez à [email-masked] ou visitez la page d'accueil de lilypond.community.
  
Pour vous désabonner de ces e-mails, modifiez vos préférences.

  

                         

    
      @media (prefers-color-scheme: dark) {
        html {
          background: #151515 !important;
        }

        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
        p,
        span,
        td {
          color: inherit !important;
        }

        [data-stripped-secure-media] {
          border-color: #454545 !important;
        }

        [data-stripped-secure-upload] {
          border-color: #454545 !important;
        }

        [dm='text-color'] {
          color: #dddddd;
        }

        [dm='header'] {
          background: #151515 !important;
        }

        [dm='topic-body'] {
          background: #151515 !important;
          border-bottom: 1px solid #454545 !important;
        }

        [dm='triangle'] {
          border-top-color: #151515 !important;
        }

        [dm='body'] {
          background: #222222 !important;
          color: #dddddd !important;
        }

        [dm='body_primary'] {
          background: #062e3d !important;
          color: #dddddd !important;
        }

        [dm='bg'] {
          background: #323232 !important;
          border-color: #454545 !important;
        }
      }

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/2).

---

From: Emmanuel Franquemagne via LilyPond <[email-masked]>
Date: Wed, 29 Oct 2025 09:32:57 +0000

Bonjour Ben

Merci pour cette réponse. Comme je l'ai dans de précédents posts, je préfère ne pas passer par des scripts systèmes et tout avoir dans le même "root file".
 J'essaye une autre approche: j'ai mis la déclaration des parties dans une fonction. C'est ici que je définis les clefs, donc ça me permet de ne pas avoir à descendre trop profondément dans les définitions.

J'ai donc défini ceci (note: j'ai remonté la transposition dans cette fonction):

[details="Résumé"]
```
partsRenderingBuilder = #(define-void-function (highKey lowKey targetPitch targetAlteration)
    (string? string? integer? number?)
    #{
      \new Devnull \structure
      
      \new ChordNames \chordNames
      
      \new ChoirStaff <<
        \new Staff
        \transpose #(ly:make-pitch 0 0) #(ly:make-pitch 0 targetPitch targetAlteration) <<
          \clef #highKey
          \new Voice = "soprano" { \voiceOne \soprano }
          \new Voice = "alto" { \voiceTwo \alto }
        \new Staff
        \transpose #(ly:make-pitch 0 0) #(ly:make-pitch 0 targetPitch targetAlteration) <<
          \clef #lowKey
          \new Voice = "tenor" { \voiceOne \tenor }
          \new Voice = "bass" { \voiceTwo \bass }
    #})
```
[/details]

et j'appelle cette fonction dans la fonction englobante bookRenderingBuilder.
bookRenderingBuilder = 

[details="Résumé"]
```
        
         \score {
          <<
            #(partsRenderingBuilder highKey lowKey targetPitch targetAlteration)
          \layout { }
        }
      }
    #}))
```
[/details]

La compilation se passe (trop) bien.Le problème que j'ai est que je prends l'avertissement
```
Avertissement : on passe un partition de durée nulle
```
Et là je sèche. Pour la fonction générant le book, il fallait appeler en tête la fonction `print-book-with-defaults`. Est-ce qu'il y a un équivalent pour produire en ligne les parties? Ou bien une façon de produire les variables `structurePart`, `chordsPart` et `choirPart`, que je pourrais utiliser hors du scope de la fonction, dans le bloc `\book`, ce qui me permettrait au passage de me passer du `bookRenderingBuilder`?

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/3).

---

From: Emmanuel Franquemagne via LilyPond <[email-masked]>
Date: Wed, 29 Oct 2025 14:58:43 +0000

Je me réponds à moi-même par souci de complétion du thread pour les suivants:
si je remplace
`partsRenderingBuilder = #(define-void-function`
par
`partsRenderingBuilder = #(define-scheme-function`

Alors j'obtiens bien une partition mais dans laquelle les 3 parties (`structure`, `chords`, `choir`) sont empilées (comme s'il y avait 3 blocs `\score`: le bloc structure génère un grand vide en haut, les accords tous ensemble au milieu, et le chœur tout seul en bas).

Si maintenant je remonte le `<< >>` du `\score` dans la fonction, alors ça fonctionne, j'ai bien toutes les parties qui jouent leur rôle dans 1 seul partition.

Donc je ne sais pas si c'est la bonne façon de faire, ni quelles sont les limitations qui font que le codage précédent ne fonctionnait pas, mais au moins maintenant ça marche, je peux générer une partition avec les bonnes clefs et les bonnes transpositions.

Je mets ici les éléments saillants de mon fichier, pour exemple/aide pour d'autres.
[details="conversion de gamme (C, D, etc.) vers octave\+pitch\+alteration pour ly\:make-pitch"]
```
#(define keyToPitch '( ; This list defines the direct required transposition in term of lilypond pitch => we want to transpose in D natural, so increase each pitch from 0 octave, 1 pitch, 0 alteration
("C" . ( 0 0 0))
("C+" . ( 0 8 0))
("C-" . ( 0 -8 0))
("Cb" . ( 0 0 -1))
("Cb+" . ( 0 8 -1))
("Cb-" . ( 0 -8 -1))
("C#" . ( 0 0 1))
("C#+" . ( 0 8 1))
("C#-" . ( 0 -8 1))
("D" . ( 0 1 0))
("D+" . ( 0 9 0))
("D-" . ( 0 -7 0))
("Db" . ( 0 1 -1))
("Db+" . ( 0 9 -1))
("Db-" . ( 0 -7 -1))
("D#" . ( 0 1 1))
("D#+" . ( 0 9 1))
("D#-" . ( 0 -7 1))
("E" . ( 0 2 0))
("E+" . ( 0 10 0))
("E-" . ( 0 -6 0))
("Eb" . ( 0 2 -1))
("Eb+" . ( 0 10 -1))
("Eb-" . ( 0 -6 -1))
("E#" . ( 0 2 1))
("E#+" . ( 0 10 1))
("E#-" . ( 0 -6 1))
("F" . ( 0 3 0))
("F+" . ( 0 11 0))
("F-" . ( 0 -5 0))
("Fb" . ( 0 3 -1))
("Fb+" . ( 0 11 -1))
("Fb-" . ( 0 -5 -1))
("F#" . ( 0 3 1))
("F#+" . ( 0 11 1))
("F#-" . ( 0 -5 1))
("G" . ( 0 -3 0))
("G+" . ( 0 4 0))
("G-" . ( 0 -11 0))
("Gb" . ( 0 -3 -1))
("Gb+" . ( 0 4 -1))
("Gb-" . ( 0 -11 -1))
("G#" . ( 0 -3 1))
("G#+" . ( 0 4 1))
("G#-" . ( 0 -11 1))
("A" . ( 0 -2 0))
("A+" . ( 0 5 0))
("A-" . ( 0 -10 0))
("Ab" . ( 0 -2 -1))
("Ab+" . ( 0 5 -1))
("Ab-" . ( 0 -10 -1))
("A#" . ( 0 -2 1))
("A#+" . ( 0 5 1))
("A#-" . ( 0 -10 1))
("B" . ( 0 -1 0))
("B+" . ( 0 6 0))
("B-" . ( 0 -1 0))
("Bb" . ( 0 -1 -1))
("Bb+" . ( 0 6 -1))
("Bb-" . ( 0 -1 -1))
("B#" . ( 0 -1 1))
("B#+" . ( 0 6 1))
("B#-" . ( 0 -1 1))
))

%% This list defines the needed transposition from instrument's root scale (Ex Bb for clarinets will get D natural as transposition)
#(define transpositorRootScale '(
("C" . ( 0 0 0))
("C+" . ( -1 0 0))
("C-" . ( 1 0 0))
("Cb" . ( 0 0 1))
("Cb+" . ( -1 0 1))
("Cb-" . ( 1 0 1))
("C#" . ( 0 7 0)) ; Instrument plays in C# => need to transpose in B NATURAL
("C#+" . ( -1 7 0)); Instrument plays in C#, 1 octave upper => need to transpose in B, 1 octave lower
("C#-" . ( 1 7 0)); Instrument plays in C#, 1 octave lower => need to transpose in B, 1 octave upper
("D" . ( 0 -1 -1))
("D+" . ( -1 -1 -1))
("D-" . ( 0 -7 0))
("Db" . ( 0 1 -1))
("Db+" . ( 0 9 -1))
("Db-" . ( 0 -7 -1))
("D#" . ( 0 1 1))
("D#+" . ( 0 9 1))
("D#-" . ( 0 -7 1))
("E" . ( 0 2 0))
("E+" . ( 0 10 0))
("E-" . ( 0 -6 0))
("Eb" . ( 0 2 -1))
("Eb+" . ( 0 10 -1))
("Eb-" . ( 0 -6 -1))
("E#" . ( 0 2 1))
("E#+" . ( 0 10 1))
("E#-" . ( 0 -6 1))
("F" . ( 0 3 0))
("F+" . ( 0 11 0))
("F-" . ( 0 -5 0))
("Fb" . ( 0 3 -1))
("Fb+" . ( 0 11 -1))
("Fb-" . ( 0 -5 -1))
("F#" . ( 0 3 1))
("F#+" . ( 0 11 1))
("F#-" . ( 0 -5 1))
("G" . ( 0 -3 0))
("G+" . ( 0 4 0))
("G-" . ( 0 -11 0))
("Gb" . ( 0 -3 -1))
("Gb+" . ( 0 4 -1))
("Gb-" . ( 0 -11 -1))
("G#" . ( 0 -3 1))
("G#+" . ( 0 4 1))
("G#-" . ( 0 -11 1))
("A" . ( 0 -2 0))
("A+" . ( 0 5 0))
("A-" . ( 0 -10 0))
("Ab" . ( 0 -2 -1))
("Ab+" . ( 0 5 -1))
("Ab-" . ( 0 -10 -1))
("A#" . ( 0 -2 1))
("A#+" . ( 0 5 1))
("A#-" . ( 0 -10 1))
("B" . ( 0 -1 0))
("B+" . ( 0 6 0))
("B-" . ( 0 -1 0))
("Bb" . ( 0 -1 -1))
("Bb+" . ( 0 6 -1))
("Bb-" . ( 0 -1 -1))
("B#" . ( 0 -1 1))
("B#+" . ( 0 6 1))
("B#-" . ( 0 -1 1))
))

#(define getTranspositionOctave (define-scheme-function (scaleKey) (string?) (list-ref (assoc-ref keyToPitch scaleKey) 0)))
#(define getTranspositionBasePitch (define-scheme-function (scaleKey) (string?) (list-ref (assoc-ref keyToPitch scaleKey) 1)))
#(define getTranspositionAlteration (define-scheme-function (scaleKey) (string?) (list-ref (assoc-ref keyToPitch scaleKey) 2)))

#(define getReverseTranspositorOctave (define-scheme-function (tranpositorKey) (string?) (list-ref (assoc-ref transpositorRootScale tranpositorKey) 0)))
#(define getReverseTranspositionBasePitch (define-scheme-function (tranpositorKey) (string?) (list-ref (assoc-ref transpositorRootScale tranpositorKey) 1)))
#(define getReverseTranspositionAlteration (define-scheme-function (tranpositorKey) (string?) (list-ref (assoc-ref transpositorRootScale tranpositorKey) 2)))
```
[/details]

Attention: ne faites pas une confiance aveugle aux valeurs de pitches définis dans la `map` !

[details="La fonction qui génère les différentes parties de la partition"]
```
partsRenderingBuilder = #(define-scheme-function (highKey lowKey targetPitch)
    (string? string? string?)
    #{
      <<
      \new Devnull \structure

      \new ChoirStaff <<
        \new Staff  \transpose #(ly:make-pitch 0 0) #(ly:make-pitch (getTranspositionOctave targetPitch) (getTranspositionScale targetPitch) (getTranspositionAlteration targetPitch))
        <<
          \clef #highKey
          \new Voice = "soprano" { \voiceOne \soprano }
          \new Voice = "alto" { \voiceTwo \alto }
        \new Staff \transpose #(ly:make-pitch 0 0) #(ly:make-pitch (getTranspositionOctave targetPitch) (getTranspositionScale targetPitch) (getTranspositionAlteration targetPitch))
        <<
          \clef #lowKey
          \new Voice = "tenor" { \voiceOne \tenor }
          \new Voice = "bass" { \voiceTwo \bass }
    #})
```
[/details]
Et enfin

[details="La fonction qui génère le bloc \book"]
```
bookRenderingBuilder = 
  #(define-void-function (highKey lowKey printKey targetPitch printableReadingClef)
    (string? string? string? string? string?)
    (print-book-with-defaults
     #{
      \book {
        \bookOutputSuffix #(string-join (list printKey printableReadingClef))
        \header {
          instrument = #(string-concatenate (list "Instruments en " printKey))
        }
        
         \score {
          <<
            #(partsRenderingBuilder highKey lowKey targetPitch)
          \layout { }
        }
      }
    #}))
```
[/details]

Il ne reste plus que l'appel lui-même
```
\bookRenderingBuilder "treble" "treble_8" "Re" "D" "Clef_Sol"
```

L'exemple ci-dessus génère une version de la partition dont toutes les portées seront écrites en clef de sol (𝄠 pour les voix graves); les voix mélodiques seront transposées un ton au-dessus.
Donc:
```
\bookRenderingBuilder "treble" "bass" "Ut" "C" "Clef_Fa_Sol"  % Flûte
\bookRenderingBuilder "treble" "treble_8" "Ut" "C" "Clef_Sol"  % Piano, chœur
\bookRenderingBuilder "treble" "treble_8" "Sib" "D" "Clef_Sol"  % Clarinettes, trompettes
\bookRenderingBuilder "treble" "treble_8" "Mib" "A" "Clef_Sol"  % Saxo
\bookRenderingBuilder "alto" "alto_8" "Ut" "C" "Clef_Alto"  % Violon alto
\bookRenderingBuilder "treble" "treble_8" "Fa" "G" "Clef_Sol"  % Cor
```
L'exemple ci-dessus produira 6 partitions de la même musique, transposant les notes de façon adéquate pour l'instrument considéré, et avec la clef attendue par le musicien.
Ceci est utile lorsqu'on joue de la musique en groupe (mais pas en orchestre officiel), dans laquelle chaque musicien peut choisir la partie qu'il souhaite jouer.

Notes:
* D'un point de vue lilypond, cela permet de ne pas multiplier les définitions de `\book` ou parts et de rendre le code génératif final bien plus lisible que de scroller.
* L'ajout d'un instrument, quel qu'il soit, ne requiert théoriquement qu'un seul appel en plus.

Auto-commentaires/`TODO`
1. Pour le moment je ne sais faire qu'une fonction par type de partitions (chords+choir par exemple). Il serait bien que je puisse définir quelque part les parties qui m'intéressent, si elles seront transposées (dans la pratique des musiciens que je côtoie, les partitions sont transposées, mais pas les accords). L'avantage serait de pouvoir mettre cette fonction générique dans un  fichier `\include`
2. Pouvoir réduire le nombre de paramètres en déduisant `highKey` et `lowKey` de `printableReadingKey`.
3. Les fonctions ne prennent pas en compte les instruments exotiques, transposant avec des quarts de ton.
4. On peut ajouter une table associative qui renvoit la chaîne de transposition à partir du nom de l'instrument ("Clarinet" => "D") et à partir de là récupérer le pitch de transposition.

Soyons clairs: j'ai produit cela avec mes maigres connaissances des bonnes pratiques de la combinaison Guile+Lilypond.
N'hésitez pas s'il y a des hérésies!

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/4).

---

From: Jean Abou Samra via LilyPond <[email-masked]>
Date: Wed, 29 Oct 2025 17:51:58 +0000

En termes de bonnes pratiques, il vaut mieux appeler `toplevel-book-handler` plutôt que `print-book-with-defaults` car `print-book-with-defaults` est la valeur par défaut de `toplevel-book-handler` mais cette valeur peut être configurée via diverses options.

Plutôt que de travailler avec des paires d'un entier représentant une échelle de la gamme et d'une altération, il est plus simple de travailler avec les objets « hauteur » de LilyPond, qui en prime peuvent s'écrire avec la syntaxe habituelle (par exemple `bes`, ou `sib` en `\language "français"`).

`(define-scheme-function (...) (...) ...)` est la syntaxe pour définir une fonction qui s'appelle avec la syntaxe LilyPond `\fonction <argument> ... <argument>`. Il se trouve que ces fonctions peuvent aussi s'appeler depuis Scheme avec la syntaxe Scheme `(fonction <argument> ... <argument>)`, mais si c'est pour n'utiliser que la syntaxe Scheme, il suffit de définir une fonction Scheme normale avec `(define (fonction ...) ...)`.

La table qui définit la transposition à appliquer pour passer des hauteurs réelles aux hauteurs lues par les instrumentistes en fonction de la transposition de l'instrument est inutile : plutôt que de calculer par exemple ré à partir de si bémol et transposer de do vers ré, il suffit de transposer de si bémol vers do.

En incorporant quelques autres simplifications, ça donne :

```
\version "2.24.4"

\language "français"

structure = { s1 }
chordNames = \chordmode { do1 }
soprano = { do''1 }
alto = { mi'1 }
tenor = { sol1 }
bass = { do1 }

#(define (build-parts high-key low-key target-pitch)
   #{
     <<
       \new Devnull \structure
       \new ChordNames \chordNames
       \new ChoirStaff \transpose #target-pitch do <<
         \new Staff <<
           \clef #high-key
           \new Voice = "soprano" { \voiceOne \soprano }
           \new Voice = "alto" { \voiceTwo \alto }
         \new Staff <<
          \clef #low-key
   #})

bookRenderingBuilder =
#(define-void-function (high-key low-key print-key target-pitch printable-reading-clef)
   (string? string? string? ly:pitch? string?)
   (toplevel-book-handler
    #{
      \book {
        \bookOutputSuffix #(format #f "~a-~a" print-key printable-reading-clef)
        \header {
          instrument = #(format #f "Instruments en ~a" print-key)
        }
        \score { #(build-parts high-key low-key target-pitch) }
       }
    #}))

\bookRenderingBuilder "treble" "bass" "Ut" do "Clef_Fa_Sol"  % Flûte
\bookRenderingBuilder "treble" "treble_8" "Ut" do "Clef_Sol"  % Piano, chœur
\bookRenderingBuilder "treble" "treble_8" "Sib" sib, "Clef_Sol"  % Clarinettes, trompettes
\bookRenderingBuilder "treble" "treble_8" "Mib" mib "Clef_Sol"  % Saxo
\bookRenderingBuilder "alto" "alto_8" "Ut" do "Clef_Alto"  % Violon alto
\bookRenderingBuilder "treble" "treble_8" "Fa" fa "Clef_Sol"  % Cor
```

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/5).

---

From: Emmanuel Franquemagne via LilyPond <[email-masked]>
Date: Thu, 30 Oct 2025 00:39:36 +0000

Merci beaucoup Jean! Effectivement c'est beauuuucoup plus simple ! :+1: 
*(au passage je ne savais pas que la commande `\layout {}` était optionnelle...)*

Il n'y a que pour le bloc `\midi` qu'il a fallu que je ruse, puisque `#(build-parts...)` attend un `ly:pitch`. Mais comme je le génère toujours non transposé, je lui passe juste un `(ly:make-pitch -1 0 0)`, et ça fait la rue Michel *(oui je ne sais pas pourquoi, si je lui passe `(0 0 0)` ça transpose d'une octave vers le bas...)*.

Un immense merci encore! :slightly_smiling_face:

---
Pour poster dans ce sujet, visitez la [page du sujet](https://lilypond.community/t/lier-une-variable-par-reference-plutot-que-par-valeur-en-scheme/6000/6).