Variable bow thickness depending on length
Appearance
If a house-style prefers to have thicker slurs (and/or ties, etc.), sometimes they can appear overly thick when their length is short. To counter this apparent increase of thickness, you can make the 'thickness property of slurs variable depending on its length.
The following snippet uses the function variable-bow-thickness which requires four values, two for min and max bow length (min-l and max-l, respectively) and two for min and max bow thickness (min-t and max-t, respectively). The final thickness is determined by the following conditions:
- Length <
min-l, then thickness =min-t - Length >
max-l, then thickness =max-t min-l≤ Length ≤max-l, then thickness = linearly interpolated betweenmin-tandmax-t
\version "2.24.0"
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% http://lists.gnu.org/archive/html/lilypond-user/2016-03/msg00328.html
% By Abraham Lee, refactored to a more convenient function by Sharon Rosner
% further edited by Harm
% Thanks to Aaron and Jean for their help.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% If excecution time gets worse you may try to go for a simpler
%% estimation of the length by calculating the linear distance between
%% the bows endpoints. Therefore comment
%% (len (bezier-approx-length cpt 0 1))
%% and uncomment the lines above in `variable-bow-thickness'.
%% --Harm
\paper { tagline = ##f }
#(define (bezier-curve control-points t)
"Given a Bezier curve of arbitrary degree specified by @var{control-points},
compute the point at the specified position @var{t}."
(if (< 1 (length control-points))
(let ((q0 (bezier-curve (drop-right control-points 1) t))
(q1 (bezier-curve (drop control-points 1) t)))
(cons
(+ (* (car q0) (- 1 t)) (* (car q1) t))
(+ (* (cdr q0) (- 1 t)) (* (cdr q1) t))))
(car control-points)))
#(define (bezier-approx-length control-points from to)
"Given a Bezier curve of arbitrary degree specified by @var{control-points},
compute its approximate arc length between the positions @var{from} and @var{to}."
(let* ((steps 10)
(params (iota steps from (/ (- to from) (1- steps))))
(points (map (lambda (x) (bezier-curve control-points x)) params))
(length
(fold
(lambda (a b prev)
(+ prev (ly:length (- (car a) (car b)) (- (cdr a) (cdr b)))))
0
(drop points 1)
(drop-right points 1))))
; Need to support negative length when the range is inverted.
(if (< from to) length (- length))))
#(define (variable-bow-thickness min-l max-l min-t max-t)
(lambda (grob)
(let* ((cpf (ly:grob-property-data grob 'control-points))
(cpt (ly:grob-property grob 'control-points))
;(cp0 (car cpt))
;(cp3 (cadddr cpt))
;(dx (- (car cp3) (car cp0)))
;(dy (- (cdr cp3) (cdr cp0)))
;(len (ly:length dx dy))
(len (bezier-approx-length cpt 0 1))
(thickness
(cond ((< len min-l) min-t)
((> len max-l) max-t)
(else
(+ min-t
(* (- len min-l)
(/ (- max-t min-t)
(- max-l min-l))))))))
(ly:grob-set-property! grob 'thickness thickness)
(ly:grob-set-property! grob 'control-points (ly:unpure-call cpf grob)))))
music =
\relative c' {
\cadenzaOn
c16[( d]) ^\( c[(\) d^\( e]) c[(\) d^\( e f]) c[( d e f g])\)
\bar ""
\break
\set tieWaitForNote = ##t
c,4~ e~ g~ c~ e~ g~ <c,, e g c e g>
\bar "|."
}
\score {
\music
\header { piece = "Thickness = 1.2 (default)" }
}
\score {
\music
\header { piece = "Thickness = 2.7 (fixed)" }
\layout {
\override Slur.thickness = #2.7
\override PhrasingSlur.thickness = #2.7
\override Tie.thickness = #2.7
}
}
\score {
\music
\header { piece = "Thickness = 1 to 3 (variable)" }
\layout {
\override PhrasingSlur.after-line-breaking = #(variable-bow-thickness 6 25 1 3)
\override Slur.after-line-breaking = #(variable-bow-thickness 6 25 1 3)
\override Tie.after-line-breaking = #(variable-bow-thickness 6 18 1 2)
}
}
\score {
{
\override Slur.after-line-breaking = #(variable-bow-thickness 1 2 1 33)
\shape #'((10 . 0) (0 . 0) (0 . 0) (0 . 0) ) Slur
b1( b')
b1-\shape #'((10 . 0) (0 . 0) (0 . 0) (0 . 0)) ( b')
}
\header { piece = "Results of \\shape are respected." }
}