Lilypond: how to add the number of repetitions above a bar

2.4k views Asked by At

I am working with a score in Lilypond that has a lot of repetitions, where basically every bar has to be repeated a certain number of times. I would like to be able to write above every bar the number of times it should be repeat, similar to the score below (which was not created in Lilypond):

enter image description here

It would be great to be able to have some brackets above the bar and also to have the "3x" centralized, just like in the example above. So far, the only (temporary) solution I was able to come up with in Lilypond was to add repeat bars and then simply write "3x" above the first note of every bar (since I could not have it centralized on the bar either). It does not look very good, but gets the job done. This temporary solution looks like this:

enter image description here

Any suggestions of how to make this example look more similar to the first inn Lilypond would be extremely welcome!

2

There are 2 answers

0
gilbertohasnofb On BEST ANSWER

This is a workaround for this problem:

\version "2.19.15"

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% COPY ALL THIS BELOW %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% repeatBracket snippet
% will add .----Nx----. above a bar, where N is the number of repetitions
% based on the wonderful spanner by David Nalesnik (see: http://lists.gnu.org/archive/html/lilypond-user/2014-10/msg00446.html )
#(define (test-stencil grob text)
   (let* ((orig (ly:grob-original grob))
          (siblings (ly:spanner-broken-into orig)) ; have we been split?
          (refp (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) refp X))
          (break-alignment-R-ext (ly:grob-extent (car break-alignment-R) refp X))
          (num
           (markup text))
          (num
           (if (or (null? siblings)
                   (eq? grob (car siblings)))
               num
               (make-parenthesize-markup num)))
          (num (grob-interpret-markup grob num))
          (num-stil-ext-X (ly:stencil-extent num X))
          (num-stil-ext-Y (ly:stencil-extent num Y))
          (num (ly:stencil-aligned-to num X CENTER))
          (num
           (ly:stencil-translate-axis
            num
            (+ (interval-length break-alignment-L-ext)
              (* 0.5
                (- (car break-alignment-R-ext)
                  (cdr break-alignment-L-ext))))
            X))
          (bracket-L
           (markup
            #:path
            0.1 ; line-thickness
            `((moveto 0.5 ,(* 0.5 (interval-length num-stil-ext-Y)))
              (lineto ,(* 0.5
                         (- (car break-alignment-R-ext)
                           (cdr break-alignment-L-ext)
                           (interval-length num-stil-ext-X)))
                ,(* 0.5 (interval-length num-stil-ext-Y)))
              (closepath)
              (rlineto 0.0
                ,(if (or (null? siblings) (eq? grob (car siblings)))
                     -1.0 0.0)))))
          (bracket-R
           (markup
            #:path
            0.1
            `((moveto ,(* 0.5
                         (- (car break-alignment-R-ext)
                           (cdr break-alignment-L-ext)
                           (interval-length num-stil-ext-X)))
                ,(* 0.5 (interval-length num-stil-ext-Y)))
              (lineto 0.5
                ,(* 0.5 (interval-length num-stil-ext-Y)))
              (closepath)
              (rlineto 0.0
                ,(if (or (null? siblings) (eq? grob (last siblings)))
                     -1.0 0.0)))))
          (bracket-L (grob-interpret-markup grob bracket-L))
          (bracket-R (grob-interpret-markup grob bracket-R))
          (num (ly:stencil-combine-at-edge num X LEFT bracket-L 0.4))
          (num (ly:stencil-combine-at-edge num X RIGHT bracket-R 0.4)))
     num))

#(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)) 
           (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 '())))))))

\layout {
  \context {
    \Staff
    \consists #Measure_attached_spanner_engraver
    \override MeasureCounter.font-encoding = #'latin1
    \override MeasureCounter.font-size = 0
    \override MeasureCounter.outside-staff-padding = 2
    \override MeasureCounter.outside-staff-horizontal-padding = #0
  }
}

repeatBracket = #(define-music-function
     (parser location N note)
     (number? ly:music?)     
      #{        
        \override Staff.MeasureCounter.stencil = 
        #(lambda (grob) (test-stencil grob #{ #(string-append(number->string N) "×") #} ))
        \startMeasureCount
        \repeat volta #N { $note }
        \stopMeasureCount
      #}
     )

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ...UNTIL HERE %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

{   
  \repeatBracket 7 {c'1}
  \repeatBracket 32 {d' g}
  \repeatBracket 14 {e' f g}
  \repeatBracket 29 {f' a bes \break cis' e''}  
  \repeatBracket 1048 {g'1}
}

This code above gives the following result:

enter image description here]


This solution was not created by myself, but sent to me by David Nalesnik, from lilypond-user mailing list. I just would like to share it here in case someone would need it as well. I've made just some very minor adjustments to what David sent me.

1
Mathias On

I just had a similar problem but preferred the style on your second example, with the 3x above the bar. The solution I found was:

f e d c |
\mark \markup {"3x"}\repeat volta 3 {c d e f}
f e d c |

generating

http://i.imgur.com/pO4Aq9I.png

Maybe someone else has a use for it.