[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