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.
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)))
Attention: ne faites pas une confiance aveugle aux valeurs de pitches définis dans la map !
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 ChordNames \chordNames
\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 }
>>
>>
>>
#})
Et enfin
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 { }
}
}
#}))
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
- 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
- Pouvoir réduire le nombre de paramètres en déduisant
highKey et lowKey de printableReadingKey.
- Les fonctions ne prennent pas en compte les instruments exotiques, transposant avec des quarts de ton.
- 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!