Big time signatures: Difference between revisions

m New category
Tags: Mobile edit Mobile web edit
m Lemzwerg moved page Big Time Signatures to Big time signatures without leaving a redirect: Only the first letter of a title should be uppercase
 
(3 intermediate revisions by one other user not shown)
Line 3: Line 3:
# creating a new <code>BigTimeSignature</code> spanner grob that spans multiple time signatures and prints an enlarged signature over their extent, and
# creating a new <code>BigTimeSignature</code> spanner grob that spans multiple time signatures and prints an enlarged signature over their extent, and
# creating an engraver that collects all time signatures, replacing them with a <code>BigTimeSignature</code> spanner on them.
# creating an engraver that collects all time signatures, replacing them with a <code>BigTimeSignature</code> spanner on them.
It is possible to limit height of the <code>BigTimeSignature</code> by overriding <code>BigTimeSignature.height-limit</code>. Similarly use <code>BigTimeSignature.details.min-height</code> to limit how small this can get. Since this implementation reuses the individual time signature stencils it is possible to modify the width thus. Scaling the width of the spanner will not affect spacing — but the calculate the actual scaling factor requires knowing the system-spacing. Thus this include a method which estimates the scaling factor for setting the width of the time signatures to a suitable value.
Scaling time signatures isotropic will lead to very strong time signatures. To get a narrower look this proposes the following mechanic: <code>BigTimeSignature.details.width-adjustment</code> may be set to a factor. If the height is increased by some percentage width will be increased by only this part of that percentage. E.g. if that value is set to 0.5 then if height is increased by 100% width will be increased by only 50%.


<lilypond version="2.24">
<lilypond version="2.24">
%%%%%%%%%%%%%%%% Big Time Signatures %%%%%%%%%%%%%%%%
% Version: 3                                        %
% Author: Tina Petzel (lilypond@petzel.at)          %
% Description: Implements large time signatures as  %
%  occasionally used in modern conducting scores.  %
%  This is done by implementing a spanner around  %
%  the individual time signatures to calculate    %
%  the full extent. The big time signature        %
%  stencil is then obtained by scaling one        %
%  original stencil to the requested extent.      %
%                                                  %
%  Setting the `height-limit` property of the      %
%  `BigTimeSignature` grob will set a limit to    %
%  the size of the time signatures (else they      %
%  will span the whole group). Since this reuses  %
%  the original stencil changes to this will be    %
%  reflected. This way e.g. the width can be      %
%  adjusted. Similarly the minimum height of the  %
%  big time signature can be set in                %
%  `details.min-height`.
%                                                  %
%  This file also defines a                        %
%  `big-time-signature::estimate-factors`-        %
%  function which estimates the scaling factors    %
%  before spacing logic is applied. The X-factor  %
%  is hereby determined by the property            %
%  details.width-adjustment. Reasonably this      %
%  should be between 0 and 1. It specifies how    %
%  much of an increase in height will be applied  %
%  to width as well. E.g. when this is 0.5 and    %
%  height is increased by 100% the width will be  %
%  increased by 50%. Set this to 0 to leave width  %
%  untouched, set to 1 to scale width similar to  %
%  height. The actual scaling is left to the      %
%  original time signature, as this way the extra  %
%  width can be considered during spacing. Note    %
%  that this means that width needs to be          %
%  determined before spacing is layed out, so      %
%  this needs to work with estimates.              %
%                                                  %
%  This file also contains a                      %
%  `time-signature::scale-to-big-width-estimate`  %
%  grob transformer which scales the X-extent of  %
%  a time signature by the X-factor estimate of    %
%  the big time signature (if it has one). Note    %
%  that this will cause UB and race conditions if  %
%  one time signature is part of multiple big      %
%  time signatures.                                %
%                                                  %
% Functions:                                        %
% * (big-time-signature::y-extent-from-elements    %
%  grob): Calculate Y-extent of big time signature %
% * (big-time-signature::print grob): Create scaled %
%  stencil from extent.                            %
% * (big-time-signature::estimate-factors grob):    %
%  Estimate scaling factors of big time            %
%  signature. currently this assumes that each    %
%  time signature corresponds to one staff which  %
%  will cause 5 staff spaces per time signature    %
%  plus 4 staff spaces of staff-staff-spacing.    %
% * (time-signature::scale-to-big-width-estimate    %
%  grob): Scale stencil of time signature by the  %
%  estimated width factor for the big time sig.    %
%                                                  %
% Engravers:                                        %
% * big-time-signature-engraver: Acknowledges time  %
%  signature grobs and creates BigTimeSignature    %
%  spanners.                                      %
%  * Acknowledges: time-signature-interface        %
%  * Creates: BigTimeSignature                    %
%  * Sets:                                        %
%    * @BigTimeSignature 'elements object          %
%    * @time-signature-interface                  %
%      :big-time-signature object                  %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Define a new `BigTimeSignature` spanner
%%% Define a new `BigTimeSignature` spanner
% Determine full extent of individual time signatures
#(define (big-time-signature::y-extent-from-elements grob)
  (let*
    ((height-limit (ly:grob-property grob 'height-limit +inf.0))
    (minimum-height
      (assoc-get 'min-height (ly:grob-property grob 'details) 0))
    (elts (ly:grob-object grob 'elements)) ; time-sig grobs
    (elts-list (ly:grob-array->list elts))
    ; common refpoint
    (ref (ly:grob-common-refpoint-of-array grob elts Y))
    (exts ; extents of all ts-grobs
      (map
      (lambda (x) (ly:grob-extent x ref Y))
      elts-list))
    (full-ext ; full extent of ts column
      (cons
      (apply min (map car exts))
      (apply max (map cdr exts))))
    (full-ext-height (interval-length full-ext))
    (full-ext-center (interval-center full-ext))
    (limited-height
      (max minimum-height (min full-ext-height height-limit)))
    (limited-ext
      (cons (- full-ext-center (/ limited-height 2))
            (+ full-ext-center (/ limited-height 2)))))
    ; Y-parent should be System = ref already,
    ; but just in case make sure
    (ly:grob-set-parent! grob Y ref)
    limited-ext))
% Print big time sig. Scaling of width is done by scaling original stencil
#(define (big-time-signature::print grob)
#(define (big-time-signature::print grob)
   (let*
   (let*
     ((elts (ly:grob-object grob 'elements)) ; time-sig grobs
     ((elts (ly:grob-object grob 'elements)) ; time-sig grobs
     (ref (ly:grob-common-refpoint-of-array grob elts Y)) ; common refpoint
     (limited-ext (ly:grob-property grob 'Y-extent))
     (exts (map (lambda (x) (ly:grob-extent x ref Y)) (ly:grob-array->list elts))) ; extents of all ts-grobs
    (limited-height (interval-length limited-ext))
     (full-ext (cons (apply min (map car exts)) (apply max (map cdr exts)))) ; full extent of ts column
    ; the stencil of one time signature
     (stc (ly:grob-property (ly:grob-array-ref elts 0) 'stencil)) ; the stencil of one time signature
     (stc (ly:grob-property (ly:grob-array-ref elts 0) 'stencil))
     (stc-ext-y (car exts)) ; the Y-extent of the time sig stencil
    ; the Y-extent of the time sig stencil
     (f (/ (interval-length full-ext) (interval-length stc-ext-y)))) ; scaling factor for the stencil
     (stc-ext-y (ly:stencil-extent stc Y))
     (ly:grob-set-parent! grob Y ref) ; Y-parent should be System = ref already, but just in case make sure
      ; scaling factor for the stencil
     (ly:stencil-translate-axis ; shift resulting stencil to begin of time sig column
    (f (/ limited-height (interval-length stc-ext-y))))
    (ly:stencil-aligned-to (ly:stencil-scale stc 1 f) Y DOWN) ; scale stencil and make sure it is not shifted
    ; shift resulting stencil to begin of time sig column
    (car full-ext) Y)))
    (ly:stencil-translate-axis
     ; scale stencil and make sure it is not shifted
    (ly:stencil-aligned-to (ly:stencil-scale stc 1 f) Y DOWN)
    (car limited-ext) Y)))
 
% Get an estimate for the scaling factors just from count
#(define (big-time-signature::estimate-factors grob)
  (let*
    ((height-limit (ly:grob-property grob 'height-limit +inf.0))
    (minimum-height
      (assoc-get 'min-height (ly:grob-property grob 'details) 0))
     (width-adjustment
      (assoc-get 'width-adjustment (ly:grob-property grob 'details) 0))
    (elts (ly:grob-object grob 'elements)) ; time-sig grobs
     (elts-list (ly:grob-array->list elts))
    (full-ext-height (+ (* 5 (length elts-list)) (* 4 (1- (length elts-list)))))
    (limited-height
      (max minimum-height (min full-ext-height height-limit)))
      ; scaling factor for the stencil
    (f (/ limited-height 5))
    (f-w (+ 1 (* (1- f) width-adjustment))))
     (cons f-w f)))
 
% Scale original time-signature width
#(define time-signature::scale-to-big-width-estimate
  (grob-transformer
    'stencil
     (lambda (grob orig)
      (let* ((bts (ly:grob-object grob 'big-time-signature))
            (est (if (ly:grob? bts)
                      (big-time-signature::estimate-factors bts)
                      '(1 . 1))))
        (if (> (car est) 1)
            (ly:stencil-scale
            orig
            (car est) 1)
            orig)))))


#(set! all-grob-descriptions
#(set! all-grob-descriptions
Line 26: Line 174:
     `(BigTimeSignature
     `(BigTimeSignature
       . ((stencil . ,big-time-signature::print)
       . ((stencil . ,big-time-signature::print)
          (Y-extent . ,big-time-signature::y-extent-from-elements)
           (meta
           (meta
           . ((class . Spanner)
           . ((class . Spanner)
Line 37: Line 186:
     \Global
     \Global
     \grobdescriptions #all-grob-descriptions
     \grobdescriptions #all-grob-descriptions
  }
  \context {
    \Score
    \override TimeSignature.stencil =
    #time-signature::scale-to-big-width-estimate
   }
   }
}
}
Line 46: Line 200:
     (make-engraver
     (make-engraver
       (acknowledgers
       (acknowledgers
       ((time-signature-interface engraver grob source-engraver) ; collect time signature grobs
      ; collect time signature grobs
       ((time-signature-interface engraver grob source-engraver)
         (set! time-sig (cons grob time-sig))))
         (set! time-sig (cons grob time-sig))))
       ((process-acknowledged engraver)
       ((process-acknowledged engraver)
       (if (not (null? time-sig)) ; if any time-signatures
       (if (not (null? time-sig)) ; if any time-signatures
           (let ; create BigTimeSignature spanner with time sigs at parents
           ; create BigTimeSignature spanner with time sigs at parents
             ((spanner (ly:engraver-make-spanner engraver 'BigTimeSignature '())))
          (let
             ((spanner
              (ly:engraver-make-spanner
              engraver
              'BigTimeSignature
              '())))
             (ly:spanner-set-bound! spanner UP (first time-sig))
             (ly:spanner-set-bound! spanner UP (first time-sig))
             (ly:spanner-set-bound! spanner DOWN (first time-sig))
             (ly:spanner-set-bound! spanner DOWN (first time-sig))
             (ly:grob-set-parent! spanner X (first time-sig)) ; set one time signature as X-parent for proper alignment
            ; set one time signature as X-parent for proper alignment
             (ly:grob-set-object! spanner 'elements (ly:grob-list->grob-array time-sig))))
             (ly:grob-set-parent! spanner X (first time-sig))
             (ly:grob-set-object!
            spanner
            'elements
            (ly:grob-list->grob-array time-sig))
            (for-each
            (lambda (ts)
              (ly:grob-set-object! ts 'big-time-signature spanner))
            time-sig)))
       (set! time-sig '())))))
       (set! time-sig '())))))


%%%%% Examples
\paper {
  print-all-headers = ##t
  scoreTitleMarkup = \markup\larger\bold\fromproperty #'header:title
}


%%% Example (score level)
%%% Example (score level)
\score {
\score {
  \header {
    title = "Example 1: Whole System, standard width"
  }
   \layout {
   \layout {
     \context {
     \context {
Line 80: Line 256:
       c''1 \time 3/4 d''2.
       c''1 \time 3/4 d''2.
     }
     }
  >>
}
%%% Example (staff group level)
\score {
  \header {
    title = "Example 2: Per group, standard width"
  }
  \layout {
    \context {
      \StaffGroup
      \consists #big-time-signature-engraver
      \override TimeSignature.transparent = ##t
    }
  }
  <<
    \new Staff {
      \numericTimeSignature
      c''1 \time 3/4 d''2.
    }
    <<
      \new StaffGroup <<
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
      >>
    >>
    <<
      \new StaffGroup <<
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
      >>
    >>
  >>
}
%%% Example (staff group level, not full height)
\score {
  \header {
    title =
    "Example 3: Per Group, limited height, 20% width adjustment"
  }
  \layout {
    \context {
      \StaffGroup
      \consists #big-time-signature-engraver
      \override TimeSignature.transparent = ##t
      \override BigTimeSignature.height-limit = 16
      \override BigTimeSignature.details.width-adjustment = 0.2
    }
  }
  <<
    \new Staff {
      \numericTimeSignature
      c''1 \time 3/4 d''2.
    }
    <<
      \new StaffGroup <<
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
      >>
    >>
    <<
      \new StaffGroup <<
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
        \new Staff {
          c''1 \time 3/4 d''2.
        }
      >>
    >>
   >>
   >>
}
}




%%% Example (staff group level)
%%% Example (staff group level, fixed height)
\score {
\score {
  \header {
    title =
    "Example 4: Per Group, fixed height, 20% width adjustment"
  }
   \layout {
   \layout {
     \context {
     \context {
Line 91: Line 362:
       \consists #big-time-signature-engraver
       \consists #big-time-signature-engraver
       \override TimeSignature.transparent = ##t
       \override TimeSignature.transparent = ##t
      \override BigTimeSignature.height-limit = 16
      \override BigTimeSignature.details.width-adjustment = 0.2
      \override BigTimeSignature.details.min-height = 16
     }
     }
   }
   }
Line 122: Line 396:
       >>
       >>
     >>
     >>
  >>
}
\score {
  \header {
    title = \markup {
      "Example 5: Whole system, comparison of"
      \typewriter "details.width-adjustment"
    }
  }
  \layout {
    \context {
      \Score
      \consists #big-time-signature-engraver
      \override TimeSignature.transparent = ##t
    }
  }
  <<
    \new Staff {
      \numericTimeSignature
      \override Score.BigTimeSignature.details.width-adjustment = 0
      c''1^"0"
      \override Score.BigTimeSignature.details.width-adjustment = 0.05
      \time 3/4 d''2.^"0.05"
      \override Score.BigTimeSignature.details.width-adjustment = 0.1
      \time 2/4 e''2^"0.1"
      \override Score.BigTimeSignature.details.width-adjustment = 0.15
      \time 3/4 f''2.^"0.15"
      \override Score.BigTimeSignature.details.width-adjustment = 0.2
      \time 4/4 e''1^"0.2"
      \override Score.BigTimeSignature.details.width-adjustment = 0.25
      \time 3/4 d''2.^"0.25"
      \override Score.BigTimeSignature.details.width-adjustment = 0.3
      \time 2/4 c''2^"0.3"
      \override Score.BigTimeSignature.details.width-adjustment = 0.35
      \time 3/4 d''2.^"0.35"
    }
    \new Staff {
      c''1 \time 3/4 d''2. \time 2/4 e''2 \time 3/4 f''2.
      \time 4/4 e''1 \time 3/4 d''2. \time 2/4 c''2 \time 3/4 d''2.
    }
    \new Staff {
      c''1 \time 3/4 d''2. \time 2/4 e''2 \time 3/4 f''2.
      \time 4/4 e''1 \time 3/4 d''2. \time 2/4 c''2 \time 3/4 d''2.
    }
   >>
   >>
}
}