]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam-quanting.cc
Run `make grand-replace'.
[lilypond.git] / lily / beam-quanting.cc
index d0a09e9530cf8027f109c919372a2b8bdb325d51..cf933d500bc3d3071d1386fdb172e8391bb51465 100644 (file)
@@ -3,7 +3,7 @@
 
   source file of the GNU LilyPond music typesetter
 
-  (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1997--2008 Han-Wen Nienhuys <hanwen@xs4all.nl>
   Jan Nieuwenhuizen <janneke@gnu.org>
 */
 
 #include <algorithm>
 using namespace std;
 
-#include "warn.hh"
-#include "staff-symbol-referencer.hh"
-#include "stem.hh"
+#include "grob.hh"
+#include "align-interface.hh"
+#include "international.hh"
 #include "output-def.hh"
 #include "pointer-group-interface.hh"
-#include "align-interface.hh"
+#include "staff-symbol-referencer.hh"
+#include "stem.hh"
+#include "warn.hh"
+#include "main.hh"
 
 Real
 get_detail (SCM alist, SCM sym, Real def)
@@ -34,15 +37,17 @@ Beam_quant_parameters::fill (Grob *him)
 {
   SCM details = him->get_property ("details");
 
+  /* 
+     TODO: The default values should be copied to define-grobs.scm.
+   */
   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);
+  HINT_DIRECTION_PENALTY = get_detail (details, ly_symbol2scm ("hint-direction-penalty"), 20);
   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);
@@ -60,8 +65,8 @@ struct Quant_score
   Real yr;
   Real demerits;
 
-#if DEBUG_QUANTING
-  String score_card_;
+#if DEBUG_BEAM_SCORING
+  string score_card_;
 #endif
 };
 
@@ -77,11 +82,11 @@ struct Quant_score
 */
 
 int
-best_quant_score_idx (Array<Quant_score> const &qscores)
+best_quant_score_idx (vector<Quant_score> const &qscores)
 {
   Real best = 1e6;
   int best_idx = -1;
-  for (int i = qscores.size (); i--;)
+  for (vsize i = qscores.size (); i--;)
     {
       if (qscores[i].demerits < best)
        {
@@ -93,23 +98,21 @@ best_quant_score_idx (Array<Quant_score> const &qscores)
   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);
 
   Beam_quant_parameters parameters;
   parameters.fill (me);
 
-  SCM s = me->get_property ("positions");
-  Real yl = scm_to_double (scm_car (s));
-  Real yr = scm_to_double (scm_cdr (s));
+  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
     divided by the current staff_space.
-
   */
   Real ss = Staff_symbol_referencer::staff_space (me);
   Real thickness = Beam::get_thickness (me) / ss;
@@ -123,14 +126,13 @@ Beam::quanting (SCM smob)
   Real quants [] = {straddle, sit, inter, hang };
 
   int num_quants = int (sizeof (quants) / sizeof (Real));
-  Array<Real> quantsl;
-  Array<Real> quantsr;
+  vector<Real> quantsl;
+  vector<Real> quantsr;
 
   /*
     going to REGION_SIZE == 2, yields another 0.6 second with
     wtk1-fugue2.
 
-
     (result indexes between 70 and 575)  ? --hwn.
 
   */
@@ -139,56 +141,56 @@ Beam::quanting (SCM smob)
     Do stem computations.  These depend on YL and YR linearly, so we can
     precompute for every stem 2 factors.
   */
-  Link_array<Grob> stems
+  vector<Grob*> stems
     = extract_grob_array (me, "stems");
-  Array<Stem_info> stem_infos;
-  Array<Real> base_lengths;
-  Array<Real> stem_xposns;
+  vector<Stem_info> stem_infos;
+  vector<Real> base_lengths;
+  vector<Real> stem_xposns;
 
   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));
 
-  Grob *fvs = first_visible_stem (me);
-  Grob *lvs = last_visible_stem (me);
+  Grob *fvs = first_normal_stem (me);
+  Grob *lvs = last_normal_stem (me);
   Real xl = fvs ? fvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
   Real xr = fvs ? lvs->relative_coordinate (common[X_AXIS], X_AXIS) : 0.0;
 
   /*
-    We store some info to quickly interpolate.
-
-    Sometimes my head is screwed on backwards.  The stemlength are
-    AFFINE linear in YL and YR. If YL == YR == 0, then we might have
+    We store some info to quickly interpolate.  The stemlength are
+    affine linear in YL and YR. If YL == YR == 0, then we might have
     stem_y != 0.0, when we're cross staff.
 
   */
-  for (int i = 0; i < stems.size (); i++)
+  for (vsize i = 0; i < stems.size (); i++)
     {
       Grob *s = stems[i];
 
       Stem_info si (Stem::get_stem_info (s));
       si.scale (1 / ss);
-      stem_infos.push (si);
-      dirs_found[stem_infos.top ().dir_] = true;
+      stem_infos.push_back (si);
+      dirs_found[stem_infos.back ().dir_] = true;
 
       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) / ss);
-      stem_xposns.push (s->relative_coordinate (common[X_AXIS], X_AXIS));
-    }
+      if (Stem::is_normal_stem (s))
+       {
+         base_lengths.push_back (calc_stem_y (me, s, common, xl, xr, CENTER, 
+                                              Interval (0, 0), f) / ss);
+       }
+      else
+       {
+         base_lengths.push_back (0);
+       }
 
-  bool xstaff = false;
-  if (lvs && fvs)
-    {
-      Grob *commony = fvs->common_refpoint (lvs, Y_AXIS);
-      xstaff = Align_interface::has_interface (commony);
+      stem_xposns.push_back (s->relative_coordinate (common[X_AXIS], X_AXIS));
     }
+  bool xstaff = Align_interface::has_interface (common[Y_AXIS]);
 
   Direction ldir = Direction (stem_infos[0].dir_);
-  Direction rdir = Direction (stem_infos.top ().dir_);
+  Direction rdir = Direction (stem_infos.back ().dir_);
   bool is_knee = dirs_found[LEFT] && dirs_found[RIGHT];
 
   int region_size = (int) parameters.REGION_SIZE;
@@ -205,28 +207,28 @@ Beam::quanting (SCM smob)
   for (int i = -region_size; i < region_size; i++)
     for (int j = 0; j < num_quants; j++)
       {
-       quantsl.push (i + quants[j] + int (yl));
-       quantsr.push (i + quants[j] + int (yr));
+       quantsl.push_back (i + quants[j] + int (yl));
+       quantsr.push_back (i + quants[j] + int (yr));
       }
 
-  Array<Quant_score> qscores;
+  vector<Quant_score> qscores;
 
-  for (int l = 0; l < quantsl.size (); l++)
-    for (int r = 0; r < quantsr.size (); r++)
+  for (vsize l = 0; l < quantsl.size (); l++)
+    for (vsize r = 0; r < quantsr.size (); r++)
       {
        Quant_score qs;
        qs.yl = quantsl[l];
        qs.yr = quantsr[r];
        qs.demerits = 0.0;
 
-       qscores.push (qs);
+       qscores.push_back (qs);
       }
 
   /* This is a longish function, but we don't separate this out into
      neat modular separate subfunctions, as the subfunctions would be
      called for many values of YL, YR. By precomputing various
      parameters outside of the loop, we can save a lot of time. */
-  for (int i = qscores.size (); i--;)
+  for (vsize i = qscores.size (); i--;)
     {
       Real d = score_slopes_dy (qscores[i].yl, qscores[i].yr,
                                dy_mus, yr- yl,
@@ -234,7 +236,7 @@ Beam::quanting (SCM smob)
                                xstaff, &parameters);
       qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
       qscores[i].score_card_ += to_string ("S%.2f", d);
 #endif
     }
@@ -242,12 +244,12 @@ Beam::quanting (SCM smob)
   Real rad = Staff_symbol_referencer::staff_radius (me);
   Drul_array<int> edge_beam_counts
     (Stem::beam_multiplicity (stems[0]).length () + 1,
-     Stem::beam_multiplicity (stems.top ()).length () + 1);
+     Stem::beam_multiplicity (stems.back ()).length () + 1);
 
   Real beam_translation = get_beam_translation (me) / ss;
 
   Real reasonable_score = (is_knee) ? 200000 : 100;
-  for (int i = qscores.size (); i--;)
+  for (vsize i = qscores.size (); i--;)
     if (qscores[i].demerits < reasonable_score)
       {
        Real d = score_forbidden_quants (qscores[i].yl, qscores[i].yr,
@@ -255,12 +257,12 @@ Beam::quanting (SCM smob)
                                         edge_beam_counts, ldir, rdir, &parameters);
        qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
        qscores[i].score_card_ += to_string (" F %.2f", d);
 #endif
       }
 
-  for (int i = qscores.size (); i--;)
+  for (vsize i = qscores.size (); i--;)
     if (qscores[i].demerits < reasonable_score)
       {
        Real d = score_stem_lengths (stems, stem_infos,
@@ -270,24 +272,22 @@ Beam::quanting (SCM smob)
                                     qscores[i].yl, qscores[i].yr, &parameters);
        qscores[i].demerits += d;
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
        qscores[i].score_card_ += to_string (" L %.2f", d);
 #endif
       }
 
   int best_idx = best_quant_score_idx (qscores);
 
-#if DEBUG_QUANTING
+#if DEBUG_BEAM_SCORING
   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-scoring")))
       && scm_is_pair (inspect_quants))
     {
       Drul_array<Real> ins = ly_scm2interval (inspect_quants);
 
-      int i = 0;
-
       Real mindist = 1e6;
-      for (; i < qscores.size (); i++)
+      for (vsize i = 0; i < qscores.size (); i++)
        {
          Real d = fabs (qscores[i].yl- ins[LEFT]) + fabs (qscores[i].yr - ins[RIGHT]);
          if (d < mindist)
@@ -297,38 +297,42 @@ Beam::quanting (SCM smob)
            }
        }
       if (mindist > 1e5)
-       programming_error ("can't find quant");
+       programming_error ("cannot find quant");
     }
 #endif
+
+  Interval final_positions;
   if (best_idx < 0)
     {
       warning (_ ("no feasible beam position"));
-      me->set_property ("positions", ly_interval2scm (Interval (0, 0)));
+      final_positions = Interval (0, 0);
     }
   else
-    me->set_property ("positions",
-                     ly_interval2scm (Drul_array<Real> (qscores[best_idx].yl,
-                                                        qscores[best_idx].yr)));
-#if DEBUG_QUANTING
+    {
+      final_positions = Drul_array<Real> (qscores[best_idx].yl,
+                                         qscores[best_idx].yr);
+    }
+  
+#if DEBUG_BEAM_SCORING
   if (best_idx >= 0
-      && to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting"))))
+      && to_boolean (me->layout ()->lookup_variable (ly_symbol2scm ("debug-beam-scoring"))))
     {
       qscores[best_idx].score_card_ += to_string ("i%d", best_idx);
 
       // debug quanting
       me->set_property ("quant-score",
-                       scm_makfrom0str (qscores[best_idx].score_card_.to_str0 ()));
+                       ly_string2scm (qscores[best_idx].score_card_));
     }
 #endif
 
-  return SCM_UNSPECIFIED;
+  return ly_interval2scm (final_positions);
 }
 
 Real
-Beam::score_stem_lengths (Link_array<Grob> const &stems,
-                         Array<Stem_info> const &stem_infos,
-                         Array<Real> const &base_stem_ys,
-                         Array<Real> const &stem_xs,
+Beam::score_stem_lengths (vector<Grob*> const &stems,
+                         vector<Stem_info> const &stem_infos,
+                         vector<Real> const &base_stem_ys,
+                         vector<Real> const &stem_xs,
                          Real xl, Real xr,
                          bool knee,
                          Real yl, Real yr,
@@ -339,10 +343,10 @@ Beam::score_stem_lengths (Link_array<Grob> const &stems,
   Drul_array<Real> score (0, 0);
   Drul_array<int> count (0, 0);
 
-  for (int i = 0; i < stems.size (); i++)
+  for (vsize i = 0; i < stems.size (); i++)
     {
       Grob *s = stems[i];
-      if (Stem::is_invisible (s))
+      if (!Stem::is_normal_stem (s))
        continue;
 
       Real x = stem_xs[i];
@@ -373,8 +377,7 @@ Beam::score_stem_lengths (Link_array<Grob> const &stems,
   Direction d = DOWN;
   do
     score[d] /= max (count[d], 1);
-  while (flip (&d) != DOWN)
-    ;
+  while (flip (&d) != DOWN);
 
   return score[LEFT] + score[RIGHT];
 }
@@ -397,10 +400,19 @@ 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) > parameters->ROUND_TO_ZERO_SLOPE
-      && sign (dy_damp) != sign (dy))
-    dem += parameters->DAMPING_DIRECTION_PENALTY;
-
+  if (sign (dy_damp) != sign (dy))
+    {
+      if (!dy)
+       {
+         if (fabs (dy_damp / dx) > parameters->ROUND_TO_ZERO_SLOPE)
+           dem += parameters->DAMPING_DIRECTION_PENALTY;
+         else
+           dem += parameters->HINT_DIRECTION_PENALTY;
+       }
+      else
+       dem += parameters->DAMPING_DIRECTION_PENALTY;
+    }
+  
   dem += parameters->MUSICAL_DIRECTION_FACTOR
     * max (0.0, (fabs (dy) - fabs (dy_mus)));