lilypond-user
[Top][All Lists]
Advanced

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

Re: Align bracket not to notes but to enclosing bars


From: Urs Liska
Subject: Re: Align bracket not to notes but to enclosing bars
Date: Tue, 5 Feb 2019 10:48:19 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0

Hi David,

Am 04.02.19 um 14:20 schrieb David Nalesnik:
Hi Urs,

On Mon, Feb 4, 2019 at 6:12 AM Urs Liska <address@hidden> wrote:
...
I believe you will need to look for the bar lines (or the containing
NonMusicalPaperColumns). Here's a (still-working as of 2.19.82)
example which uses the MeasureCounter and a custom stencil:
http://lists.gnu.org/archive/html/lilypond-user/2014-10/msg00446.html.
It may be usable as a source of code for your task.  At the moment I
unfortunately can't devote time to a more thorough-going
recommendation!


thank you very much for this. Indeed it provided me with all the starting points to achieve my task at hand. Actually I could *simplify* your code because a) I don't have to take broken spanners into account and b) I don't need the split bracket effect. I did not touch the engraver because I didn't immediately see how it works, and it *did* work right as it was.

So what I ended up with is more limited than yours but I'll share it anyway. Maybe it's of some use for some.

What I was thinking about is that it would be useful to provide some more convenient access to the type of information used in that snippet (I had already thought of it when I had to create custom slurs from scratch). These various steps that are necessary navigating the staff, refpoints and object lists wouldn't have to be redone everytime when there were a function like "analyseSpanner" that returns an alist with all sort of usable information about the spanner.

Best
Urs

%%%%%

\version "2.19.82"

% Create horizontal brackets with included text,
% attached to one or multiple measures.
% If no text is desired an empty string has to be given.
%
% Based on code by David Nalesnik:
% http://lists.gnu.org/archive/html/lilypond-user/2014-10/msg00446.html
% (referenced from http://lists.gnu.org/archive/html/lilypond-user/2019-02/msg00084.html)
% Note that support for broken spanners has deliberately been removed.
% Currently the function is limited to be printed above the staff
%
% Use \startMeasureBracket "text" *before* the first note. The bracket will
% attach itself to the barlines (or right after the time signature at staff start)
% and center the given markup underneath the bracket.

% Configuration variables
#(define measure-text-padding 0)
#(define measure-staff-padding 4)
#(define measure-bracket-thickness 0.25)

#(define (measure-bracket-stencil grob has-bracket text)
   ;; stencil override that determines the width of a MeasureCounter
   ;; and creates the annotated bracket
   (let*
    ((ref-point (ly:grob-system grob))
     (left-bound (ly:spanner-bound grob LEFT))
     (right-bound (ly:spanner-bound grob RIGHT))
     (elts-L (ly:grob-array->list (ly:grob-object left-bound 'elements)))
     (elts-R (ly:grob-array->list (ly:grob-object right-bound 'elements)))
     (break-alignment-L
      (filter
       (lambda (elt) (grob::has-interface elt 'break-alignment-interface))
       elts-L))
     (break-alignment-R
      (filter
       (lambda (elt) (grob::has-interface elt 'break-alignment-interface))
       elts-R))
     (break-alignment-L-ext (ly:grob-extent (car break-alignment-L) ref-point X))
     (break-alignment-R-ext (ly:grob-extent (car break-alignment-R) ref-point X))
     (width (- (car break-alignment-R-ext) (cdr break-alignment-L-ext)))
     (heading (ly:stencil-aligned-to
               (grob-interpret-markup grob (markup text))
               X CENTER))
     (heading-centered
      (ly:stencil-translate-axis
       heading
       (+ (interval-length break-alignment-L-ext)
         (* 0.5
           (- (car break-alignment-R-ext)
             (cdr break-alignment-L-ext))))
       X))
     (bracket-path
      (markup #:path measure-bracket-thickness
        `((moveto 0 0)
          (lineto 0 1)
          (lineto ,width 1)
          (lineto ,width 0))))
     (bracket
      (ly:stencil-translate-axis
       (grob-interpret-markup grob bracket-path)
       (interval-length break-alignment-L-ext)
       X))
     (combined-stencil
      (ly:stencil-combine-at-edge
       heading-centered Y UP bracket
       measure-text-padding)))
    (if has-bracket
        combined-stencil
        heading-centered)))

#(define-public (Measure_attached_spanner_engraver context)
   (let ((span '())
         (finished '())
         (event-start '())
         (event-stop '()))
     (make-engraver
      (listeners ((measure-counter-event engraver event)
                  (if (= START (ly:event-property event 'span-direction))
                      (set! event-start event)
                      (set! event-stop event))))
      ((process-music trans)
       (if (ly:stream-event? event-stop)
           (if (null? span)
               (ly:warning "You're trying to end a measure-attached spanner but you haven't started one.")
               (begin (set! finished span)
                 (ly:engraver-announce-end-grob trans finished event-start)
                 (set! span '())
                 (set! event-stop '()))))
       (if (ly:stream-event? event-start)
           (begin (set! span (ly:engraver-make-grob trans 'MeasureCounter event-start))
             (set! event-start '()))))
      ((stop-translation-timestep trans)
       (if (and (ly:spanner? span)
                (null? (ly:spanner-bound span LEFT))
                (moment<=? (ly:context-property context 'measurePosition) ZERO-MOMENT))
           ; NOTE: the following does not work--BUG? It will cause regtest
           ; scheme-text-spanner.ly to crash!
           ;(set! (ly:spanner-bound span LEFT)
           ;   (ly:context-property context 'currentcommandColumn))
           (ly:spanner-set-bound! span LEFT
             (ly:context-property context 'currentCommandColumn)))
       (if (and (ly:spanner? finished)
                (moment<=? (ly:context-property context 'measurePosition) ZERO-MOMENT))
           (begin
            (if (null? (ly:spanner-bound finished RIGHT))
                (ly:spanner-set-bound! finished RIGHT
                  (ly:context-property context 'currentCommandColumn)))
            (set! finished '())
            (set! event-start '())
            (set! event-stop '()))))
      ((finalize trans)
       (if (ly:spanner? finished)
           (begin
            (if (null? (ly:spanner-bound finished RIGHT))
                (set! (ly:spanner-bound finished RIGHT)
                      (ly:context-property context 'currentCommandColumn)))
            (set! finished '())))
       (if (ly:spanner? span)
           (begin
            (ly:warning "I think there's a dangling measure-attached spanner :-(")
            (ly:grob-suicide! span)
            (set! span '())))))))

% Install engraver
\layout {
  \context {
    \Staff
    \consists #Measure_attached_spanner_engraver
    \override MeasureCounter.font-encoding = #'latin1
    \override MeasureCounter.font-size = 0
  }
}


% Central entry point for any commands
#(define start-measure-bracket
   (define-music-function (has-bracket text)((boolean? #t) markup?)
     #{
       \override Staff.MeasureCounter.staff-padding =
       #measure-staff-padding
       \override Staff.MeasureCounter.outside-staff-horizontal-padding = #0
       \override Staff.MeasureCounter.stencil =
       #(lambda (grob) (measure-bracket-stencil grob has-bracket text))
       \startMeasureCount
     #}))

% Several examples of user-facing commands

bracketHeading =
#(define-music-function (text music)(markup? ly:music?)
   #{
     \start-measure-bracket ##t \markup \bold #text
     #music
     \stopMeasureCount
   #})

measureCenteredHeading =
#(define-music-function (text music)(markup? ly:music?)
   #{
     \start-measure-bracket ##f \markup \bold #text
     #music
     \stopMeasureCount
   #})

centeredText =
#(define-music-function (text music)(markup? ly:music?)
   #{
     \start-measure-bracket ##f \markup #text
     #music
     \stopMeasureCount
   #})

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Some score examples
% Remove for reuse of the code
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\relative {
  \bracketHeading "Test 1" {
    c'1 d c
  }
  \bar "||"
  \measureCenteredHeading "Test 2" {
    b1 c
  }
}

\relative {
  #(set! measure-staff-padding 2)
  \centeredText "Centered comment" {
    c''2 b a g f e
  }
  \measureCenteredHeading "!" {
    d c
  }
}

%%%%%

...

Best,
David

reply via email to

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