Excerpt below. Works for all test cases I threw at it and it significantly less 
logic. 

I *think* I can see how to do this without an engraver but the last 4-5 days 
has been long enough. I think that in the unpure call I can do something like: 

- Get VerticalAxis Group (VAG) with ly:grob-get-vertical-axis-group-index
- Probe around the elements of the that parent's Vertical Alignment 
- Find the two VAG's and do the same calculation. 

The only thing that I think I am missing is to make sure that the staves I am 
working with are up and down and not an occasional oasis. 

Thank you, Kieren

-kwb 

%%%  SNIPPET BEGINS
\version "2.24.3"

% Define new grob properties so that every grob can have a reference to
% what is it going to use for alignment later
#(set-object-property! 'up-staff 'backend-type? ly:grob?)
#(set-object-property! 'down-staff 'backend-type? ly:grob?)


#(define (Multi_measure_rest_positioner context)
   (let (
          ; collection of staff refs that we may want to use later
          ; this will hold a list of (grob . source-engraver) pairs
          (maybe-staff-ref '())
          ; After determining that they are the staves we need, they will
          ; be stored here
          (staff-ref (cons '() '()))
          ; If we see a MM rest number, store it here.
          (maybe-mm-number-ref '())
          )
     (make-engraver
      (acknowledgers
       ((staff-symbol-interface this-engraver grob source-engraver)
        ; Catch any staff symbols and set them to be processed in a second
        (when (or (null? (car staff-ref)) (null? (cdr staff-ref)))
          (set! maybe-staff-ref (cons (cons grob source-engraver) 
maybe-staff-ref))))
       ; And record the MM rest number we see
       ((multi-measure-rest-number-interface this-engraver grob source-engraver)
        (set! maybe-mm-number-ref (cons (cons grob source-engraver) 
maybe-mm-number-ref))))
      ((process-acknowledged this-engraver)
       ; Process staff symbols first. If we do not have two staves, we need to 
not even worry about
       ; the MMrest numbers as there is nothing to center it to.
       ; TODO: Move this to a fold
       (for-each (lambda (ms)
                   (let (
                          (ctx-id (ly:context-id (ly:translator-context (cdr 
ms)))))
                     (cond
                      ((string=? ctx-id "up")
                       (set-car! staff-ref (car ms)))
                      ((string=? ctx-id "down")
                       (set-cdr! staff-ref (car ms)))
                      (else
                       (ly:warning "Unknown staff found: ~a~%" ctx-id))))) 
maybe-staff-ref)
       ; then see if we have a MMRest number that lives in the down ctx
       (let (
              (mm-ref-res (find (lambda (mrr)
                                  (string=? (ly:context-id (ly:context-find 
(ly:translator-context (cdr mrr)) 'Staff)) "down")) maybe-mm-number-ref)))
         (when
          (not (eqv? mm-ref-res #f))
          (ly:grob-set-object! (car mm-ref-res) 'up-staff (car staff-ref))
          (ly:grob-set-object! (car mm-ref-res) 'down-staff (cdr staff-ref))))
       ; Clean up before next round
       (set! maybe-staff-ref '())
       (set! maybe-mm-number-ref '())
       ) ; End process acknowledger block
      )))

#(ly:set-option 'debug-skylines #t)


% Begin Score Output
\score {
  \new PianoStaff <<
    \new Staff = "up" \with {
      \omit MultiMeasureRestNumber
      \override MultiMeasureRest.expand-limit = #1
    } \relative c'' {
      \clef treble \key a \major \time 6/8
      R2.*2
      \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
      R2.*2 | 
      \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
      \break
      \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
      R2.*2 |
      \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
    }
    \new Dynamics {
      s2.*2 | s2.*2 | s2.*2 | s8 s8 s8\ff s4. | s2.
      s2.*2 | s2.*2 | s8 s8 s8\ff s4. | s2.
    }
    \new customStaffDown = "down" \relative c {
      \clef bass \key a \major \time 6/8
      \compressMMRests { R2.*2 } |
      \repeat unfold 2 {
        r8 r8 <e e'> r8 r8 <e e'> |
      }
      \compressMMRests { R2.*2 } |
      \repeat unfold 2 {
        r8 r8 <e e'> r8 r8 <e e'> |
      }
      \break
      \repeat unfold 2 {
        r8 r8 <e e'> r8 r8 <e e'> |
      }
      \compressMMRests { R2.*2 } |
      \repeat unfold 2 {
        r8 r8 e r8 r8 e |
      }
    }
  >>


  \layout {
    #(layout-set-staff-size 18.5)
    \context {
      \Staff
      \name customStaffDown
      \alias Staff
      \inherit-acceptability customStaffDown Staff
      \override MultiMeasureRest.expand-limit = #1
      \override MultiMeasureRestNumber.font-size = #2.0
    }

    \context {
      \PianoStaff
      \consists #Multi_measure_rest_positioner
    }
    \context {
      \customStaffDown
      % Turn off skylines so that Lilypond doesn't get any wise ideas and try
      % to space or align this for us.
      \override MultiMeasureRestNumber.vertical-skylines = ##f
      \override MultiMeasureRestNumber.Y-offset =
      #(ly:make-unpure-pure-container
        ; Unpure
        (lambda (grob)
          (let*
           (
             (up-staff-ref (ly:grob-object grob 'up-staff))
             (down-staff-ref (ly:grob-object grob 'down-staff))
             ; We need to get to a place where the up staff and the
             ; down staff share a common parent. We should be able to
             ; get this with the below method
             (common-ref (ly:grob-common-refpoint-of-array grob 
(ly:grob-list->grob-array (list up-staff-ref down-staff-ref)) Y))
             ; Now get the distances
             (up-y-offset (ly:grob-relative-coordinate up-staff-ref common-ref 
Y))
             (down-y-offset (ly:grob-relative-coordinate down-staff-ref 
common-ref Y))
             (offset-center (/ (+ up-y-offset down-y-offset) 2))
             )
           ; Set parent of MMR Number to the common parent from above
           (ly:grob-set-parent! grob Y common-ref)
           ; Return middle. Offset by one. I believe to account for different 
ref points positions on
           ; staves and text.
           (- offset-center 1)

           ))
        ; Pure
        ; Skylines are off so this doesn't really matter where it goes. Credo.
        (lambda (grob start stop) 0)
        )
    }
  }
}


%%%  SNIPPET ENDS

> On Jun 21, 2025, at 6:00 AM, Kieren MacMillan <[email protected]> 
> wrote:
> 
> Hi again,
> 
> Here’s the example with the layout bug fixed, and starting with an MMR (per 
> your other issue). The only thing I’d want to fix is to decouple the vertical 
> positioning from the axis line, so that the MMR number would float down to 
> true centre (the way dynamics do, as in that earlier piano example I sent).
> 
> Cheers,
> Kieren.
> 
> %%%  SNIPPET BEGINS
> 
> \layout {
> 
>  #(layout-set-staff-size 18.5)
> 
>  \context {
>    \Staff
>    \name customStaffDown
>    \alias Staff
>    \inherit-acceptability customStaffDown Staff
>    \omit MultiMeasureRestNumber
>    \override MultiMeasureRest.expand-limit = #1
>  }
> 
>  \context {
>    \Staff
>    \name customStaffUp
>    \alias Staff
>    \inherit-acceptability customStaffUp Staff
>    \accidentalStyle piano
>    \omit MultiMeasureRestNumber
>    \override MultiMeasureRest.expand-limit = #1
>  }
> 
>  \context {
>    \name PianoMMR
>    \type "Engraver_group"
>    \inherit-acceptability PianoMMR Dynamics
>    \consists "Axis_group_engraver"
>    \override VerticalAxisGroup.staff-affinity = #CENTER
>    \override VerticalAxisGroup.nonstaff-relatedstaff-spacing =
>    #'((basic-distance . 2) (minimum-distance . 1) (padding . 0.5) 
> (stretchability . 1))
>    \consists "Dynamic_engraver"
>    \consists "Multi_measure_rest_engraver"
>    \hide MultiMeasureRest
>    \override MultiMeasureRestNumber.direction = #DOWN
>    \override MultiMeasureRestNumber.Y-offset = -1
>  }
> 
>  \context {
>    \StaffGroup
>    \name CustomStaffGroup
>    \alias StaffGroup
>    \inherit-acceptability CustomStaffGroup StaffGroup
>    systemStartDelimiterHierarchy = #'(SystemStartBrace a b)
>  }
> 
> }
> 
> % Begin Score Output
> theGroup = \new CustomStaffGroup <<
>  \new customStaffUp = "up" \relative c'' {
>    \clef treble \key a \major \time 6/8
>    R2.*2
>    \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
>    R2.*2 |
>    \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
>    \break
>    \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
>    R2.*2 |
>    \repeat unfold 2 { r8 r8 <e e'> r8 r8 <e e'> | }
>  }
>  \new PianoMMR {
>    \compressMMRests { R2.*2 }
>    \repeat unfold 2 {
>      s2.*2 | \compressMMRests { R2.*2 } | s8 s8 s8\ff s4. | s2.
>    }
>  }
>  \new customStaffDown = "down" \relative c {
>    \clef bass \key a \major \time 6/8
>    R2.*2
>    \repeat unfold 2 {
>      r8 r8 <e e'> r8 r8 <e e'> |
>    }
>    R2.*2 |
>    \repeat unfold 2 {
>      r8 r8 <e e'> r8 r8 <e e'> |
>    }
>    \break
>    \repeat unfold 2 {
>      r8 r8 <e e'> r8 r8 <e e'> |
>    }
>    R2.*2 |
>    \repeat unfold 2 {
>      r8 r8 e r8 r8 e |
>    }
>  }
>>> 
> 
>  \score {
>    \theGroup
>    \layout {
>      \context {
>        \CustomStaffGroup
>        \override VerticalAxisGroup.staff-staff-spacing.padding = #4
>      }
>    }
>  }
> 
>  \markup \vspace #10
> 
>  \score {
>    \theGroup
>    \layout {
>      \context {
>        \CustomStaffGroup
>        \override VerticalAxisGroup.staff-staff-spacing.padding = #14
>      }
>    }
>  }
> 
>  \version “2.24.4"
> %%%  SNIPPET ENDS
> __________________________________________________
> 
> My work day may look different than your work day. Please do not feel 
> obligated to read or respond to this email outside of your normal working 
> hours.
> 


Reply via email to