source file of the GNU LilyPond music typesetter
- (c) 1997--2003 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
+
+
*/
#include <math.h>
#include "warn.hh"
-#include "grob.hh"
#include "staff-symbol-referencer.hh"
#include "beam.hh"
#include "stem.hh"
-#include "paper-def.hh"
+#include "output-def.hh"
#include "group-interface.hh"
#include "align-interface.hh"
const Real SECONDARY_BEAM_DEMERIT = 10.0;
const int STEM_LENGTH_DEMERIT_FACTOR = 5;
+/*
+ threshold to combat rounding errors.
+ */
+const Real BEAM_EPS = 1e-3;
+
// possibly ridiculous, but too short stems just won't do
const int STEM_LENGTH_LIMIT_PENALTY = 5000;
-const int DAMPING_DIRECTIION_PENALTY = 800;
+const int DAMPING_DIRECTION_PENALTY = 800;
const int MUSICAL_DIRECTION_FACTOR = 400;
const int IDEAL_SLOPE_FACTOR = 10;
-
-extern bool debug_beam_quanting_flag;
+const Real ROUND_TO_ZERO_SLOPE = 0.02;
static Real
shrink_extra_weight (Real x, Real fac)
*/
-int best_quant_score_idx (Array<Quant_score> const & qscores)
+int
+best_quant_score_idx (Array<Quant_score> const & qscores)
{
Real best = 1e6;
int best_idx = -1;
}
}
+ if (best_idx < 0)
+ {
+ programming_error ("Huh? No best beam quant score?");
+ best_idx = 0;
+ }
+
+
return best_idx;
}
{
Grob *me = unsmob_grob (smob);
- SCM s = me->get_grob_property ("positions");
- Real yl = gh_scm2double (gh_car (s));
- Real yr = gh_scm2double (gh_cdr (s));
+ SCM s = me->get_property ("positions");
+ Real yl = scm_to_double (scm_car (s));
+ Real yr = scm_to_double (scm_cdr (s));
- Real ss = Staff_symbol_referencer::staff_space (me);
- Real thickness = gh_scm2double (me->get_grob_property ("thickness")) / ss;
- Real slt = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness")) / ss;
+ /*
+ Calculations are relative to a unit-scaled staff, i.e. the quants are
+ divided by the current staff_space.
+
+ */
+ Real ss = Staff_symbol_referencer::staff_space (me);
+ Real thickness = Beam::get_thickness (me) / ss ;
+ Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
- SCM sdy = me->get_grob_property ("least-squares-dy");
- Real dy_mus = gh_number_p (sdy) ? gh_scm2double (sdy) : 0.0;
-
+ Real dy_mus = robust_scm2double (me->get_property ("least-squares-dy"), 0);
Real straddle = 0.0;
Real sit = (thickness - slt) / 2;
Real inter = 0.5;
Real hang = 1.0 - (thickness - slt) / 2;
Real quants [] = {straddle, sit, inter, hang };
+
+
int num_quants = int (sizeof (quants)/sizeof (Real));
Array<Real> quantsl;
Array<Real> base_lengths;
Array<Real> stem_xposns;
- Drul_array<bool> dirs_found(0,0);
+ Drul_array<bool> dirs_found (0,0);
Grob *common[2];
for (int a = 2; a--;)
- common[a] = common_refpoint_of_array (stems, me, Axis(a));
+ common[a] = common_refpoint_of_array (stems, me, Axis (a));
Grob * fvs = first_visible_stem (me);
Grob *lvs = last_visible_stem (me);
stem_y != 0.0, when we're cross staff.
*/
- for (int i= 0; i < stems.size(); i++)
+ for (int i= 0; i < stems.size (); i++)
{
Grob*s = stems[i];
- stem_infos.push (Stem::get_stem_info (s));
+
+ Stem_info si (Stem::get_stem_info (s));
+ si.scale (1 / ss);
+ stem_infos.push (si);
dirs_found[stem_infos.top ().dir_] = true;
- bool f = to_boolean (s->get_grob_property ("french-beaming"))
+ bool f = to_boolean (s->get_property ("french-beaming"))
&& s != lvs && s != fvs;
base_lengths.push (calc_stem_y (me, s, common, xl, xr,
- Interval (0,0), f));
+ Interval (0,0), f) / ss);
stem_xposns.push (s->relative_coordinate (common[X_AXIS], X_AXIS));
}
Direction ldir = Direction (stem_infos[0].dir_);
Direction rdir = Direction (stem_infos.top ().dir_);
- bool knee_b = dirs_found[LEFT] && dirs_found[RIGHT];
+ bool is_knee = dirs_found[LEFT] && dirs_found[RIGHT];
int region_size = REGION_SIZE;
/*
Knees are harder, lets try some more possibilities for knees.
*/
- if (knee_b)
+ if (is_knee)
region_size += 2;
/*
for (int i = qscores.size (); i--;)
{
Real d = score_slopes_dy (qscores[i].yl, qscores[i].yr,
- dy_mus, yr- yl, xstaff);
+ dy_mus, yr- yl,
+ xr - xl,
+ xstaff);
qscores[i].demerits += d;
#if DEBUG_QUANTING
}
Real rad = Staff_symbol_referencer::staff_radius (me);
- int beam_count = get_beam_count (me);
- Real beam_translation = get_beam_translation (me);
- Real reasonable_score = (knee_b) ? 200000 : 100;
+
+
+ Drul_array<int> edge_beam_counts
+ (Stem::beam_multiplicity (stems[0]).length () + 1,
+ Stem::beam_multiplicity (stems.top ()).length () + 1);
+
+ Real beam_translation = get_beam_translation (me) / ss;
+
+ Real reasonable_score = (is_knee) ? 200000 : 100;
for (int i = qscores.size (); i--;)
if (qscores[i].demerits < reasonable_score)
{
Real d = score_forbidden_quants (qscores[i].yl, qscores[i].yr,
rad, slt, thickness, beam_translation,
- beam_count, ldir, rdir);
+ edge_beam_counts, ldir, rdir);
qscores[i].demerits += d;
#if DEBUG_QUANTING
Real d=score_stem_lengths (stems, stem_infos,
base_lengths, stem_xposns,
xl, xr,
- knee_b,
+ is_knee,
qscores[i].yl, qscores[i].yr);
qscores[i].demerits += d;
int best_idx = best_quant_score_idx (qscores);
-
#if DEBUG_QUANTING
- SCM inspect_quants = me->get_grob_property ("inspect-quants");
- if (debug_beam_quanting_flag
- && gh_pair_p (inspect_quants))
+ SCM inspect_quants = me->get_property ("inspect-quants");
+ if (to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
+ && scm_is_pair (inspect_quants))
{
- Real il = gh_scm2double (gh_car (inspect_quants));
- Real ir = gh_scm2double (gh_cdr (inspect_quants));
+ Drul_array<Real> ins = ly_scm2interval (inspect_quants);
int i = 0;
Real mindist = 1e6;
- for (; i < qscores.size(); i ++)
+ for (; i < qscores.size (); i ++)
{
- Real d =fabs (qscores[i].yl-il) + fabs (qscores[i].yr - ir);
+ Real d =fabs (qscores[i].yl- ins[LEFT]) + fabs (qscores[i].yr - ins[RIGHT]);
if (d < mindist)
{
best_idx = i;
}
#endif
- me->set_grob_property ("positions",
- gh_cons (gh_double2scm (qscores[best_idx].yl),
- gh_double2scm (qscores[best_idx].yr)));
+ me->set_property ("positions",
+ ly_interval2scm (Drul_array<Real> (qscores[best_idx].yl,
+ qscores[best_idx].yr)));
#if DEBUG_QUANTING
- if (debug_beam_quanting_flag)
+ if (to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
{
qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
// debug quanting
- me->set_grob_property ("quant-score",
- scm_makfrom0str (qscores[best_idx].score_card_.to_str0 ()));
+ me->set_property ("quant-score",
+ scm_makfrom0str (qscores[best_idx].score_card_.to_str0 ()));
}
#endif
for (int i=0; i < stems.size (); i++)
{
Grob* s = stems[i];
- if (Stem::invisible_b (s))
+ if (Stem::is_invisible (s))
continue;
Real x = stem_xs[i];
Real
Beam::score_slopes_dy (Real yl, Real yr,
Real dy_mus, Real dy_damp,
+ Real dx,
bool xstaff)
{
Real dy = yr - yl;
-
Real dem = 0.0;
- if (sign (dy_damp) != sign (dy))
+
+ /*
+ DAMPING_DIRECTION_PENALTY is a very harsh measure, while for
+ complex beaming patterns, horizontal is often a good choice.
+
+ TODO: find a way to incorporate the complexity of the beam in this
+ penalty.
+ */
+ if (fabs (dy/dx) > ROUND_TO_ZERO_SLOPE
+ && sign (dy_damp) != sign (dy))
{
- dem += DAMPING_DIRECTIION_PENALTY;
+ dem += DAMPING_DIRECTION_PENALTY;
}
dem += MUSICAL_DIRECTION_FACTOR * (0 >? (fabs (dy) - fabs (dy_mus)));
/* Huh, why would a too steep beam be better than a too flat one ? */
dem += shrink_extra_weight (fabs (dy_damp) - fabs (dy), 1.5)
* slope_penalty;
+
return dem;
}
+
static Real
my_modf (Real x)
{
Real radius,
Real slt,
Real thickness, Real beam_translation,
- int beam_count,
+ Drul_array<int> beam_counts,
Direction ldir, Direction rdir)
{
Real dy = yr - yl;
- Drul_array<Real> y(yl,yr);
- Drul_array<Direction> dirs(ldir,rdir);
+ Drul_array<Real> y (yl,yr);
+ Drul_array<Direction> dirs (ldir,rdir);
- Real extra_demerit = SECONDARY_BEAM_DEMERIT / beam_count;
+ Real extra_demerit = SECONDARY_BEAM_DEMERIT / (beam_counts[LEFT] >? beam_counts[RIGHT]);
- /*
- Inside the staff, inter quants are forbidden.
- */
- Real dem = 0.0;
Direction d = LEFT;
- do
- {
- if (fabs (y[d]) <= (radius + 0.5) && fabs (my_modf (y[d]) - 0.5) < 1e-3)
- dem += INTER_QUANT_PENALTY;
- }
- while ((flip (&d))!= LEFT);
-
+ Real dem = 0.0;
+
- for (int j = 1; j <= beam_count; j++)
+ do
{
- do
+ for (int j = 1; j <= beam_counts[d]; j++)
{
- /*
- see if the outer staffline falls in a beam-gap
-
- This test is too weak; we should really check all lines.
- */
Direction stem_dir = dirs[d];
- Real gap1 = y[d] - stem_dir * ((j-1) * beam_translation + thickness / 2 - slt/2 );
- Real gap2 = y[d] - stem_dir * (j * beam_translation - thickness / 2 + slt/2);
+
+ /*
+ The 2.2 factor is to provide a little leniency for
+ borderline cases. If we do 2.0, then the upper outer line
+ will be in the gap of the (2,sit) quant, leading to a
+ false demerit.
+ */
+ Real gap1 = y[d] - stem_dir * ((j-1) * beam_translation + thickness / 2 - slt/2.2 );
+ Real gap2 = y[d] - stem_dir * (j * beam_translation - thickness / 2 + slt/2.2);
Interval gap;
gap.add_point (gap1);
gap.add_point (gap2);
- if (gap.elem_b (radius))
- dem += extra_demerit;
+ for (Real k = - radius ;
+ k <= radius + BEAM_EPS; k += 1.0)
+ if (gap.contains (k))
+ {
+ Real dist = fabs (gap[UP]-k) <? fabs (gap[DOWN] - k);
+
+ /*
+ this parameter is tuned to grace-stem-length.ly
+ */
+ Real fixed_demerit = 0.4;
+
+ dem += extra_demerit
+ * (fixed_demerit +
+ (1-fixed_demerit) * (dist / gap.length())* 2);
+ }
}
- while ((flip (&d))!= LEFT);
}
+ while ((flip (&d))!= LEFT);
-
- // todo: use beam_count of outer stems.
- if (beam_count >= 2)
+ if ((beam_counts[LEFT] >? beam_counts[RIGHT]) >= 2)
{
Real straddle = 0.0;
Real sit = (thickness - slt) / 2;
Real inter = 0.5;
Real hang = 1.0 - (thickness - slt) / 2;
- Real eps = 1e-3;
-
- // hmm, without Interval/Drul_array, you get ~ 4x same code...
- if (fabs (y[LEFT] - dirs[LEFT] * beam_translation) < radius + inter)
- {
- if (dirs[LEFT] == UP && dy <= eps
- && fabs (my_modf (y[LEFT]) - sit) < eps)
- dem += extra_demerit;
-
- if (dirs[LEFT] == DOWN && dy >= eps
- && fabs (my_modf (y[LEFT]) - hang) < eps)
- dem += extra_demerit;
- }
- if (fabs (y[RIGHT] - dirs[RIGHT] * beam_translation) < radius + inter)
- {
- if (dirs[RIGHT] == UP && dy >= eps
- && fabs (my_modf (y[RIGHT]) - sit) < eps)
- dem += extra_demerit;
-
- if (dirs[RIGHT] == DOWN && dy <= eps
- && fabs (my_modf (y[RIGHT]) - hang) < eps)
- dem += extra_demerit;
- }
-
- if (beam_count >= 3)
+ Direction d = LEFT;
+ do
{
- if (fabs (y[LEFT] - 2 * dirs[LEFT] * beam_translation) < radius + inter)
+ if (beam_counts[d] >= 2
+ && fabs (y[d] - dirs[d] * beam_translation) < radius + inter)
{
- if (dirs[LEFT] == UP && dy <= eps
- && fabs (my_modf (y[LEFT]) - straddle) < eps)
+ if (dirs[d] == UP && dy <= BEAM_EPS
+ && fabs (my_modf (y[d]) - sit) < BEAM_EPS)
dem += extra_demerit;
-
- if (dirs[LEFT] == DOWN && dy >= eps
- && fabs (my_modf (y[LEFT]) - straddle) < eps)
+
+ if (dirs[d] == DOWN && dy >= BEAM_EPS
+ && fabs (my_modf (y[d]) - hang) < BEAM_EPS)
dem += extra_demerit;
}
-
- if (fabs (y[RIGHT] - 2 * dirs[RIGHT] * beam_translation) < radius + inter)
+
+ if (beam_counts[d] >= 3
+ && fabs (y[d] - 2 * dirs[d] * beam_translation) < radius + inter)
{
- if (dirs[RIGHT] == UP && dy >= eps
- && fabs (my_modf (y[RIGHT]) - straddle) < eps)
+ if (dirs[d] == UP && dy <= BEAM_EPS
+ && fabs (my_modf (y[d]) - straddle) < BEAM_EPS)
dem += extra_demerit;
- if (dirs[RIGHT] == DOWN && dy <= eps
- && fabs (my_modf (y[RIGHT]) - straddle) < eps)
+ if (dirs[d] == DOWN && dy >= BEAM_EPS
+ && fabs (my_modf (y[d]) - straddle) < BEAM_EPS)
dem += extra_demerit;
}
}
+ while (flip (&d) != LEFT);
}
return dem;