Subject: Test de chordGrid version 2.23.10

From: Vincent Gay <[email-masked]>
Date: Mon, 18 Jul 2022 22:58:21 +0200

Hello la liste,

j'espère que vous résistez à la chaleur ! Du coup après le confinement 
Covid on a droit au confinement canicule 🙁 Bon, nous en montagne on ne 
vas pas trop se plaindre, surtout dans nos vielles maisons avec des murs 
d'un mètre d’épaisseur. Enfin, je dit ça c'est juste pour faire envie,

Mais retournons à nos moutons, j'ai profité de cette réclusion pour 
tester à fond le petit bijou que nous a concocté Jean. Et sans surprise 
le résultat est remarquable. En voici quelques morceaux choisis qui 
serviront (peut-être) de base à quelques snippets dans la documentation 
officielle.

Propos liminaires : dans tous les fragments de codes ci-dessous 
j'utilise LilyJazz. Ce n'est évidemment pas obligatoire et il suffit de 
commenter les \include en question pour ceux qui ne l'ont pas installé.  
En même temps c'est principalement (exclusivement ?) les jazzeux qui 
utilisent les grilles harmoniques donc ça fait couleur locale.

Plan du post :

  * Les reprises alternatives <#alt>
  * Les nuances <#dyn>
  * Les indications rythmiques <#rythm>
  * Les articulations <#art>
  * ChordGrid et PolyMarks <#poly>
  * PolyMarks mis à jour <#maj>

      1) Les reprises alternatives

jusqu'à présent j'utilisais un système à base de stopStaff / startStaff, 
silences invisibles (s1) barres invisibles (\bar "") et gestion 
manuelles des alternatives. Rappel du principe : la grille est présentée 
par blocs de 4 mesures (on peut tenter 8 mais ça ne doit pas être très 
lisible) et en cas d'alternatives ne sont visibles que la partie différente.

Le principe est une sorte de portée d'ossia contenant la 2ème 
alternative. La clef du coup est dans la notation polymétrique 
<https://lilypond.org/doc/v2.23/Documentation/notation/displaying-rhythms#polymetric-notation> 
qui permet d'avoir des barres de mesures différentes (voir le \layout). 
Voir aussi les explications de Jean 
<https://lists.gnu.org/archive/html/lilypond-user-fr/2022-07/msg00059.html>. 

Le code :

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
\include "jazzchords.ily"
\include "lilyjazz.ily"

\paper {
   ragged-right = ##f
   indent = 0
}

\layout {
   \enablePolymeter
   \context {
     \ChordGridScore
     \remove Volta_engraver
     \remove Staff_collecting_engraver
     startRepeatBarType = #"[|:"
     endRepeatBarType = #":|]"
     doubleRepeatBarType = #":|][|:"
   }
   \context {
     \ChordGrid
     \consists Volta_engraver
     \consists Staff_collecting_engraver
   }
}

\new ChordGrid \chordmode {
   \bar "[|:"
   \repeat volta 2 {
    \repeat unfold 3 {  c1:7  }
     <<
       \alternative {
         \volta 1 { c1:7 }
       }
       \new ChordGrid {
         \alternative {
           \volta 2 { c1:7 \bar "||" }
         }
      \stopStaff  }
     >>
   }
   \break
   \repeat unfold 4 {  c1:7  }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      2) Les nuances

Ça c'est facile, il suffit d'un \new Dynamics. Pour obtenir un 
espacement régulier entre les lignes même en l'absence de nuances 
j'utilise  system-system-spacing = #'((basic-distance . 20)) dans le 
bloc \paper

Le code :

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
\include "lilyjazz.ily" %facultatif

\paper {
   indent = 0
   ragged-right = ##f
   system-system-spacing = #'((basic-distance . 20))
}

\new ChordGridScore
<<
   \new ChordGrid
   \chordmode {
     \repeat unfold 3 { \repeat unfold 4 { c1:7 } \break } \bar ".."
   }
   \new Dynamics { s2 s2 \p \< s1 s1 \f \> s2 s2 \p }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      3) Les indications rythmiques

Je vous en avais déjà donné une pré-version. Les indications sont dans 
une RhythmicStaff. Notez également l'accord entre parenthèse et le 
\repeat % dont le traitement était plus compliqué dans les versions 
antérieures.

Le code :

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
\include "jazzchords.ily"
\include "lilyjazz.ily"

\paper {
   indent = 0
   ragged-right = ##f
}

\layout {
   \enablePolymeter
   \context {
     \ChordGridScore
     \remove Volta_engraver
     \remove Staff_collecting_engraver
     startRepeatBarType = #"[|:"
     endRepeatBarType = #":|]"
     doubleRepeatBarType = #":|][|:"
     \override Parentheses.font-size = #2
   }
   \context {
     \ChordGrid
     \consists Volta_engraver
     \consists Staff_collecting_engraver
   }
}

accords = \chordmode {
   \bar "[|:"
   \repeat volta 2 {
     g2:7+ bes4:m7 ees:7
     \repeat percent 2 { a2:m7 \parenthesize b2:7.11+ }
     e4:m7 e4:m7/d a4:7/cis c4:m7
} }

\new ChordGridScore
<<
   \new RhythmicStaff \with {
     \improvisationOn
     \override StaffSymbol.line-count = 0
     \remove Time_signature_engraver
     \remove Bar_engraver
   }
   \magnifyMusic 0.66 { c2 4 8 8~ 2 4. 8~ 2 4. 8~ 4 4 4. 8 }
   \new ChordGrid \accords
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      4) Les articulations

Il y a quelques articulations qu'il serait intéressant d'utiliser dans 
une grille harmonique. Essentiellement les accents, les marcati et les 
points d'orgue. C'est possible en ajoutant \consists Script_engraver à 
ChordGrid. Par contre les articulations se placent où elle veulent et il 
faut les repositionner à grand coups de \override Script.extra-offset. 
C'est franchement bidouille ! Si c'est possible il faudrait qu'elles 
soient automatiquement positionnées au dessus de l'accord.
Notez qu'il faut un \override Script.direction = #'1 sinon Lily, ne 
disposant pas de hauteur de note pour se repérer, se plaint  de ne pas 
savoir dans quel sens les tourner.

Le code :

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
\include "lilyjazz.ily"
\include "jazzchords.ily"

\paper {
   indent = 0
   ragged-right = ##f
}

\markup \fill-line { \null "Sans \override Script.extra-offset" \null }
\new ChordGridScore {
   \new ChordGrid \with { \consists Script_engraver }
   \chordmode {
     \override Script.direction = #'1
     \repeat unfold 3 { b1:7+ \accent }
     a4:7+ \marcato bes2.:7+ \fermata \bar ".." }
}

\markup \fill-line { \null "Avec \override Script.extra-offset" \null }
\new ChordGridScore {
   \new ChordGrid \with { \consists Script_engraver }
   \chordmode {
     \override Script.direction = #'1
     \repeat unfold 3 { \once \override Script.extra-offset = #'(11.5 . 
-5) b1:7+ \accent }
     \once \override Script.extra-offset = #'(0.5 . 1.5)  a4:7+ \marcato
     \once \override Script.extra-offset = #'(8 . -5) bes2.:7+ \fermata 
\bar ".." }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      5) ChordGrid et PolyMarks

Même si la version 2.23 introduit d'intéressantes évolutions en matière 
de gestion des reprises (D.C. D.S. Coda....) j'aurai toujours besoin de 
textes rattachés aux systèmes quand je veux et où je veux. Et PolyMarks 
fait parfaitement le boulot.

Pour cela il faut

  * passer poly-mark-engraver à convert.ly
  * le corriger manuellement en utilisant les explications de Jean
    <https://lists.gnu.org/archive/html/lilypond-user-fr/2022-07/msg00051.html>.
    Lire aussi ses commentaires, c'est intéressant.
  * ajouter  \consists #poly-mark-engraver à ChordGridScore

J'ai mis ci-dessous une version corrigée par mes soins

Le code :

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
\include "lilyjazz.ily" %facultatif
\include "poly-mark-engraver223.ly"

\paper {
   indent = 0
   ragged-right = ##f
   system-system-spacing = #'((basic-distance . 20))
}

\layout {
   \context {
     \ChordGridScore
     \remove "Mark_engraver"
     \remove "Mark_tracking_translator"
     \consists #poly-mark-engraver
     \consists "Tweak_engraver"
     rehearsalMarkFormatter = #format-mark-box-alphabet }
}

\new ChordGridScore {
   \new ChordGrid
   \chordmode {
     \polyMark \default
     \repeat unfold 4 { c1:7 } \break
     \polyMark #'RightEnd "Right End"
     \polyMark #'RightEndDown "Right End Down"
     \polyMark \default
     \repeat unfold 4 { c1:7 } \bar ".."
   }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

      6) PolyMarks mis à jour

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\version "2.23.10"
%{
   build an alternate \mark command and Mark_engraver
   additional options to the new variant of \mark:
     \polyMark symb text
     \polyMark #'(symb opt ...) text
       text: as is in \mark, the text or \default
       symb: optional a 'key symbol'
       opt: optional pairs for options, generally GROB overrides
     - parser does not allow \mark \default #'A ..., because
       \default = #'() = argument list ends parsing, and an optional
       argument before the label does not work well and easy, too.
   Enhanced Mark_engraver functionality:
     only accept the first Rehearsal Mark
       per key symbol
       within one main time period
     anchor new Rehearsal Mark GROBs at the first GraceTime seen in the
      (hopefully Score) context, even if the event occurs later in the same
      main time period.
      This functionality may be turned off by setting the new context 
property
      propagateIntoPast = ##f
   Special 'key symbols' have special GROB overrides build in, e.g.:
     #'RightUp = right aligned text, begin-of-line-invisible, direction 
= #UP
     #'CenterDown = center aligned text, direction = #DOWN
   Benefit:
     + allows multiple Rehearsal Marks at one Moment, even with different
       settings (grob properties)
     + but filters out the duplicates (from different parts / staves),
       identified by the key
     + eliminates the 'grace echo'
     + places Rehersal Marks at the bar line, even if they are defined 
'late',
       i.e. in a control voice without grace skips.
   Caveats:
     - If one mark command sets the current mark number while another 
polyMark
       command displays the current mark number, the sequence they are 
evaluated
       defines the result.
     - No input data checks, e.g. no warning, if different values to set are
       defined.
     - creates an extra RehearsalMark to obtain a BreakAlignment, even 
if the
       BreakAlignment is (finally) never used.
     - Expect problems with the grace synchronisation when put into Staff
       context. Perhaps the BreakAlignment grob should be caught with an 
extra
       engraver in Score context, while this polymark engraver will then 
work
       in Staff context.

   A more reliable method to create 'early grobs' would be welcome, 
maybe called
   ly:engraver-make-early-grob and ly:engraver-announce-early-end-grob.

GLOSSARY:
main time period = all translation timesteps with the same main time, 
i.e. all
                    timesteps of grace notes offset until the final timestep
                    without grace note offset, incl.
early grob       = a grob created by an engraver at a timestep later 
than the
                    first grace note timestep (of the same main time) in 
the score,
                    but the grob has to be adjusted to the column of tis 
first
                    grace note timestep.

%}

#(define (translator-property-description symbol type? description)
   (if (not (and
             (symbol? symbol)
             (procedure? type?)
             (string? description)))
       (throw 'init-format-error))

   (if (not (equal? #f (object-property symbol 'translation-doc)))
       (ly:error (_ "symbol ~S redefined" symbol)))

   (set-object-property! symbol 'translation-type? type?)
   (set-object-property! symbol 'translation-doc description)
   (set! all-translation-properties (cons symbol 
all-translation-properties))
   symbol)

#(define custom-translation-properties
`(
   (propagateIntoPast
    ,boolean?
    "Engravers may anchor the GROBs they create at a PaperColumn of
an already gone timestep, usually the first grace note timestep of
the same main moment.")

   (inhibitDummyRehearsalMark
    ,boolean?
    "If true, do not create a zero size RehearsalMark in advance, just to
obtain a BreakAlignment which may be needed later in the process.
If you only need to purge 'grace echos' of RehearsalMarks but do not need
to 'shift' any RehearsalMark before the grace notes, you may want to set
this option to reduce memory consumption.")
; I could not detect a significant memory saving!

   (RehearsalMarkVisibleAtEndOfContext
    ,boolean?
    "If true, then set the visibility of those RehearsalMarks, which are
placed at the end of the context, to end-of-line-visible.")

   (RehearsalMarkPriorityRenumbering
    ,boolean?
   "If true, then renumber the priority of the RehearsalMarks created
at one timestep.")

   (polyMarkOptions
    ,list?
   "Default options for user defined keys of RehearsalMarks")
   ))

#(for-each
   (lambda (x) (apply translator-property-description x))
   custom-translation-properties)

#(define (poly-mark-engraver ctx)
    (define default-option-lists
     `((RightUp       (direction        . ,UP)
                      (self-alignment-X . 1)
                      (break-visibility . ,begin-of-line-invisible))
       (RightDown     (direction        . ,DOWN)
                      (self-alignment-X . 1)
                      (break-visibility . ,begin-of-line-invisible))
       (Right         (self-alignment-X . 1)
                      (break-visibility . ,begin-of-line-invisible))
       (RightEnd      (direction        . ,UP)
                      (self-alignment-X . 1)
                      (break-visibility . ,begin-of-line-invisible))
       (RightEndDown  (direction        . ,DOWN)
                      (self-alignment-X . 1)
                      (break-visibility . ,begin-of-line-invisible))
       (CenterEndDown (direction        . ,DOWN)
                      (self-alignment-X . 0)
                      (break-visibility . ,begin-of-line-invisible))
       (CenterEnd     (self-alignment-X . 0)
                      (break-visibility . ,begin-of-line-invisible))
       (LeftUp        (direction        . ,UP)
                      (self-alignment-X . -1)
                      (break-visibility . ,end-of-line-invisible))
       (LeftDown      (direction        . ,DOWN)
                      (self-alignment-X . -1)
                      (break-visibility . ,end-of-line-invisible))
       (Left          (self-alignment-X . -1)
                      (break-visibility . ,end-of-line-invisible))
       (CenterUp      (direction        . ,UP)
                      (self-alignment-X . 0))
       (CenterDown    (direction        . ,DOWN)
                      (self-alignment-X . 0))
       (Center        (self-alignment-X . 0))
       (CenterEndBoth (direction        . both)
                      (self-alignment-X . 0)
                      (break-visibility . ,begin-of-line-invisible))
       (CenterEndBothRotated
                      (direction        . both-rotated)
                      (self-alignment-X . 0)
                      (break-visibility . ,begin-of-line-invisible))
       (CenterEndBothMirrored
                      (direction        . both-mirrored)
                      (self-alignment-X . 0)
                      (break-visibility . ,begin-of-line-invisible))))

    (let ((texts '())             ;; the created Rehearsal Mark GROBs,
                                  ;; collected during a time step
          (late-texts '())        ;; the Rehearsal Mark GROBs created 
later than at the
                                  ;; first timestep of this main time 
period - we need to
                                  ;; modify their X anchor
          (final-texts '())       ;; the created GROBs after they're 
completed at
                                  ;; 'stop-translation-timestep', used 
to make them visible
                                  ;; at the end of line, if the context 
terminates there.
          (helper-text '())       ;; a null-markup Rehearsal Mark GROB. 
Only created to obtain
                                  ;; the related BreakAlignment GROB.
          (events '())            ;; list of MarkEvents, collected 
during a time step
          (last-main-mom '())     ;; the value of the last main time 
moment seen
          (late #f)               ;; true if this time step is NOT the 
first one of the
                                  ;; current main time period
          (keys '())              ;; list of 'entry keys' of them a grob 
is already created
                                  ;; during the current main time period
          (first-grace-now #f)    ;; is this the first grace time step 
in the current main
                                  ;; time period?
          (b-a-g '())             ;; the 'early' breakAlignment GROB, in 
case we need it
                                  ;; to modify the RehearsalMarks X anchor
          (priority-index 0)      ;; used to renumber the outside staff 
priority
          (label-incremented #f)) ;; is the ctx prop 'rehearsalMark 
allready incremented
                                  ;; during the current main time period?

      `((start-translation-timestep
         . ,(lambda (trans)
              (let* ((current-mom (ly:context-current-moment ctx))
                     (main-mom (ly:moment-main current-mom))
                     (grace-mom (ly:moment-grace current-mom)))
               (if (or (null? last-main-mom) (> main-mom last-main-mom))
                 (begin
                   (set! last-main-mom main-mom)
                   (set! keys '())
                   (set! priority-index 0)
                   (set! label-incremented #f)
                   (set! late #f)
                   (set! first-grace-now (not (or late (= 0 grace-mom)))))
                 (begin
                   (set! late #t)
                   (set! first-grace-now #f))))
               (set! final-texts '())))

        (listeners
         (mark-event
          . ,(lambda (trans ev)
               (set! events (cons ev events)))))

        (acknowledgers
         (break-alignment-interface
          . ,(lambda (trans grob source)
               (if first-grace-now (set! b-a-g grob))
               (for-each (lambda (mark)
                   (set! (ly:grob-parent mark X) grob))
                 texts))))

        (process-music
         . ,(lambda (trans)
              (for-each
                (lambda (ev)
                  (let* ((key (ly:event-property ev 'key #t))
                         (opts (ly:event-property ev 'additional-options 
'())))
                    (if (not (memq key keys))
                      (let* ((mark-grob
                               (ly:engraver-make-grob trans 
'RehearsalMark ev))
                             (label (ly:event-property ev 'label))
                             (formatter (ly:context-property ctx 
'rehearsalMarkFormatter)))

                        (set! keys (cons key keys))

                        (if (and (procedure? formatter)
                                 (not (markup? label)))
                          (begin
                            (if (not (number? label))
                              (if label-incremented
                                (set! label
                                  (1- (ly:context-property ctx 
'rehearsalMark)))
                                (set! label
                                  (ly:context-property ctx 
'rehearsalMark))))

                            (if (and (integer? label)
                                     (exact? label)
                                     (not label-incremented))
                              (begin
                                (set! (ly:context-property ctx 
'rehearsalMark)
                                      (1+ label))
                                (set! label-incremented #t)))

                            (if (number? label)
                              (set! label (apply formatter (list label 
ctx)))
                              (ly:warning "rehearsalMark must have 
integer value"))))

                        (if (markup? label)
                          (begin
                            (set! (ly:grob-property mark-grob 'text) label)
                            (let ((dir (ly:event-property ev 'direction)))
                              (and (ly:dir? dir)
                                 (set! (ly:grob-property mark-grob 
'direction)
                                     dir))))
                                (ly:warning "mark label must be a markup 
object"))

                        (let ((both-dirs #f)
                              (predef-opts (or
                                (ly:assoc-get key (ly:context-property 
ctx 'polyMarkOptions) #f)
                                (ly:assoc-get key default-option-lists 
#f))))
                         (if (pair? predef-opts) (for-each (lambda (opt)
                            (let ((opt-name (car opt))
                                  (opt-val (cdr opt)))
                             (if (and (eq? opt-name 'direction)
                                      (or (eq? opt-val 'both)
                                          (eq? opt-val 'both-rotated)
                                          (eq? opt-val 'both-mirrored))) 
(begin
                               (ly:grob-set-property! mark-grob opt-name UP)
                               (set! both-dirs opt-val))
                              (ly:grob-set-property! mark-grob opt-name 
opt-val))))
                           predef-opts))
                         (if both-dirs
                          (let ((opposite-mark-grob
                                 (ly:engraver-make-grob trans 
'RehearsalMark ev)))
                           (ly:grob-set-property! opposite-mark-grob 
'direction DOWN)
                           (let ((orig-text (ly:grob-property mark-grob 
'text)))
                            ;; (if (markup? orig-text)
                            ;;  (set! orig-text (copy-tree orig-text)))
                            (if (eq? both-dirs 'both-rotated)
                             (set! orig-text (make-rotate-markup 180 
orig-text)))
                            (if (eq? both-dirs 'both-mirrored)
                             (set! orig-text (make-scale-markup '(1 . 
-1) orig-text)))
                            (ly:grob-set-property! opposite-mark-grob 
'text orig-text))
                           (set! texts (cons opposite-mark-grob texts))
                           (if (pair? predef-opts) (for-each (lambda (opt)
                              (let ((opt-name (car opt))
                                    (opt-val (cdr opt)))
                               (if (not (eq? opt-name 'direction))
                                (ly:grob-set-property! 
opposite-mark-grob opt-name opt-val))))
                             predef-opts))
                           (if (and late
                                    (ly:context-property ctx 
'propagateIntoPast #t))
                            (set! late-texts (cons opposite-mark-grob 
late-texts))))))

                        ; if 'direction == 'both*, then apply these 
`options on the fly`
                        ; only to the UP instance
                        (if (pair? opts)
                          (for-each (lambda (opt)
                              (if (pair? opt)
                                (let ((opt-name (car opt))
                                      (opt-val (cdr opt)))
                                  (ly:grob-set-property! mark-grob 
opt-name opt-val))))
                            opts))

                        (set! texts (cons mark-grob texts))
                        (if (and late
                                 (ly:context-property ctx 
'propagateIntoPast #t))
                          (set! late-texts (cons mark-grob late-texts)))))))
                (reverse events))
              (if (and first-grace-now
                   (null? events)
                   (not (ly:context-property ctx 
'inhibitDummyRehearsalMark #f)))
                  ;; create a dummy mark to get a BreakAlignment GROB ;-(
               (let* ((mark-grob (ly:engraver-make-grob trans 
'RehearsalMark '()))
                      (null-label (make-null-markup)))
                (ly:grob-set-property! mark-grob 
'outside-staff-horizontal-padding 0)
                (ly:grob-set-property! mark-grob 'padding 0)
                (ly:grob-set-property! mark-grob 'text null-label)
                (set! texts (cons mark-grob texts))
                (set! helper-text mark-grob)))))

        (stop-translation-timestep
         . ,(lambda (trans)
              (if (pair? texts)
                  (let ((staves (ly:context-property ctx 'stavesFound)))
                    (for-each (lambda (grob)
                      (let ((my-priority (ly:grob-property grob 
'outside-staff-priority 1500)))
                       ;;;(if (boolean? my-priority) (set! my-priority 
1500))
                       ;!! I'm not sure. May I realy skip this interface 
call for
                       ;!! RehearsalMarks I have to anchor at a past 
grace timing?
                       (if (not (and late (ly:context-property ctx 
'propagateIntoPast #t)))
                        (for-each (lambda (stave)
                          (ly:pointer-group-interface::add-grob
                           grob 'side-support-elements stave))
                         staves))
                       ;! some RehearsalMarks had the value #f assigned 
to 'outside-staff-priority
                       ;! perhaps due to 'extra-spacing-height = 
'(-inf.0 . +inf.0)
                       (if (and (ly:context-property ctx 
'RehearsalMarkPriorityRenumbering #t)
                                (number? my-priority)) (begin
                         (set! (ly:grob-property grob 
'outside-staff-priority) (+ my-priority priority-index))
                         (set! priority-index (1+ priority-index))))
                       (set! final-texts (cons grob final-texts))))
                   (reverse texts))
                 (if (pair? late-texts)
                  (for-each (lambda (grob)
                    (if (not (null? b-a-g))
                     (set! (ly:grob-parent grob X) b-a-g))) late-texts))
                  (set! late-texts '())
                 (set! texts '())))
              (set! events '())
              (if (= 0 (ly:moment-grace (ly:context-current-moment ctx)))
               (begin
                (if (not (null? helper-text)) (begin
                  (ly:grob-suicide! helper-text)
                  (set! helper-text '())))
                (set! b-a-g '())))))

         (finalize
          . ,(lambda (trans)
               (and (pair? final-texts)
                    (ly:context-property ctx 
'RehearsalMarkVisibleAtEndOfContext #f)
                    (for-each (lambda (grob)
                                (set! (ly:grob-property grob 
'break-visibility)
                                      end-of-line-visible))
                              final-texts)))))))

% copy of 'mark' from music-functions.ly, then extended:
polyMark =
#(define-music-function
    (key label)
    (((lambda (x) (or (symbol? x)
                   (and (pair? x) (symbol? (car x))))) #f)
     (scheme? '()))
   "Make the music for the \\polyMark command."
   (let* ((set (and (integer? label)
                    (context-spec-music (make-property-set 
'rehearsalMark label)
                                        'Score)))
          (ev (make-music 'RehearsalMarkEvent
                          'origin (*location*)))
          (entry-key (if (symbol? key) key
                      (if (and (list? key) (symbol? (car key))) (car key)
                       #f))))
     (if (symbol? entry-key)
       (ly:music-set-property! ev 'key entry-key))
     (if (pair? key)
       (ly:music-set-property! ev 'additional-options (cdr key)))

     (if set
         (make-sequential-music (list set ev))
         (begin
           (set! (ly:music-property ev 'label) label)
           ev))))

%%% comment the following lines, if you do not want to turn it on by default
%%% and define it in the score block instead.
\layout {
  \context {
    \Score
    \remove "Mark_engraver"
    \remove "Mark_tracking_translator"
    \consists #poly-mark-engraver
    \consists "Tweak_engraver"
  }
}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Et Voilou, bonne semaine.

-- 
Vincent Gay
Envoyé depuis mon saxo-phone :)
https://myrealbook.vintherine.org/  -http://photos.vintherine.org/