lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: treble and bass clef simultaneously


From: Thomas Morley
Subject: Re: treble and bass clef simultaneously
Date: Sat, 30 Mar 2019 22:20:33 +0100

Am Sa., 30. März 2019 um 13:06 Uhr schrieb Thomas Morley
<address@hidden>:
>
> Am Sa., 30. März 2019 um 09:04 Uhr schrieb Werner LEMBERG <address@hidden>:
>
> > > More robust: [...]
>
> > Being a perfectionist I see a last spacing issue: If there are
> > accidentals in the main chord, the fake bass clef gets aligned with
> > the leftmost accidental (in the image, I've slightly moved the clef
> > down for testing purposes to assure that there is no collision with
> > the accidentals).  I wonder why this is so – I'm not aware of the
> > necessity to do such an alignment at all –, and whether this can be
> > circumvented.
>
> The distance from bass-clef to the following note is set by
> \override Clef.space-alist.next-note = #'(fixed-space . 2)
> So the current alignment is more by accident.
>
> Above does not hold if the ClefVoice starts at line-begin.
> Per default main and additional bass-clef are vertical aligned then.
>
> I tried to get the bass-clef closer to the note in question with
> \override Clef.after-line-breaking = ...
> Though, this override does not work sufficiently. Try chords with and
> without accidentals in the main Voice to what I mean.
> Up to now I've not found a good method to do it better ...
>
> Cheers,
>   Harm

Below my current approach for adjusting the additional clef at line-begin.

\version "2.19.82"

#(define shift-clef-at-line-begin
  (lambda (grob)
    ;; If at line-start, this Clef is usually aligned with the main Clef.
    ;; Only for this case we try to move this clef towards the first
    ;; NoteColumn
    (if (eqv? (ly:item-break-dir grob) 1)
        (let* ((col (ly:item-get-column grob))
               (min-dist (ly:grob-object col 'minimum-distances))
               ;; We try to find the next PaperColumn, hopefully with the
               ;; first event initiating a NoteColumn
               (pap-col-dists
                 (filter
                   (lambda (x)
                     (and (pair? x)
                          (ly:grob? (car x))
                          (eq? (grob::name (car x)) 'PaperColumn)))
                   min-dist)))
          ;; Only proceed if a PaperColumn is found
          (if (pair? pap-col-dists)
              (let*(;; TODO sorting may be superfluous.
                    (sorted-pap-col-dists
                      (sort
                        pap-col-dists
                        (lambda (p q) (< (cdr p) (cdr q)))))
                    ;; The relevant PaperColumn with distance.
                    (rel-pap-col-dist
                      (car sorted-pap-col-dists))
                    ;; The relevant PaperColumn.
                    (pap-col
                      (car rel-pap-col-dist))
                    ;; Clef's X-extent
                    (x-ext (ly:grob-property grob 'X-extent))
                    (space-alist
                      (ly:grob-property grob 'space-alist))
                    (sys (ly:grob-system grob))
                    ;; Clef's X-extent relative to System.
                    (clef-grob-x-ext
                      (ly:grob-extent grob sys X))
                    ;; A hackish method to get the relevant NoteColumn.
                    ;; 'id is set in `clefTst´-function.
                    ;; And here used for selection.
                    ;; Lateron we want to move the clef relying only
                    ;; on the (possible) Accidentals of _this_ NoteColumn,
                    ;; not on Staff's AccidentalPlacement
                    (rel-nc
                      (filter
                        (lambda (g)
                          (and
                            (grob::has-interface g 'note-column-interface)
                            (equal? (ly:grob-property g 'id) "this")))
                        ;; TODO do we need to check for ly:grob-array?
                        (ly:grob-array->list
                          (ly:grob-object pap-col 'elements))))
                    ;; TODO if there are several entries in rel-nc,
                    ;;      simple car is likely insufficient
                    (rel-nc-grob-x-ext
                      (ly:grob-extent (car rel-nc) sys X))
                    ;; Get the relevant NoteHeads
                    (nhs-array (ly:grob-object (car rel-nc) 'note-heads))
                    (nhs-list
                      (if (ly:grob-array? nhs-array)
                          (ly:grob-array->list nhs-array)
                          '()))
                    ;; And their Accidentals
                    (raw-accs
                      (map
                        (lambda (nh)
                          (ly:grob-object nh 'accidental-grob))
                        nhs-list))
                    (accs
                      (remove null? raw-accs))
                    ;; Get the left coordinate of most left Accidental
                    (most-left-acc-left-coord
                      (apply
                        min
                        ;; If no Accidentals, use NoteCoulmn extent instead
                        (car rel-nc-grob-x-ext)
                        (map
                          (lambda (acc)
                            (car (ly:grob-extent acc sys X)))
                          accs)))
                    (amount
                      (-
                         ;; As 1. step we move the clef towards the
                         ;; NoteColumn and half clef's x-ext back.
                         ;; The clef's left edge is now algned with left
                         ;; edge of the NoteColumn ot the most left
                         ;; Accidental
                         most-left-acc-left-coord
                         (interval-center x-ext)
                         ;; Next we move the Clef to the left relying
                         ;; on the relevant NoteColumns X-dimension
                         (interval-length rel-nc-grob-x-ext)
                         ;; The default Clef doesn't sit on zero-X
                         ;; thus we move it back this amount
                         (car clef-grob-x-ext)
                         ;; Finally we apply the amount we get from
                         ;; Clef.space-alist.next-note
                         (cdr (assoc-get 'next-note space-alist)))))
                ;; Very little moving is rather disturbing,
                ;; thus we provide a threshold
                (if (> amount 1.5)
                    (ly:grob-translate-axis! grob amount X))))))))

\layout {
  \context {
    \Voice
    \name "ClefVoice"
    \alias "Voice"
    \consists "Clef_engraver"
    clefGlyph = #"clefs.F"
    middleCPosition = #6
    clefPosition = #-8
    explicitClefVisibility = ##(#f #t #t)
    \override Clef.full-size-change = ##t
    \override Clef.font-size = #-4
    \override Clef.space-alist.next-note = #'(fixed-space . 1)
    %% If adjusting clef at line-begin is not desired, comment the line below
    %% and the NoteColumn.id-override in `clefTst´
    \override Clef.after-line-breaking = #shift-clef-at-line-begin
  }
  %% probably let ClefVoice be accepted by other contexts too
  \context {
    \Staff
    \accepts "ClefVoice"
  }
}


clefTst =
#(define-music-function (m1 m2) (ly:music? ly:music?)
  (ly:music-set-property! m2 'elements
    (let* ((m2-elts (ly:music-property m2 'elements))
           (idx
             (list-index
               (lambda (m) (or (music-is-of-type? m 'note-event)
                               (music-is-of-type? m 'event-chord)))
               m2-elts)))
     (call-with-values
       (lambda () (split-at m2-elts idx))
       (lambda (a b)
         (append
           a
           (list
             #{
               \context ClefVoice = "ClefVoice" {
                    %% Sometimes needed
                    \override Staff.TimeSignature.space-alist.clef =
                      #'(fixed-space . 1)
                 %% Mmmh, this is a Score-override, may cause problems ...
                 \temporary
                   \override Score.BreakAlignment.before-line-breaking =
                      #(lambda (grob)
                        (if (eqv? (ly:item-break-dir grob) 0)
                            (ly:grob-set-property! grob 'break-align-orders
                                (make-vector 3 '(span-bar
                                                  breathing-sign
                                                  staff-bar
                                                  key-cancellation
                                                  key-signature
                                                  time-signature
                                                  clef)))))
                    \voiceTwo
                    %% Hackish ...
                    \once \override NoteColumn.id = "this"
                    #(make-sequential-music b)
                    \revert Score.BreakAlignment.before-line-breaking
               }
             #}))))))

  #{ << $m1 $m2 >> #})


\new PianoStaff <<
  \new Staff = "right" {
    \repeat unfold 8 { c'8_[ b''' b''' c'] } |
  }
  \new Staff = "left" \relative c'' {
      \key ces \major
    c8 g'' a g,, \clefTst { <fis ais cis> g } { c,,,4 } a'''8 g |
    \clefTst { <fis ais cis>8 g } { s8 cis,,,16 s } a'''8 g c g a g |

    \break

    \clefTst { <fis ais cis>8 g } { <ces,,, ees>4 } a'''8 g c g a g |
    c8 g'' a g,, \clefTst { <fis ais cis> g } { s ces,,,8 } a'''8 g |
  }
>>

HTH,
  Harm



reply via email to

[Prev in Thread] Current Thread [Next in Thread]