]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/spacing-spanner.cc
patch::: 1.3.54.hwn2
[lilypond.git] / lily / spacing-spanner.cc
index 9c77ccea57ae7905b9486842676974d9e5233064..4b413ec6a8cc61d06498e992ef88e0ff93e1dad3 100644 (file)
@@ -3,83 +3,79 @@
   
   source file of the GNU LilyPond music typesetter
   
   
   source file of the GNU LilyPond music typesetter
   
-  (c) 1999 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 1999--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
 
 #include "spacing-spanner.hh"
   
  */
 
 #include "spacing-spanner.hh"
-#include "score-column.hh"
+#include "paper-column.hh"
 #include "dimensions.hh"
 #include "paper-def.hh"
 #include "warn.hh"
 #include "dimensions.hh"
 #include "paper-def.hh"
 #include "warn.hh"
-#include "p-score.hh"
+#include "paper-score.hh"
 #include "line-of-score.hh"
 #include "line-of-score.hh"
+#include "misc.hh"
 
 Spacing_spanner::Spacing_spanner ()
 {
 
 Spacing_spanner::Spacing_spanner ()
 {
-  set_elt_property (break_helper_only_scm_sym, SCM_BOOL_T);
-  set_elt_property (transparent_scm_sym, SCM_BOOL_T);
-}
-
-int
-Spacing_spanner::col_count () const
-{
-  return pscore_l_->line_l_->cols_.size ();
-}
-
-Score_column *
-Spacing_spanner::scol (int i)const
-{
-  return dynamic_cast<Score_column*> (pscore_l_->line_l_->cols_[i]);
+  set_extent_callback (0, X_AXIS);
+  set_extent_callback (0, Y_AXIS);  
+  set_elt_property ("transparent", SCM_BOOL_T);
 }
 
 /*
 }
 
 /*
-  cut 'n paste from spring-spacer.cc
-
-  generate springs between columns.
-
 
   The algorithm is partly taken from :
 
   John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
   OSU-CISRC-10/87-TR35, Department of Computer and Information
   Science, The Ohio State University, 1987.
 
   The algorithm is partly taken from :
 
   John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
   OSU-CISRC-10/87-TR35, Department of Computer and Information
   Science, The Ohio State University, 1987.
+
+  TOO HAIRY.
+
+  TODO: write comments 
   
  */
 Array<Spring>
   
  */
 Array<Spring>
-Spacing_spanner::do_measure (int col1, int col2) const
+Spacing_spanner::do_measure (Link_array<Paper_column> cols) const
 {
 {
-  for (int i =col1; i < col2; i++)
-    {
-      scol (i)->preprocess ();
-      scol (i)->print ();
-    }
-
   Moment shortest;
   Moment shortest;
+  Moment mean_shortest;
   shortest.set_infinite (1);
   shortest.set_infinite (1);
-  for (int i =col1; i < col2; i++)
+
+  int n = 0;
+  for (int i =0 ; i < cols.size (); i++)  
     {
     {
-      if (scol(i)->musical_b ())
+      if (cols[i]->musical_b ())
        {
        {
-         shortest = shortest <? scol(i)->shortest_starter_mom_;
+         SCM  st = cols[i]->get_elt_property ("shortest-starter-duration");
+         Moment this_shortest = (*SMOB_TO_TYPE(Moment, st));
+         shortest = shortest <? this_shortest;
+         if (!mean_shortest.infty_b ())
+           {
+             n++;
+             mean_shortest += this_shortest;
+           }
        }
     }
        }
     }
+  mean_shortest /= n;
 
   Array<Spring> meas_springs;
 
 
   Array<Spring> meas_springs;
 
-  for (int i= col1; i < col2; i++)
+  Real non_musical_space_strength = paper_l ()->get_var ("breakable_column_space_strength");
+  for (int i= 0; i < cols.size () - 1; i++)
     {
     {
-      Item * l = scol(i);
-      Item * r = scol(i+1);
+      Item * l = cols[i];
+      Item * r = cols[i+1];
       Item * lb = l->find_prebroken_piece (RIGHT);
       Item * rb = r->find_prebroken_piece (LEFT);      
 
       Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
 
       Item * lb = l->find_prebroken_piece (RIGHT);
       Item * rb = r->find_prebroken_piece (LEFT);      
 
       Item* combinations[4][2]={{l,r}, {lb,r}, {l,rb},{lb,rb}};
 
-      for (int i=0; i < 4; i++)
+      for (int j=0; j < 4; j++)
        {
        {
-         Score_column * lc = dynamic_cast<Score_column*> (combinations[i][0]);
-         Score_column *rc = dynamic_cast<Score_column*> (combinations[i][1]);
+         Paper_column * lc = dynamic_cast<Paper_column*> (combinations[j][0]);
+         Paper_column *rc = dynamic_cast<Paper_column*> (combinations[j][1]);
          if (!lc || !rc)
            continue;
 
          if (!lc || !rc)
            continue;
 
@@ -87,46 +83,92 @@ Spacing_spanner::do_measure (int col1, int col2) const
          s.item_l_drul_[LEFT] = lc;
          s.item_l_drul_[RIGHT] = rc;
          
          s.item_l_drul_[LEFT] = lc;
          s.item_l_drul_[RIGHT] = rc;
          
-         SCM hint = lc->get_elt_property (extra_space_scm_sym);
-         SCM next_hint = rc->get_elt_property (extra_space_scm_sym);
-       
-         if (hint != SCM_BOOL_F)
+         SCM hint = lc->get_elt_property ("extra-space");
+         SCM next_hint = rc->get_elt_property ("extra-space");
+         SCM stretch_hint = lc->get_elt_property ("stretch-distance");
+         SCM next_stretch_hint = rc->get_elt_property ("stretch-distance");      
+
+         Real left_distance;
+         if (gh_pair_p (hint))
            {
            {
-             hint = SCM_CDDR (hint);
-             
-             s.distance_f_ = gh_scm2double (hint); 
-             if (!lc->musical_b ())
-               s.strength_f_ = 2.0;
+             left_distance = gh_scm2double (gh_cdr (hint)); 
            }
            }
-         else if (!lc->musical_b() && i+1 < col_count())
+          // 2nd condition should be (i+1 < col_count()), ie. not the last column in score.  FIXME
+         else if (!lc->musical_b() && i+1 < cols.size ()) 
            {
            {
-             s.distance_f_ = default_bar_spacing (lc,rc,shortest);
-             s.strength_f_ = 2.0;
+             left_distance= default_bar_spacing (lc,rc,shortest);
            }
          else if (lc->musical_b())
            {
            }
          else if (lc->musical_b())
            {
-             s.distance_f_ = note_spacing (lc, rc, shortest);
-             
+             left_distance  = note_spacing (lc, rc, shortest);
            }
            }
+
+         s.distance_f_ = left_distance;
+
+         /*
+           Only do tight spaces *after* barlines (breakable columns),
+           not before.
+
+           We want the space before barline to be like the note
+           spacing in the measure.
+         */
+         if (lc->breakable_b () || lc->original_l_)
+           s.strength_f_ = non_musical_space_strength;
+         else if (!lc->musical_b ())
+           left_distance *= paper_l ()->get_var ("decrease_nonmus_spacing_factor");
+
          
          
-         if (next_hint != SCM_BOOL_F)
+         Real right_dist = 0.0;
+         if (gh_pair_p (next_hint))
            {
            {
-            next_hint = SCM_CADR(next_hint);
-            s.distance_f_ += gh_scm2double (next_hint);
+             right_dist += - gh_scm2double (gh_car (next_hint));
            }
          else
            {
              Interval ext (rc->extent (X_AXIS));
            }
          else
            {
              Interval ext (rc->extent (X_AXIS));
-             Real correction =  ext.empty_b() ? 0.0 : - ext [LEFT];
+             right_dist =  ext.empty_b() ? 0.0 : - ext [LEFT];
+           }
+
+         /*
+           don't want to create too much extra space for accidentals
+         */
+         if (lc->musical_b () && rc->musical_b ())
+           {
+             if (!to_boolean (rc->get_elt_property ("contains-grace")))
+               right_dist *= paper_l ()->get_var ("musical_to_musical_left_spacing_factor");
+           }
+
+         if (rc->musical_b () && to_boolean (rc->get_elt_property ("contains-grace")))
+           right_dist *= paper_l ()->get_var ("before_grace_spacing_factor");
+         s.distance_f_ = left_distance + right_dist;
+           
+         Real stretch_dist = 0.;
+         if (gh_number_p (stretch_hint))
+           stretch_dist += gh_scm2double (stretch_hint);
+         else
+           stretch_dist += left_distance;
+         
+         if (gh_pair_p (next_stretch_hint))
+           // see regtest spacing-tight
+           stretch_dist += - gh_scm2double (gh_car  (next_stretch_hint));
+         else
+           stretch_dist += right_dist;
 
 
+         if (s.distance_f_ <0)
+           {
+             programming_error("Negative dist, setting to 1.0 PT");
+             s.distance_f_ = 1.0;
+           }
+         if (stretch_dist == 0.0)
+           {
              /*
              /*
-               don't want to create too much extra space for accidentals
+               \bar "".  We give it 0 space, with high strength. 
               */
               */
-             if (lc->musical_b () && rc->musical_b ())
-               correction /= 2.0;
-
-             s.distance_f_ += correction;
+             s.strength_f_ = 20.0; 
            }
            }
+         else
+           s.strength_f_ /= stretch_dist;
          
          meas_springs.push (s);        
        }
          
          meas_springs.push (s);        
        }
@@ -139,44 +181,68 @@ Spacing_spanner::do_measure (int col1, int col2) const
    Do something if breakable column has no spacing hints set.
  */
 Real
    Do something if breakable column has no spacing hints set.
  */
 Real
-Spacing_spanner::default_bar_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
+Spacing_spanner::default_bar_spacing (Paper_column *lc, Paper_column *rc,
+                                     Moment shortest) const
 {
   Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
   Real durational_distance = 0;
   Moment delta_t =  rc->when_mom () - lc->when_mom () ;
 
 {
   Real symbol_distance = lc->extent (X_AXIS)[RIGHT] ;
   Real durational_distance = 0;
   Moment delta_t =  rc->when_mom () - lc->when_mom () ;
 
-             /*
+  /*
                ugh should use shortest_playing distance
                ugh should use shortest_playing distance
-             */
+  */
   if (delta_t)
     {
   if (delta_t)
     {
-      Real k=  paper_l()->arithmetic_constant (shortest);
-      durational_distance =  paper_l()->length_mom_to_dist (delta_t,k);
+      durational_distance =  get_duration_space (delta_t, shortest);
     }
 
   return  symbol_distance >? durational_distance;
 }
 
 
     }
 
   return  symbol_distance >? durational_distance;
 }
 
 
+/**
+  Get the measure wide constant for arithmetic spacing.
+
+  @see
+  John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
+  OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
+  The Ohio State University, 1987.
+
+  */
 Real
 Real
-Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shortest) const
+Spacing_spanner::get_duration_space (Moment d, Moment shortest) const
 {
 {
-  Moment shortest_playing_len = lc->shortest_playing_mom_;
+  Real log = log_2 (Moment (1,8) <? shortest);
+  Real k=   paper_l ()->get_var ("arithmetic_basicspace")
+    - log;
+  
+  return (log_2 (d) + k) * paper_l ()->get_var ("arithmetic_multiplier");
+}
+
+
+Real
+Spacing_spanner::note_spacing (Paper_column *lc, Paper_column *rc, Moment shortest) const
+{
+  Moment shortest_playing_len = 0;
+  SCM s = lc->get_elt_property ("shortest-playing-duration");
+  //  SCM s = lc->get_elt_property ("mean-playing-duration");  
+  if (SMOB_IS_TYPE_B(Moment, s))
+    shortest_playing_len = *SMOB_TO_TYPE (Moment, s);
+
+  
   if (! shortest_playing_len)
     {
   if (! shortest_playing_len)
     {
-      warning (_f ("can't find a ruling note at %s", 
-                  lc->when_mom ().str ()));
+      programming_error ("can't find a ruling note at " + lc->when_mom ().str ());
       shortest_playing_len = 1;
     }
       shortest_playing_len = 1;
     }
+  
   if (! shortest)
     {
   if (! shortest)
     {
-      warning (_f ("no minimum in measure at %s", 
-                  lc->when_mom ().str ()));
+      programming_error ("no minimum in measure at " + lc->when_mom ().str ());
       shortest = 1;
     }
   Moment delta_t = rc->when_mom () - lc->when_mom ();
       shortest = 1;
     }
   Moment delta_t = rc->when_mom () - lc->when_mom ();
-  Real k=  paper_l()->arithmetic_constant(shortest);
-  Real dist = paper_l()->length_mom_to_dist (shortest_playing_len, k);
+  Real dist = get_duration_space (shortest_playing_len, shortest);
   dist *= (double)(delta_t / shortest_playing_len);
 
   dist += stem_dir_correction (lc,rc);
   dist *= (double)(delta_t / shortest_playing_len);
 
   dist += stem_dir_correction (lc,rc);
@@ -192,29 +258,27 @@ Spacing_spanner::note_spacing (Score_column *lc, Score_column *rc, Moment shorte
    This should be more advanced, since relative heights of the note
    heads also influence required correction.
 
    This should be more advanced, since relative heights of the note
    heads also influence required correction.
 
-   Also might not work correctly ico. multi voices or staff changing voices
+   Also might not work correctly in case of multi voices or staff
+   changing voices
 
    TODO: lookup correction distances?  More advanced correction?
    Possibly turn this off?
 
 
    TODO: lookup correction distances?  More advanced correction?
    Possibly turn this off?
 
-   This routine reads the DIR_LIST property of both its L and R arguments.
-*/
+   This routine reads the DIR-LIST property of both its L and R arguments.  */
 Real
 Real
-Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
+Spacing_spanner::stem_dir_correction (Paper_column*l, Paper_column*r) const
 {
 {
-  SCM dl = l->get_elt_property (dir_list_scm_sym);
-  SCM dr = r->get_elt_property (dir_list_scm_sym);
-  if (dl == SCM_BOOL_F || dr == SCM_BOOL_F)
+  SCM dl = l->get_elt_property ("dir-list");
+  SCM dr = r->get_elt_property ("dir-list");
+  if (dl == SCM_UNDEFINED || dr == SCM_UNDEFINED)
     return 0.0;
 
     return 0.0;
 
-  dl = SCM_CDR (dl);
-  dr = SCM_CDR (dr);
 
   if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
     return 0.;
 
 
   if (scm_ilength (dl) != 1 && scm_ilength (dr) != 1)
     return 0.;
 
-  dl = SCM_CAR(dl);
-  dr = SCM_CAR(dr);
+  dl = gh_car (dl);
+  dr = gh_car (dr);
 
   assert (gh_number_p (dl) && gh_number_p(dr));
   int d1 = gh_scm2int (dl);
 
   assert (gh_number_p (dl) && gh_number_p(dr));
   int d1 = gh_scm2int (dl);
@@ -225,7 +289,7 @@ Spacing_spanner::stem_dir_correction (Score_column*l, Score_column*r) const
 
   bool err = false;
   Real correction = 0.0;
 
   bool err = false;
   Real correction = 0.0;
-  Real ssc = paper_l ()->get_realvar(ly_symbol ("stemSpacingCorrection"));
+  Real ssc = paper_l ()->get_var("stemSpacingCorrection");
 
 
   if (d1 && d2)
 
 
   if (d1 && d2)
@@ -251,18 +315,31 @@ Array<Spring>
 Spacing_spanner::get_springs () const
 {
   Array<Spring> springs;
 Spacing_spanner::get_springs () const
 {
   Array<Spring> springs;
-  int last_break =0;
-  for (int i=1; i < col_count (); i++)
+
+  Link_array<Paper_column> all (pscore_l_->line_l_->column_l_arr ()) ;
+
+  int j = 0;
+
+  for (int i = 1; i < all.size (); i++)
     {
     {
-      if (scol (i)->breakable_b ())
+      Paper_column* sc = dynamic_cast<Paper_column*> (all[i]);
+      if (sc->breakable_b ())
         {
         {
-          springs.concat (do_measure (last_break, i));
-          last_break  = i;
+         Link_array<Paper_column> measure (all.slice (j, i+1));          
+          springs.concat (do_measure (measure));
+         j = i;
         }
     }
         }
     }
+
+  /*
+    farewell, cruel world
+   */
+  ((Spacing_spanner*)this)->suicide ();
+  
   return springs;
 }
 
 
 
 
   return springs;
 }
 
 
 
 
+