]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam-quanting.cc
(class Grob): move pscore, dim_cache_,
[lilypond.git] / lily / beam-quanting.cc
index eb9d3b0c8c0c5154ab917e2dd7856c8156d911fa..5f44ef840cf2fa4b8892d4cf0622c20f6fa44fcc 100644 (file)
@@ -7,31 +7,46 @@
   Jan Nieuwenhuizen <janneke@gnu.org>
 */
 
-#include <math.h>
+#include "beam.hh"
+
+#include <algorithm>
+using namespace std;
 
 #include "warn.hh"
 #include "staff-symbol-referencer.hh"
-#include "beam.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)
@@ -75,24 +90,20 @@ best_quant_score_idx (Array<Quant_score> const &qscores)
        }
     }
 
-  if (best_idx < 0)
-    {
-      programming_error ("Huh? 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
@@ -128,7 +139,7 @@ Beam::quanting (SCM smob)
     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;
@@ -179,7 +190,8 @@ Beam::quanting (SCM smob)
   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.
   */
@@ -218,7 +230,7 @@ Beam::quanting (SCM smob)
       Real d = score_slopes_dy (qscores[i].yl, qscores[i].yr,
                                dy_mus, yr- yl,
                                xr - xl,
-                               xstaff);
+                               xstaff, &parameters);
       qscores[i].demerits += d;
 
 #if DEBUG_QUANTING
@@ -239,7 +251,7 @@ Beam::quanting (SCM smob)
       {
        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, &parameters);
        qscores[i].demerits += d;
 
 #if DEBUG_QUANTING
@@ -254,7 +266,7 @@ Beam::quanting (SCM smob)
                                     base_lengths, stem_xposns,
                                     xl, xr,
                                     is_knee,
-                                    qscores[i].yl, qscores[i].yr);
+                                    qscores[i].yl, qscores[i].yr, &parameters);
        qscores[i].demerits += d;
 
 #if DEBUG_QUANTING
@@ -266,7 +278,7 @@ Beam::quanting (SCM smob)
 
 #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);
@@ -284,15 +296,25 @@ Beam::quanting (SCM smob)
            }
        }
       if (mindist > 1e5)
-       programming_error ("Could not find quant.");
+       programming_error ("can't find quant");
     }
 #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);
 
@@ -302,7 +324,7 @@ Beam::quanting (SCM smob)
     }
 #endif
 
-  return SCM_UNSPECIFIED;
+  return ly_interval2scm (final_positions);
 }
 
 Real
@@ -312,9 +334,11 @@ Beam::score_stem_lengths (Link_array<Grob> const &stems,
                          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);
 
@@ -328,12 +352,12 @@ Beam::score_stem_lengths (Link_array<Grob> const &stems,
       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 * (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);
@@ -351,10 +375,9 @@ Beam::score_stem_lengths (Link_array<Grob> const &stems,
 
   Direction d = DOWN;
   do
-    {
-      score[d] /= (count[d] >? 1);
-    }
-  while (flip (&d) != DOWN);
+    score[d] /= max (count[d], 1);
+  while (flip (&d) != DOWN)
+    ;
 
   return score[LEFT] + score[RIGHT];
 }
@@ -363,7 +386,9 @@ Real
 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;
@@ -375,15 +400,14 @@ Beam::score_slopes_dy (Real yl, Real yr,
     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 *(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. */
@@ -414,16 +438,19 @@ Beam::score_forbidden_quants (Real yl, Real yr,
                              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 / (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
     {
@@ -445,10 +472,10 @@ Beam::score_forbidden_quants (Real yl, Real yr,
          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 = fabs (gap[UP] - k) <? fabs (gap[DOWN] - k);
+               Real dist = min (fabs (gap[UP] - k), fabs (gap[DOWN] - k));
 
                /*
                  this parameter is tuned to grace-stem-length.ly
@@ -463,7 +490,7 @@ Beam::score_forbidden_quants (Real yl, Real yr,
     }
   while ((flip (&d)) != LEFT);
 
-  if ((beam_counts[LEFT] >? beam_counts[RIGHT]) >= 2)
+  if (max (beam_counts[LEFT], beam_counts[RIGHT]) >= 2)
     {
       Real straddle = 0.0;
       Real sit = (thickness - slt) / 2;
@@ -476,24 +503,24 @@ Beam::score_forbidden_quants (Real yl, Real yr,
          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;
            }
        }