I'm typesetting a piece which has circular rehearsal marks.

enter image description here

That's easy enough to achieve in lilypond with

\set Score.rehearsalMarkFormatter = #format-mark-circle-numbers

However, later in the score, the numbers get big and that causes the circle radius to become comically large.

enter image description here

Lilypond's notation reference suggests looking to scm/translation-functions.scm for inspiration, and in there I found format-mark-generic accepts an oval option. It helps with the vertical space, but it's still not pretty:

\set Score.rehearsalMarkFormatter = #(format-mark-generic '(numbers oval)) 

enter image description here

The original score deals with this by just using a box with a large-rounded corners. I'd like to use that same approach.

enter image description here

The closest I can get is by using \rounded-box, but the corner-radius seems to max-out at 2 and it would be nice if it was 1/2 the height of the box.

#(define (format-mark-roundbox-numbers number context)                          
   #{ \markup \override #'(corner-radius . 2) \rounded-box #(format-mark-numbers number context) #})

\set Score.rehearsalMarkFormatter = #format-mark-roundbox-numbers

enter image description here

1 Answer 1


The problem is not that 'corner-radius' maxes out at 2. It is limited by half of the shorter side (which should be a circle).

Now the real issue is that the underlying function rounded-box-stencil assumes blot to be the blot radius, while the actual drawing C++ function ly:round-filled-box and Lookup::round_filled_box assume that blot is the blot diameter. These also limit the blot, so rounded-box-stencil shouldn’t really need to do so (apart from making inner and outer box the same blot, which can look weird anyway).

So we can simply get rid of that and do

#(define (my-rounded-box-stencil stencil thickness padding blot)
  (let* ((xext (interval-widen (ly:stencil-extent stencil 0) padding))
         (yext (interval-widen (ly:stencil-extent stencil 1) padding))
         (min-ext (min (-(cdr xext) (car xext)) (-(cdr yext) (car yext))))
         (ideal-blot blot)
         (ideal-thickness (min thickness (/ min-ext 2)))
         (outer (ly:round-filled-box
                 (interval-widen xext ideal-thickness)
                 (interval-widen yext ideal-thickness)
         (inner (ly:stencil-in-color
                  xext yext (- ideal-blot ideal-thickness))
    (ly:stencil-add outer inner stencil)))

#(define-markup-command (my-rounded-box layout props arg)
  #:category graphic
  #:properties ((thickness 1)
                (corner-radius 1)
                (font-size 0)
                (box-padding 0.5))
  #:as-string (format #f "[~a]"
                      (markup->string arg #:layout layout #:props props))
  (let ((th (* (ly:output-def-lookup layout 'line-thickness)
        (pad (* (magstep font-size) box-padding))
        (m (interpret-markup layout props arg)))
    (my-rounded-box-stencil m th pad corner-radius)))

#(define-markup-command (wide-dimension layout props mup) (markup?)
   (let* ((m (interpret-markup layout props mup))
          (ext-x (ly:stencil-extent m X))
          (ext-y (ly:stencil-extent m Y))
          (width (interval-length ext-x))
          (height (interval-length ext-y)))
     (if (< width height)
         (ly:make-stencil (ly:stencil-expr m) (interval-widen ext-x (/ (- height width) 2)) ext-y)

#(define (format-mark-roundbox-numbers number context)                          
   #{ \markup \override #'(corner-radius . +inf.0) \my-rounded-box \wide-dimension #(format-mark-numbers number context) #})

  \set Score.rehearsalMarkFormatter = #format-mark-roundbox-numbers
  \repeat unfold 200 { \mark\default c1 }

I’ve also added a function that makes sure that the mark is at least as wide as it is high to have single digits circled (rather than using a narrow rectangle).

The result:

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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