Création de glyphes

Est-ce une vieillerie à éviter aussi ça ?
\markup #(make-column-markup var)

Non. C'est juste moins pratique ici de mon point de vue (mais ça peut être assez utile ailleurs).

Merci Jean !

Bonjour à tous,
Merci pour vos contributions ; j'ai beaucoup appris sur Scheme grâce à vous mais aussi grâce à la documentation de Jean portant sur un guide d'extension de Lilypond, qui est encore en cours de construction mais qui est déjà très complet.
Le résultat que j'obtiens, ne me convient pas trop.


Vous verrez sur l'image que les deux marques codées (battement et tremblement que j'ai mis en rouge), recouvrent partiellement une barre de mesure et le point d'une note pointée, respectivement.
Idéalement, le comportement que je recherche est identique à celui des doigtées : par défaut la marque se positionnerait au dessus de la note (ou en dessous, dans le cas d'un contexte \voiceTwo) et lorsque le positionnement est forcé à gauche ou à droite, la marque est placée à coté de la tête de note et prend l'espace nécessaire pour qu'il n'y ait pas de superposition avec un autre élément de la musique.
Je me demande si define-markup-command est vraiment adapté...
Pour info, voici les morceaux de codes du tremblement et du battement:

#(define-markup-command (draw-tremblement layout props)()
   #:properties (
                  (thickness 0.2)
                  (color color_for_marks)
                  )
   "...Documentation of this beautiful function..."  
   (let ((thickness (* thickness 1.1)) )
     (interpret-markup layout props                    
                       #{
                         \markup
                         \with-dimensions-from \null
                         \with-color #color                         
                         \path #thickness
                         #(list                         
                           (list 'moveto 1.5 -0.1 )
                           (list 'rcurveto 0.2 0.2 0.6 -0.5 -0 -0.9 ) 
                           )
                       #}
                       )))
#(define-markup-command (draw-battement layout props points)(number-pair?)
   #:properties (
                  (thickness 0.2)
                  (color color_for_marks)
                  )
   "...Documentation of this beautiful function..."  
   (let (( x0 (+ 0.5 (car points)))
         ( y0 (+ 0.5 (cdr points))))
     (interpret-markup layout props
                       #{
                         \markup
                         \with-dimensions-from \null
                         \with-color #color
                         \path #thickness
                         #(list
                           (list 'moveto x0 y0)
                           (list 'rcurveto 0 0.4 0.7 0.85 1 1)
                           (list 'rmoveto -1 0)
                           (list 'rcurveto 0 -0.4 0.7 -0.85 1 -1))
                       #}
                       )))

Je vais continuer à creuser mais n'hésitez pas à m'alimenter de vos idées/réflexions/liens.
Merci et très bonne journée !
Rémy

Le problème n'est pas dans define-markup-command en soi. C'est plutôt que le \with-dimensions-from \null dit très précisément à LilyPond "construis ce markup comme un dessin qui ne prend aucune place, qui n'a aucun contour, qui est comme un dessin vide pour tout ce qui est du positionnement". Donc, LilyPond obéit et n'évite aucune collision avec ce dessin. Ceci peut être utile, quand c'est trop compliqué de faire éviter les collisions de manière automatique et plus facile de placer manuellement (un peu comme extra-offset). Après, si tu veux que le dessin se place comme un doigté, l'une des possibilités (faute de mieux) est de mettre un doigté (peu importe lequel) et de changer son dessin, quelque chose comme < c' \tweak text \markup \battement -1 >. À partir de là, tu peux utiliser les méthodes normales pour positionner les doigtés (chercher fingeringOrientations dans la doc).

Bonne idée Jean. :wink:
Par contre, ça peut entrer en conflit de positionnement avec d'autres doigtés et demande alors quelques ajustements.
Petit essai avec des event fonctions (évidemment le pb des conflits de positions reste le même) :

\version "2.25.14"

batt = #(define-event-function (points)(number-pair?)
   (let (( x0 (+ 0.5 (car points)))
         ( y0 (+ 0.5 (cdr points))))
             #{
               \finger
               \markup
               \with-color #red
               \path #0.2
               #(list
                 (list 'moveto x0 y0)
                 (list 'rcurveto 0 0.4 0.7 0.85 1 1)
                 (list 'rmoveto -1 0)
                 (list 'rcurveto 0 -0.4 0.7 -0.85 1 -1))
             #}))

tremb = #(define-event-function ()()
           #{
             \finger
             \markup
             \with-color #red
             \path #0.2
             #(list                        
               (list 'moveto 1.5 -0.1 )
               (list 'rcurveto 0.2 0.2 0.6 -0.5 -0 -0.9 ))
           #})

\fixed c'' {
  \time 2/2
  \voiceOne
  \set fingeringOrientations = #'(left)
  s1 <e-\batt #'(0 . -10)>4 f8.( e16) \grace { <e-1>16( f) } g8.( f16)
  <f-2>8.-\tweak extra-offset #'(2 . -4)-\tremb ( <e> 16)
}

Peut-être un peu HS : je me souviens d'un article de Nicolas Sceaux sur a créations des ornements de Bach. C'était assez bien pensé et complet. Il l'avait publié sur un blog qui a disparu ("Scores Of Beauty" si ma mémoire est bonne). J'ai checké son github en vitesse mais rien trouvé. Peut-être quelqu'un de la liste en a conservé une trace ?

J'en ai conservé (et utilisé plus que de raison…) une partie, celle des pincés gauche et droite:

\version "2.18.2"

%%%
%%% Utilities for defining new grobs, grob properties and music event types
%%% (there should be built-in commands to do that in LilyPond)
%%%
#(define (define-grob-type grob-name grob-entry)
   "Define a new grob and add it to `all-grob-definitions', after
scm/define-grobs.scm fashion.
After grob definitions are added, use:

\\layout {
  \\context {
    \\Global
    \\grobdescriptions #all-grob-descriptions
  }
}

to register them."
   (let* ((meta-entry   (assoc-get 'meta grob-entry))
          (class        (assoc-get 'class meta-entry))
          (ifaces-entry (assoc-get 'interfaces meta-entry)))
     (set-object-property! grob-name 'translation-type? list?)
     (set-object-property! grob-name 'is-grob? #t)
     (set! ifaces-entry (append (case class
                                  ((Item) '(item-interface))
                                  ((Spanner) '(spanner-interface))
                                  ((Paper_column) '((item-interface
                                                     paper-column-interface)))
                                  ((System) '((system-interface
                                               spanner-interface)))
                                  (else '(unknown-interface)))
                                ifaces-entry))
     (set! ifaces-entry (uniq-list (sort ifaces-entry symbol<?)))
     (set! ifaces-entry (cons 'grob-interface ifaces-entry))
     (set! meta-entry (assoc-set! meta-entry 'name grob-name))
     (set! meta-entry (assoc-set! meta-entry 'interfaces
                                  ifaces-entry))
     (set! grob-entry (assoc-set! grob-entry 'meta meta-entry))
     (set! all-grob-descriptions
           (cons (cons grob-name grob-entry)
                 all-grob-descriptions))))

#(define-public (define-grob-property symbol type? description)
   "Define a new grob property.
`symbol': the property name
`type?': the type predicate for this property
`description': the type documentation"
  (set-object-property! symbol 'backend-type? type?)
  (set-object-property! symbol 'backend-doc description)
  symbol)

#(defmacro*-public define-music-type (type-name parents #:rest properties)
     "Add a new music type description to `music-descriptions'
and `music-name-to-property-table'.

`type-name': the music type name (a symbol)
`parents': the parent event classes (a list of symbols)
`properties': a (key . value) property set, which shall contain at least
   description and type properties.
"
   (let ((gproperties (gensym "properties")))
     `(let ((,gproperties (list-copy ',properties)))
        ,@(map (lambda (parent)
                `(define-event-class ',(ly:camel-case->lisp-identifier type-name)
                   ',parent))
               parents)
        (set-object-property! ',type-name
                              'music-description
                              (cdr (assq 'description ,gproperties)))
        (set! ,gproperties (assoc-set! ,gproperties 'name ',type-name))
        (set! ,gproperties (assq-remove! ,gproperties 'description))
        (hashq-set! music-name-to-property-table ',type-name ,gproperties)
        (set! music-descriptions
              (cons (cons ',type-name ,gproperties)
                    music-descriptions)))))

%%%
%%% Grob definition
%%%
#(define (head-ornamentation::print me)
   "Prints a HeadOrnamentation grob, on the left or right side of the
note head, depending on the grob direction."
   (let* ((notes (ly:grob-object me 'elements))
          (y-ref (ly:grob-common-refpoint-of-array me notes Y))
          (x-ref (ly:grob-common-refpoint-of-array me notes X))
          (x-ext (ly:relative-group-extent notes x-ref X))
          (y-ext (ly:relative-group-extent notes y-ref Y))
          (y-coord (interval-center y-ext))
          (text (ly:text-interface::print me))
          (width (/ (interval-length (ly:stencil-extent text X)) 2.0))
          (x-coord (if (= (ly:grob-property me 'direction) LEFT)
                       (- (car x-ext) width)
                       (+ (cdr x-ext) width))))
     (ly:stencil-translate
      text
      (cons
       (- x-coord (ly:grob-relative-coordinate me x-ref X))
       (- y-coord (ly:grob-relative-coordinate me y-ref Y))))))

#(define-grob-type 'HeadOrnamentation
  `((font-size . 0)
    (stencil . ,head-ornamentation::print)
    (meta . ((class . Item)
             (interfaces . (font-interface))))))

\layout {
  \context {
    \Global
    \grobdescriptions #all-grob-descriptions
  }
}

%%%
%%% Engraver
%%%
%% The head-ornamentation engraver, with its note-head acknowledger
%% (which add HeadOrnamentation grobs to note heads)
#(define head-ornamentation-engraver
   (make-engraver
    (acknowledgers
     ((note-head-interface engraver note-grob source)
      ;; helper function to create HeadOrnamentation grobs
      (define (make-ornament-grob text direction)
        (let ((ornament-grob (ly:engraver-make-grob engraver
                                                    'HeadOrnamentation
                                                    note-grob)))
          ;; use the ornament event text as the grob text property
          (set! (ly:grob-property ornament-grob 'text) text)
          ;; set the grob direction (either LEFT or RIGHT)
          (set! (ly:grob-property ornament-grob 'direction) direction)
          (ly:pointer-group-interface::add-grob ornament-grob
                                                'elements
                                                note-grob)
          ;; the ornamentation is vertically aligned with the note head
          (set! (ly:grob-parent ornament-grob Y) note-grob)
          ;; compute its font size
          (set! (ly:grob-property ornament-grob 'font-size)
                (+ (ly:grob-property ornament-grob 'font-size 0.0)
                   (ly:grob-property note-grob 'font-size 0.0)))
          ornament-grob))
      ;; When the note-head event attached to the note-head grob has
      ;; ornamentation events among its articulations, then create a
      ;; HeadOrnamentation grob
      (for-each
       (lambda (articulation)
         (if (memq 'head-ornamentation-event
                   (ly:event-property articulation 'class))
             ;; this articulation is an ornamentation => make the grob
             ;; (either on LEFT or RIGHT direction)
             (begin
               (if (markup? (ly:event-property articulation 'left-text))
                   (make-ornament-grob (ly:event-property articulation 'left-text)
                                       LEFT))
               (if (markup? (ly:event-property articulation 'right-text))
                   (make-ornament-grob (ly:event-property articulation 'right-text)
                                       RIGHT)))))
         (ly:event-property (ly:grob-property note-grob 'cause) 'articulations))))))

\layout {
  \context {
    \Voice
    \consists #head-ornamentation-engraver
  }
}

%%%
%%% Event type definition
%%%
#(define-music-type HeadOrnamentationEvent (music-event)
   (description . "Print an ornamentation at a note head side")
   (types . (general-music post-event event head-ornamentation-event)))

pincepointeLR =
#(make-music 'HeadOrnamentationEvent
             'left-text #{ \markup \concat {
    \fontsize #1 \rotate #190 
    \musicglyph #"scripts.rcomma"
    \hspace #1 } #}
             'right-text #{
  \markup \concat{ \rotate #10 
  \fontsize #1 \musicglyph #"scripts.rcomma" \hspace #1.5 } #})

pinceLR =
#(make-music 'HeadOrnamentationEvent
             'left-text #{ \markup \override #'(font-name . "1610_Cancellaresca_lim") \fontsize #10 \concat {
    \lower #3.2
    \rotate #190
    "'" \hspace #0.3 } #}
             'right-text #{ \markup \override #'(font-name . "1610_Cancellaresca_lim") \fontsize #10 \concat {
  
  \lower #3.3
  "'" \hspace #-3 } #})

pinceR =
#(make-music 'HeadOrnamentationEvent
             'right-text #{ \markup \override #'(font-name . "1610_Cancellaresca_lim") \fontsize #10
                            { \lower #3.2 \rotate #10
                              "'" \hspace #-3 } #})

pincepointeR =
#(make-music 'HeadOrnamentationEvent
             'right-text #{ \markup \override #'(font-name . "1610_Cancellaresca_lim") \fontsize #10
                            { %\null 
                              \lower #-0
                              "," \hspace #1.5 } #})

pinceL =
#(make-music 'HeadOrnamentationEvent
             'left-text #{ \markup \override #'(font-name . "Arial Black") \fontsize #-2
                            { \null \lower #0.5 "(" \hspace #-1 } #})

cadenceL =
#(make-music 'HeadOrnamentationEvent
             'left-text #{ \markup\concat {
    \fontsize #1 \musicglyph #"scripts.prall"
    \hspace #0.5 } #})

Cordialement.

Bernard

Bonjour,

L'article de Nicolas Sceaux en 2 parties via la Wayback Machine:

Cordialement,
Xavier

Merci à vous deux :wink:

Les articles de N. Sceaux sont très très complets et complexes.
J'espère pouvoir tout comprendre, même si je ne me sens pas vraiment au niveau requis...
En tous cas merci de m'avoir aider et bon WE !
Rémy