
From:  Auto mailings of changes to Lily Issues via Testlilyissuesauto 
Subject:  [Lilypondauto] [LilyIssuesauto] [testlilyissues:issues] #1493 Problem with horizontal beams 
Date:  Thu, 08 Feb 2018 15:50:45 0000 
I've spent a lot of time on thinking about what to write. On the one hand, I didn't want to write screeds and screeds, on the other hand I wanted to supply background information to underpin my favoured solution.
For those not interested in the details, please skip to "Proposed solutions".
Starting off with a completely undamped beam, damping is implemented by raising one end and lowering the other end of the beam.
Let dy be the vertical distance between left and right end of the completely undamped beam. With infinite damping, LilyPond will raise the lower end by dy/2 and raise the lower end by dy/2. Theoretically, this will lead to two end points with the exact same y value, i.e. a horizontal beam.
Problem: due to limited numerical precision there may be tiny rounding problems when dividing by 2 and adding.
Even the slightest vertical distance between the end points, however, will later be quantized (i.e. increased) to valid sit/straddle/hang positions and thus yield noticeable slopes.
The numeric rounding issue may even overcompensate the slope so that the beam's direction flips.
That's what happened when we see a raising beam that really should be descending (or, ideally, be horizontal).
All these calculations are very sensitive to the slightest deviations and highly depend on beam slope, beam span, stave size, line width, indent, etc.
One solution would be to avoid the precision problem.
In the following list, DELTA unquanted_y is the remaining vertical distance (should be 0) of both ends of the beam.
As you can see, even the original dy sign may flip and the numeric "error" is so small I had to use exponential notation:
original dy = 0.680277, DELTA unquanted_y = 5.5511e17 original dy = 0.431074, DELTA unquanted_y = 2.7756e17 original dy = 1.301622, DELTA unquanted_y = 0.0000e+00 original dy = 0.680277, DELTA unquanted_y = 5.5511e17 original dy = 0.431074, DELTA unquanted_y = 2.7756e17 original dy = 1.301622, DELTA unquanted_y = 0.0000e+00 original dy = 1.303842, DELTA unquanted_y = 0.0000e+00 original dy = 0.428570, DELTA unquanted_y = 2.7756e17 original dy = 0.679738, DELTA unquanted_y = 5.5511e17 original dy = 1.303842, DELTA unquanted_y = 0.0000e+00 original dy = 0.428570, DELTA unquanted_y = 2.7756e17 original dy = 0.679738, DELTA unquanted_y = 5.5511e17
The sligthest deviation between left and right beam end Y position will be drastically amplified by quanting to valid sit/straddle/hang positions later on.
After avoiding the rounding problem, there are no unwanted DELTAs left in the case of infinite damping:
original dy = 0.680277, DELTA unquanted_y = 0.0000e+00 original dy = 0.431074, DELTA unquanted_y = 0.0000e+00 original dy = 1.301622, DELTA unquanted_y = 0.0000e+00 original dy = 0.680277, DELTA unquanted_y = 0.0000e+00 original dy = 0.431074, DELTA unquanted_y = 0.0000e+00 original dy = 1.301622, DELTA unquanted_y = 0.0000e+00 original dy = 1.303842, DELTA unquanted_y = 0.0000e+00 original dy = 0.428570, DELTA unquanted_y = 0.0000e+00 original dy = 0.679738, DELTA unquanted_y = 0.0000e+00 original dy = 1.303842, DELTA unquanted_y = 0.0000e+00 original dy = 0.428570, DELTA unquanted_y = 0.0000e+00 original dy = 0.679738, DELTA unquanted_y = 0.0000e+00
Beam damping is needed because "beam angles should not deviate far from the horizontal" (Gould).
Starting off with the slope of a straight line that links the outer noteheads of the beam, LilyPond applies a rather simple damping formula to the slope:
slope = 0.6 * tanh (slope) / (damping + concaveness);
Let's have a look a the numerator first:
Numerator
One may wonder about the hyperbolic tangent (tanh), but it turns out to be very suitable as a damping factor:
Consequently, the numerator of the damping term 0.6 * tanh(slope) an never exceed the value of 0.6 (i.e. an angle of 31°).
Denominator
damping has a default value of 1, concaveness is 0 for nonconcave beams.
Concave groups of notes should always have a horizontal beam  independent of damping.So S So that's a special case we'll set aside for the moment.
By specifying damping values other than 1, we can increase damping (damping > 1) to get flatter beams
From a purely mathematical point of view, damping and concaveness play a very similar role, because the tanhdamped numerator is divided by the sum of damping and concaveness.
The idea of achieving horizontal beams by dividing a denominator (that can never becom greater than 0.6) by an infinite damping value is absolutely correct, but there are numeric problems (see below).
While damping may theoretically lead to a very flat slope, according to the wellknown sit/straddle/hang rules even the faintest slope will be "rounded up" to a noticeable slant. That's why we need "infinite" damping to get actual 0 slopes.
The smallest remaining slope after damping will inevitably be "rounded up" as described.
As concaveness and damping play the exact same role in the damping formula, it suggests itself to treat them in the same way:
Why not setting the same threshold of 10000 for damping than it has already been done for concaveness?
That way, a damping value >= 10000 will force the beams to be horizontal completely avoiding numeric calamities:
if (concaveness >= 10000) +if ((concaveness >= 10000)  (damping >= 10000))
This would be, in my opinion, the preferable and consistent solution.
A concaveness value >= 10000 will lead to horizontal beaming, and so will a damping value of >= 10000.
Why should be a concavenss of 10000 be sufficient, but damping has to be inifinte if both play a similar role in the damping formula.
Full regression test passed.
As we have seen, the odd inconsistencies are a side effect of numeric rounding inaccuracies that can be avoided by avoiding the division by 2.
Original coding:
unquanted_y_[LEFT] += (dy  damped_dy) / 2; unquanted_y_[RIGHT] = (dy  damped_dy) / 2;
Easiest solution:
unquanted_y_[LEFT] += dy  damped_dy);
That way, left end will be changed by the full amount, thus avoiding the malicious division while leaving the right end untouched.
The absolute Y positions are not important, they will be adjusted anyway later on.
Safest solution
unquanted_y_[LEFT] = unquanted_y_[LEFT] + (dy  damped_dy)  ((dy  damped_dy) / 2); unquanted_y_[RIGHT] = (dy  damped_dy) / 2;
Sacrificing the += abbreviation is essential to avoid cumulation of rounding errors here.
LEFT and RIGHT unquanted_y values now are identical to the original coding, apart from the slight rounding problem 17 places after the decimal point.
Full regression test passed for both variants.
I'm well aware of the fact that conding discussions should take place in rietveld, but this time it's about deciding between two approaches.
As soon as we've agreed on one of the possible solutions, I'll upload a patch.
What do you think?
I'll favour the threshold solution (1)
Thanks
Torsten
[issues:#1493] Problem with horizontal beams
Status: Started
Created: Wed Jan 26, 2011 12:21 PM UTC by Anonymous
Last Updated: Mon Jan 15, 2018 04:36 PM UTC
Owner: Torsten Hämmerle
Attachments:
Originally created by: *anonymous
Originally created by: address@hidden
James Lowe :
There seems to be an inconsistency with setting horizontal beams.
We have a snippet where we state that
\override Beam #'damping = #+inf.0
Should generate horizontal beams in all cases.
However the simple example attached shows some odd inconsistencies.
\version "2.13.40"
\relative c'' {
\override Beam #'damping = #+inf.0
f16 g a b a c d g, a b a c d e f g, % all beams horizontal
f16 g a b a c d g, a b a c d e f g, % all beams horizontal
f16 g a b a c d g, a b a c d e f g, % 2nd and 4th group not Horizontal
f16 g a b a c d g, a b a c d e f g, % 2nd and 4th group not Horizontal
}
\relative c'' {
\override Beam #'damping = #+inf.0
f16 g a b a c d g, a b a c d e f g, \break % 4th group not Horizontal
f16 g a b a c d g, a b a c d e f g, \break % 2nd and 4th group not Horizontal
f16 g a b a c d g, a b a c d e f g, \break % 2nd and 4th group not Horizontal
f16 g a b a c d g, a b a c d e f g, \break % 2nd and 4th group not Horizontal
}
Phil Holmes :
I'd suggest the snippet is worth sorting out, too. What do you reckon  adding the commands
\override Beam #'details #'dampingdirectionpenalty = #0
\override Beam #'details #'roundtozeroslope = #0
to the existing snippet, or a new one pointed to by the old one, that says "if \override Beam #'damping = #+inf.0 doesn't do what you want, add the other commands too, as shown here"?
Sent from sourceforge.net because address@hidden is subscribed to https://sourceforge.net/p/testlilyissues/issues/
To unsubscribe from further messages, a project admin can change settings at https://sourceforge.net/p/testlilyissues/admin/issues/options. Or, if this is a mailing list, you can unsubscribe from the mailing list.
 Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________ Testlilyissuesauto mailing list address@hidden https://lists.sourceforge.net/lists/listinfo/testlilyissuesauto
[Prev in Thread]  Current Thread  [Next in Thread] 