Hello,

our problem here is that such things like the positioning of beams are not 
known for quite some time. But we could use something like after-line-breaking 
to adjust the results. Somewhat like here.

Valentin

Am Sonntag, 20. Februar 2022, 21:17:31 CET schrieb Luca Fascione:
> So... would anybody be able to lend a hand here please?
> 
> Many thanks
> Luca
> 
> On Sat, Feb 12, 2022 at 7:49 PM Luca Fascione <l.fasci...@gmail.com> wrote:
> > Hello,
> > sorry for the double-post, I'm unsure whether this should go to -user or
> > -devel.
> > 
> > I'm looking for some guidance to set up fingering on classical guitar
> > sheets.
> > 
> > I am attaching a simple piece of music, with two engraving sets (measures
> > 1-5 and 6-10), one "as-is" from lilypond, the other using some trickery
> > involving one-note chords, purely to show a sample of what the result I'm
> > after (and it's an approximation), vs what I get at the moment.
> > 
> > Measures 1-5 in the source look like what I am intending to type, but it
> > has a number of engraving defects I don't understand (you can see the
> > beams
> > don't  avoid the fingerings, nor they are located correctly wrt the
> > accidentals, the second beat of measure 5 illustrates this well. I'm not
> > super in love with measure 10 either, but if I understand the docs
> > correctly, the issue there is that the 'offset' correction is applied
> > post-layout, and so naturally it won't back-affect the placement of the
> > beams.
> > 
> > I have made several other experiments, I'm just not wanting to waste
> > people's time. But setting Fingering.side-axis = #X seems somewhat
> > promising, but it seems unable to find any usable Y data about the
> > parents,
> > and smashes all numbers on the B line, as well as not dealing with
> > accidentals.
> > 
> > I have an engraving project in front of me, for which I'm more than happy
> > to put in the time to contribute the code to a proper solution myself, and
> > I really don't want to make poor use of time from folks busy with other
> > work, but I feel I'll need some level of guidance as to what to do. For
> > context I can do C++ and I can manage guile ok (I'm a software engineer
> > for
> > work, I'm mostly working in the field of computer graphics).
> > 
> > I was looking into this problem several years ago also, and Han-Wen
> > Nienhuys at the time suggested I should use a positioning callback
> > attached
> > to the Fingering grobs, but I couldn't find a way to do such a thing (in
> > particular I can't find what property to use for this). So far I've traced
> > the Fingering system to be an instance of the Articulations/Scripts
> > system,
> > but that's as far as I got.
> > 
> > It seems to me what's needed would be to decide where the heads go, then
> > the accidentals, at this stage deal with the fingering and only then there
> > would be enough bboxes to reason about the beaming (this is the skyline
> > concept I think). In reasoning about how Articulations are engraved, it's
> > possible the order of events for fingering would be different from the
> > order of events in other articulations (which I think are laid out after
> > beams are in place, if I am not mistaken), warranting a bigger change, but
> > I have no idea where that is located/managed.
> > 
> > Many thanks for your time,
> > Luca

\version "2.22.1"

% file to test various requirements to engrave fingering for guitar
% the main goal is to obtain fingering places approx NorthEast of the note heads, right at
% the head.
% In all other respects this is a minimal working example

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Functions and global definitions

% string numbers orientation UP
stringUp = \set stringNumberOrientations = #'(up) 
% string numbers orientation DOWN
stringDown = \set stringNumberOrientations = #'(down)


Barre = #(define-music-function (barre location str music) (string? ly:music?)
   (let ((elts (extract-named-music music '(NoteEvent EventChord RestEvent SkipEvent))))
     (if (pair? elts)
         (let ((first-element (first elts))
               (last-element (last elts)))
           (set! (ly:music-property first-element 'articulations)
                 (cons (make-music 'TextSpanEvent 'span-direction -1)
                       (ly:music-property first-element 'articulations)))
           (set! (ly:music-property last-element 'articulations)
                 (cons (make-music 'TextSpanEvent 'span-direction 1)
                       (ly:music-property last-element 'articulations))))))
   #{
       \once \override TextSpanner.font-size = #1
       \once \override TextSpanner.staff-padding = #3
       \once \override TextSpanner.style = #'line
       \once \override TextSpanner.to-barline = ##f
       \once \override TextSpanner.direction = #UP
       \once \override TextSpanner.bound-details =
            #`((left
                (text . ,#{ \markup { #str } #})
                (Y . 0)
                (padding . -0.5)
                (stencil-align-dir-y . .0)
                (attach-dir . -1))
               (right
                (text . ,#{ \markup { \draw-line #'( .25 . -.5) } #})
                (Y . 0)
                (padding . 0.5)
                (attach-dir . 1)))
       \once \override TextSpanner.bound-details.left-broken.attach-dir = #-1
       \once \override TextSpanner.bound-details.left-broken.text = ##f 
       \once \override TextSpanner.bound-details.right-broken.text = ##f
       $music
   #})

Barref = #(define-music-function (barre location num den str music) (string? string? string? ly:music?)
   (let ((elts (extract-named-music music '(NoteEvent EventChord RestEvent SkipEvent))))
     (if (pair? elts)
         (let ((first-element (first elts))
               (last-element (last elts)))
           (set! (ly:music-property first-element 'articulations)
                 (cons (make-music 'TextSpanEvent 'span-direction -1)
                       (ly:music-property first-element 'articulations)))
           (set! (ly:music-property last-element 'articulations)
                 (cons (make-music 'TextSpanEvent 'span-direction 1)
                       (ly:music-property last-element 'articulations))))))
   #{
       \once \override TextSpanner.font-size = #1
       \once \override TextSpanner.staff-padding = #3
       \once \override TextSpanner.style = #'line
       \once \override TextSpanner.to-barline = ##f
       \once \override TextSpanner.direction = #UP
       \once \override TextSpanner.bound-details =
            #`((left
                (text . ,#{ \markup { \tiny \fraction #num #den  #str } #})
                (Y . 0)
                (padding . -0.5)
                (stencil-align-dir-y . .0)
                (attach-dir . -1))
               (right
                (text . ,#{ \markup { \draw-line #'( .25 . -.5) } #})
                (Y . 0)
                (padding . 0.5)
                (attach-dir . 1)))
       \once \override TextSpanner.bound-details.left-broken.attach-dir = #-1
       \once \override TextSpanner.bound-details.left-broken.text = ##f 
       \once \override TextSpanner.bound-details.right-broken.text = ##f
       $music
   #})

stringNumberSpanner =
  #(define-music-function (StringNumber) (string?)
    #{
      \override TextSpanner.style = #'solid
      \override TextSpanner.font-name = #'"Minion Pro Bold"
      \override TextSpanner.font-size = #-2
      \override TextSpanner.bound-details.left.stencil-align-dir-y = #CENTER
      \override TextSpanner.bound-details.left.text =
        \markup { \circle \number $StringNumber }
    #})


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Configuration for the fingering

#(define (Fingering_stuff_engraver context)
   (let ((head #f) (stem #f) (fingering #f))
     (make-engraver
      (acknowledgers
       ((finger-interface engraver grob source-engraver)
        (set! fingering grob))
       ((note-head-interface engraver grob source-engraver)
        (set! head grob))
       ((stem-interface engraver grob source-engraver)
        (set! stem grob)))
      ((process-music engraver)
       (if (and fingering stem head)
           (ly:grob-set-property! fingering 'details
                                  `((head . ,head) (stem . ,stem) . ,(ly:grob-property fingering 'details))))
       (set! head #f)
       (set! stem #f)
       (set! fingering #f)))))

\layout {
  \context {
    \Voice
    \consists #Fingering_stuff_engraver
    % setup fingering on the left of the noteheads
    %\override Voice.fingeringOrientations = #'(left)
    % now move it up one stave-space and right a little
    \override Fingering.extra-offset = #'(0 . 0)
    \override Fingering.X-offset = #0.5
    \override Fingering.Y-offset = 0
    \override Fingering.after-line-breaking =
    #(lambda (grob)
       (let* ((det (ly:grob-property grob 'details))
              (stem (assoc-get 'stem det))
              (stem-height (interval-length (ly:grob-property stem 'Y-extent)))
              (bm (if stem (ly:grob-property stem 'beaming) '()))
              (bm-left (if (null? bm) #f (car bm)))
              (total-beams (if bm-left (1+ (apply max bm-left)) 0))
              (CONST_BEAM_SPACE 1)
              (effective-stem-length (- stem-height (* total-beams CONST_BEAM_SPACE)))
              (prev-offset (ly:grob-property grob 'Y-offset))
              (grob-height (interval-length (ly:grob-property grob 'Y-extent)))
              (head (assoc-get 'head det))
              (head-offset (if head (ly:grob-property head 'Y-offset)))
              (offset-diff (- prev-offset head-offset))
              (nescessary-height (+ offset-diff grob-height 0.7))
              (shift (- effective-stem-length nescessary-height))
              (offset-diff-after-shift (- (+ prev-offset shift) head-offset))
              (x-shift (if (< offset-diff-after-shift 0.1) -0.7
                           (if (< offset-diff-after-shift 0.3) -0.5 0))))
         (if (and stem head)
             (if (and bm-left (< effective-stem-length nescessary-height))
                 (ly:grob-set-property! grob 'extra-offset (cons x-shift (- effective-stem-length nescessary-height)))
                  ))))
    % align to side of parent grob (-1 left, 0 center, 1 right)
    % if another number, it's in half-parent's width units
    \override Fingering.parent-alignment-X = #-1
    % align to side of parent grob (1 top, 0 center, -1 bottom)
    % if another number, it's in half-parent's height units
    %\override Fingering.parent-alignment-Y = #1
    % align referenced to this side of stencil (-1 left, 0 center, 1 right)
    % if another number, it's in half-object's width units
    \override Fingering.self-alignment-X = #1
    % align referenced to this side of stencil (1 top, 0 center, -1 bottom)
    % if another number, it's in half-object's height units
    %\override Fingering.self-alignment-Y = #-1
    % align to the side of the parent, not above
    %\override Fingering.side-axis = #X
    %\override Fingering.use-skylines = ##t
    % fingering should sit inside the staff
    \override Fingering.staff-padding = #'()
    % fingering should sit right at the note head, no worries about the beaming
    \override Fingering.add-stem-support = ##f
    \override Fingering.direction = #LEFT
    
    % setup the size for the right-hand fingering notation
    \override StrokeFinger.font-size = -2
    % setup the shape for the right-hand fingering notation
    \override StrokeFinger.font-shape = #'upright
    % keep right-hand fingering inside slurs
    \override StrokeFinger.avoid-slur = #'inside
    % string numbers below the notehead
    %\override Voice.stringNumberOrientations = #'(down)
    % plucking fingering notation above the notehead
    %\override Voice.strokeFingerOrientations = #'(up)
    %\once \override StringNumber.self-alignment-X = #RIGHT
    %\once \override Fingering.self-alignment-X = #RIGHT
    %\override StringNumber.self-alignment-X = #RIGHT
    
  }
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Minimal document setup

\paper  {
   #(set-paper-size "a4")
}

\header{
  title = "Fingering tests"
  subtitle = "A little sampler to setup guitar fingering"
  composer = "Luca Fascione"
  lastupdated = "2022/Feb/12"
  tagline = ##f
}

% various pieces of sample music
\parallelMusic guitarHi,guitarMid,guitarLo {
    \mergeDifferentlyHeadedOn
    
    \bar "[|:"  
    \slurDown \stringUp cis'4-1  gis,16 b e'-0 b |
    s2 |
    \Barref "4" "6" "CII" { a,16-0 a-1 e-1 a-1 } gis,4-3 |
    
    a4-1 e,16 cis'-1 d'-2 e'-0 |
    s2 |
    \Barre "CII" { fis,16-1 fis-4 cis-3 fis } e,4-0 |
    
    \Barref "1" "2" "CII" { fis'16-1 cis'-1( d'-2) fis' } e'-0 gis-1 b-0 d'-4 |
    s2 |
    d4-0 e,-0 |
    
    \break
    
    cis'2-1 |
    s2|
    \Barref "4" "6" "CII" {a,16-0 a-1 e-1 a  a,-0( cis-3) e-1 a-1 } |
    
    %5
    cis'4-2 \Barre "CIV" {cis16 eis'32-3( fis'-4) gis'16-1 a'-2} |
    s2 |
    eis16-3 gis-1 d-0 gis cis4-1 |
    
}

\parallelMusic guitarHiB,guitarMidB,guitarLoB {
    \mergeDifferentlyHeadedOn
    
    \bar "[|:"  
    \slurDown \stringUp <cis'-1>4  <gis,>16 b <e'-0> b |
    s2 |
    \Barref "4" "6" "CII" { <a,-0>16 <a-1> <e-1> <a-1> } <gis,-3>4 |
    
    <a-1>4 e,16 <cis'-1> <d'-2> <e'-0> |
    s2 |
    \Barre "CII" { <fis,-1>16 <fis-4> <cis-3> fis } <e,-0>4 |
    
    \Barref "1" "2" "CII" { <fis'-1>16 <cis'-1(> <d'-2)> fis' } <e'-0> <gis-1> <b-0> <d'-4> |
    s2 |
    <d-0>4 <e,-0> |
    
    \break
    
    <cis'-1>2 |
    s2|
    \Barref "4" "6" "CII" {<a,-0>16 <a-1> <e-1> a  <a,-0(> <cis-3)> <e-1> <a-1> } |
    
    %5
    cis'4-2 \Barre "CIV" {cis16 <eis'-3(>32 <fis'-4)> <gis'-1>16 <a'-2>} |
    s2 |
    <eis-3>16 <gis-1> <d-0> gis <cis-1>4 |
    
}

guitar = {
    \accidentalStyle modern-cautionary
    
    {
        \key a \major
        \time 2/4
        \clef "violin_8"      
        
        <<
            \voiceOne  \guitarHi \\ 
            \voiceFour \guitarMid \\ 
            \voiceTwo  \guitarLo
        >>
    }
}

fingeringSetup = {
    % setup fingering on the left of the noteheads
    \set fingeringOrientations = #'(left)
    % now move it up and right a little
    \override Fingering.extra-offset = #'(0.125 . 0.5)
}

guitarB = {
    \accidentalStyle modern-cautionary
    
    {
        \key a \major
        \time 2/4
        \clef "violin_8"      
        
        <<
            \new Voice = "hi" { \fingeringSetup \voiceOne  \guitarHiB } 
            \new Voice = "mid" { \fingeringSetup \voiceFour \guitarMidB } 
            \new Voice = "lo" { \fingeringSetup \voiceTwo  \guitarLoB }
        >>
    }
}

\score {
  \new Staff = "guitar" { \guitar \break \guitarB }
  \layout {  }
}

Attachment: signature.asc
Description: This is a digitally signed message part.

Reply via email to