[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Shortening hairpins
From: |
Thomas Morley |
Subject: |
Re: Shortening hairpins |
Date: |
Wed, 8 Apr 2015 22:16:18 +0200 |
Hi Andrew,
2015-04-08 9:02 GMT+02:00 Andrew Bernard <address@hidden>:
> Recently there was a discussion about this. Now I need to do it. The answers
> in the discussion, whilst erudite, seem very kludgy, and not appropriate for
> my score.
>
> Why is there no simple way to shorten a hairpin in lilypond? It’s easy to
> use shorten-pair to adjust tuplet bracket lengths. Why don’t hairpins follow
> a similar method?
>
> It was mentioned that the stencil code is in C++. For some time I have been
> looking for something worthwhile to do in the internals to get to the point
> where I could contribute something. Is this a candidate? Does the stencil
> need rewriting in Scheme? I am sure there are other more worthy tasks, but I
> happen to really need this one at present. Should this discussion be on the
> lilypond-devel list instead?
>
> So what is the technical reason why this is so difficult? From an end user
> point of view a hairpin is just an object that should be able to be resized
> easily.
>
> Andrew
I'm guessing, because I don't know C++:
Hairpins are already styled to a high level. Changing anything will be
most likely a complex and maybe complicated task.
Nevertheless you can take the default-Hairpin and create a new one
based on this.
How about:
\version "2.19.18"
%% taken from output-lib.ly and extended
#(define ((elbowed-hairpin coords mirrored?) grob)
"Create hairpin based on a list of @var{coords} in @code{(cons x y)}
form. @code{x} is the portion of the width consumed for a given line
and @code{y} is the portion of the height. For example,
@code{'((0.3 . 0.7) (0.8 . 0.9) (1.0 . 1.0))} means that at the point
where the hairpin has consumed 30% of its width, it must
be at 70% of its height. Once it is to 80% width, it
must be at 90% height. It finishes at
100% width and 100% height. @var{mirrored?} indicates if the hairpin
is mirrored over the Y-axis or if just the upper part is drawn.
Returns a function that accepts a hairpin grob as an argument
and draws the stencil based on its coordinates.
@lilypond[verbatim,quote]
#(define simple-hairpin
(elbowed-hairpin '((1.0 . 1.0)) #t))
\\relative c' {
\\override Hairpin #'stencil = #simple-hairpin
a\\p\\< a a a\\f
}
@end lilypond
"
(define (pair-to-list pair)
(list (car pair) (cdr pair)))
(define (normalize-coords goods x y)
(map
(lambda (coord)
(cons (* x (car coord)) (* y (cdr coord))))
goods))
(define (my-c-p-s points thick decresc?)
(make-connected-path-stencil
points
thick
(if decresc? -1.0 1.0)
1.0
#f
#f))
(define (rewrite-hairpin val grobl)
(let* ((decresc? (eq? (ly:grob-property grobl 'grow-direction) LEFT))
(thick (ly:grob-property grobl 'thickness 0.1))
(thick (* thick (layout-line-thickness grobl)))
(stil (ly:hairpin::print grobl))
(xex (ly:stencil-extent stil X))
(lenx (+ (interval-length xex)
(+ (car val) (cdr val)))) ;;!!
(yex (ly:stencil-extent stil Y))
(leny (interval-length yex))
(xtrans (+ (* -1 (car val))
(car xex)
(if decresc? lenx 0)))
(ytrans (car yex))
(uplist (map pair-to-list
(normalize-coords coords lenx (/ leny 2))))
(downlist (map pair-to-list
(normalize-coords coords lenx (/ leny -2)))))
(ly:stencil-translate
(ly:stencil-add
(my-c-p-s uplist thick decresc?)
(if mirrored? (my-c-p-s downlist thick decresc?) empty-stencil))
(cons xtrans ytrans))))
;; outer let to trigger suicide
(let ((sten (ly:hairpin::print grob)))
(if (grob::is-live? grob)
(let* ((decresc? (eq? (ly:grob-property grob 'grow-direction) LEFT))
(orig (ly:grob-original grob))
(siblings (if (ly:grob? orig)
(ly:spanner-broken-into orig)
'()))
(thick (ly:grob-property grob 'thickness 0.1))
(thick (* thick (layout-line-thickness grob)))
(shorten-pair (ly:grob-property grob 'shorten-pair '(0 . 0))))
(if (not (null? siblings))
(begin
(ly:grob-set-property! (car siblings) 'stencil
(rewrite-hairpin
(cons (car shorten-pair) 0)
(car siblings)))
(ly:grob-set-property! (last siblings) 'stencil
(rewrite-hairpin
(cons 0 (cdr shorten-pair))
(last siblings)))))
(if (null? siblings)
(ly:grob-set-property! grob 'stencil
(rewrite-hairpin shorten-pair grob))))
'())))
#(define simple-hairpin
(elbowed-hairpin '((1.0 . 1.0)) #t))
shortenHairpin =
#(define-music-function (parser location shortening-pair)(pair?)
"Takes the defaultHairpin and rewrites the stencil taking into account the
settings for @code{shorten-pair}.
At line-break only the beginning of the first and the end of the last Hairpin
are affected"
#{
\once \override Hairpin.shorten-pair = $shortening-pair
\once \override Hairpin #'after-line-breaking = #simple-hairpin
#})
%%%%%%%%%%%%%%%%%
%% EXAMPLE
%%%%%%%%%%%%%%%%%
\relative c' {
%% maybe needed:
%\override DynamicLineSpanner.padding = 4
\shortenHairpin #'(-5 . -10)
c2 \ppppp \> c\!
\break
\shortenHairpin #'(-15 . -10)
c1 \ppppp \<
\break
c c\ffff\!
}
Shortening/lengthen is possible right and/or left.
Also works at line-breaks.
HTH,
Harm