]> git.donarmstrong.com Git - lilypond.git/blobdiff - lily/beam.cc
(convert-to-dvi): redirect output to
[lilypond.git] / lily / beam.cc
index ebec7111a432c1a2944d619bd7b8fa70b02f627f..dcf2e1893a10f58a5e773e9f2c8fa4ddd818954a 100644 (file)
@@ -3,21 +3,22 @@
   
   source file of the GNU LilyPond music typesetter
   
   
   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>
 */
 
 /*
 TODO:
 
   Jan Nieuwenhuizen <janneke@gnu.org>
 */
 
 /*
 TODO:
 
-  * Use Number_pair i.s.o Interval to represent (yl, yr).
-  
   - Determine auto knees based on positions if it's set by the user.
 
   - Determine auto knees based on positions if it's set by the user.
 
+  - the code is littered with * and / staff_space calls for
+    #'positions. Consider moving to real-world coordinates?
 
 
+    Problematic issue is user tweaks (user tweaks are in staff-coordinates.) 
+  
 Notes:
 
 Notes:
 
-
  - Stems run to the Y-center of the beam.
   
  - beam_translation is the offset between Y centers of the beam.
  - Stems run to the Y-center of the beam.
   
  - beam_translation is the offset between Y centers of the beam.
@@ -27,14 +28,15 @@ Notes:
 
 #include <math.h> // tanh.
 
 
 #include <math.h> // tanh.
 
-#include "molecule.hh" 
+#include "interval-set.hh"
+#include "stencil.hh" 
 #include "directional-element-interface.hh"
 #include "beaming.hh"
 #include "beam.hh"
 #include "misc.hh"
 #include "least-squares.hh"
 #include "stem.hh"
 #include "directional-element-interface.hh"
 #include "beaming.hh"
 #include "beam.hh"
 #include "misc.hh"
 #include "least-squares.hh"
 #include "stem.hh"
-#include "paper-def.hh"
+#include "output-def.hh"
 #include "lookup.hh"
 #include "group-interface.hh"
 #include "staff-symbol-referencer.hh"
 #include "lookup.hh"
 #include "group-interface.hh"
 #include "staff-symbol-referencer.hh"
@@ -43,9 +45,6 @@ Notes:
 #include "warn.hh"
 
 
 #include "warn.hh"
 
 
-#define DEBUG_QUANTING 0
-
-
 #if DEBUG_QUANTING
 #include "text-item.hh"  // debug output.
 #include "font-interface.hh"  // debug output.
 #if DEBUG_QUANTING
 #include "text-item.hh"  // debug output.
 #include "font-interface.hh"  // debug output.
@@ -60,7 +59,7 @@ Beam::add_stem (Grob *me, Grob *s)
   s->add_dependency (me);
 
   assert (!Stem::get_beam (s));
   s->add_dependency (me);
 
   assert (!Stem::get_beam (s));
-  s->set_grob_property ("beam", me->self_scm ());
+  s->set_property ("beam", me->self_scm ());
 
   add_bound_item (dynamic_cast<Spanner*> (me), dynamic_cast<Item*> (s));
 }
 
   add_bound_item (dynamic_cast<Spanner*> (me), dynamic_cast<Item*> (s));
 }
@@ -69,20 +68,25 @@ Beam::add_stem (Grob *me, Grob *s)
 Real
 Beam::get_thickness (Grob * me)
 {
 Real
 Beam::get_thickness (Grob * me)
 {
-  SCM th = me->get_grob_property ("thickness");
-  if (gh_number_p (th))
-    return gh_scm2double (th)* Staff_symbol_referencer::staff_space (me);
-  else
-    return 0.0;
+  return robust_scm2double (me->get_property ("thickness"), 0)
+    * Staff_symbol_referencer::staff_space (me);
 }
 
 /* Return the translation between 2 adjoining beams. */
 Real
 Beam::get_beam_translation (Grob *me)
 {
 }
 
 /* Return the translation between 2 adjoining beams. */
 Real
 Beam::get_beam_translation (Grob *me)
 {
-  SCM func = me->get_grob_property ("space-function");
-  SCM s = gh_call2 (func, me->self_scm (), scm_int2num (get_beam_count (me)));
-  return gh_scm2double (s);
+  SCM func = me->get_property ("space-function");
+
+  if (ly_c_procedure_p (func))
+    {
+      SCM s = scm_call_2 (func, me->self_scm (), scm_int2num (get_beam_count (me)));
+      return scm_to_double (s);
+    }
+  else
+    {
+      return 0.81;
+    }
 }
 
 /* Maximum beam_count. */
 }
 
 /* Maximum beam_count. */
@@ -90,9 +94,9 @@ int
 Beam::get_beam_count (Grob *me) 
 {
   int m = 0;
 Beam::get_beam_count (Grob *me) 
 {
   int m = 0;
-  for (SCM s = me->get_grob_property ("stems"); gh_pair_p (s); s = ly_cdr (s))
+  for (SCM s = me->get_property ("stems"); scm_is_pair (s); s = scm_cdr (s))
     {
     {
-      Grob *stem = unsmob_grob (ly_car (s));
+      Grob *stem = unsmob_grob (scm_car (s));
       m = m >? (Stem::beam_multiplicity (stem).length () + 1);
     }
   return m;
       m = m >? (Stem::beam_multiplicity (stem).length () + 1);
     }
   return m;
@@ -109,14 +113,14 @@ Beam::space_function (SCM smob, SCM beam_count)
   Grob *me = unsmob_grob (smob);
   
   Real staff_space = Staff_symbol_referencer::staff_space (me);
   Grob *me = unsmob_grob (smob);
   
   Real staff_space = Staff_symbol_referencer::staff_space (me);
-  Real line = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness"));
+  Real line = Staff_symbol_referencer::line_thickness (me);
   Real thickness = get_thickness (me);
   
   Real thickness = get_thickness (me);
   
-  Real beam_translation = gh_scm2int (beam_count) < 4
+  Real beam_translation = scm_to_int (beam_count) < 4
     ? (2*staff_space + line - thickness) / 2.0
     : (3*staff_space + line - thickness) / 3.0;
   
     ? (2*staff_space + line - thickness) / 2.0
     : (3*staff_space + line - thickness) / 3.0;
   
-  return gh_double2scm (beam_translation);
+  return scm_make_real (beam_translation);
 }
 
 
 }
 
 
@@ -145,12 +149,12 @@ Beam::before_line_breaking (SCM smob)
     {
       me->warning (_ ("beam has less than two visible stems"));
 
     {
       me->warning (_ ("beam has less than two visible stems"));
 
-      SCM stems = me->get_grob_property ("stems");
+      SCM stems = me->get_property ("stems");
       if (scm_ilength (stems) == 1)
        {
       if (scm_ilength (stems) == 1)
        {
-         me->warning (_ ("Beam has less than two stems. Removing beam."));
+         me->warning (_ ("removing beam with less than two stems"));
 
 
-         unsmob_grob (gh_car (stems))->set_grob_property ("beam", SCM_EOL);
+         unsmob_grob (scm_car (stems))->set_property ("beam", SCM_EOL);
          me->suicide ();
 
          return SCM_UNSPECIFIED;
          me->suicide ();
 
          return SCM_UNSPECIFIED;
@@ -196,7 +200,7 @@ position_with_maximal_common_beams (SCM left_beaming, SCM right_beaming,
                                    Direction left_dir,
                                    Direction right_dir)
 {
                                    Direction left_dir,
                                    Direction right_dir)
 {
-  Slice lslice = int_list_to_slice (gh_cdr (left_beaming));
+  Slice lslice = int_list_to_slice (scm_cdr (left_beaming));
 
   int best_count = 0;
   int best_start = 0;
 
   int best_count = 0;
   int best_start = 0;
@@ -204,10 +208,10 @@ position_with_maximal_common_beams (SCM left_beaming, SCM right_beaming,
        (i - lslice[left_dir])* left_dir <= 0 ; i+= left_dir) 
     {
       int count =0;
        (i - lslice[left_dir])* left_dir <= 0 ; i+= left_dir) 
     {
       int count =0;
-      for ( SCM s = gh_car (right_beaming); gh_pair_p (s); s = gh_cdr (s))
+      for ( SCM s = scm_car (right_beaming); scm_is_pair (s); s = scm_cdr (s))
        {
        {
-         int k = - right_dir * gh_scm2int (gh_car (s)) + i;
-         if (scm_memq (scm_int2num (k), left_beaming) != SCM_BOOL_F)
+         int k = - right_dir * scm_to_int (scm_car (s)) + i;
+         if (scm_c_memq (scm_int2num (k), left_beaming) != SCM_BOOL_F)
            count ++;
        }
 
            count ++;
        }
 
@@ -228,16 +232,16 @@ Beam::connect_beams (Grob *me)
     Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
 
   Slice last_int;
     Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
 
   Slice last_int;
-  last_int.set_empty();
+  last_int.set_empty ();
   SCM last_beaming = SCM_EOL;
   Direction last_dir = CENTER;
   SCM last_beaming = SCM_EOL;
   Direction last_dir = CENTER;
-  for (int i = 0; i< stems.size(); i++)
+  for (int i = 0; i< stems.size (); i++)
     {
       Grob *this_stem = stems[i];
     {
       Grob *this_stem = stems[i];
-      SCM this_beaming = this_stem->get_grob_property ("beaming");
+      SCM this_beaming = this_stem->get_property ("beaming");
 
 
-      Direction this_dir = Directional_element_interface::get(this_stem);
-      if (gh_pair_p (last_beaming) && gh_pair_p (this_beaming))
+      Direction this_dir = get_grob_direction (this_stem);
+      if (scm_is_pair (last_beaming) && scm_is_pair (this_beaming))
        {
          int start_point = position_with_maximal_common_beams
            (last_beaming, this_beaming,
        {
          int start_point = position_with_maximal_common_beams
            (last_beaming, this_beaming,
@@ -247,45 +251,45 @@ Beam::connect_beams (Grob *me)
          Slice new_slice ; 
          do
            {
          Slice new_slice ; 
          do
            {
-             if (d == RIGHT && i == stems.size()-1)
+             if (d == RIGHT && i == stems.size ()-1)
                continue;
              
                continue;
              
-             new_slice.set_empty();
+             new_slice.set_empty ();
              SCM s = index_get_cell (this_beaming, d);
              SCM s = index_get_cell (this_beaming, d);
-             for (; gh_pair_p (s); s = gh_cdr (s))
+             for (; scm_is_pair (s); s = scm_cdr (s))
                {
                  int new_beam_pos =
                {
                  int new_beam_pos =
-                   start_point - this_dir * gh_scm2int (gh_car (s));
+                   start_point - this_dir * scm_to_int (scm_car (s));
 
                  new_slice.add_point (new_beam_pos);
 
                  new_slice.add_point (new_beam_pos);
-                 gh_set_car_x (s, scm_int2num (new_beam_pos));
+                 scm_set_car_x (s, scm_int2num (new_beam_pos));
                }
 
 
            }
          while (flip (&d) != LEFT);
 
                }
 
 
            }
          while (flip (&d) != LEFT);
 
-         if (!new_slice.empty_b())
+         if (!new_slice.is_empty ())
            last_int =  new_slice;
        }
       else
        {
            last_int =  new_slice;
        }
       else
        {
-         gh_set_car_x ( this_beaming, SCM_EOL);
-         SCM s = gh_cdr (this_beaming);
-         for (; gh_pair_p (s); s = gh_cdr (s))
+         scm_set_car_x ( this_beaming, SCM_EOL);
+         SCM s = scm_cdr (this_beaming);
+         for (; scm_is_pair (s); s = scm_cdr (s))
            {
            {
-             int np = - this_dir * gh_scm2int (gh_car(s));
-             gh_set_car_x (s, scm_int2num (np));
+             int np = - this_dir * scm_to_int (scm_car (s));
+             scm_set_car_x (s, scm_int2num (np));
              last_int.add_point (np);
            }
        }
 
       if (i == stems.size () -1)
        {
              last_int.add_point (np);
            }
        }
 
       if (i == stems.size () -1)
        {
-         gh_set_cdr_x (this_beaming, SCM_EOL);
+         scm_set_cdr_x (this_beaming, SCM_EOL);
        }
 
        }
 
-      if (scm_ilength (gh_cdr (this_beaming)) > 0)
+      if (scm_ilength (scm_cdr (this_beaming)) > 0)
        {
          last_beaming = this_beaming;
          last_dir = this_dir;
        {
          last_beaming = this_beaming;
          last_dir = this_dir;
@@ -293,15 +297,24 @@ Beam::connect_beams (Grob *me)
     }
  }
 
     }
  }
 
-MAKE_SCHEME_CALLBACK (Beam, brew_molecule, 1);
+
+/*
+  TODO: should not make beams per stem, but per Y-level.
+ */
+MAKE_SCHEME_CALLBACK (Beam, print, 1);
 SCM
 SCM
-Beam::brew_molecule (SCM grob)
+Beam::print (SCM grob)
 {
 {
-  Grob *me = unsmob_grob (grob);
+  Spanner *me = unsmob_spanner (grob);
+  position_beam (me);
+  
   Link_array<Grob> stems=
     Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
   Grob* xcommon = common_refpoint_of_array (stems, me, X_AXIS);
 
   Link_array<Grob> stems=
     Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
   Grob* xcommon = common_refpoint_of_array (stems, me, X_AXIS);
 
+  xcommon = me->get_bound (LEFT)->common_refpoint (xcommon, X_AXIS);
+  xcommon = me->get_bound (RIGHT)->common_refpoint (xcommon, X_AXIS);
+
   Real x0, dx;
   if (visible_stem_count (me))
     {
   Real x0, dx;
   if (visible_stem_count (me))
     {
@@ -315,58 +328,60 @@ Beam::brew_molecule (SCM grob)
       dx = stems.top ()->relative_coordinate (xcommon, X_AXIS) - x0;
     }
 
       dx = stems.top ()->relative_coordinate (xcommon, X_AXIS) - x0;
     }
 
-  SCM posns = me->get_grob_property ("positions");
-  Interval pos;
-  if (!ly_number_pair_p (posns))
+  SCM posns = me->get_property ("positions");
+  Drul_array<Real> pos;
+  if (!is_number_pair (posns))
     {
       programming_error ("No beam posns");
       pos = Interval (0,0);
     }
   else
     {
       programming_error ("No beam posns");
       pos = Interval (0,0);
     }
   else
-    pos= ly_scm2interval (posns);
+    pos= ly_scm2realdrul (posns);
 
 
-  Real dy = pos.delta ();
-  Real dydx = dy && dx ? dy/dx : 0;
+  scale_drul (&pos,  Staff_symbol_referencer::staff_space (me));
+  
+  Real dy = pos[RIGHT] - pos[LEFT];
+  Real slope = (dy && dx) ? dy/dx : 0;
   
   Real thick = get_thickness (me);
   Real bdy = get_beam_translation (me);
 
   
   Real thick = get_thickness (me);
   Real bdy = get_beam_translation (me);
 
-  SCM last_beaming = SCM_EOL;;
+  SCM last_beaming = SCM_EOL;
   Real last_xposn = -1;
   Real last_xposn = -1;
-  Real last_width = -1 ;
-
+  Real last_stem_width = -1 ;
 
 
-  SCM gap = me->get_grob_property ("gap");
-  Molecule the_beam;
-  Real lt = me->get_paper ()->get_realvar (ly_symbol2scm ("linethickness"));
+  Real gap_length = robust_scm2double (me->get_property ("gap"), 0.0);
   
   
-  for (int i = 0; i<= stems.size(); i++)
+  Stencil the_beam;
+  Real lt = me->get_layout ()->get_dimension (ly_symbol2scm ("linethickness"));
+  
+  for (int i = 0; i<= stems.size (); i++)
     {
     {
-      Grob * st = (i < stems.size()) ? stems[i] : 0;
+      Grob * st = (i < stems.size ()) ? stems[i] : 0;
       
       
-      SCM this_beaming = st ? st->get_grob_property ("beaming") : SCM_EOL;
+      SCM this_beaming = st ? st->get_property ("beaming") : SCM_EOL;
       Real xposn = st ? st->relative_coordinate (xcommon, X_AXIS) : 0.0;
       Real xposn = st ? st->relative_coordinate (xcommon, X_AXIS) : 0.0;
-      Real stem_width = st ? gh_scm2double (st->get_grob_property ("thickness")) *lt : 0 ;
-
+      Real stem_width = st ? robust_scm2double (st->get_property ("thickness"), 1.0) *lt : 0 ;
+      Direction stem_dir = st ? to_dir (st->get_property ("direction")) : CENTER;
       /*
        We do the space left of ST, with lfliebertjes pointing to the
        right from the left stem, and rfliebertjes pointing left from
        right stem.
        */
       /*
        We do the space left of ST, with lfliebertjes pointing to the
        right from the left stem, and rfliebertjes pointing left from
        right stem.
        */
-      SCM left = (i>0) ? gh_cdr (last_beaming) : SCM_EOL;
-      SCM right = st ? gh_car (this_beaming) : SCM_EOL;
+      SCM left = (i > 0) ? scm_cdr (last_beaming) : SCM_EOL;
+      SCM right = st ? scm_car (this_beaming) : SCM_EOL;
 
 
-      Array<int> fullbeams;
+      Array<int> full_beams;
       Array<int> lfliebertjes;
       Array<int> rfliebertjes;   
 
       for (SCM s = left;
       Array<int> lfliebertjes;
       Array<int> rfliebertjes;   
 
       for (SCM s = left;
-          gh_pair_p (s); s =gh_cdr (s))
+          scm_is_pair (s); s =scm_cdr (s))
        {
        {
-         int b = gh_scm2int (gh_car (s));
-         if (scm_memq (gh_car(s), right) != SCM_BOOL_F)
+         int b = scm_to_int (scm_car (s));
+         if (scm_c_memq (scm_car (s), right) != SCM_BOOL_F)
            {
            {
-             fullbeams.push (b);
+             full_beams.push (b);
            }
          else
            {
            }
          else
            {
@@ -374,10 +389,10 @@ Beam::brew_molecule (SCM grob)
            }
        }
       for (SCM s = right;
            }
        }
       for (SCM s = right;
-          gh_pair_p (s); s =gh_cdr (s))
+          scm_is_pair (s); s =scm_cdr (s))
        {
        {
-         int b = gh_scm2int (gh_car (s));
-         if (scm_memq (gh_car(s), left) == SCM_BOOL_F)
+         int b = scm_to_int (scm_car (s));
+         if (scm_c_memq (scm_car (s), left) == SCM_BOOL_F)
            {
              rfliebertjes.push (b);
            }
            {
              rfliebertjes.push (b);
            }
@@ -387,37 +402,51 @@ Beam::brew_molecule (SCM grob)
        how much to stick out for beams across linebreaks
        */
       Real break_overshoot = 3.0;
        how much to stick out for beams across linebreaks
        */
       Real break_overshoot = 3.0;
-      Real w = (i>0 && st)? xposn - last_xposn : break_overshoot;
-      Real stem_offset = 0.0;
-      Real width_corr = 0.0;
-      if (i == 1)
+      Real w = (i > 0 && st) ? (xposn - last_xposn) : break_overshoot;
+
+      Real stem_offset =0.0;
+      if (i > 0)
        {
        {
-         stem_offset -= last_width/2;
-         width_corr += last_width/2;
+         w += last_stem_width / 2;
+         stem_offset = -last_stem_width / 2;
        }
        }
-         
-      if (i == stems.size() -1)
+
+      if (st)
+       w += stem_width/ 2 ;
+      
+
+      Real blot = me->get_layout ()->get_dimension (ly_symbol2scm ("blotdiameter"));
+      Stencil whole = Lookup::beam (slope, w, thick, blot);
+      Stencil gapped;
+
+      int gap_count = 0;
+      if (scm_is_number (me->get_property ("gap-count")))
        {
        {
-         width_corr += stem_width/2;
+         gap_count = scm_to_int (me->get_property ("gap-count"));
+         gapped = Lookup::beam (slope, w - 2 * gap_length, thick, blot);
+
+         full_beams.sort (default_compare);
+         if (stem_dir == UP)
+           full_beams.reverse ();
        }
 
        }
 
-      if (gh_number_p (gap))
+      int k = 0;
+      for (int j = full_beams.size (); j--;)
        {
        {
-         Real g = gh_scm2double (gap);
-         stem_offset += g;
-         width_corr -= 2*g; 
-       }
+         Stencil b (whole);
          
          
-      Molecule whole = Lookup::beam (dydx, w + width_corr, thick);
-      for (int j = fullbeams.size(); j--;)
-       {
-         Molecule b (whole);
+         if (k++ < gap_count)
+           {
+             b = gapped;
+             b.translate_axis (gap_length, X_AXIS);
+           }
          b.translate_axis (last_xposn -  x0 + stem_offset, X_AXIS);
          b.translate_axis (last_xposn -  x0 + stem_offset, X_AXIS);
-         b.translate_axis (dydx * (last_xposn - x0) + bdy * fullbeams[j], Y_AXIS);
-         the_beam.add_molecule (b);          
-       }
+         b.translate_axis (slope * (last_xposn - x0) + bdy * full_beams[j], Y_AXIS);
 
 
-      if (lfliebertjes.size() || rfliebertjes.size())
+         the_beam.add_stencil (b);           
+       }
+         
+      if (lfliebertjes.size () || rfliebertjes.size ())
        {
          Real nw_f;
 
        {
          Real nw_f;
 
@@ -425,38 +454,53 @@ Beam::brew_molecule (SCM grob)
            {
              int t = Stem::duration_log (st); 
 
            {
              int t = Stem::duration_log (st); 
 
-             SCM proc = me->get_grob_property ("flag-width-function");
-             SCM result = gh_call1 (proc, scm_int2num (t));
-             nw_f = gh_scm2double (result);
+             SCM proc = me->get_property ("flag-width-function");
+             SCM result = scm_call_1 (proc, scm_int2num (t));
+             nw_f = scm_to_double (result);
            }
          else
            }
          else
-           nw_f = break_overshoot;
+           nw_f = break_overshoot / 2;
              
          /* Half beam should be one note-width,
             but let's make sure two half-beams never touch */
              
          /* Half beam should be one note-width,
             but let's make sure two half-beams never touch */
-         Real w = (i>0 && st) ? (xposn - last_xposn) : break_overshoot;
-         w = w/2 <? nw_f;
+         Real lw = nw_f;
+         Real rw = nw_f;
+         if (i > 0)
+           rw = nw_f <? ( (xposn - last_xposn) / 2);
+         else
+           /*
+             TODO: 0.5 is a guess.
+           */
+           rw = xposn - me->get_bound (LEFT)->extent (xcommon, X_AXIS)[RIGHT]
+             - 0.5;
+         
+         if (st)
+           lw = nw_f <? ( (xposn - last_xposn) / 2);
+         else
+           lw = me->get_bound (RIGHT)->relative_coordinate (xcommon, X_AXIS)
+             - last_xposn;
 
 
-         Molecule half = Lookup::beam (dydx, w, thick);
-         for (int j = lfliebertjes.size(); j--;)
+         Stencil rhalf = Lookup::beam (slope, rw, thick, blot);
+         Stencil lhalf = Lookup::beam (slope, lw, thick, blot);
+         for (int j = lfliebertjes.size (); j--;)
            {
            {
-             Molecule b (half);
+             Stencil b (lhalf);
              b.translate_axis (last_xposn -  x0, X_AXIS);
              b.translate_axis (last_xposn -  x0, X_AXIS);
-             b.translate_axis (dydx * (last_xposn-x0) + bdy * lfliebertjes[j], Y_AXIS);
-             the_beam.add_molecule (b);              
+             b.translate_axis (slope * (last_xposn-x0) + bdy * lfliebertjes[j], Y_AXIS);
+             the_beam.add_stencil (b);       
            }
            }
-         for (int j = rfliebertjes.size(); j--;)
+         for (int j = rfliebertjes.size (); j--;)
            {
            {
-             Molecule b (half);
-             b.translate_axis (xposn -  x0 - w , X_AXIS);
-             b.translate_axis (dydx * (xposn-x0 -w) + bdy * rfliebertjes[j], Y_AXIS);
-             the_beam.add_molecule (b);              
+             Stencil b (rhalf);
+             b.translate_axis (xposn -  x0 - rw , X_AXIS);
+             b.translate_axis (slope * (xposn-x0 -rw) + bdy * rfliebertjes[j], Y_AXIS);
+             the_beam.add_stencil (b);       
            }
        }
 
 
       last_xposn = xposn;
            }
        }
 
 
       last_xposn = xposn;
-      last_width = stem_width;
+      last_stem_width = stem_width;
       last_beaming = this_beaming;
     }
 
       last_beaming = this_beaming;
     }
 
@@ -464,32 +508,28 @@ Beam::brew_molecule (SCM grob)
   the_beam.translate_axis (pos[LEFT], Y_AXIS);
 
 #if (DEBUG_QUANTING)
   the_beam.translate_axis (pos[LEFT], Y_AXIS);
 
 #if (DEBUG_QUANTING)
+  SCM quant_score = me->get_property ("quant-score");
+  if (to_boolean (me->get_layout ()->lookup_variable (ly_symbol2scm ("debug-beam-quanting")))
+      && scm_is_string (quant_score))
     {
     {
+      
       /*
        This code prints the demerits for each beam. Perhaps this
        should be switchable for those who want to twiddle with the
        parameters.
       */
       String str;
       /*
        This code prints the demerits for each beam. Perhaps this
        should be switchable for those who want to twiddle with the
        parameters.
       */
       String str;
-      if (1)
-       {
-         str += to_string (gh_scm2int (me->get_grob_property ("best-idx")));
-         str += ":";
-       }
-      str += to_string (gh_scm2double (me->get_grob_property ("quant-score")),
-                    "%.2f");
+      SCM properties = Font_interface::text_font_alist_chain (me);
 
 
-      SCM properties = Font_interface::font_alist_chain (me);
-
-      Molecule tm = Text_item::interpret_new_markup
-       (me->self_scm(),  properties, scm_makfrom0str (str.to_str0 ()));
-      the_beam.add_at_edge (Y_AXIS, UP, tm, 5.0, 0);
+      Direction stem_dir = stems.size() ? to_dir (stems[0]->get_property ("direction")) : UP;
+    
+      Stencil tm = *unsmob_stencil (Text_interface::interpret_markup
+        (me->get_layout ()->self_scm (), properties, quant_score));
+      the_beam.add_at_edge (Y_AXIS, stem_dir, tm, 1.0, 0);
     }
 #endif
     }
 #endif
-    
   
   
-  
-  return the_beam.smobbed_copy();
+  return the_beam.smobbed_copy ();
 }
   
 
 }
   
 
@@ -507,12 +547,12 @@ Beam::get_default_dir (Grob *me)
   Link_array<Grob> stems=
        Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
 
   Link_array<Grob> stems=
        Pointer_group_interface__extract_grobs (me, (Grob*)0, "stems");
 
-  for (int i=0; i <stems.size (); i++)
+  for (int i=0; i < stems.size (); i++)
     do {
       Grob *s = stems[i];
     do {
       Grob *s = stems[i];
-      Direction sd = Directional_element_interface::get (s);
+      Direction sd = get_grob_direction (s);
 
 
-      int center_distance = int(- d * Stem::head_positions (s) [-d]) >? 0;
+      int center_distance = int (- d * Stem::head_positions (s) [-d]) >? 0;
       int current = sd ? (1 + d * sd)/2 : center_distance;
 
       if (current)
       int current = sd ? (1 + d * sd)/2 : center_distance;
 
       if (current)
@@ -522,18 +562,18 @@ Beam::get_default_dir (Grob *me)
        }
     } while (flip (&d) != DOWN);
   
        }
     } while (flip (&d) != DOWN);
   
-  SCM func = me->get_grob_property ("dir-function");
-  SCM s = gh_call2 (func,
-                   gh_cons (scm_int2num (count[UP]),
+  SCM func = me->get_property ("dir-function");
+  SCM s = scm_call_2 (func,
+                   scm_cons (scm_int2num (count[UP]),
                             scm_int2num (count[DOWN])),
                             scm_int2num (count[DOWN])),
-                   gh_cons (scm_int2num (total[UP]),
+                   scm_cons (scm_int2num (total[UP]),
                             scm_int2num (total[DOWN])));
 
                             scm_int2num (total[DOWN])));
 
-  if (gh_number_p (s) && gh_scm2int (s))
+  if (scm_is_number (s) && scm_to_int (s))
     return to_dir (s);
   
   /* If dir is not determined: get default */
     return to_dir (s);
   
   /* If dir is not determined: get default */
-  return to_dir (me->get_grob_property ("neutral-direction"));
+  return to_dir (me->get_property ("neutral-direction"));
 }
 
 
 }
 
 
@@ -550,71 +590,12 @@ Beam::set_stem_directions (Grob *me, Direction d)
     {
       Grob *s = stems[i];
   
     {
       Grob *s = stems[i];
   
-      SCM forcedir = s->get_grob_property ("direction");
+      SCM forcedir = s->get_property ("direction");
       if (!to_dir (forcedir))
       if (!to_dir (forcedir))
-       Directional_element_interface::set (s, d);
+       set_grob_direction (s,  d);
     }
 }
 
     }
 }
 
-/*
-  A union of intervals in the real line.
-
-  Abysmal performance (quadratic) for large N, hopefully we don't have
-  that large N. In any case, this should probably be rewritten to use
-  a balanced tree.
- */
-struct Int_set
-{
-  Array<Interval> allowed_regions_;
-
-  Int_set()
-  {
-    set_full();
-  }
-
-  void set_full()
-  {
-    allowed_regions_.clear();
-    Interval s;
-    s.set_full ();
-    allowed_regions_.push (s);
-  }
-
-  void remove_interval (Interval rm)
-  {
-    for (int i = 0; i < allowed_regions_.size(); )
-      {
-       Interval s = rm;
-
-       s.intersect (allowed_regions_[i]);
-
-       if (!s.empty_b ())
-         {
-           Interval before = allowed_regions_[i];
-           Interval after = allowed_regions_[i];
-
-           before[RIGHT] = s[LEFT];
-           after[LEFT] = s[RIGHT];
-
-           if (!before.empty_b() && before.length () > 0.0)
-             {
-               allowed_regions_.insert (before, i);
-               i++;
-             }
-           allowed_regions_.del (i);
-           if (!after.empty_b () && after.length () > 0.0)
-             {
-               allowed_regions_.insert (after, i);
-               i++;
-             }
-         }
-       else
-         i++;
-      }
-  }
-};
-
-
 /*
   Only try horizontal beams for knees.  No reliable detection of
   anything else is possible here, since we don't know funky-beaming
 /*
   Only try horizontal beams for knees.  No reliable detection of
   anything else is possible here, since we don't know funky-beaming
@@ -624,13 +605,13 @@ struct Int_set
 void
 Beam::consider_auto_knees (Grob* me)
 {
 void
 Beam::consider_auto_knees (Grob* me)
 {
-  SCM scm = me->get_grob_property ("auto-knee-gap");
-  if (!gh_number_p (scm))
+  SCM scm = me->get_property ("auto-knee-gap");
+  if (!scm_is_number (scm))
     return ;
 
     return ;
 
-  Real threshold = gh_scm2double (scm);
+  Real threshold = scm_to_double (scm);
   
   
-  Int_set gaps;
+  Interval_set gaps;
 
   gaps.set_full ();
 
 
   gaps.set_full ();
 
@@ -644,11 +625,11 @@ Beam::consider_auto_knees (Grob* me)
   for (int i=0; i < stems.size (); i++)
     {
       Grob* stem = stems[i];
   for (int i=0; i < stems.size (); i++)
     {
       Grob* stem = stems[i];
-      if (Stem::invisible_b (stem))
+      if (Stem::is_invisible (stem))
        continue;
 
       Interval hps = Stem::head_positions (stem);
        continue;
 
       Interval hps = Stem::head_positions (stem);
-      if(!hps.empty_b())
+      if (!hps.is_empty ())
        {
          hps[LEFT] += -1;
          hps[RIGHT] += 1; 
        {
          hps[LEFT] += -1;
          hps[RIGHT] += 1; 
@@ -662,9 +643,9 @@ Beam::consider_auto_knees (Grob* me)
           */
          hps += stem->relative_coordinate (common, Y_AXIS);
 
           */
          hps += stem->relative_coordinate (common, Y_AXIS);
 
-         if (to_dir (stem->get_grob_property ("direction")))
+         if (to_dir (stem->get_property ("direction")))
            {
            {
-             Direction stemdir = to_dir (stem->get_grob_property ("direction"));
+             Direction stemdir = to_dir (stem->get_property ("direction"));
              hps[-stemdir] = - stemdir * infinity_f;
            }
        }
              hps[-stemdir] = - stemdir * infinity_f;
            }
        }
@@ -676,19 +657,19 @@ Beam::consider_auto_knees (Grob* me)
   Interval max_gap;
   Real max_gap_len =0.0;
 
   Interval max_gap;
   Real max_gap_len =0.0;
 
-  for (int i  = gaps.allowed_regions_.size() -1;  i >=  0 ; i--)
+  for (int i  = gaps.allowed_regions_.size () -1;  i >=  0 ; i--)
     {
       Interval gap = gaps.allowed_regions_[i];
 
       /*
        the outer gaps are not knees.
        */
     {
       Interval gap = gaps.allowed_regions_[i];
 
       /*
        the outer gaps are not knees.
        */
-      if (isinf (gap[LEFT]) || isinf(gap[RIGHT]))
+      if (isinf (gap[LEFT]) || isinf (gap[RIGHT]))
        continue;
       
       if (gap.length () >= max_gap_len)
        {
        continue;
       
       if (gap.length () >= max_gap_len)
        {
-         max_gap_len = gap.length();
+         max_gap_len = gap.length ();
          max_gap = gap;
        }
     }
          max_gap = gap;
        }
     }
@@ -696,22 +677,22 @@ Beam::consider_auto_knees (Grob* me)
   if (max_gap_len > threshold)
     {
       int j = 0;
   if (max_gap_len > threshold)
     {
       int j = 0;
-      for (int i = 0; i < stems.size(); i++)
+      for (int i = 0; i < stems.size (); i++)
        {
          Grob* stem = stems[i];
        {
          Grob* stem = stems[i];
-         if (Stem::invisible_b (stem))
+         if (Stem::is_invisible (stem))
            continue;
 
          Interval hps = hps_array[j++];
 
 
            continue;
 
          Interval hps = hps_array[j++];
 
 
-         Direction d =  (hps.center () < max_gap.center()) ?
+         Direction d =  (hps.center () < max_gap.center ()) ?
            UP : DOWN ;
          
            UP : DOWN ;
          
-         stem->set_grob_property ("direction", scm_int2num (d));
+         stem->set_property ("direction", scm_int2num (d));
          
          hps.intersect (max_gap);
          
          hps.intersect (max_gap);
-         assert (hps.empty_b () || hps.length () < 1e-6 );
+         assert (hps.is_empty () || hps.length () < 1e-6 );
        }
     }
 }
        }
     }
 }
@@ -734,7 +715,7 @@ Beam::set_stem_shorten (Grob *me)
   /*
     shortening looks silly for x staff beams
    */
   /*
     shortening looks silly for x staff beams
    */
-  if (knee_b(me))
+  if (is_knee (me))
     return ;
   
   Real forced_fraction = 1.0 * forced_stem_count (me)
     return ;
   
   Real forced_fraction = 1.0 * forced_stem_count (me)
@@ -742,7 +723,7 @@ Beam::set_stem_shorten (Grob *me)
 
   int beam_count = get_beam_count (me);
 
 
   int beam_count = get_beam_count (me);
 
-  SCM shorten_list = me->get_grob_property ("beamed-stem-shorten");
+  SCM shorten_list = me->get_property ("beamed-stem-shorten");
   if (shorten_list == SCM_EOL)
     return;
 
   if (shorten_list == SCM_EOL)
     return;
 
@@ -750,13 +731,13 @@ Beam::set_stem_shorten (Grob *me)
   
   SCM shorten_elt =
     robust_list_ref (beam_count -1, shorten_list);
   
   SCM shorten_elt =
     robust_list_ref (beam_count -1, shorten_list);
-  Real shorten_f = gh_scm2double (shorten_elt) * staff_space;
+  Real shorten_f = scm_to_double (shorten_elt) * staff_space;
 
   /* your similar cute comment here */
   shorten_f *= forced_fraction;
 
   if (shorten_f)
 
   /* your similar cute comment here */
   shorten_f *= forced_fraction;
 
   if (shorten_f)
-    me->set_grob_property ("shorten", gh_double2scm (shorten_f));
+    me->set_property ("shorten", scm_make_real (shorten_f));
 }
 
 /*  Call list of y-dy-callbacks, that handle setting of
 }
 
 /*  Call list of y-dy-callbacks, that handle setting of
@@ -768,25 +749,60 @@ SCM
 Beam::after_line_breaking (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
 Beam::after_line_breaking (SCM smob)
 {
   Grob *me = unsmob_grob (smob);
-  
+
+  position_beam (me);
+  return SCM_UNSPECIFIED;
+}
+
+void
+Beam::position_beam (Grob *me)
+{
+  if (!me->is_live ())
+    return ;
+  if (to_boolean (me->get_property ("positioning-done")))
+    return ;
+
+  me->set_property ("positioning-done", SCM_BOOL_T);
+
   /* Copy to mutable list. */
   /* Copy to mutable list. */
-  SCM s = ly_deep_copy (me->get_grob_property ("positions"));
-  me->set_grob_property ("positions", s);
+  SCM s = ly_deep_copy (me->get_property ("positions"));
+  me->set_property ("positions", s);
 
 
-  if (ly_car (s) == SCM_BOOL_F)
+  if (scm_car (s) == SCM_BOOL_F)
     {
     {
-
       // one wonders if such genericity is necessary  --hwn.
       // one wonders if such genericity is necessary  --hwn.
-      SCM callbacks = me->get_grob_property ("position-callbacks");
-      for (SCM i = callbacks; gh_pair_p (i); i = ly_cdr (i))
-       gh_call1 (ly_car (i), smob);
+      SCM callbacks = me->get_property ("position-callbacks");
+      for (SCM i = callbacks; scm_is_pair (i); i = scm_cdr (i))
+       scm_call_1 (scm_car (i), me->self_scm ());
     }
 
   set_stem_lengths (me);  
     }
 
   set_stem_lengths (me);  
-  return SCM_UNSPECIFIED;
 }
 
 
 }
 
 
+void
+set_minimum_dy (Grob *me, Real * dy)
+{
+  if (*dy)
+    {
+      /*
+       If dy is smaller than the smallest quant, we
+       get absurd direction-sign penalties. 
+      */
+         
+      Real ss = Staff_symbol_referencer::staff_space (me);
+      Real thickness = Beam::get_thickness (me) / ss ;
+      Real slt = Staff_symbol_referencer::line_thickness (me) / ss;
+      Real sit = (thickness - slt) / 2;
+      Real inter = 0.5;
+      Real hang = 1.0 - (thickness - slt) / 2;
+         
+      *dy = sign (*dy) * (fabs (*dy)
+                       >?
+                       (sit <? inter <? hang));
+    }
+}
+
 /*
   Compute  a first approximation to the beam slope.
  */
 /*
   Compute  a first approximation to the beam slope.
  */
@@ -801,7 +817,7 @@ Beam::least_squares (SCM smob)
   
   if (count < 1)
     {
   
   if (count < 1)
     {
-      me->set_grob_property ("positions", ly_interval2scm (pos));
+      me->set_property ("positions", ly_interval2scm (pos));
       return SCM_UNSPECIFIED;
     }
 
       return SCM_UNSPECIFIED;
     }
 
@@ -834,7 +850,7 @@ Beam::least_squares (SCM smob)
 
   
   Real y =0;  
 
   
   Real y =0;  
-  Real dydx = 0;
+  Real slope = 0;
   Real dy = 0;
   
   if (!ideal.delta ())
   Real dy = 0;
   
   if (!ideal.delta ())
@@ -853,7 +869,7 @@ Beam::least_squares (SCM smob)
        {
          /* FIXME. -> UP */
          Direction d = (Direction) (sign (chord.delta ()) * UP);
        {
          /* FIXME. -> UP */
          Direction d = (Direction) (sign (chord.delta ()) * UP);
-         pos[d] = gh_scm2double (me->get_grob_property ("thickness")) / 2;
+         pos[d] = get_thickness (me) / 2;
          pos[-d] = - pos[d];
        }
       else
          pos[-d] = - pos[d];
        }
       else
@@ -863,16 +879,11 @@ Beam::least_squares (SCM smob)
 
       /*
        For broken beams this doesn't work well. In this case, the
 
       /*
        For broken beams this doesn't work well. In this case, the
-        slope esp. of the first part of a broken beam should predict
-        where the second part goes.
-       */
-
-      y = pos[LEFT];
-      dy = pos[RIGHT]- y;
-      dydx = dy/dx;
-
-
-
+       slope esp. of the first part of a broken beam should predict
+       where the second part goes.
+      */
+      me->set_property ("least-squares-dy",
+                       scm_make_real (pos[RIGHT] - pos[LEFT]));
     }
   else
     {
     }
   else
     {
@@ -880,7 +891,7 @@ Beam::least_squares (SCM smob)
       for (int i=0; i < stems.size (); i++)
        {
          Grob* s = stems[i];
       for (int i=0; i < stems.size (); i++)
        {
          Grob* s = stems[i];
-         if (Stem::invisible_b (s))
+         if (Stem::is_invisible (s))
            continue;
          ideals.push (Offset (x_posns[i],
                               Stem::get_stem_info (s).ideal_y_
            continue;
          ideals.push (Offset (x_posns[i],
                               Stem::get_stem_info (s).ideal_y_
@@ -888,14 +899,21 @@ Beam::least_squares (SCM smob)
                               - my_y));
        }
       
                               - my_y));
        }
       
-      minimise_least_squares (&dydx, &y, ideals);
+      minimise_least_squares (&slope, &y, ideals);
 
 
-      dy = dydx * dx;
-      me->set_grob_property ("least-squares-dy", gh_double2scm (dy));
+      dy = slope * dx;
+
+      set_minimum_dy (me,&dy);
+      me->set_property ("least-squares-dy", scm_make_real (dy));
       pos = Interval (y, (y+dy));
     }
 
       pos = Interval (y, (y+dy));
     }
 
-  me->set_grob_property ("positions", ly_interval2scm (pos));
+  /*
+    "position" is relative to the staff.
+   */
+  scale_drul (&pos,  1/ Staff_symbol_referencer::staff_space (me)); 
+  
+  me->set_property ("positions", ly_interval2scm (pos));
  
   return SCM_UNSPECIFIED;
 }
  
   return SCM_UNSPECIFIED;
 }
@@ -905,10 +923,10 @@ Beam::least_squares (SCM smob)
   We can't combine with previous function, since check concave and
   slope damping comes first.
 
   We can't combine with previous function, since check concave and
   slope damping comes first.
 
-TODO: we should use the concaveness to control the amount of damping
-applied.
+  TODO: we should use the concaveness to control the amount of damping
+  applied.
   
   
- */
+*/
 MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 1);
 SCM
 Beam::shift_region_to_valid (SCM grob)
 MAKE_SCHEME_CALLBACK (Beam, shift_region_to_valid, 1);
 SCM
 Beam::shift_region_to_valid (SCM grob)
@@ -943,10 +961,13 @@ Beam::shift_region_to_valid (SCM grob)
   
   Real dx = lvs->relative_coordinate (commonx, X_AXIS) - x0;
 
   
   Real dx = lvs->relative_coordinate (commonx, X_AXIS) - x0;
 
-  Interval pos = ly_scm2interval ( me->get_grob_property ("positions"));
-  Real dy = pos.delta();
+  Drul_array<Real> pos = ly_scm2interval ( me->get_property ("positions"));
+
+  scale_drul (&pos,  Staff_symbol_referencer::staff_space (me));
+  
+  Real dy = pos[RIGHT] - pos[LEFT];
   Real y = pos[LEFT];
   Real y = pos[LEFT];
-  Real dydx =dy/dx;
+  Real slope =dy/dx;
 
   
   /*
 
   
   /*
@@ -958,14 +979,14 @@ Beam::shift_region_to_valid (SCM grob)
   for (int i=0; i < stems.size (); i++)
     {
       Grob* s = stems[i];
   for (int i=0; i < stems.size (); i++)
     {
       Grob* s = stems[i];
-      if (Stem::invisible_b (s))
+      if (Stem::is_invisible (s))
        continue;
 
       Direction d = Stem::get_direction (s);
 
       Real left_y =
        Stem::get_stem_info (s).shortest_y_
        continue;
 
       Direction d = Stem::get_direction (s);
 
       Real left_y =
        Stem::get_stem_info (s).shortest_y_
-       - dydx * x_posns [i];
+       - slope * x_posns [i];
 
       /*
        left_y is now relative to the stem S. We want relative to
 
       /*
        left_y is now relative to the stem S. We want relative to
@@ -982,11 +1003,9 @@ Beam::shift_region_to_valid (SCM grob)
       feasible_left_point.intersect (flp);
     }
       
       feasible_left_point.intersect (flp);
     }
       
-  if (feasible_left_point.empty_b())
-    {
-      warning (_("Not sure that we can find a nice beam slope (no viable initial configuration found)."));
-    }
-  else if (!feasible_left_point.elem_b(y))
+  if (feasible_left_point.is_empty ())
+    warning (_ ("no viable initial configuration found: may not find good beam slope"));
+  else if (!feasible_left_point.contains (y))
     {
       if (isinf (feasible_left_point[DOWN]))
        y = feasible_left_point[UP] - REGION_SIZE;
     {
       if (isinf (feasible_left_point[DOWN]))
        y = feasible_left_point[UP] - REGION_SIZE;
@@ -995,134 +1014,11 @@ Beam::shift_region_to_valid (SCM grob)
       else
        y = feasible_left_point.center ();
     }
       else
        y = feasible_left_point.center ();
     }
-  pos = Interval (y, (y+dy));
-  me->set_grob_property ("positions", ly_interval2scm (pos));
-  return SCM_UNSPECIFIED;
-}
-
-
-MAKE_SCHEME_CALLBACK (Beam, check_concave, 1);
-SCM
-Beam::check_concave (SCM smob)
-{
-  Grob *me = unsmob_grob (smob);
-
-  Link_array<Grob> stems = 
-    Pointer_group_interface__extract_grobs (me, (Grob*) 0, "stems");
-
-  for (int i = 0; i < stems.size ();)
-    {
-      if (Stem::invisible_b (stems[i]))
-       stems.del (i);
-      else
-       i++;
-    }
-  
-  if (stems.size () < 3)
-    return SCM_UNSPECIFIED;
-
-
-  /* Concaveness #1: If distance of an inner notehead to line between
-     two outer noteheads is bigger than CONCAVENESS-GAP (2.0ss),
-     beam is concave (Heinz Stolba).
-
-     In the case of knees, the line connecting outer heads is often
-     not related to the beam slope (it may even go in the other
-     direction). Skip the check when the outer stems point in
-     different directions. --hwn
-     
-  */
-  bool concaveness1 = false;
-  SCM gap = me->get_grob_property ("concaveness-gap");
-  if (gh_number_p (gap)
-      && Stem::get_direction(stems.top ())
-         == Stem::get_direction(stems[0]))
-    {
-      Real r1 = gh_scm2double (gap);
-      Real dy = Stem::chord_start_y (stems.top ())
-       - Stem::chord_start_y (stems[0]);
-
-      
-      Real slope = dy / (stems.size () - 1);
-      
-      Real y0 = Stem::chord_start_y (stems[0]);
-      for (int i = 1; i < stems.size () - 1; i++)
-       {
-         Real c = (Stem::chord_start_y (stems[i]) - y0) - i * slope;
-         if (c > r1)
-           {
-             concaveness1 = true;
-             break;
-           }
-       }
-    }
-
-    
-  /* Concaveness #2: Sum distances of inner noteheads that fall
-     outside the interval of the two outer noteheads.
-
-     We only do this for beams where first and last stem have the same
-     direction. --hwn.
-
-
-     Note that "convex" stems compensate for "concave" stems.
-     (is that intentional?) --hwn.
-  */
   
   
-  Real concaveness2 = 0;
-  SCM thresh = me->get_grob_property ("concaveness-threshold");
-  Real r2 = infinity_f;
-  if (!concaveness1 && gh_number_p (thresh)
-      && Stem::get_direction(stems.top ())
-         == Stem::get_direction(stems[0]))
-    {
-      r2 = gh_scm2double (thresh);
-
-      Direction dir = Stem::get_direction(stems.top ());
-      Real concave = 0;
-      Interval iv (Stem::chord_start_y (stems[0]),
-                  Stem::chord_start_y (stems.top ()));
-      
-      if (iv[MAX] < iv[MIN])
-       iv.swap ();
-      
-      for (int i = 1; i < stems.size () - 1; i++)
-       {
-         Real f = Stem::chord_start_y (stems[i]);
-         concave += ((f - iv[MAX] ) >? 0) +
-           ((f - iv[MIN] ) <? 0);
-       }
-      concave *= dir;
-      concaveness2 = concave / (stems.size () - 2);
-      
-      /*
-
-      ugh: this is the a kludge to get
-      input/regression/beam-concave.ly to behave as
-      baerenreiter.
-
-      */
-
-      /*
-       huh? we're dividing twice (which is not scalable) meaning that
-       the longer the beam, the more unlikely it will be
-       concave. Maybe you would even expect the other way around??
-
-       --hwn.
-       
-       */
-      concaveness2 /= (stems.size () - 2);
-    }
+  pos = Drul_array<Real> (y, (y+dy));
+  scale_drul (&pos, 1/ Staff_symbol_referencer::staff_space (me));
   
   
-  /* TODO: some sort of damping iso -> plain horizontal */
-  if (concaveness1 || concaveness2 > r2)
-    {
-      Interval pos = ly_scm2interval (me->get_grob_property ("positions"));
-      Real r = pos.linear_combination (0);
-      me->set_grob_property ("positions", ly_interval2scm (Interval (r, r)));
-      me->set_grob_property ("least-squares-dy", gh_double2scm (0));
-    }
-
+  me->set_property ("positions", ly_interval2scm (pos));
   return SCM_UNSPECIFIED;
 }
 
   return SCM_UNSPECIFIED;
 }
 
@@ -1138,13 +1034,15 @@ Beam::slope_damping (SCM smob)
   if (visible_stem_count (me) <= 1)
     return SCM_UNSPECIFIED;
 
   if (visible_stem_count (me) <= 1)
     return SCM_UNSPECIFIED;
 
-  SCM s = me->get_grob_property ("damping"); 
-  int damping = gh_scm2int (s);
+  SCM s = me->get_property ("damping"); 
+  Real damping = scm_to_double (s);
 
   if (damping)
     {
 
   if (damping)
     {
-      Interval pos = ly_scm2interval (me->get_grob_property ("positions"));
-      Real dy = pos.delta ();
+      Drul_array<Real> pos = ly_scm2interval (me->get_property ("positions"));
+      scale_drul (&pos,  Staff_symbol_referencer::staff_space (me));
+      
+      Real dy = pos[RIGHT] - pos[LEFT];
 
       Grob *fvs  = first_visible_stem (me);
       Grob *lvs  = last_visible_stem (me);
 
       Grob *fvs  = first_visible_stem (me);
       Grob *lvs  = last_visible_stem (me);
@@ -1154,14 +1052,23 @@ Beam::slope_damping (SCM smob)
 
       Real dx = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS)
        - first_visible_stem (me)->relative_coordinate (commonx, X_AXIS);
 
       Real dx = last_visible_stem (me)->relative_coordinate (commonx, X_AXIS)
        - first_visible_stem (me)->relative_coordinate (commonx, X_AXIS);
-      Real dydx = dy && dx ? dy/dx : 0;
-      dydx = 0.6 * tanh (dydx) / damping;
 
 
-      Real damped_dy = dydx * dx;
+      Real slope = dy && dx ? dy/dx : 0;
+
+      Real concaveness = robust_scm2double (me->get_property ("concaveness"), 0.0);
+      
+      slope = 0.6 * tanh (slope) / (damping + concaveness);
+
+      Real damped_dy = slope * dx;
+
+      set_minimum_dy (me, &damped_dy);
+      
       pos[LEFT] += (dy - damped_dy) / 2;
       pos[RIGHT] -= (dy - damped_dy) / 2;
       pos[LEFT] += (dy - damped_dy) / 2;
       pos[RIGHT] -= (dy - damped_dy) / 2;
+
+      scale_drul (&pos, 1/Staff_symbol_referencer::staff_space (me));
       
       
-      me->set_grob_property ("positions", ly_interval2scm (pos));
+      me->set_property ("positions", ly_interval2scm (pos));
     }
   return SCM_UNSPECIFIED;
 }
     }
   return SCM_UNSPECIFIED;
 }
@@ -1171,15 +1078,15 @@ Beam::slope_damping (SCM smob)
   and (cdr BEAMING)
  */
 Slice
   and (cdr BEAMING)
  */
 Slice
-where_are_the_whole_beams(SCM beaming)
+where_are_the_whole_beams (SCM beaming)
 {
   Slice l; 
   
 {
   Slice l; 
   
-  for( SCM s = gh_car (beaming); gh_pair_p (s) ; s = gh_cdr (s))
+  for ( SCM s = scm_car (beaming); scm_is_pair (s) ; s = scm_cdr (s))
     {
     {
-      if (scm_memq (gh_car (s), gh_cdr (beaming)) != SCM_BOOL_F)
+      if (scm_c_memq (scm_car (s), scm_cdr (beaming)) != SCM_BOOL_F)
        
        
-       l.add_point (gh_scm2int (gh_car (s)));
+       l.add_point (scm_to_int (scm_car (s)));
     }
 
   return l;
     }
 
   return l;
@@ -1190,33 +1097,33 @@ where_are_the_whole_beams(SCM beaming)
 Real
 Beam::calc_stem_y (Grob *me, Grob* s, Grob ** common,
                   Real xl, Real xr,
 Real
 Beam::calc_stem_y (Grob *me, Grob* s, Grob ** common,
                   Real xl, Real xr,
-                  Interval pos, bool french) 
+                  Drul_array<Real> pos, bool french) 
 {
   Real beam_translation = get_beam_translation (me);
 
     
   Real r = s->relative_coordinate (common[X_AXIS], X_AXIS) - xl;
 {
   Real beam_translation = get_beam_translation (me);
 
     
   Real r = s->relative_coordinate (common[X_AXIS], X_AXIS) - xl;
-  Real dy = pos.delta ();
+  Real dy = pos[RIGHT] - pos[LEFT];
   Real dx = xr - xl;
   Real stem_y_beam0 = (dy && dx
                       ? r / dx
                       * dy
                       : 0) + pos[LEFT];
   
   Real dx = xr - xl;
   Real stem_y_beam0 = (dy && dx
                       ? r / dx
                       * dy
                       : 0) + pos[LEFT];
   
-  Direction my_dir = Directional_element_interface::get (s);
-  SCM beaming = s->get_grob_property ("beaming");
+  Direction my_dir = get_grob_direction (s);
+  SCM beaming = s->get_property ("beaming");
  
   Real stem_y = stem_y_beam0;
   if (french)
     {
       Slice bm = where_are_the_whole_beams (beaming);
  
   Real stem_y = stem_y_beam0;
   if (french)
     {
       Slice bm = where_are_the_whole_beams (beaming);
-      if (!bm.empty_b())
+      if (!bm.is_empty ())
        stem_y += beam_translation * bm[-my_dir];
     }
   else
     {
        stem_y += beam_translation * bm[-my_dir];
     }
   else
     {
-      Slice bm = Stem::beam_multiplicity(s);
-      if (!bm.empty_b())
+      Slice bm = Stem::beam_multiplicity (s);
+      if (!bm.is_empty ())
        stem_y +=bm[my_dir] * beam_translation;
     }
   
        stem_y +=bm[my_dir] * beam_translation;
     }
   
@@ -1241,18 +1148,19 @@ Beam::set_stem_lengths (Grob *me)
   
   Grob *common[2];
   for (int a = 2; a--;)
   
   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));
   
   
-  Interval pos = ly_scm2interval (me->get_grob_property ("positions"));
+  Drul_array<Real> pos = ly_scm2realdrul (me->get_property ("positions"));
   Real staff_space = Staff_symbol_referencer::staff_space (me);
   Real staff_space = Staff_symbol_referencer::staff_space (me);
+  scale_drul (&pos,  staff_space);
 
   bool gap = false;
   Real thick =0.0;
 
   bool gap = false;
   Real thick =0.0;
-  if (gh_number_p (me->get_grob_property ("gap"))
-      &&gh_scm2double (me->get_grob_property ("gap")))
+  if (scm_is_number (me->get_property ("gap-count"))
+      &&scm_to_int (me->get_property ("gap-count")))
     {
       gap = true;
     {
       gap = true;
-      thick = get_thickness(me);
+      thick = get_thickness (me);
     }
       
   // ugh -> use commonx
     }
       
   // ugh -> use commonx
@@ -1265,10 +1173,10 @@ Beam::set_stem_lengths (Grob *me)
   for (int i=0; i < stems.size (); i++)
     {
       Grob* s = stems[i];
   for (int i=0; i < stems.size (); i++)
     {
       Grob* s = stems[i];
-      if (Stem::invisible_b (s))
+      if (Stem::is_invisible (s))
        continue;
 
        continue;
 
-      bool french = to_boolean (s->get_grob_property ("french-beaming"));
+      bool french = to_boolean (s->get_property ("french-beaming"));
       Real stem_y = calc_stem_y (me, s, common,
                                 xl, xr,
                                 pos, french && s != lvs && s!= fvs);
       Real stem_y = calc_stem_y (me, s, common,
                                 xl, xr,
                                 pos, french && s != lvs && s!= fvs);
@@ -1278,7 +1186,7 @@ Beam::set_stem_lengths (Grob *me)
        for normal beams, but for tremolo beams it looks silly otherwise.
        */
       if (gap)
        for normal beams, but for tremolo beams it looks silly otherwise.
        */
       if (gap)
-       stem_y += thick * 0.5 * Directional_element_interface::get(s);
+       stem_y += thick * 0.5 * get_grob_direction (s);
 
       Stem::set_stemend (s, 2* stem_y / staff_space);
     }
 
       Stem::set_stemend (s, 2* stem_y / staff_space);
     }
@@ -1300,20 +1208,20 @@ Beam::set_beaming (Grob *me, Beaming_info_list *beaming)
       do
        {
          /* Don't set beaming for outside of outer stems */      
       do
        {
          /* Don't set beaming for outside of outer stems */      
-         if ((d == LEFT && i == 0)
-             ||(d == RIGHT && i == stems.size () -1))
+         if ( (d == LEFT && i == 0)
+             || (d == RIGHT && i == stems.size () -1))
            continue;
 
          Grob *st =  stems[i];
            continue;
 
          Grob *st =  stems[i];
-         SCM beaming_prop = st->get_grob_property ("beaming");
+         SCM beaming_prop = st->get_property ("beaming");
          if (beaming_prop == SCM_EOL ||
              index_get_cell (beaming_prop, d) == SCM_EOL)
            {
              int b = beaming->infos_.elem (i).beams_i_drul_[d];
              if (i>0
          if (beaming_prop == SCM_EOL ||
              index_get_cell (beaming_prop, d) == SCM_EOL)
            {
              int b = beaming->infos_.elem (i).beams_i_drul_[d];
              if (i>0
-                 && i < stems.size() -1
-                 && Stem::invisible_b (st))
-               b = b <? beaming->infos_.elem(i).beams_i_drul_[-d];
+                 && i < stems.size () -1
+                 && Stem::is_invisible (st))
+               b = b <? beaming->infos_.elem (i).beams_i_drul_[-d];
              
              Stem::set_beaming (st, b, d);
            }
              
              Stem::set_beaming (st, b, d);
            }
@@ -1332,7 +1240,7 @@ Beam::forced_stem_count (Grob *me)
     {
       Grob *s = stems[i];
 
     {
       Grob *s = stems[i];
 
-      if (Stem::invisible_b (s))
+      if (Stem::is_invisible (s))
        continue;
 
       /* I can imagine counting those boundaries as a half forced stem,
        continue;
 
       /* I can imagine counting those boundaries as a half forced stem,
@@ -1355,7 +1263,7 @@ Beam::visible_stem_count (Grob *me)
   int c = 0;
   for (int i = stems.size (); i--;)
     {
   int c = 0;
   for (int i = stems.size (); i--;)
     {
-      if (!Stem::invisible_b (stems[i]))
+      if (!Stem::is_invisible (stems[i]))
         c++;
     }
   return c;
         c++;
     }
   return c;
@@ -1369,7 +1277,7 @@ Beam::first_visible_stem (Grob *me)
   
   for (int i = 0; i < stems.size (); i++)
     {
   
   for (int i = 0; i < stems.size (); i++)
     {
-      if (!Stem::invisible_b (stems[i]))
+      if (!Stem::is_invisible (stems[i]))
         return stems[i];
     }
   return 0;
         return stems[i];
     }
   return 0;
@@ -1382,7 +1290,7 @@ Beam::last_visible_stem (Grob *me)
     Pointer_group_interface__extract_grobs (me, (Grob*) 0, "stems");
   for (int i = stems.size (); i--;)
     {
     Pointer_group_interface__extract_grobs (me, (Grob*) 0, "stems");
   for (int i = stems.size (); i--;)
     {
-      if (!Stem::invisible_b (stems[i]))
+      if (!Stem::is_invisible (stems[i]))
         return stems[i];
     }
   return 0;
         return stems[i];
     }
   return 0;
@@ -1404,88 +1312,86 @@ SCM
 Beam::rest_collision_callback (SCM element_smob, SCM axis)
 {
   Grob *rest = unsmob_grob (element_smob);
 Beam::rest_collision_callback (SCM element_smob, SCM axis)
 {
   Grob *rest = unsmob_grob (element_smob);
-  Axis a = (Axis) gh_scm2int (axis);
+  Axis a = (Axis) scm_to_int (axis);
+
+  if (scm_is_number (rest->get_property ("staff-position")))
+    return scm_int2num (0);
   
   assert (a == Y_AXIS);
 
   
   assert (a == Y_AXIS);
 
-  Grob *st = unsmob_grob (rest->get_grob_property ("stem"));
+  Grob *st = unsmob_grob (rest->get_property ("stem"));
   Grob *stem = st;
   if (!stem)
   Grob *stem = st;
   if (!stem)
-    return gh_double2scm (0.0);
-  Grob *beam = unsmob_grob (stem->get_grob_property ("beam"));
+    return scm_make_real (0.0);
+  Grob *beam = unsmob_grob (stem->get_property ("beam"));
   if (!beam
       || !Beam::has_interface (beam)
       || !Beam::visible_stem_count (beam))
   if (!beam
       || !Beam::has_interface (beam)
       || !Beam::visible_stem_count (beam))
-    return gh_double2scm (0.0);
+    return scm_make_real (0.0);
 
 
-  Interval pos (0, 0);
-  SCM s = beam->get_grob_property ("positions");
-  if (gh_pair_p (s) && gh_number_p (ly_car (s)))
+  Drul_array<Real> pos (0, 0);
+  SCM s = beam->get_property ("positions");
+  if (scm_is_pair (s) && scm_is_number (scm_car (s)))
     pos = ly_scm2interval (s);
     pos = ly_scm2interval (s);
+  Real staff_space = Staff_symbol_referencer::staff_space (rest);
+
+  scale_drul (&pos, staff_space);
+  
 
 
-  Real dy = pos.delta ();
+  Real dy = pos[RIGHT] - pos[LEFT];
+  
   // ugh -> use commonx
   Real x0 = first_visible_stem (beam)->relative_coordinate (0, X_AXIS);
   Real dx = last_visible_stem (beam)->relative_coordinate (0, X_AXIS) - x0;
   // ugh -> use commonx
   Real x0 = first_visible_stem (beam)->relative_coordinate (0, X_AXIS);
   Real dx = last_visible_stem (beam)->relative_coordinate (0, X_AXIS) - x0;
-  Real dydx = dy && dx ? dy/dx : 0;
+  Real slope = dy && dx ? dy/dx : 0;
   
   Direction d = Stem::get_direction (stem);
   
   Direction d = Stem::get_direction (stem);
-  Real stem_y = (pos[LEFT]
-                + (stem->relative_coordinate (0, X_AXIS) - x0) * dydx)
-    * d;
+  Real stem_y = pos[LEFT] + (stem->relative_coordinate (0, X_AXIS) - x0) * slope;
   
   Real beam_translation = get_beam_translation (beam);
   
   Real beam_translation = get_beam_translation (beam);
-  Real beam_thickness = gh_scm2double (beam->get_grob_property ("thickness"));
+  Real beam_thickness = Beam::get_thickness (beam);
+  
   int beam_count = get_direction_beam_count (beam, d);
   int beam_count = get_direction_beam_count (beam, d);
-  Real height_of_my_beams = beam_thickness
+  Real height_of_my_beams = beam_thickness / 2
     + (beam_count - 1) * beam_translation;
     + (beam_count - 1) * beam_translation;
-  Real beam_y = stem_y - height_of_my_beams + beam_thickness / 2.0;
+  Real beam_y = stem_y - d * height_of_my_beams;
 
 
-  Real staff_space = Staff_symbol_referencer::staff_space (rest);
+  Grob *common_y = rest->common_refpoint (beam, Y_AXIS);
 
 
-  /* Better calculate relative-distance directly, rather than using
-     rest_dim? */
-  Grob *common_x = rest->common_refpoint (beam, Y_AXIS);
-  Real rest_dim = rest->extent (common_x, Y_AXIS)[d] / staff_space * d;
+  Real rest_dim = rest->extent (common_y, Y_AXIS)[d];
+  Real minimum_distance =
+    staff_space * robust_scm2double (rest->get_property ("minimum-distance"), 0.0);
 
 
-  Real minimum_distance = gh_scm2double
-    (rest->get_grob_property ("minimum-beam-collision-distance"));
+  Real shift = d * ( ((beam_y - d * minimum_distance) - rest_dim) * d  <? 0.0);
 
 
-  Real distance = beam_y - rest_dim;
-  Real shift = 0;
-  if (distance < 0)
-    shift = minimum_distance - distance;
-  else if (minimum_distance > distance)
-    shift = minimum_distance - distance;
-      
-  int stafflines = Staff_symbol_referencer::line_count (rest);
+  shift /= staff_space;
+  Real rad = Staff_symbol_referencer::line_count (rest) * staff_space / 2;
 
   /* Always move discretely by half spaces */
 
   /* Always move discretely by half spaces */
-  Real discrete_shift = ceil (shift * 2.0) / 2.0;
+  shift = ceil (fabs (shift * 2.0)) / 2.0 * sign (shift);
 
   /* Inside staff, move by whole spaces*/
 
   /* Inside staff, move by whole spaces*/
-  if ((rest->extent (common_x, Y_AXIS)[d] + discrete_shift) * d
-      < stafflines / 2.0
-      ||(rest->extent (common_x, Y_AXIS)[-d] + discrete_shift) * -d
-      < stafflines / 2.0)
-    discrete_shift = ceil (discrete_shift);
+  if ( (rest->extent (common_y, Y_AXIS)[d] + staff_space * shift) * d
+      < rad
+      || (rest->extent (common_y, Y_AXIS)[-d] + staff_space * shift) * -d
+      < rad)
+    shift = ceil (fabs (shift)) *sign (shift);
 
 
-  return gh_double2scm (-d * discrete_shift);
+  return scm_make_real (staff_space * shift);
 }
 
 bool
 }
 
 bool
-Beam::knee_b (Grob* me)
+Beam::is_knee (Grob* me)
 {
 {
-  SCM k = me->get_grob_property ("knee");
-  if (gh_boolean_p (k))
-    return gh_scm2bool (k);
+  SCM k = me->get_property ("knee");
+  if (scm_is_bool (k))
+    return ly_scm2bool (k);
 
   bool knee = false;
   int d = 0;
 
   bool knee = false;
   int d = 0;
-  for (SCM s = me->get_grob_property ("stems"); gh_pair_p (s); s = ly_cdr (s))
+  for (SCM s = me->get_property ("stems"); scm_is_pair (s); s = scm_cdr (s))
     {
     {
-      Direction dir = Directional_element_interface::get
-       (unsmob_grob (ly_car (s)));
+      Direction dir = get_grob_direction (unsmob_grob (scm_car (s)));
       if (d && d != dir)
        {
          knee = true;
       if (d && d != dir)
        {
          knee = true;
@@ -1494,7 +1400,7 @@ Beam::knee_b (Grob* me)
       d = dir;
     }
   
       d = dir;
     }
   
-  me->set_grob_property ("knee", gh_bool2scm (knee));
+  me->set_property ("knee", ly_bool2scm (knee));
 
   return knee;
 }
 
   return knee;
 }
@@ -1520,22 +1426,14 @@ Beam::get_direction_beam_count (Grob *me, Direction d )
 
 
 ADD_INTERFACE (Beam, "beam-interface",
 
 
 ADD_INTERFACE (Beam, "beam-interface",
-  "A beam. \n\n"
-" "
-"#'thickness= weight of beams, in staffspace "
-" "
-" "
-"We take the least squares line through the ideal-length stems, and "
-"then damp that using "
-" \n"
-"      damped = tanh (slope) \n"
-" \n"
-"this gives an unquantized left and right position for the beam end. "
-"Then we take all combinations of quantings near these left and right "
-"positions, and give them a score (according to how close they are to "
-"the ideal slope, how close the result is to the ideal stems, etc.). We "
-"take the best scoring combination. "
-,
-  "knee position-callbacks concaveness-gap concaveness-threshold dir-function quant-score auto-knee-gap gap chord-tremolo beamed-stem-shorten shorten least-squares-dy damping flag-width-function neutral-direction positions space-function thickness");
+              "A beam. \n\n"
+              "The @code{thickness} property is the weight of beams, and is measured "
+              "in  staffspace"
+              ,
+              "knee positioning-done position-callbacks "
+              "concaveness dir-function quant-score auto-knee-gap gap "
+              "gap-count chord-tremolo beamed-stem-shorten shorten least-squares-dy "
+              "damping inspect-quants flag-width-function neutral-direction positions space-function "
+              "thickness");