4

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!

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
gilbertohasnofb
  • 1,984
  • 16
  • 28
  • 2
    I don't know the answer to this, but just as a comment to any moderators who don't know Lilypond but who might think of this Q as offtopic for StackOverflow: Lilypond is a notation software whose file-format is essentially a set of Scheme subroutines, so q's about usage tend to be on topic. – Michael Scott Asato Cuthbert Aug 29 '13 at 03:46
  • 1
    Thanks for your comment, Michael. Indeed there is very little about LilyPond here at StackOverflow, and that is one of the reasons I like to post questions (and answers as well, if I discover them). This could be a nice complement to the lilypond-user mailing list, which is certainly the best place to ask questions related to LilyPond. – gilbertohasnofb Aug 29 '13 at 13:30
  • 2
    @Michael I use LilyPond and think it's fantastic, but I'd still call questions about usage off-topic *for Stack Overflow*. The fact that its data files are closer to programming than most programs' strikes me as a technicality; you could make a similar argument for any software that consumes PostScript :P This question seems like a good fit for [music.se], though. **Edit**: there's even a [meta question](http://meta.stackexchange.com/questions/168297/on-which-site-are-lilypond-questions-on-topic) on the subject. – anton.burger Aug 29 '13 at 14:13
  • @shambulator Well, I don't know if I agree with you on this one. I think that no musical knowledge is actually needed to answer my question above; this was a pure technical question about LilyPond. If I had asked "what looks better" or "how do composers usually notate this" then I would agree with you, but that was not the case. Asking how to print a "3x" above a bar on LilyPond is very similar to asking how to print "3x" in the middle of a line in Fortran, in my view. – gilbertohasnofb Aug 29 '13 at 14:32
  • Also, I personally believe that since LilyPond has its own language syntax and vocabulary, it should be considered as a programming language. I think that nobody would say that questions concerning Matlab should be asked only in forums about mathematics. – gilbertohasnofb Aug 29 '13 at 14:33
  • 1
    It's a bit of a fuzzy one in my mind, and I haven't voted to close :P It's definitely [on-topic](http://music.stackexchange.com/help/on-topic) for Music.SE *("usage of specific music software")* - I don't agree that there needs to be some kind of "musical knowledge" bar - and I think LilyPond users there would appreciate having these kinds of questions. But at the same time, how many non-programmers use LilyPond in favour of something not quite so... programming language-like? :) – anton.burger Aug 29 '13 at 15:58
  • @shambulator While I do appreciate hearing your opinions, and I honestly understand on what they are based, I still think that LilyPond questions are better suited here. I have the feeling that the *Musical Practice and Performance* website is miles behind *StackOverflow* in the sense of quality and deepness. While neither website has more than 20 LilyPond questions, the quality of the questions and answers (of all subjects) seem far superior here. I have the impression that website is mainly about *which guitar should I buy* or *how to read tabs* than about any deep musical exchange. – gilbertohasnofb Aug 29 '13 at 21:48
  • 3
    @shambulator -- I agree that in general how to solve problems in music notation software is better for Music.SE (and voted up comment despite disagreeing), but I think a look at the "solution" posted below shows why (1) this seems the most appropriate place for discussing using lilypond (just like a question on "how can I use [C# library] to access [other library]) and (2) why few musicians have taken up lilypond. :-) – Michael Scott Asato Cuthbert Aug 30 '13 at 03:44

2 Answers2

8

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.

gilbertohasnofb
  • 1,984
  • 16
  • 28
6

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.

Mathias
  • 1,470
  • 10
  • 20
  • Follow issue 1409 - Enhancement: printing the repeat count when no alternatives are present: https://sourceforge.net/p/testlilyissues/issues/1409/ – fedelibre Feb 08 '19 at 13:27