lilypond-user
[Top][All Lists]
Advanced

[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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]