lilypond-user
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Tweak beam slashes for small staves


From: Edward Neeman
Subject: Re: Tweak beam slashes for small staves
Date: Mon, 23 Jul 2018 08:42:02 +1000

Hello Harm,

I just started playing around with this but it’s obviously a huge improvement. 
Thanks a lot for nailing yet another one of my nagging Lilypond issues!

Best,
Edward
---
Dr. Edward Neeman
www.neemanpianoduo.com



> On 22 Jul 2018, at 8:04 pm, Thomas Morley <address@hidden> wrote:
> 
> 2018-07-22 6:30 GMT+02:00 Edward Neeman <address@hidden>:
>> Hello,
>> 
>> This snippet produces very nice slashed grace note beams: 
>> http://lsr.di.unimi.it/LSR/Snippet?id=721
>> 
>> However the slashes don’t adjust properly for smaller staves that are 
>> tweaked with the \magnifyStaff function. In the example below, the slash on 
>> the second (smaller) staff is too high and too long. How might I change the 
>> function to accommodate the \magnifyStaff value?
>> 
>> Thanks,
>> Edward
>> 
>> \version "2.19.80"
>> 
>> slash =
>> #(define-music-function (ang stem-fraction protrusion)
>>   (number? number? number?)
>>   (remove-grace-property 'Voice 'Stem 'direction) ; necessary?
>>   #{
>>     \once \override Stem #'stencil =
>>     #(lambda (grob)
>>       (let* ((X-parent (ly:grob-parent grob X))
>>              (is-rest? (ly:grob? (ly:grob-object X-parent 'rest))))
>>         (if is-rest?
>>             empty-stencil
>>             (let* ((ang (degrees->radians ang))
>>                    ; We need the beam and its slope so that slash will
>>                    ; extend uniformly past the stem and the beam
>>                    (beam (ly:grob-object grob 'beam))
>>                    (beam-X-pos (ly:grob-property beam 'X-positions))
>>                    (beam-Y-pos (ly:grob-property beam 'positions))
>>                    (beam-slope (/ (- (cdr beam-Y-pos) (car beam-Y-pos))
>>                                   (- (cdr beam-X-pos) (car beam-X-pos))))
>>                    (beam-angle (atan beam-slope))
>>                    (stem-Y-ext (ly:grob-extent grob grob Y))
>>                    ; Stem.length is expressed in half staff-spaces
>>                    (stem-length (/ (ly:grob-property grob 'length) 2.0))
>>                    (dir (ly:grob-property grob 'direction))
>>                    ; if stem points up. car represents segment of stem
>>                    ; closest to notehead; if down, cdr does
>>                    (stem-ref (if (= dir 1) (car stem-Y-ext) (cdr 
>> stem-Y-ext)))
>>                    (stem-segment (* stem-length stem-fraction))
>>                    ; Where does slash cross the stem?
>>                    (slash-stem-Y (+ stem-ref (* dir stem-segment)))
>>                    ; These are values for the portion of the slash that
>>                    ; intersects the beamed group.
>>                    (dx (/ (- stem-length stem-segment)
>>                           (- (tan ang) (* dir beam-slope))))
>>                    (dy (* (tan ang) dx))
>>                    ; Now, we add in the wings
>>                    (protrusion-dx (* (cos ang) protrusion))
>>                    (protrusion-dy (* (sin ang) protrusion))
>>                    (x1 (- protrusion-dx))
>>                    (y1 (- slash-stem-Y (* dir protrusion-dy)))
>>                    (x2 (+ dx protrusion-dx))
>>                    (y2 (+ slash-stem-Y
>>                           (* dir (+ dy protrusion-dy))))
>>                    (th (ly:staff-symbol-line-thickness grob))
>>                    (stil (ly:stem::print grob)))
>> 
>>              (ly:stencil-add
>>                stil
>>                (make-line-stencil th x1 y1 x2 y2))))))
>>   #})
>> 
>> slashI = {
>>  \slash 50 0.6 1.0
>> }
>> 
>>  <<
>>   \new Staff { \grace { \slashI b''8[ c'''] } c'' }
>>   \new Staff \with { \magnifyStaff #2/3 } { \grace { \slashI b''8[ c'''] } 
>> c'' }
>>>> 
>> 
>> ---
>> Dr. Edward Neeman
>> www.neemanpianoduo.com
> 
> 
> Hi,
> 
> the LSR-snippet does not take the changed staff-space into account,
> thus the calculations are wrong, if staff-space isn't default.
> The used trigonomitrcs makes it even harder to debug: Simply applying
> the changed staff-space to the found x1/2 y1/2 values will not
> succeed.
> 
> Further more I was always dissatisfied, because no automatic slashed
> beams were possible.
> 
> Over the years I repeatedly tried different approaches and erlier this
> year I've finally found something more satisfying.
> 
> It overrides Beam not Stem.
> 
> No trogonometrics.
> 
> Several adjustments are possible by overriding sub-properties of
> Beam.details. Here the defaults as overrides:
>  %% defaults:
>  %% \override Beam.details.attach-side = #'left
>  %% \override Beam.details.stem-part = 1
>  %% \override Beam.details.slash-gradient = 1/2
>  %% \override Beam.details.slash-x-y-over-shoot = #'(0.3 . 0.8)
>  %% \override Beam.details.slash-thickness = 0.1
> They suited me well in an own project, though for Beams of 8th-notes
> the slash may collide with the NoteHead.
> I always found Stems of 8th-notes are too often at minimum size in
> LilyPond in general. For adding a slash this means there is (too)
> little space.
> It's one of the TODOs: automatic adjust slash-placement depending on
> the duration.
> For the examples below I therefore used modified values.
> The other TODO is 'attach-side 'right. Atm it's buggy, it is possible
> to adjust the other details sub-properties to get a nice output, but
> not out-of-the-box.
> 
> 
> But here the code with your example, additionally I included the LSR-examples.
> 
> 
> 
> \version "2.19.82"
> 
> %% c/p from lily-library.scm (it is not public)
> #(define (sign x)
>  (if (= x 0)
>      0
>      (if (< x 0) -1 1)))
> 
> #(define (slashed-beam beam-stil)
>  (lambda (grob)
>    (let* ((orig-grob (ly:grob-original grob))
>           (broken-beams (ly:spanner-broken-into orig-grob))
>           (beam-stil-x-ext (ly:stencil-extent beam-stil X))
>           (side
>             (assoc-get 'attach-side (ly:grob-property grob 'details) 'left))
>           ;; which side?
>           (on-left? (eq? side 'left))
>           ;; get beam direction, can be found by examining stem direction.
>           (stems (ly:grob-object grob 'stems))
>           ;; on the left, use the first stem. on the right, use last stem.
>           ;; this allows the function to work with kneed beams as well.
>           (stem
>             (if on-left?
>                 (ly:grob-array-ref stems 0)
>                 (ly:grob-array-ref stems (1- (ly:grob-array-length stems)))))
>           (stem-dir (ly:grob-property stem 'direction #f))
>           (beam-X-pos (ly:grob-property grob 'X-positions))
>           (beam-Y-pos (ly:grob-property grob 'positions))
>           (beam-start-y (car beam-Y-pos))
>           (beam-end-y (cdr beam-Y-pos))
>           (beam-gradient
>             (/ (- beam-end-y beam-start-y)
>                (interval-length beam-X-pos)))
>           (beam-slope
>             (* stem-dir (sign (- (abs beam-end-y) (abs beam-start-y)))))
>           (relevant-beam-y
>             (if on-left?
>                 beam-start-y
>                 beam-end-y))
>           (beam-thick (ly:grob-property grob 'beam-thickness))
>           (half-beam-thick (/ beam-thick 2))
>           (length-fraction (ly:grob-property grob 'length-fraction 1))
>           (stem-part
>             (assoc-get 'stem-part (ly:grob-property grob 'details) 1))
>           (slash-thick
>             (assoc-get
>               'slash-thickness
>               (ly:grob-property grob 'details)
>               (ly:output-def-lookup
>                 (ly:grob-layout grob)
>                 'line-thickness
>                 0.1)))
>           (slash-gradient
>             (assoc-get
>               'slash-gradient
>               (ly:grob-property grob 'details)
>               (cons 1 2)))
>           (slash-gradient-fraction
>             (/ (cdr slash-gradient) (car slash-gradient)))
>           (slash-x-y-over-shoot
>             (assoc-get
>               'slash-x-y-over-shoot
>               (ly:grob-property grob 'details)
>               '(0.3 . 0.8)))
>           (stick-out-x (car slash-x-y-over-shoot))
>           (stick-out-y (cdr slash-x-y-over-shoot))
>           ;; We first construct a line starting at the relevant stem, ending
>           ;; in the middle of the beam, relying on an appropriate move in
>           ;; y-direction, ensured by `stem-y'
>           (stem-y
>             (- relevant-beam-y (* length-fraction stem-part stem-dir)))
>           ;; Get a x-value, where the slash will match the beam
>           (inner-x
>             (if on-left?
>                 (/ (* -1 length-fraction stem-part stem-dir)
>                    (- beam-gradient (* stem-dir slash-gradient-fraction)))
>                 (/ (* length-fraction stem-part stem-dir)
>                    (+ beam-gradient (* stem-dir slash-gradient-fraction)))))
>           ;; We ensure a constant gap between the end-point of the slash and
>           ;; the beam, by transforming the given `stick-out-y' into a value
>           ;; which is added to `inner-x' later.
>           (add-x
>             (if (or (and (> stem-dir 0) on-left?)
>                     (and (<= stem-dir 0) (not on-left?)))
>                 (/ stick-out-y (- slash-gradient-fraction beam-gradient))
>                 (/ stick-out-y (+ slash-gradient-fraction beam-gradient))))
>           ;; To get the slash sticking out to the left, apply `stick-out-x'
>           ;; to the starting x-value and apply `slash-gradient-fraction' to 
> the
>           ;; starting y-value.
>           (slash-start-x
>             (if on-left?
>                 (- (car beam-stil-x-ext) stick-out-x)
>                 (+ (cdr beam-stil-x-ext) stick-out-x)))
>           (slash-start-y
>             (+ stem-y
>                (*
>                   stem-dir
>                   (- (+ half-beam-thick stick-out-x))
>                   slash-gradient-fraction)))
>           (slash-end-x
>             (if on-left?
>                 (+ inner-x add-x)
>                 (- (cdr beam-stil-x-ext) (+ inner-x add-x))))
>           (slash-end-y
>             (+ stem-y
>                (* stem-dir (+ inner-x add-x) slash-gradient-fraction)))
>           (staff-space (ly:staff-symbol-staff-space grob)))
>      (ly:stencil-add
>        beam-stil
>        (if (or (not (pair? broken-beams))
>                (equal? grob (car broken-beams)))
>            ;; for debugging purposes we let the color in place, commented
>            ;(stencil-with-color
>              (make-line-stencil
>                ;; thick
>                slash-thick
>                ;; start-coords
>                (* staff-space slash-start-x)
>                (* staff-space slash-start-y)
>                ;; end-coords
>                (* staff-space slash-end-x)
>                (* staff-space slash-end-y))
>            ;  red)
>            empty-stencil)))))
> 
> slashedBeam =
>  \override Beam.stencil =
>    #(lambda (grob)
>      ;; TODO
>      ;; this will catch the default-stencil, to get an already tweaked
>      ;; stencil call (ly:grob-property grob 'stencil) and apply it
>      ;; and set the stencil 'after-line-breaking.
>      (slashed-beam (ly:beam::print grob)))
> 
> startAcciaccaturaMusic =  {
>    <>\startGraceSlur
>    \temporary \override Flag.stroke-style = #"grace"
>    \temporary \slashedBeam
> }
> 
> stopAcciaccaturaMusic =  {
>    \revert Flag.stroke-style
>    \revert Beam.stencil
>    <>\stopGraceSlur
> }
> 
> %%%%%%%%%%%%%%%%%%%%%%
> %% EXAMPLES
> %%%%%%%%%%%%%%%%%%%%%%
> 
> \layout {
>  \override Beam.details.stem-part = 0.8
>  \override Beam.details.slash-gradient = 2/3
>  \override Beam.details.slash-x-y-over-shoot = #'(0.3 . 0.6)
> }
> 
> <<
> \new Staff
>   {
>     \grace { \slashedBeam b''8[ c'''] } c''
>   }
> \new Staff
>   \with { \magnifyStaff #2/3 }
>   {
>     \grace { \slashedBeam b''8[ c'''] } c''
>   }
>>> 
> 
> %% Examples from http://lsr.di.unimi.it/LSR/Snippet?id=721
> %% \magnifyStaff #2/3 always applied
> 
> \new Staff \with { \magnifyStaff #2/3 } {
>  \relative c' {
>    \acciaccatura { d8[ e f g] } d4
>    \acciaccatura { g8[ a b c] } d4
>    \acciaccatura { g8[ a b c] } d4
>    \acciaccatura { g8[ a b c ] } d4
>    \clef bass
>    \acciaccatura { d,,,8[ c b a ] } g4
>    \acciaccatura { d8[ c b a ] } g4
>    \acciaccatura { d8[ c b a ] } g4
>    \acciaccatura { d8[ c b a ] } g4
>  }
> }
> 
> \new Staff \with { \magnifyStaff #2/3 } {
>  \relative c'' {
>    \acciaccatura {
>      dis32[ e, a' bes, cis, d' ]
>    }
>    es,4
>  }
> }
> 
> \new PianoStaff <<
>  \new Staff = "1" \with { \magnifyStaff #2/3 } {
>    s1*0
>    \grace {
>      \slashedBeam
>      \stemDown
>      a'''16[
>      \change Staff = "2"
>      \stemUp
>      bes,
>      \change Staff = "1"
>      \stemDown
>      fis''16
>      \change Staff = "2"
>      \stemUp
>      g]
>    }
>    \change Staff = "1"
>    es'4
>  }
>  \new Staff = "2" \with { \magnifyStaff #2/3 } {
>    \clef bass
>    \grace s4
>    s4
>  }
>>> 
> 
> 
> I've used this in a large own project, so I think it's pretty robust.
> 
> 
> HTH,
>  harm




reply via email to

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