Engraving Statistics: Slurs and Ties

This post is part of a series analyzing LilyPond’s performance during the preparation of a new edition of Oskar Fried’s songs.

Oh my! A lot of time has passed since my last article about the “Fried project” – and I’ve almost forgotten that I have some drafts waiting for publishing since November. Fortunately they don’t require lots of updates 🙂 So, after describing the various engraving challenges in the previous posts, let’s now take a look at some long-promised statistics.

Seeing how often I had to adjust slurs and ties, I was very curious to extract some hard data and make statistics. Getting the number of adjustments was easy – all I had to do was to count occurrences of the \shape command. Counting all slurs and ties was, however, a bit more tricky (slurs in LilyPond are entered using parentheses, but I couldn’t simply count all parentheses in the source files, because they are also used for other things than slurs). Fortunately, thanks to David Kastrup’s recent improvements and a script he provided, this task was also completed swiftly (David’s solution was to redefine LilyPond commands used for inserting slurs and ties into functions that counted how many times they were called).

In total, I got 2450 slurs (and phrasing slurs) – quite a few! 1086 of them (44%) were manually adjusted using \shape.

Urs had noticed a very interesting correlation between musical complexity and the percentage of adjusted slurs. There are songs that are nearly classical in their writing, and they have a very low rate of curve shaping (2%, 7%, 13%) while the percentage goes through the roof with some more complex pieces (up to 90% adjusted slurs).

What about ties? The situation is similar; 550 out of 1540 ties had to be manually corrected (36%). I suppose that the percentage is lower because ties are typographically simpler: they are always horizontal, and they don’t span multiple notes.

Unlike slurs, for correcting ugly ties I have used several different techniques – here are more detailed numbers:

  • 130 explicit uses of \shape
  • 150 overrides of the tie-configuration property
  • 270 predefined shorthands

Predefined shorthands were simple one-line wrappers for the most commonly occurring \shape adjustments. For example, ties near staff edges usually had to be moved just a bit vertically, so I’ve created a shorthand like this:

% fix tie staff edge up
ftseu = { \shape #'((0 . 0.2)(0 . 0.2)(0 . 0.2)(0 . 0.2)) Tie }

It’s interesting that about half of all ugly ties could be fixed with just a handful of shorthands.

What should I say about these numbers? In my opinion the percentages are unsatisfactorily high – after all, LilyPond’s aim is to produce beautiful sheet music automatically. Of course, the complexity of the music contributed to this; we also demanded really high quality from the scores. I suppose that it may have been enough to tweak just about 5-10% of the curves if all we wanted was basic legibility.

To get an idea of what the changes in the slurs looked like, you may look at the Engraving Challenges: Slurs and Ties post – or at the before/after comparison below:

op. 3 no. 2 - default slurs (click to enlarge)

op. 3 no. 2: default slurs – ugh! (click to enlarge)

op. 3 no. 2 - beautified slurs (click to enlarge)

op. 3 no. 2: beautified slurs – yum! (click to enlarge)

I hope to investigate slur formatting code (I’ve already found one thing that I managed to improve with Keith’s help) and make the situation better, but considering the internship I have and general lack of time it I don’t expect to have any more results soon… Maybe other developers would like to look at this area of LilyPond source code? 😉

9 thoughts on “Engraving Statistics: Slurs and Ties

  1. noeck

    Hi Janek,

    thanks for this great post! The \shape command is really a cool feature.
    I encountered exactly these slur problems and it’s nice to see that those are already fixed.
    The relatively high number of modifications with the same values (shortcut) is a reason to hope that your tie crusade project can in principle be quite successful.
    Could you post the other/some other shortcut fixes, too? That would be potentially helpful.

    Cheers,
    Joram

    Reply
    1. Janek WarchoƂ Post author

      You mean (a) other tie-shaping shortcuts or (b) other functions in general used in the project? The next post will be about (b).

      Reply
      1. noeck

        I meant a) because they might be useful in other projects, too. As you could fix over 100 ties in your project. But surely I am looking forward to b), too.

        Reply
        1. Janek WarchoƂ Post author

          Hooray! Pasting LilyPond code into comments works as expected 🙂 Here they are:

          \version "2.17.3"
          
          % fix tie long space up
          ftlsu = { \shape Tie #'((0 . -0.2)  (0 . 0.2)  (-0.2 . 0.2)  (-0.2 . -0.2)) }
          % fix tie long space down
          ftlsd = { \shape Tie #'((0 . 0.2)  (0 . -0.2)  (0 . -0.2)  (0 . 0.
          2)) }
          
          % fix tie long line down dotted whole note
          ftllddwn = { \shape Tie #'((0 . 0.5)  (0 . 0.2)  (-1 . 0.2)  (-1 . 0.5)) }
          
          % fix tie long line down whole note
          ftlldw = { \shape Tie #'((1 . 0.3)  (1.7 . -0.2)  (-1.7 . -0.2)  (-1 . 0.3)) }
          % fix tie long line down quarter note
          ftlldq = { \shape Tie #'((1 . 0.3)  (1.7 . -0.2)  (-1.5 . -0.2)  (-0.8 . 0.3)) }
          % fix tie long line down quarter note downstem
          ftlldqd = { \shape Tie #'((1 . 0.3)  (1.7 . -0.2)  (-0.7 . -0.2)  (0 . 0.3)) }
          
          % fix tie long line up whole note
          ftlluw = { \shape Tie #'((1 . -0.3)  (1.7 . 0.2)  (-1.7 . 0.2)  (-1 . -0.3)) }
          % fix tie long line up quarter note
          ftlluq = { \shape Tie #'((1 . -0.3)  (1.7 . 0.2)  (-1.5 . 0.2)  (-0.8 . -0.3)) }
          
          % fix tie short space up
          ftssu = { \shape Tie #'((0 . -0.45) (0 . -0.55) (-0.2 . -0.55) (-0.2 . -0.45)) }
          % fix tie short space down
          ftssd = { \shape Tie #'((0 . 0.45) (0 . 0.55) (0 . 0.55) (0 . 0.
          45)) }
          
          % fix slur mini arc up
          fsmau = { \shape Slur #'((0 . 0.1)  (0 . 0.2)  (0 . 0.2)  (0 . 0.
          1)) }
          
          % fix slur arc up
          fsau = { \shape Slur #'((0 . 0)  (0 . 0.5)  (0 . 0.5)  (0 . 0)) }
          % fix slur arc down
          fsad = { \shape Slur #'((0 . 0)  (0 . -0.5)  (0 . -0.5)  (0 . 0)) }
          
          % flatten slur upwards
          flsu = { \shape Slur #'((0 . 0.2)  (0 . 0.65)  (0 . 0.65)  (0 . 0.
          2)) }
          % flatten slur downwards
          flsd = { \shape Slur #'((0 . -0.2)  (0 . -0.65)  (0 . -0.65)  (0 . -0.2)) }
          Reply
          1. Janek WarchoƂ Post author

            Quite frankly, i’m not fully saisfied with these. If i had to use them again, i would probably rewrite them using new shape and polar coordinates (quite frankly, i’m amazed myself by the possibilities that polar coordinates give, and that’s telling something since it was i who designed new shape 😉 )

            Reply
  2. Jan-Peter

    Hi Janek,
    nice article 🙂

    I’d like to add a snippet, which often helps, when shape is needed:


    \version "2.18.0"

    % these scheme functions are to be used with the shape command
    % for example: { \shape \shY #.3 c8( d e) }
    % to shape the slur a little bit more concave
    #(define (shy-type? v)
    (or (number? v)
    (number-pair? v)
    (and
    (list? v)
    (every (lambda (x) (or (number? x)(number-pair? x))) v)
    )
    ))
    % produce shape argument
    shY =
    #(define-scheme-function (parser location dy)(shy-type?)
    (let ((mod-fun (lambda (m) (cond ((number-pair? m)
    (let ((dy (car m))(dz (cdr m)))
    `((0 . ,dy)(0 . ,(+ dy dz))(0 . ,(+ dy dz))(0 . ,dy))
    ))
    ((number? m)
    `((0 . 0)(0 . ,m)(0 . ,m)(0 . 0))
    )
    (else (ly:input-warning location "type??? ~A ~A ~A" m grob dy) '((0 . 0)(0 . 0)(0 . 0)(0 . 0)))
    )
    )))
    (if (list? dy)
    (map (lambda (y) (mod-fun y)) dy)
    (mod-fun dy)
    )
    ))
    % short
    shy =
    #(define-music-function (parser location dy grob)(shy-type? symbol-list-or-music?)
    #{ \shape \shY #dy $grob #})

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %%% example: flatten Tie slightly ... its a matter of taste ;)

    \relative c'' { c2~ c | \shy #-.2 Tie c~ c }

    Reply
    1. Janek WarchoƂ Post author

      Sure, go ahead and make a pull request to the openlilylib/snippets.

      By the way, are you aware that my improved version of \shape makes it possible to easily do such adjustments without having to write an additional function? This would be \shapeII #'(()(0 -0.2)) (and it would make the tie flatter also when it is downwards).

      Reply
      1. Jan-Peter

        well, I have to admit, I didn’t realize all aspects of your shapeII developments …
        I probably will commit my thoughts … but you know it … lack of time 😉

        Reply

Leave a Reply

Your email address will not be published. Required fields are marked *