lilypond-user
[Top][All Lists]
Advanced

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

Re: updating tremolo snippet for 2.16


From: David Kastrup
Subject: Re: updating tremolo snippet for 2.16
Date: Wed, 29 Aug 2012 11:53:41 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.2.50 (gnu/linux)

Shevek <address@hidden> writes:

> First off, thanks to all the people who worked on 2.16! I'm super excited
> about it, and I'm already noticing drastically reduced compile times for my
> large projects, compared to 2.14.
>
> I'm looking at updating my snippet library, and the first issue I've run
> into is that http://lsr.dsi.unimi.it/LSR/Snippet?id=604 stopped working in
> 2.16. It's pretty simple to fix using event-chord-wrap!, but I was wondering
> what a real solution should look like. I'm assuming similar situations will
> crop up with other snippets, so I suppose this is just an instance of a more
> general question. I'm hoping that maybe updating some snippets will be a
> good way for me to learn more Scheme.

This snippet is fairly simple.  The first thing to note is that the
usual problem with snippets failing as a consequence of implementing
issue 2240 <URL:http://code.google.com/p/lilypond/issues/detail?id=2240>
is the assumption that even single notes appear as an EventChord.

The blackbox giveaway is pretty much when the snippet stopped working in
version 2.15.28 and worked in 2.15.27: there are not all that many other
highly significant changes.  This change is likely the largest contender
for LilyPond programs to stop working when moving from 2.14 to 2.16.

If we are looking at the LilyPond code itself, the usual giveaway is the
use of (ly:music-property ... 'elements) without checking the type of
... beforehand, or checks for EventChord or event-chord without any
check for NoteEvent, RestEvent, or rhythmic-event.

Now instead of trying a piece-by-piece fix, in this case it is
worthwhile to rethink the whole approach and see whether we can fit its
operation into #{ #}.  Why would we want to do that?  Because the
internals of the tremolo repeat are non-trivial to calculate, and
indeed, there have been several fixes to get the respective code in the
LilyPond codebase for entering and displaying tremolo repeats correctly.

Taking a look at the user interface, we see

%\tremolos <base duration> <music>
%Makes each note in music a tremolo repeat.
%dur is 8, 16, 32, etc.
tremolos =
#(define-music-function (parser location dur mus) (integer? ly:music?)
   (music-map (lambda (x) (tremoloize dur x)) mus))

It is immediately apparent that entering a duration as an integer rather
than, well, a duration is less than optimal.  music-map works
recursively bottom-up.  In this case, we don't really want to rerecurse,
so using the new function map-some-music seems more appropriate, in
particular since it avoids a bit of unnecessary copying and we stop
recursing when reaching a target.  After all that introduction, let's
get to business:

tremolos =
#(define-music-function (parser location dur mus) (ly:duration? ly:music?)
   (map-some-music
    (lambda (m)
      (and (or (music-is-of-type? m 'event-chord)
               (music-is-of-type? m 'note-event))
           #{ \repeat tremolo
              $(ly:moment-main
                (ly:moment-div (ly:music-length m)
                               (ly:duration-length dur)))
              $(map-some-music
                (lambda (elt)
                  (and (ly:music-property elt 'duration #f)
                       (begin
                         (set! (ly:music-property elt 'duration) dur)
                         elt)))
                m)
           #}))
    mus))

\relative c' {
  \tremolos 16 { c4 d2 e4 | f1 | g8 f e d c2 | }
}

What does this mean?  We recurse top-down through the whole music,
stopping at event-chord and note-event nodes (there are likely some
other rhythmic-event types which would also be susceptible to tremoli,
but things like rest-event aren't really, so we play this
conservatively, only adding more specific types as needed).  The tremolo
count is calculated by dividing the respective lengths (the ly:moment-*
arithmetic is a bit weird, coming from a time where Guile did not have
rational numbers).  The repeated music is arrived at by replacing every
duration inside of the repeated music with the given duration.

We will get a weird error message when the repeat count is not an
integer: this could be caught and handled more gracefully, but making a
nicer error message is really all one can do in that situation.

This should work fine with chords and also when dotted durations come
into play.

It turns out that the unfoldTremolo stuff in the snippet does not really
need any changes.

-- 
David Kastrup




reply via email to

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