source file of the GNU LilyPond music typesetter
- (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+ (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
Jan Nieuwenhuizen <janneke@gnu.org>
*/
#include "beam.hh"
#include <algorithm>
-#include <math.h>
+using namespace std;
#include "warn.hh"
#include "staff-symbol-referencer.hh"
#include "stem.hh"
#include "output-def.hh"
-#include "group-interface.hh"
+#include "pointer-group-interface.hh"
#include "align-interface.hh"
-const int INTER_QUANT_PENALTY = 1000;
-const Real SECONDARY_BEAM_DEMERIT = 10.0;
-const int STEM_LENGTH_DEMERIT_FACTOR = 5;
+Real
+get_detail (SCM alist, SCM sym, Real def)
+{
+ SCM entry = scm_assq (sym, alist);
-/*
- threshold to combat rounding errors.
-*/
-const Real BEAM_EPS = 1e-3;
+ if (scm_is_pair (entry))
+ return robust_scm2double (scm_cdr (entry), def);
+ return def;
+}
-// possibly ridiculous, but too short stems just won't do
-const int STEM_LENGTH_LIMIT_PENALTY = 5000;
-const int DAMPING_DIRECTION_PENALTY = 800;
-const int MUSICAL_DIRECTION_FACTOR = 400;
-const int IDEAL_SLOPE_FACTOR = 10;
-const Real ROUND_TO_ZERO_SLOPE = 0.02;
+void
+Beam_quant_parameters::fill (Grob *him)
+{
+ SCM details = him->get_property ("details");
+
+ INTER_QUANT_PENALTY = get_detail (details, ly_symbol2scm ("inter-quant-penalty"), 1000.0);
+ SECONDARY_BEAM_DEMERIT = get_detail (details, ly_symbol2scm ("secondary-beam-demerit"), 10.0);
+ STEM_LENGTH_DEMERIT_FACTOR = get_detail (details, ly_symbol2scm ("stem-length-demerit-factor"), 5);
+ REGION_SIZE = get_detail (details, ly_symbol2scm ("region-size"), 2);
+ BEAM_EPS = get_detail (details, ly_symbol2scm ("beam-eps"), 1e-3);
+
+ // possibly ridiculous, but too short stems just won't do
+ STEM_LENGTH_LIMIT_PENALTY = get_detail (details, ly_symbol2scm ("stem-length-limit-penalty"), 5000);
+ DAMPING_DIRECTION_PENALTY = get_detail (details, ly_symbol2scm ("damping-direction-penalty"), 800);
+ MUSICAL_DIRECTION_FACTOR = get_detail (details, ly_symbol2scm ("musical-direction-factor"), 400);
+ IDEAL_SLOPE_FACTOR = get_detail (details, ly_symbol2scm ("ideal-slope-factor"), 10);
+ ROUND_TO_ZERO_SLOPE = get_detail (details, ly_symbol2scm ("round-to-zero-slope"), 0.02);
+}
static Real
shrink_extra_weight (Real x, Real fac)
}
}
- if (best_idx < 0)
- {
- programming_error ("no best beam quant score");
- best_idx = 0;
- }
-
return best_idx;
}
-MAKE_SCHEME_CALLBACK (Beam, quanting, 1);
+MAKE_SCHEME_CALLBACK (Beam, quanting, 2);
SCM
-Beam::quanting (SCM smob)
+Beam::quanting (SCM smob, SCM posns)
{
Grob *me = unsmob_grob (smob);
- SCM s = me->get_property ("positions");
- Real yl = scm_to_double (scm_car (s));
- Real yr = scm_to_double (scm_cdr (s));
+ Beam_quant_parameters parameters;
+ parameters.fill (me);
+
+ Real yl = scm_to_double (scm_car (posns));
+ Real yr = scm_to_double (scm_cdr (posns));
/*
Calculations are relative to a unit-scaled staff, i.e. the quants are
precompute for every stem 2 factors.
*/
Link_array<Grob> stems
- = extract_grob_array (me, ly_symbol2scm ("stems"));
+ = extract_grob_array (me, "stems");
Array<Stem_info> stem_infos;
Array<Real> base_lengths;
Array<Real> stem_xposns;
Direction rdir = Direction (stem_infos.top ().dir_);
bool is_knee = dirs_found[LEFT] && dirs_found[RIGHT];
- int region_size = REGION_SIZE;
+ int region_size = (int) parameters.REGION_SIZE;
+
/*
Knees are harder, lets try some more possibilities for knees.
*/
Real d = score_slopes_dy (qscores[i].yl, qscores[i].yr,
dy_mus, yr- yl,
xr - xl,
- xstaff);
+ xstaff, ¶meters);
qscores[i].demerits += d;
#if DEBUG_QUANTING
{
Real d = score_forbidden_quants (qscores[i].yl, qscores[i].yr,
rad, slt, thickness, beam_translation,
- edge_beam_counts, ldir, rdir);
+ edge_beam_counts, ldir, rdir, ¶meters);
qscores[i].demerits += d;
#if DEBUG_QUANTING
base_lengths, stem_xposns,
xl, xr,
is_knee,
- qscores[i].yl, qscores[i].yr);
+ qscores[i].yl, qscores[i].yr, ¶meters);
qscores[i].demerits += d;
#if DEBUG_QUANTING
#if DEBUG_QUANTING
SCM inspect_quants = me->get_property ("inspect-quants");
- if (to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
+ if (to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
&& scm_is_pair (inspect_quants))
{
Drul_array<Real> ins = ly_scm2interval (inspect_quants);
}
#endif
- me->set_property ("positions",
- ly_interval2scm (Drul_array<Real> (qscores[best_idx].yl,
- qscores[best_idx].yr)));
+ Interval final_positions;
+ if (best_idx < 0)
+ {
+ warning (_ ("no feasible beam position"));
+ final_positions = Interval (0, 0);
+ }
+ else
+ {
+ final_positions = Drul_array<Real> (qscores[best_idx].yl,
+ qscores[best_idx].yr);
+ }
+
#if DEBUG_QUANTING
- if (to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
+ if (best_idx >= 0
+ && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
{
qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
}
#endif
- return SCM_UNSPECIFIED;
+ return ly_interval2scm (final_positions);
}
Real
Array<Real> const &stem_xs,
Real xl, Real xr,
bool knee,
- Real yl, Real yr)
+ Real yl, Real yr,
+
+ Beam_quant_parameters const *parameters)
{
- Real limit_penalty = STEM_LENGTH_LIMIT_PENALTY;
+ Real limit_penalty = parameters->STEM_LENGTH_LIMIT_PENALTY;
Drul_array<Real> score (0, 0);
Drul_array<int> count (0, 0);
Real dx = xr - xl;
Real beam_y = dx ? yr * (x - xl) / dx + yl * (xr - x) / dx : (yr + yl) / 2;
Real current_y = beam_y + base_stem_ys[i];
- Real length_pen = STEM_LENGTH_DEMERIT_FACTOR;
+ Real length_pen = parameters->STEM_LENGTH_DEMERIT_FACTOR;
Stem_info info = stem_infos[i];
Direction d = info.dir_;
- score[d] += limit_penalty * max (0.0, (d * (info.shortest_y_ - current_y)));
+ score[d] += limit_penalty * max (0.0, (d * (info.shortest_y_ - current_y)));
Real ideal_diff = d * (current_y - info.ideal_y_);
Real ideal_score = shrink_extra_weight (ideal_diff, 1.5);
Direction d = DOWN;
do
- {
- score[d] /= max (count[d], 1);
- }
- while (flip (&d) != DOWN);
+ score[d] /= max (count[d], 1);
+ while (flip (&d) != DOWN)
+ ;
return score[LEFT] + score[RIGHT];
}
Beam::score_slopes_dy (Real yl, Real yr,
Real dy_mus, Real dy_damp,
Real dx,
- bool xstaff)
+ bool xstaff,
+
+ Beam_quant_parameters const *parameters)
{
Real dy = yr - yl;
Real dem = 0.0;
TODO: find a way to incorporate the complexity of the beam in this
penalty.
*/
- if (fabs (dy / dx) > ROUND_TO_ZERO_SLOPE
+ if (fabs (dy / dx) > parameters->ROUND_TO_ZERO_SLOPE
&& sign (dy_damp) != sign (dy))
- {
- dem += DAMPING_DIRECTION_PENALTY;
- }
+ dem += parameters->DAMPING_DIRECTION_PENALTY;
- dem += MUSICAL_DIRECTION_FACTOR * max (0.0, (fabs (dy) - fabs (dy_mus)));
+ dem += parameters->MUSICAL_DIRECTION_FACTOR
+ * max (0.0, (fabs (dy) - fabs (dy_mus)));
- Real slope_penalty = IDEAL_SLOPE_FACTOR;
+ Real slope_penalty = parameters->IDEAL_SLOPE_FACTOR;
/* Xstaff beams tend to use extreme slopes to get short stems. We
put in a penalty here. */
Real slt,
Real thickness, Real beam_translation,
Drul_array<int> beam_counts,
- Direction ldir, Direction rdir)
+ Direction ldir, Direction rdir,
+
+ Beam_quant_parameters const *parameters)
{
Real dy = yr - yl;
Drul_array<Real> y (yl, yr);
Drul_array<Direction> dirs (ldir, rdir);
- Real extra_demerit = SECONDARY_BEAM_DEMERIT / (max (beam_counts[LEFT], beam_counts[RIGHT]));
+ Real extra_demerit = parameters->SECONDARY_BEAM_DEMERIT / (max (beam_counts[LEFT], beam_counts[RIGHT]));
Direction d = LEFT;
Real dem = 0.0;
+ Real eps = parameters->BEAM_EPS;
do
{
gap.add_point (gap2);
for (Real k = -radius;
- k <= radius + BEAM_EPS; k += 1.0)
+ k <= radius + eps; k += 1.0)
if (gap.contains (k))
{
Real dist = min (fabs (gap[UP] - k), fabs (gap[DOWN] - k));
if (beam_counts[d] >= 2
&& fabs (y[d] - dirs[d] * beam_translation) < radius + inter)
{
- if (dirs[d] == UP && dy <= BEAM_EPS
- && fabs (my_modf (y[d]) - sit) < BEAM_EPS)
+ if (dirs[d] == UP && dy <= eps
+ && fabs (my_modf (y[d]) - sit) < eps)
dem += extra_demerit;
- if (dirs[d] == DOWN && dy >= BEAM_EPS
- && fabs (my_modf (y[d]) - hang) < BEAM_EPS)
+ if (dirs[d] == DOWN && dy >= eps
+ && fabs (my_modf (y[d]) - hang) < eps)
dem += extra_demerit;
}
if (beam_counts[d] >= 3
&& fabs (y[d] - 2 * dirs[d] * beam_translation) < radius + inter)
{
- if (dirs[d] == UP && dy <= BEAM_EPS
- && fabs (my_modf (y[d]) - straddle) < BEAM_EPS)
+ if (dirs[d] == UP && dy <= eps
+ && fabs (my_modf (y[d]) - straddle) < eps)
dem += extra_demerit;
- if (dirs[d] == DOWN && dy >= BEAM_EPS
- && fabs (my_modf (y[d]) - straddle) < BEAM_EPS)
+ if (dirs[d] == DOWN && dy >= eps
+ && fabs (my_modf (y[d]) - straddle) < eps)
dem += extra_demerit;
}
}