7

I would like to annotate a RhythmicStaff with Beat Numbers - as in the following picture: RhythmicStaff with Beat numbers below the staff

Perhaps, one could use the '_' character after a note to add numbers connected to a note at the beginning of the beat, but how about empty beats - where there is no note or rest, but the beat still needs to be shown - like the last measures in the example image.

What would be the correct way to do this? Ideally, so that - every measure, every bar in the score is automatically annotated with the beat numbers at the correct places?

2

Some way to get this automatically:

#(define (Beat_counter_engraver context)
   (let ((measpos #f) (grouping #f) (basemom #f) (beatmom #f))
     (define (mom->dur mom)
       (let ((pair (moment->fraction mom)))
         (/ (car pair) (cdr pair))))
     (define (is-beat-moment? count gping beatcount)
       (if (= (* count (mom->dur basemom)) (mom->dur measpos))
           (+ 1 beatcount)
           (if (> (* count (mom->dur basemom)) (mom->dur measpos))
               #f
               (if (null? gping)
                   #f
                   (is-beat-moment? (+ count (car gping)) (cdr gping) (+ 1 beatcount))))))
     (make-engraver
       ((process-music engraver)
          (set! measpos (ly:context-property context 'measurePosition 'noof))
          (set! grouping (ly:context-property context 'beatStructure 'noof))
          (set! basemom (ly:context-property context 'baseMoment 'noof))
          (set! beatmom (is-beat-moment? 0 grouping 0))
          (if beatmom
            (let ((grob (ly:engraver-make-grob engraver 'TextScript '())))
                  (ly:grob-set-property! grob 'text (number->string beatmom))
                  (ly:grob-set-property! grob 'direction DOWN)
                  (ly:grob-set-property! grob 'padding 3)))))))

\layout {
  \context {
    \RhythmicStaff
    \consists #Beat_counter_engraver
  }
}

\new RhythmicStaff
{
  \set RhythmicStaff.baseMoment = #(ly:make-moment 1 16) % manually make sure base moment is 1/16
  \set RhythmicStaff.beatStructure = 3,3,3,3 % manually make sure that beats always have 3 16th
  \time 6/16
  16 16 16 16 16 16|
  r16 16 16 8.
  \time 3/16
  16[ \once\set stemRightBeamCount = 1
      \once\set stemLeftBeamCount = 1
       r16 16]
  \time 6/16
  16 16 r r8. \bar "|."
}


%% with different moments:

\new RhythmicStaff {
  \time 2/4
  8 16 16 8 16 16
  \time 3/8
  16 16 16 16 16 16
  \time 6/8
  8 16 16 8 16 16 16 16 16 16
  \time 9/7 \tuplet 7/8 { 8 8 8 8 8 8 8 8 8 }
}

which results in enter image description here

One issue here is that this only works when these is some event on the beat, so if you have something like \time 4/4 8 4 8 this will not output anything on the second beat, since there is nothing there. So you might want to do something like

<< \music \repeat unfold #(floor (/ (/ (car (moment->fraction (ly:music-length music))) (cdr (moment->fraction (ly:music-length music)))) 1/16)) s16 >>

EDIT: To achieve something like your example you can also do something like this:

#(define (Beat_counter_engraver context)
   (let ((measpos #f) (grouping #f) (basemom #f) (beatmom #f))
     (define (mom->dur mom)
       (let ((pair (moment->fraction mom)))
         (/ (car pair) (cdr pair))))
     (define (is-beat-moment? count gping beatcount)
       (if (= (* count (mom->dur basemom)) (mom->dur measpos))
           (+ 1 beatcount)
           (if (> (* count (mom->dur basemom)) (mom->dur measpos))
               #f
               (if (null? gping)
                   #f
                   (is-beat-moment? (+ count (car gping)) (cdr gping) (+ 1 beatcount))))))
     (make-engraver
       ((process-music engraver)
          (set! measpos (ly:context-property context 'measurePosition 'noof))
          (set! grouping (ly:context-property context 'beatStructure 'noof))
          (set! basemom (ly:context-property context 'baseMoment 'noof))
          (set! beatmom (is-beat-moment? 0 grouping 0))
          (if beatmom
            (let ((grob (ly:engraver-make-grob engraver 'TextScript '())))
                  (ly:grob-set-property! grob 'text (number->string beatmom))
                  (ly:grob-set-property! grob 'direction DOWN)))))))

\layout {
  \context {
    \Dynamics
    \consists #Beat_counter_engraver
    \override TextScript.font-shape = ##f
    \override TextScript.Y-offset = #-0.8
    \consists Instrument_name_engraver
  }
}

sixteenth-grid-during =
#(define-music-function (m) (ly:music?)
   #{
     \repeat unfold #(floor (/ (/ (car (moment->fraction (ly:music-length m))) (cdr (moment->fraction (ly:music-length m)))) 1/16)) s16
   #})

\paper {
  ragged-last = ##f
}

musI = {
  \mark "In 3"
  \time 3/8
  8 8 16 r |
  8 16 16 8 |
  16[ 16 8 r16 16] |
  4. \bar "|."
}

>

musII = {
  \mark "In 4"
  \time 4/8
  \set Score.beatStructure = 1,1,1,1
  8 16 16~ 8 r8 |
  r16 16[ r16 16] r16 8.~ |
  4 ~ 16 8 16 |
  16 r16 4 r8 \bar "|."
}

>

which gives you enter image description here

7
  • What does "Lazy" stand for?
    – user83172
    Nov 24 at 0:25
  • @user83172 en.wiktionary.org/wiki/lazy
    – Lazy
    Nov 24 at 0:29
  • Lot to learn in this post - I see that lilypond uses a form of Scheme.
    – saraf
    Nov 24 at 5:09
  • Thank you for the detailed answer - Lot to learn in this post - I see that lilypond uses a form of Scheme. It'd be very helpful if you please add a paragraph commenting and summarizing what the code snippets are doing - for those unfamiliar with lisp-like languages. Also, where should the Beat_Counter_Engraver definition be placed so that it can be used in all my .ly files - this is about extending the standard lilypond scheme libraries, so could be a separate question ...
    – saraf
    Nov 24 at 5:16
  • To be exact, lilypond uses the GNU implementation of scheme which is called guile. If you want to use this in all your files you can put such stuff into a separate Lilypond file and use \include "path/to/your/file" in any of your files that might need this. By using the command line argument -I you can add folders to lilyponds standard include paths, and frescobaldi has a preference for that. So you can alias lilypond to lilypond -I some/path (or if you use Frescobaldi use the setting), put all your includes into that path, and then you can simply do \include "file" from anywhere.
    – Lazy
    Nov 24 at 11:51
9

Try

<<
  \new RhythmicStaff
  {
    \repeat volta 2 {
      \tempo "in 3"
      \time 3/8
      8 8 16 r |
      8 16 16 8 |
      16[ 16 8 r16 16] |
    }
    \repeat volta 2 {
      \tempo "in 4"
      \time 4/8
      8 16 16~8 r |
      r16 16[ r16 16] r16 8.~ |
      4~16 8 16 |
      16 r16 4 r8 |
    }
  }
  \new Lyrics \lyricmode {
    \repeat unfold 3 { "1"8 "2" "3" | }
    \repeat unfold 4 { "1" "2" "3" "4" | }
  }
>>

output

The basic trick here is to use Lyrics without \addlyrics or \lyricsto, allowing you to explicitly specify the duration: "1"8 is a syllable of "1" with a duration of 8 and that duration is then used as default for everything else.

1
  • Thank you for this solution - both the answers are teaching me something new!
    – saraf
    Nov 24 at 5:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.