--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Dot size and beamlet length should be scaled along
+with notation size when using the @code{\magnifyMusic} command."
+}
+
+\score {
+ \new Voice {
+ \omit Staff.TimeSignature
+ \time 7/4
+ <<
+ { \repeat unfold 7 \relative { g'8.[ g16] } }
+ {
+ \magnifyMusic 0.50 s4
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+ }
+ >>
+ }
+ \addlyrics {
+ "50%" _ _ _ _ _
+ "100%" _ _ _ _ _
+ "200%" _
+ }
+}
--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Laissez vibrer ties should be scaled along with
+notation size when using the @code{\magnifyMusic} command. They
+can get thicker than the default, but not thinner."
+}
+
+template = {
+ \omit Staff.TimeSignature
+ \time 7/2
+ \magnifyMusic 0.50 s2
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+}
+
+\score {
+ \new StaffGroup <<
+ \new Staff \new Voice = "upper" <<
+ \template
+ \repeat unfold 7 { g'4\laissezVibrer \hide Rest r4 }
+ >>
+ \new Lyrics \with {
+ \override VerticalAxisGroup.staff-affinity = #DOWN
+ } \lyricsto "upper" {
+ " 50%" \skip 1 \skip 1 " 100%" \skip 1 \skip 1 " 200%"
+ }
+ \new Staff \new Voice <<
+ \clef bass
+ \template
+ \repeat unfold 7 { f4\laissezVibrer \hide Rest r4 }
+ >>
+ >>
+}
--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Phrasing slurs should be scaled along with notation
+size when using the @code{\magnifyMusic} command. They can get
+thicker than the default, but not thinner."
+}
+
+\score {
+ \new Voice {
+ \omit Staff.TimeSignature
+ \time 7/8
+ <<
+ { \repeat unfold 7 \relative { g'32[\( a b c\)] } }
+ {
+ \magnifyMusic 0.50 s8
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+ }
+ >>
+ }
+ \addlyrics {
+ "50%" _ _ _ _ _ _ _ _ _ _ _
+ "100%" _ _ _ _ _ _ _ _ _ _ _
+ "200%" _ _ _
+ }
+}
--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Repeat ties should be scaled along with notation size
+when using the @code{\magnifyMusic} command. They can get thicker
+than the default, but not thinner."
+}
+
+template = {
+ \omit Staff.TimeSignature
+ \time 7/2
+ \magnifyMusic 0.50 s2
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+}
+
+\score {
+ \new StaffGroup <<
+ \new Staff \new Voice = "upper" <<
+ \template
+ \repeat unfold 7 { g'4\repeatTie \hide Rest r4 }
+ >>
+ \new Lyrics \with {
+ \override VerticalAxisGroup.staff-affinity = #DOWN
+ } \lyricsto "upper" {
+ " 50%" \skip 1 \skip 1 " 100%" \skip 1 \skip 1 " 200%"
+ }
+ \new Staff \new Voice <<
+ \clef bass
+ \template
+ \repeat unfold 7 { f4\repeatTie \hide Rest r4 }
+ >>
+ >>
+}
--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Slurs should be scaled along with notation size when
+using the @code{\magnifyMusic} command. They can get thicker than
+the default, but not thinner."
+}
+
+\score {
+ \new Voice {
+ \omit Staff.TimeSignature
+ \time 7/8
+ <<
+ { \repeat unfold 7 \relative { g'32[( a b c)] } }
+ {
+ \magnifyMusic 0.50 s8
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+ }
+ >>
+ }
+ \addlyrics { "50%" _ _ "100%" _ _ "200%" }
+}
\version "2.19.8"
\header {
- texidoc = "Stem lengths, beam spacing/thickness, and horizontal
-spacing should be scaled along with notation size when using the
-@code{\magnifyMusic} command."
+ texidoc = "Stem length/thickness, beam spacing/thickness, and
+horizontal spacing should be scaled along with notation size when
+using the @code{\magnifyMusic} command. Stems can get thicker
+than the default, but not thinner."
}
-\layout { ragged-right = ##t }
-
-\relative <<
- { \repeat unfold 7 { g'32[ a b c] } }
- {
- \magnifyMusic 0.50 { s8_"50%" }
- \magnifyMusic 0.63 { s }
- \magnifyMusic 0.80 { s }
- \magnifyMusic 1.00 { s_"100%" }
- \magnifyMusic 1.26 { s }
- \magnifyMusic 1.59 { s }
- \magnifyMusic 2.00 { s_"200%" }
+\score {
+ \new Voice {
+ \omit Staff.TimeSignature
+ \time 7/8
+ <<
+ { \repeat unfold 7 \relative { g'32[ a b c] } }
+ {
+ \magnifyMusic 0.50 s8
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+ }
+ >>
+ }
+ \addlyrics {
+ "50%" _ _ _ _ _ _ _ _ _ _ _
+ "100%" _ _ _ _ _ _ _ _ _ _ _
+ "200%" _ _ _
}
->>
+}
--- /dev/null
+\version "2.19.8"
+
+\header {
+ texidoc = "Ties should be scaled along with notation size when
+using the @code{\magnifyMusic} command. They can get thicker than
+the default, but not thinner."
+}
+
+template = {
+ \omit Staff.TimeSignature
+ \time 7/8
+ \magnifyMusic 0.50 s8
+ \magnifyMusic 0.63 s
+ \magnifyMusic 0.80 s
+ \magnifyMusic 1.00 s
+ \magnifyMusic 1.26 s
+ \magnifyMusic 1.59 s
+ \magnifyMusic 2.00 s
+}
+
+\score {
+ \new StaffGroup <<
+ \new Staff \new Voice = "upper" <<
+ \template
+ \repeat unfold 7 { g'32[~ g' a'~ a'] }
+ >>
+ \new Staff \new Voice <<
+ \template
+ \repeat unfold 7 { \tieUp g'32[~ g' a'~ a'] }
+ >>
+ \new Lyrics \with {
+ \override VerticalAxisGroup.staff-affinity = #DOWN
+ } \lyricsto "upper" {
+ "50%" _ _ _ _ _ "100%" _ _ _ _ _ " 200%"
+ }
+ \new Staff \new Voice <<
+ \clef bass
+ \template
+ \repeat unfold 7 { f32[~ f e~ e] }
+ >>
+ \new Staff \new Voice <<
+ \clef bass
+ \template
+ \repeat unfold 7 { \tieDown f32[~ f e~ e] }
+ >>
+ >>
+}
magnifyMusic =
-#(define-music-function (parser location mag mus) (number? ly:music?)
- (_i "Magnify the notation of @var{mus} without changing the
-staff-size, using @var{mag} as a size factor. Stems, beams, and
-horizontal spacing are adjusted automatically.")
+#(define-music-function (parser location mag music) (positive? ly:music?)
+ (_i "Magnify the notation of @var{music} without changing the
+staff-size, using @var{mag} as a size factor. Stems, beams,
+slurs, ties, and horizontal spacing are adjusted automatically.")
+
+ ;; these props are NOT allowed to shrink below default size
+ (define unshrinkable-props
+ '(
+ ;; stems
+ Stem.thickness
+ ;; slurs
+ Slur.line-thickness
+ Slur.thickness
+ PhrasingSlur.line-thickness
+ PhrasingSlur.thickness
+ ;; ties
+ Tie.line-thickness
+ Tie.thickness
+ LaissezVibrerTie.line-thickness
+ LaissezVibrerTie.thickness
+ RepeatTie.line-thickness
+ RepeatTie.thickness
+ ))
+
+ ;; these props ARE allowed to shrink below default size
+ (define shrinkable-props
+ '(
+ ;; override at the 'Score level
+ SpacingSpanner.spacing-increment
+
+ ;; Beam.beam-thickness is dealt with separately below
+
+ ;; lengths and heights
+ Beam.length-fraction
+ Stem.length-fraction
+ Stem.beamlet-default-length
+ Slur.height-limit
+ Slur.minimum-length
+ PhrasingSlur.height-limit
+ PhrasingSlur.minimum-length
+
+ ;; every Slur.details prop that's
+ ;; not a factor, penalty, ratio, or slope
+ Slur.details.region-size
+ Slur.details.free-head-distance
+ Slur.details.free-slur-distance
+ Slur.details.gap-to-staffline-inside
+ Slur.details.gap-to-staffline-outside
+ Slur.details.extra-encompass-free-distance
+ Slur.details.extra-encompass-collision-distance
+ Slur.details.close-to-edge-length
+ Slur.details.encompass-object-range-overshoot
+ Slur.details.slur-tie-extrema-min-distance
+
+ ;; every PhrasingSlur.details prop that's
+ ;; not a factor, penalty, ratio, or slope
+ PhrasingSlur.details.region-size
+ PhrasingSlur.details.free-head-distance
+ PhrasingSlur.details.free-slur-distance
+ PhrasingSlur.details.gap-to-staffline-inside
+ PhrasingSlur.details.gap-to-staffline-outside
+ PhrasingSlur.details.extra-encompass-free-distance
+ PhrasingSlur.details.extra-encompass-collision-distance
+ PhrasingSlur.details.close-to-edge-length
+ PhrasingSlur.details.encompass-object-range-overshoot
+ PhrasingSlur.details.slur-tie-extrema-min-distance
+
+ ;; every Tie.details prop that's
+ ;; not a factor, penalty, ratio, or slope
+ Tie.details.center-staff-line-clearance
+ Tie.details.tip-staff-line-clearance
+ Tie.details.note-head-gap
+ Tie.details.stem-gap
+ Tie.details.height-limit
+ Tie.details.tie-tie-collision-distance
+ Tie.details.intra-space-threshold
+ Tie.details.outer-tie-vertical-gap
+ Tie.details.multi-tie-region-size
+ Tie.details.single-tie-region-size
+ Tie.details.between-length-limit
+ ))
#{
- \set fontSize = #(magnification->font-size mag)
- % gives beam-thickness=0.48 when mag=1 (like default),
- % gives beam-thickness=0.35 when mag=0.63 (like CueVoice)
- \temporary \override Beam.beam-thickness = #(+ 119/925 (* mag 13/37))
- \temporary \override Beam.length-fraction = #mag
- \temporary \override Stem.length-fraction = #mag
- \temporary \override Stem.thickness = #(* 1.3 (max 1 mag))
- \temporary \override Score.SpacingSpanner.spacing-increment = #(* 1.2 mag)
- #mus
- \set fontSize = 0
- \revert Beam.beam-thickness
- \revert Beam.length-fraction
- \revert Stem.length-fraction
- \revert Stem.thickness
- \revert Score.SpacingSpanner.spacing-increment
+ \context Voice {
+ \newSpacingSection
+ #(scale-fontSize mag)
+ #(scale-props unshrinkable-props mag #f)
+ #(scale-props shrinkable-props mag #t)
+ #(scale-beam-thickness mag)
+
+ #music
+
+ \newSpacingSection
+ %% reverse engineer the former fontSize value instead of using \unset
+ #(revert-fontSize mag)
+ #(revert-props (append unshrinkable-props
+ shrinkable-props
+ (list 'Beam.beam-thickness)))
+ }
#})
makeClusters =
vals))))
; return the closure named `self'
self)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; The following are used by \magnifyMusic
+
+(define-public (scale-fontSize mag)
+ "Used by @code{\\magnifyMusic}. Look up the current fontSize and
+scale it by the magnification factor @var{mag}."
+ (make-apply-context
+ (lambda (context)
+ (let* ((fontSize (ly:context-property context 'fontSize 0))
+ (new-fontSize (+ fontSize (magnification->font-size mag))))
+ (ly:context-set-property! context 'fontSize new-fontSize)))))
+
+(define-public (revert-fontSize mag)
+ "Used by @code{\\magnifyMusic}. Calculate the previous fontSize value
+(before scaling) by factoring out the magnification factor @var{mag}."
+ (make-apply-context
+ (lambda (context)
+ (let* ((fontSize (ly:context-property context 'fontSize 0))
+ (old-fontSize (- fontSize (magnification->font-size mag))))
+ (ly:context-set-property! context 'fontSize old-fontSize)))))
+
+(define-public (scale-props props mag allowed-to-shrink?)
+ "Used by @code{\\magnifyMusic}. For each prop in @var{props}, find
+the current value of the requested prop, scale it by the magnification
+factor @var{mag}, and do the equivalent of a
+@code{\\temporary@tie{}\\override} with the new value. If
+@code{allowed-to-shrink?} is @code{#f}, don't let the new value be less
+than the current value. Props are formatted like:
+
+@example
+Slur.height-limit
+Slur.details.region-size
+@end example"
+ (make-apply-context
+ (lambda (context)
+ (define (scale-prop grob.prop)
+ (let* ((grob-prop-list (map string->symbol
+ (string-split
+ (symbol->string grob.prop) #\.)))
+ (prop-is-alist? (eq? 3 (length grob-prop-list)))
+ (grob (car grob-prop-list))
+ (prop (cadr grob-prop-list))
+ (where (if (eq? grob 'SpacingSpanner)
+ (ly:context-find context 'Score)
+ context))
+ (grob-def (ly:context-grob-definition where grob)))
+ (if prop-is-alist?
+ (let* ((subprop (caddr grob-prop-list))
+ (old-alist (ly:assoc-get prop grob-def))
+ (val (ly:assoc-get subprop old-alist 1))
+ (round-if-needed
+ (lambda (x)
+ ;; these props require exact integers
+ (if (or (eq? subprop 'multi-tie-region-size)
+ (eq? subprop 'single-tie-region-size))
+ (inexact->exact (round x))
+ x)))
+ (new-val (if allowed-to-shrink?
+ (round-if-needed (* val mag))
+ (round-if-needed (* val (max 1 mag)))))
+ (new-alist (cons (cons subprop new-val) old-alist)))
+ (ly:context-pushpop-property where grob prop new-alist))
+ (let* ((val (ly:assoc-get prop grob-def 1))
+ (proc (lambda (x)
+ (if allowed-to-shrink?
+ (* x mag)
+ (* x (max 1 mag)))))
+ (new-val (if (number-pair? val)
+ (cons (proc (car val))
+ (proc (cdr val)))
+ (proc val))))
+ (ly:context-pushpop-property where grob prop new-val)))))
+ (for-each scale-prop props))))
+
+(define-public (scale-beam-thickness mag)
+ "Used by @code{\\magnifyMusic}. Scaling @code{Beam.beam-thickness}
+exactly to the @var{mag} value won't work. This uses two reference
+values for @code{beam-thickness} to determine an acceptable value when
+scaling, then does the equivalent of a
+@code{\\temporary@tie{}\\override} with the new value."
+ (make-apply-context
+ (lambda (context)
+ (let* ((grob-def (ly:context-grob-definition context 'Beam))
+ (val (ly:assoc-get 'beam-thickness grob-def 0.48))
+ (ratio-to-default (/ val 0.48))
+ ;; gives beam-thickness=0.48 when mag=1 (like default),
+ ;; gives beam-thickness=0.35 when mag=0.63 (like CueVoice)
+ (scaled-default (+ 119/925 (* mag 13/37)))
+ (new-val (* scaled-default ratio-to-default)))
+ (ly:context-pushpop-property context 'Beam 'beam-thickness new-val)))))
+
+(define-public (revert-props props)
+ "Used by @code{\\magnifyMusic}. Revert each prop in @var{props}.
+Props are formatted like:
+
+@example
+Slur.height-limit
+Slur.details.region-size
+@end example
+
+Nested properties are reverted by reverting the parent property only.
+For example, @code{Slur.details.region-size} gets reverted like this:
+
+@example
+\revert Slur.details
+@end example
+
+This is safe as long as the number of reverts matches the number of
+overrides. Any user overrides within a @code{\\magnifyMusic} block
+should be reverted before closing the block."
+ (make-apply-context
+ (lambda (context)
+ (define (revert-prop grob.prop)
+ (let* ((grob-prop-list (map string->symbol
+ (string-split
+ (symbol->string grob.prop) #\.)))
+ (grob (car grob-prop-list))
+ (prop (cadr grob-prop-list))
+ (where (if (eq? grob 'SpacingSpanner)
+ (ly:context-find context 'Score)
+ context)))
+ (ly:context-pushpop-property where grob prop)))
+ (for-each revert-prop props))))