A slur enclosed by parentheses or brackets

classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

A slur enclosed by parentheses or brackets

Jun Tamura
Hello,

Is there an easy way to have a slur enclosed by parentheses or brackets? Some urtext editions use parenthesized slurs to indicate editorial additions.

Best regards,

Jun
Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Aaron Hill
On 2020-09-11 9:18 pm, Jun Tamura wrote:
> Hello,
>
> Is there an easy way to have a slur enclosed by parentheses or
> brackets? Some urtext editions use parenthesized slurs to indicate
> editorial additions.

\parenthesize does not currently handle spanners, so you would need to
do some manual work.

Consider:

%%%%
\version "2.20.0"

parenthesizeSlur =
   -\tweak stencil
   #(lambda (grob)
     (let* ((cp (ly:grob-property grob 'control-points))
            (lp (grob-interpret-markup grob (markup #:teeny "(")))
            (rp (grob-interpret-markup grob (markup #:teeny ")"))))
       (set! lp (ly:stencil-aligned-to lp Y CENTER))
       (set! lp (ly:stencil-aligned-to lp X 0.2))
       (set! lp (ly:stencil-translate lp (first cp)))
       (set! rp (ly:stencil-aligned-to rp Y CENTER))
       (set! rp (ly:stencil-aligned-to rp X -0.2))
       (set! rp (ly:stencil-translate rp (last cp)))
       (list-set! cp 0
         (cons (cdr (ly:stencil-extent lp X))
               (cdr (first cp))))
       (list-set! cp (1- (length cp))
         (cons (car (ly:stencil-extent rp X))
               (cdr (last cp))))
       (ly:grob-set-property! grob 'control-points cp)
       (apply ly:stencil-add (list lp rp
         (ly:slur::print grob)))))
   \etc

{ g'4\parenthesizeSlur (
      \parenthesizeSlur \( b' c''2 ) |
   g'2\parenthesizeSlur ( f'4 e' ) \) }
%%%%


-- Aaron Hill

paren-slur.cropped.png (14K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Jun Tamura
Dear Aaron,

> 2020/09/12 14:25、Aaron Hill <[hidden email]>のメール:
>
> On 2020-09-11 9:18 pm, Jun Tamura wrote:
>> Hello,
>> Is there an easy way to have a slur enclosed by parentheses or
>> brackets? Some urtext editions use parenthesized slurs to indicate
>> editorial additions.
>
> \parenthesize does not currently handle spanners, so you would need to do some manual work.
>
> Consider:
>
> %%%%
> \version "2.20.0"
>
> parenthesizeSlur =
>  -\tweak stencil
>  #(lambda (grob)
>    (let* ((cp (ly:grob-property grob 'control-points))
>           (lp (grob-interpret-markup grob (markup #:teeny "(")))
>           (rp (grob-interpret-markup grob (markup #:teeny ")"))))
>      (set! lp (ly:stencil-aligned-to lp Y CENTER))
>      (set! lp (ly:stencil-aligned-to lp X 0.2))
>      (set! lp (ly:stencil-translate lp (first cp)))
>      (set! rp (ly:stencil-aligned-to rp Y CENTER))
>      (set! rp (ly:stencil-aligned-to rp X -0.2))
>      (set! rp (ly:stencil-translate rp (last cp)))
>      (list-set! cp 0
>        (cons (cdr (ly:stencil-extent lp X))
>              (cdr (first cp))))
>      (list-set! cp (1- (length cp))
>        (cons (car (ly:stencil-extent rp X))
>              (cdr (last cp))))
>      (ly:grob-set-property! grob 'control-points cp)
>      (apply ly:stencil-add (list lp rp
>        (ly:slur::print grob)))))
>  \etc
>
> { g'4\parenthesizeSlur (
>     \parenthesizeSlur \( b' c''2 ) |
>  g'2\parenthesizeSlur ( f'4 e' ) \) }
> %%%%
>
>
> -- Aaron Hill<paren-slur.cropped.png>

Thank you!  This is exactly what I was looking for.  I think that this is worthwhile to be in the LSR.  (I wish I could understand Scheme code better.)

Jun



Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Werner LEMBERG
In reply to this post by Aaron Hill

>> Is there an easy way to have a slur enclosed by parentheses or
>> brackets? Some urtext editions use parenthesized slurs to indicate
>> editorial additions.
>
> \parenthesize does not currently handle spanners, so you would need to
> do some manual work.
>
> Consider: [...]

Here is a slightly improved version with rotated parentheses.  There's
certainly room for more improvements...


    Werner

-------------------------------------------------------------------------------

\version "2.20.0"

parenthesizeSlur =
   -\tweak stencil
   #(lambda (grob)
     (let* ((cp (ly:grob-property grob 'control-points))
            (lp (grob-interpret-markup grob (markup #:fontsize -7 "(")))
            (rp (grob-interpret-markup grob (markup #:fontsize -7 ")")))
            (cp1 (first cp))
            (cp2 (second cp))
            (cpn-1 (list-ref cp (- (length cp) 2)))
            (cpn (last cp))
            (langle (/ (atan (- (cdr cp2) (cdr cp1))
                             (- (car cp2) (car cp1))) PI-OVER-180))
            (rangle (/ (atan (- (cdr cpn) (cdr cpn-1))
                             (- (car cpn) (car cpn-1))) PI-OVER-180)))

       (set! lp (ly:stencil-aligned-to lp Y CENTER))
       (set! lp (ly:stencil-aligned-to lp X 0.5))
       (set! lp (ly:stencil-translate lp (first cp)))

       (set! rp (ly:stencil-aligned-to rp Y CENTER))
       (set! rp (ly:stencil-aligned-to rp X -0.5))
       (set! rp (ly:stencil-translate rp cpn))

       (list-set! cp 0
         (cons (cdr (ly:stencil-extent lp X))
               (cdr cp1)))
       (set! lp (ly:stencil-rotate lp langle 0 0))
       (list-set! cp (1- (length cp))
         (cons (car (ly:stencil-extent rp X))
               (cdr cpn)))
       (set! rp (ly:stencil-rotate rp rangle 0 0))
       (ly:grob-set-property! grob 'control-points cp)

       (apply ly:stencil-add (list lp rp
         (ly:slur::print grob)))))
   \etc

{ g'4\parenthesizeSlur (
      \parenthesizeSlur \( b' c''2 ) |
   g'2\parenthesizeSlur ( f'4 e' ) \) }

parenslur.png (16K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Jun Tamura
Thanks for another suggestion. I’m not so sure whether rotating the parentheses would improve the legibility or not, however. I understand that people have different preferences. What I had in mind was Vivaldi’s urtext edition published by Ricordi, in which the editorial slurs are enclosed by parentheses but the parentheses are not rotated.

Jun

> 2020/09/12 21:27、Werner LEMBERG <[hidden email]>のメール:
>
>
>>> Is there an easy way to have a slur enclosed by parentheses or
>>> brackets? Some urtext editions use parenthesized slurs to indicate
>>> editorial additions.
>>
>> \parenthesize does not currently handle spanners, so you would need to
>> do some manual work.
>>
>> Consider: [...]
>
> Here is a slightly improved version with rotated parentheses.  There's
> certainly room for more improvements...
>
>
>    Werner
>
> -------------------------------------------------------------------------------
>
> \version "2.20.0"
>
> parenthesizeSlur =
>   -\tweak stencil
>   #(lambda (grob)
>     (let* ((cp (ly:grob-property grob 'control-points))
>            (lp (grob-interpret-markup grob (markup #:fontsize -7 "(")))
>            (rp (grob-interpret-markup grob (markup #:fontsize -7 ")")))
>            (cp1 (first cp))
>            (cp2 (second cp))
>            (cpn-1 (list-ref cp (- (length cp) 2)))
>            (cpn (last cp))
>            (langle (/ (atan (- (cdr cp2) (cdr cp1))
>                             (- (car cp2) (car cp1))) PI-OVER-180))
>            (rangle (/ (atan (- (cdr cpn) (cdr cpn-1))
>                             (- (car cpn) (car cpn-1))) PI-OVER-180)))
>
>       (set! lp (ly:stencil-aligned-to lp Y CENTER))
>       (set! lp (ly:stencil-aligned-to lp X 0.5))
>       (set! lp (ly:stencil-translate lp (first cp)))
>
>       (set! rp (ly:stencil-aligned-to rp Y CENTER))
>       (set! rp (ly:stencil-aligned-to rp X -0.5))
>       (set! rp (ly:stencil-translate rp cpn))
>
>       (list-set! cp 0
>         (cons (cdr (ly:stencil-extent lp X))
>               (cdr cp1)))
>       (set! lp (ly:stencil-rotate lp langle 0 0))
>       (list-set! cp (1- (length cp))
>         (cons (car (ly:stencil-extent rp X))
>               (cdr cpn)))
>       (set! rp (ly:stencil-rotate rp rangle 0 0))
>       (ly:grob-set-property! grob 'control-points cp)
>
>       (apply ly:stencil-add (list lp rp
>         (ly:slur::print grob)))))
>   \etc
>
> { g'4\parenthesizeSlur (
>      \parenthesizeSlur \( b' c''2 ) |
>   g'2\parenthesizeSlur ( f'4 e' ) \) }
> <parenslur.png>


Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Kieren MacMillan
Hi all,

> I’m not so sure whether rotating the parentheses would improve the legibility or not, however. I understand that people have different preferences. What I had in mind was Vivaldi’s urtext edition published by Ricordi, in which the editorial slurs are enclosed by parentheses but the parentheses are not rotated.

I think having both options would be optimal.
My vote for the default would be unrotated parentheses.

Cheers,
Kieren.
________________________________

Kieren MacMillan, composer (he/him/his)
‣ website: www.kierenmacmillan.info
‣ email: [hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: A slur enclosed by parentheses or brackets

Luca Rossetto Casel-2
Il 12/09/20 16:38, Kieren MacMillan ha scritto:
>
> I’m not so sure whether rotating the parentheses would improve the legibility or not, however. [...] What I had in mind was Vivaldi’s urtext edition published by Ricordi, in which the editorial slurs are enclosed by parentheses but the parentheses are not rotated.
> I think having both options would be optimal.
> My vote for the default would be unrotated parentheses.

I'd like to express a huge *thanks!* to all you you for the marvellous
work! As Kieren, I'd also find very useful being able to choose between
rotated and unrotated parentheses (which I personally prefer too) and,
if I can suggest, also between square brackets and semibrackets.

Thanks to all the list for the priceless, continuous assistance and
inspiration,

     Luca

Reply | Threaded
Open this post in threaded view
|

\decorateSlur (was Re: A slur enclosed by parentheses or brackets)

Aaron Hill
On 2020-09-12 7:58 am, Luca Rossetto Casel wrote:
> I'd like to express a huge *thanks!* to all you you for the marvellous
> work! As Kieren, I'd also find very useful being able to choose
> between rotated and unrotated parentheses (which I personally prefer
> too) and, if I can suggest, also between square brackets and
> semibrackets.

Expanding upon my earlier snippet, I was inspired to author this one:

%%%%
\version "2.20.0"

decorateSlur =
#(define-scheme-function
   (options)
   (ly:context-mod?)
   (define (option side prop def)
     (let* ((sym (string->symbol (format #f "~s-~s" side prop)))
            (mod (find (lambda (x) (and (eq? 'assign (first x))
                                        (eq? sym (second x))))
                       (ly:get-context-mods options))))
       (if (list? mod) (third mod) def)))
   (define (bezier-core cp t)
     (define (lerp a b t)
       (cons (+ (* (- 1 t) (car a)) (* t (car b)))
             (+ (* (- 1 t) (cdr a)) (* t (cdr b)))))
     (let loop ((pre '()) (post '()) (cp cp) (t t))
       (set! pre (append pre (list (first cp))))
       (set! post (append post (list (last cp))))
       (if (< 1 (length cp))
           (loop pre post
                 (map (lambda (a b) (lerp a b t))
                      (drop-right cp 1) (drop cp 1)) t)
           (list (first cp) pre (reverse post)))))
   (define (bezier cp t) (first (bezier-core cp t)))
   (define (bezier-pre cp t) (second (bezier-core cp t)))
   (define (bezier-post cp t) (third (bezier-core cp t)))
   (define (bezier-slope cp t)
     (define (slope a b)
       (cons (- (car b) (car a))
             (- (cdr b) (cdr a))))
     (bezier (map slope (drop-right cp 1) (drop cp 1)) t))
   (define (slope-angle slope)
     (ly:angle (car slope) (cdr slope)))
   (define (stencil-aligned sten x y)
     (ly:stencil-aligned-to (ly:stencil-aligned-to sten X x) Y y))
   (define (build-stencil grob cp side)
     (let* ((text (option side 'text (markup #:null)))
            (sten (grob-interpret-markup grob text))
            (t (case side ((left) 0) ((center) 0.5) ((right) 1)))
            (rot? (option side 'rotate #f)))
       (set! sten
         (stencil-aligned sten
           (option side 'X-align CENTER)
           (option side 'Y-align CENTER)))
       (and rot? (set! sten
         (ly:stencil-rotate-absolute sten
           (slope-angle (bezier-slope cp t)) 0 0)))
       (ly:stencil-translate sten (bezier cp t))))
   (define (stencil-proc grob)
     (let* ((cp (ly:grob-property grob 'control-points))
            (left (build-stencil grob cp 'left))
            (center (build-stencil grob cp 'center))
            (right (build-stencil grob cp 'right))
            (lshort (option 'left 'shorten #f))
            (rshort (option 'right 'shorten #f)))
       (and (number? lshort) (number? rshort)
            (set! rshort (/ rshort (- 1 lshort))))
       (if (number? lshort) (set! cp (bezier-post cp lshort)))
       (if (number? rshort) (set! cp (bezier-pre cp (- 1 rshort))))
       (ly:grob-set-property! grob 'control-points cp)
       (apply ly:stencil-add
              (list (ly:slur::print grob) left center right))))
   #{ -\tweak stencil #stencil-proc \etc #})

parenthesizeSlur =
\decorateSlur \with {
   left-text = \markup \teeny "("
   left-Y-align = #-0.25
   left-shorten = #0.1
   right-text = \markup \teeny ")"
   right-Y-align = #-0.25
   right-shorten = #0.1
}

arrowSlur =
\decorateSlur \with {
   left-text = \markup \draw-circle #0.3 #0.1 ##f
   right-text = \markup \arrow-head #X #RIGHT ##t
   right-X-align = #LEFT
   right-rotate = ##t
}

bracketSlur =
\decorateSlur \with {
   left-text = \markup \fontsize #-5 \bold "["
   left-X-align = #RIGHT
   left-rotate = ##t
   center-text = \markup \fontsize #-5 \bold "|"
   center-Y-align = #DOWN
   center-rotate = ##t
   right-text = \markup \fontsize #-5 \bold "]"
   right-X-align = #LEFT
   right-rotate = ##t
}

{ g'4 \parenthesizeSlur (
       \bracketSlur _\( b' c''2 ) |
   b'4 \arrowSlur ( a' c''2 ) \) }
%%%%

While this might need some refactoring and could be harboring bugs, it
is a bigger step towards a more generalized system; and I wanted to get
this posted sooner than later.


-- Aaron Hill

decorate-slur.cropped.png (15K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: \decorateSlur (was Re: A slur enclosed by parentheses or brackets)

Luca Rossetto Casel-2
On 2020-09-12 17:47, Aaron Hill ha scritto:
> Expanding upon my earlier snippet, I was inspired to author this one:
>
> [...]
>
> While this might need some refactoring and could be harboring bugs, it
> is a bigger step towards a more generalized system; and I wanted to
> get this posted sooner than later.
>

Dear Aaron,

this is magnificent! Thank you,

Luca

Reply | Threaded
Open this post in threaded view
|

Re: \decorateSlur

Aaron Hill
>> Expanding upon my earlier snippet, I was inspired to author this one:
>>
>> [...]
>>
>> While this might need some refactoring and could be harboring bugs, it
>> is
>> a bigger step towards a more generalized system; and I wanted to get
>> this
>> posted sooner than later.

Some usage improvements and new features:

- Replaced fixed left/center/right decorations with a customizable list.
   (An "anchor" associates a name with a position along the curve.)
- Replaced (left|right)-shorten with curve-(start|stop) that lets you
adjust
   the extents of the original Slur.
- Renamed -rotate to -orient and -(X|Y)-align to -align-(X|Y).
- Added use-direction to have the direction property affect -align-Y.  
This
   makes #UP/#DOWN effectively "inside"/"outside" relative to the Slur.
- Added common-* to specify values applying to all anchors.  A specific
   value takes precedence, and there is still an internal fallback value.
- Changed to event-function to permit inline usage within music while
also
   supporting \tweaks when defining wrapper functions.

Known issues and future plans:

- Anchor positions and curve-(start|stop) are specified in relative
units.
   It would be nice to be able to specify absolute distances.
- Broken Slurs share the same decorations.  Ideally, anchor positions
and
   attributes would be customizable per each segment of a broken Slur.
   Perhaps there would be a way to work with \alterBroken.
- Anchors are always being realigned.  It might make sense to provide an
   option (use #f?) to keep the stencil's original alignment.  This helps
   preserve baseline alignment within \markup.
- Enable an anchor to be associated with a list of positions:
     \with { anchors = #'((a . 0) (a . 0.5) (a . 1)) }
        ...becomes...
     \with { anchors = #'((a . (0 0.5 1))) }
- Support Ties as well as potentially any Spanners.
- Add debug annotations to assist in positioning and aligning anchors.
- Coordinate changes to control-points via bezier-adjust with the dash-
   definition set for the Slur.


%%%%
\version "2.20.0"

decorateSlur =
#(define-event-function
   (options slur)
   (ly:context-mod? ly:music?)
   (define (option name default)
     (if (symbol-list? name)
         (set! name (string->symbol
           (string-join (map symbol->string name) "-"))))
     (let ((mod (find (lambda (mod) (and (eq? 'assign (first mod))
                                         (eq? name (second mod))))
                      (ly:get-context-mods options))))
       (if (list? mod) (third mod) default)))

   (define (bezier-core cpts param)
     (define (lerp a b t)
       (cons (+ (* (- 1 t) (car a)) (* t (car b)))
             (+ (* (- 1 t) (cdr a)) (* t (cdr b)))))
     (let loop ((pre '()) (post '()) (cpts cpts))
       (set! pre (append pre (list (first cpts))))
       (set! post (append (list (last cpts)) post))
       (if (< 1 (length cpts))
           (loop pre post (map (lambda (a b) (lerp a b param))
                               (drop-right cpts 1)
                               (drop cpts 1)))
           (list (first cpts) pre post))))
   (define (bezier cpts param) (first (bezier-core cpts param)))
   (define (bezier-pre cpts param) (second (bezier-core cpts param)))
   (define (bezier-post cpts param) (third (bezier-core cpts param)))
   (define (bezier-slope cpts param)
     (define (slope a b) (cons (- (car b) (car a)) (- (cdr b) (cdr a))))
     (bezier (map slope (drop-right cpts 1) (drop cpts 1)) param))
   (define (bezier-adjust cpts start stop)
     (if (> start stop)
       (bezier-adjust (reverse cpts) (- 1 start) (- 1 stop))
       (if (< (- 1 start) stop)
         (bezier-post (bezier-pre cpts stop) (/ start stop))
         (bezier-pre (bezier-post cpts start)
                     (- 1 (/ (- 1 stop) (- 1 start)))))))

   (define (slope-angle slope)
     (ly:angle (car slope) (cdr slope)))
   (define (stencil-aligned sten x y)
     (ly:stencil-aligned-to (ly:stencil-aligned-to sten X x) Y y))
   (define (handle-anchor anchor grob cpts)
     (let* ((name (car anchor))
            (param (cdr anchor))
            (text (option (list name 'text)
                          (option 'common-text (markup #:null))))
            (sten (grob-interpret-markup grob text))
            (use-dir? (option 'use-direction #f))
            (dir (ly:grob-property grob 'direction))
            (orient? (option (list name 'orient)
                             (option 'common-orient #f)))
            (align-X (option (list name 'align-X)
                             (option 'common-align-X CENTER)))
            (align-Y (option (list name 'align-Y)
                             (option 'common-align-Y CENTER))))
       (if use-dir? (set! align-Y (* align-Y dir)))
       (set! sten (stencil-aligned sten align-X align-Y))
       (and orient? (set! sten (ly:stencil-rotate-absolute sten
                                 (slope-angle (bezier-slope cpts param))
                                 0 0)))
       (ly:stencil-translate sten (bezier cpts param))))

   (define (stencil-proc grob)
     (let ((cpts (ly:grob-property grob 'control-points)))
       (ly:grob-set-property! grob 'control-points
         (bezier-adjust cpts
           (option 'curve-start 0)
           (option 'curve-stop 1)))
       (apply ly:stencil-add
         (ly:slur::print grob)
         (map (lambda (anchor) (handle-anchor anchor grob cpts))
              (option 'anchors '())))))
   #{ \tweak stencil #stencil-proc #slur #})

parenthesizeSlur =
\decorateSlur \with {
   curve-start = #0.05
   curve-stop = #0.95
   use-direction = ##t
   anchors = #'((left . 0) (right . 1))
   common-align-Y = #-0.3
   left-text = \markup \fontsize #-4 "("
   right-text = \markup \fontsize #-4 ")"
} \etc

bracketizeSlur =
-\alterBroken color #(list blue red)
-\tweak font-size #-4
\decorateSlur \with {
   anchors = #'((left . 0.1) (rule . 0.3) (rule . 0.5)
                (rule . 0.7) (right . 0.9))
   common-orient = ##t
   left-text = "["
   rule-text = "|"
   right-text = "]"
} \etc

arrowizeSlur =
\decorateSlur \with {
   anchors = #'((tail . 0) (label . 0.5) (head . 1))
   use-direction = ##t
   tail-text = \markup \draw-circle #0.3 #0.1 ##f
   label-text = \markup
     \override #'(style . outline) \whiteout
     \fontsize #-5 \italic "?!"
   label-align-Y = #DOWN
   head-text = \markup \arrow-head #X #RIGHT ##t
   head-orient = ##t
} \etc

\paper { line-width = 6\cm indent = 1\cm ragged-right = ##f }
\layout { \context { \Score \omit BarNumber } }
{ g'4 \bracketizeSlur _\(
       \parenthesizeSlur ^( b' c''2 ) |
   b'4 \arrowizeSlur ^( a' c''2 ) \) |
   g'2 \bracketizeSlur ^\(
       \arrowizeSlur _( b'4 a' ) |
   g'2 \parenthesizeSlur _( a'4 c'' ) \) |
   g'2 \bracketizeSlur ^\(
       \parenthesizeSlur _( b'4 a' ) |
   g'2 \arrowizeSlur _( a'4 c'' ) \) |
   g'4 \bracketizeSlur _\(
       \arrowizeSlur ^( b' c''2 ) |
   b'4 \parenthesizeSlur ^( a' c''2 ) \) |
   \bar "|." }
%%%%


-- Aaron Hill

decorate-slur.cropped.png (55K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: \decorateSlur

Andrew Bernard
Aaron, Put it in openlilylib? A worthy contribution.

I can do the work for you if you like.

Andrew


On 13/09/2020 12:40 pm, Aaron Hill wrote:
>>> Expanding upon my earlier snippet, I was inspired to author this one: