Le dimanche 23 avril 2023 à 12:37 +1000, Andrew Bernard a écrit :

> Just checking - you can't make circular staves with notes in lilypond, 
> can you? I know you can do nice circle of fifths diagrams as per an LSR 
> example, but circular staves are way out of scope, aren't they?
> 
> This came up in the Dorico forum and several users assert with no 
> evidence or examples that lilypond can, so I wanted to check my view.


What exactly makes you think it is not possible, given the control LilyPond 
gives you on the notation via Scheme?

Attached is an include file showing that you can do basic circular scores in 
<100 lines of straightforward Scheme code. This is a quickly coded demo, it 
would need a bit of love to gracefully print beams or ledger lines. (I won't 
invest that effort if the person is staying on Dorico and not actually using 
it, though.)

\version "2.25.4"

#(define TAU (* 2 PI))

#(define (interval-rev-index-01 iv x)
   (/ (- x (interval-start iv))
      (interval-length iv)))

#(define (interval-rev-index iv x)
   (1- (* 2 (interval-rev-index-01 iv x))))

#(define (system::staff-iv grob)
   (let ((left (ly:spanner-bound grob LEFT))
         (right (ly:spanner-bound grob RIGHT)))
     (cons (ly:grob-relative-coordinate left grob X)
           (interval-end (ly:paper-column::break-align-width right 
'staff-bar)))))

#(define (find-column-parent grob)
   "Like ly:item-get-column, but also works on spanners."
   (if (grob::has-interface grob 'paper-column-interface)
       grob
       (find-column-parent (ly:grob-parent grob X))))

#(define (system::make-circular sys)
   (let* ((elts (filter grob::is-live?
                        (ly:grob-array->list (ly:grob-object sys 
'all-elements))))
          (staff-iv (system::staff-iv sys))
          (staff-start (interval-start staff-iv))
          (staff-len (interval-length staff-iv))
          (radius (/ staff-len TAU)))
     (for-each
      (lambda (elt)
        (let* ((staff-symbol (ly:grob-object elt 'staff-symbol #f))
               (stencil (ly:grob-property elt 'stencil #f)))
          (when (and staff-symbol
                     (ly:stencil? stencil)
                     (interval-sane? (ly:stencil-extent stencil X))
                     (interval-sane? (ly:stencil-extent stencil Y)))
            (let* ((vag (ly:grob-parent staff-symbol Y))
                   (col (find-column-parent elt))
                   (staff-space (ly:staff-symbol-staff-space staff-symbol))
                   (line-thickness (ly:staff-symbol-line-thickness 
staff-symbol))
                   (col-x (ly:grob-relative-coordinate col sys X))
                   (x (ly:grob-relative-coordinate elt col X))
                   (y (ly:grob-relative-coordinate elt vag Y))
                   (rel-x (interval-rev-index-01 staff-iv col-x))
                   (rotate-ang (* -360 rel-x))
                   (place-ang (+ rotate-ang 90))
                   (stil-x-ext (ly:stencil-extent stencil X))
                   (stil-y-ext (ly:stencil-extent stencil Y)))
              (set! (ly:grob-property elt 'rotation)
                    (list rotate-ang
                          (interval-rev-index stil-x-ext (- x))
                          (interval-rev-index stil-y-ext (- y))))
              (match-let (((new-x . new-y)
                           (interval-scale (ly:directed place-ang)
                                           radius)))
                (set! (ly:grob-property elt 'extra-offset)
                      (cons (- new-x col-x) new-y)))))))
      elts)))

#(define (staff-symbol::circular grob)
   (let* ((staff-space (ly:staff-symbol-staff-space grob))
          (thickness (ly:staff-symbol-line-thickness grob))
          (len (interval-length (system::staff-iv (ly:grob-system grob))))
          (middle-radius (/ len (* 2 PI))))
     (ly:stencil-translate-axis
      (apply ly:stencil-add
             (map (lambda (pos)
                    (let ((radius (+ middle-radius (* pos 0.5 staff-space))))
                      (make-circle-stencil radius thickness #f)))
                  (ly:grob-property grob 'line-positions)))
      (- middle-radius)
      Y)))


\layout {
  \override Score.System.stencil = #system::make-circular
  \override Score.StaffSymbol.stencil = #staff-symbol::circular
  \context {
    \Staff
    \remove Clef_engraver
    \remove Time_signature_engraver
  }
}

\paper {
  page-breaking = #ly:one-line-breaking
}
\version "2.25.4"

\include "circular.ily"

\paper {
  left-margin = 4\cm
  top-margin = 4\cm
}

\fixed c' {
  \autoBeamOff
  | d g fis g
  | d8 e f g a g e d
  | e4 dis e d
  | f e f b8 a
  | a4 gis8 a4 c'8 e g
}

Attachment: circular-example.pdf
Description: Adobe PDF document

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to