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". # Numerical precision: rounding problem 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.5511e-17 original dy = -0.431074, DELTA unquanted_y = 2.7756e-17 original dy = 1.301622, DELTA unquanted_y = 0.0000e+00 original dy = -0.680277, DELTA unquanted_y = -5.5511e-17 original dy = -0.431074, DELTA unquanted_y = 2.7756e-17 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.7756e-17 original dy = -0.679738, DELTA unquanted_y = 5.5511e-17 original dy = 1.303842, DELTA unquanted_y = 0.0000e+00 original dy = -0.428570, DELTA unquanted_y = 2.7756e-17 original dy = -0.679738, DELTA unquanted_y = 5.5511e-17 ~~~ 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 ~~~ # Damping mechanism 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: ![](https://upload.wikimedia.org/wikipedia/commons/8/87/Hyperbolic_Tangent.svg) * It's symmetric to the origin and can be used both for positive and negative slopes * For small |x|, there is practically no damping at all * |tanh(x)| will never become greater than 1, however large x may be. * For values of |x| > 3, tanh(x) is practically 1. 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 non-concave 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 tanh-damped 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). # "Rounding up" While damping may theoretically lead to a very flat slope, according to the well-known 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. # Proposed solution (1) 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. # Proposed solution (2) 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. # Solution (1) or (2)? 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:** - [beams.ly](https://sourceforge.net/p/testlilyissues/issues/1493/attachment/beams.ly) (807 Bytes; application/octet-stream) - [screenshot.png](https://sourceforge.net/p/testlilyissues/issues/1493/attachment/screenshot.png) (18.9 kB; image/png) *Originally created by:* *anonymous *Originally created by:* [ralphbug...@gmail.com](http://code.google.com/u/106131861630194758622/) 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 \#'damping-direction-penalty = \#0 \override Beam \#'details \#'round-to-zero-slope = \#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 testlilyissues-a...@lists.sourceforge.net 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

_______________________________________________ Testlilyissues-auto mailing list testlilyissues-a...@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/testlilyissues-auto