From 443592be643df8c65ecf514c249cb3d41d2a7ecb Mon Sep 17 00:00:00 2001
From: fred <fred>
Date: Tue, 26 Mar 2002 21:45:58 +0000
Subject: [PATCH] lilypond-1.1.20

---
 init/engraver.ly                            |   3 +-
 init/params.ly                              |  45 +--
 input/test/beam-damp.ly                     |  19 ++
 input/test/beam-interstaff.ly               |  31 ++
 input/test/beam-isknee.ly                   |  22 ++
 input/test/beam-suspect.ly                  |  16 +
 input/test/wtk-huh.ly                       |  18 ++
 lily/beam.cc                                | 330 +++++++-------------
 lily/include/beam.hh                        |   8 +-
 lily/include/multi-measure-rest-engraver.hh |   9 +-
 lily/include/multi-measure-rest.hh          |  14 +-
 lily/include/score-column.hh                |   2 +-
 lily/include/stem-info.hh                   |   4 +-
 lily/include/stem.hh                        |   5 +-
 lily/include/volta-spanner.hh               |   6 +-
 lily/multi-measure-rest-engraver.cc         |  60 +++-
 lily/multi-measure-rest.cc                  |  49 ++-
 lily/score-column.cc                        |   4 +-
 lily/stem-engraver.cc                       |   2 +
 lily/stem-info.cc                           | 129 ++++----
 lily/stem.cc                                |  31 +-
 lily/timing-translator.cc                   |   2 +-
 lily/volta-spanner.cc                       |  70 ++---
 mutopia/J.S.Bach/wtk1-fugue2.ly             |  37 ++-
 24 files changed, 505 insertions(+), 411 deletions(-)
 create mode 100644 input/test/beam-damp.ly
 create mode 100644 input/test/beam-interstaff.ly
 create mode 100644 input/test/beam-isknee.ly
 create mode 100644 input/test/beam-suspect.ly
 create mode 100644 input/test/wtk-huh.ly

diff --git a/init/engraver.ly b/init/engraver.ly
index 11f0884081..6ad41f5600 100644
--- a/init/engraver.ly
+++ b/init/engraver.ly
@@ -15,6 +15,7 @@ StaffContext=\translator {
 %}
 %	\type "Hara_kiri_line_group_engraver";
 
+	\consists "Multi_measure_rest_engraver";
 	\consists "Repeat_engraver";
 	\consists "Bar_engraver";
 	\consists "Clef_engraver";
@@ -97,7 +98,7 @@ VoiceContext = \translator {
 	\consists "Stem_engraver";
 	\consists "Beam_engraver";
 	\consists "Abbreviation_beam_engraver";
-	\consists "Multi_measure_rest_engraver";
+%	\consists "Multi_measure_rest_engraver";
 
 	% ugh.  Order matters here.
 	\consists "Text_engraver";
diff --git a/init/params.ly b/init/params.ly
index 35ab7533d4..650f51783b 100644
--- a/init/params.ly
+++ b/init/params.ly
@@ -16,20 +16,31 @@ beam_thickness = 0.52 * (\interline - \staffline);
 interbeam = (2.0 * \interline - \beam_thickness) / 2.0;
 interbeam4 = (3.0 * \interline - \beam_thickness) / 3.0;
 
-
 % stems and beams
 %
-% not used for beams
-stem_length = 3.5*\interline;
-
+% poor man's array size
+stem_max = 3.0;
 %
+stem_length0 = 3.5*\interline;
+stem_length1 = 2.5 * \interline;
+stem_length2 = 2.0 * \interline;
+stem_length3 = 1.5 * \interline;
+
+% only used for beams
+minimum_stem_length0 = 0.0; % not used
+minimum_stem_length1 = 1.5 * \interline;
+minimum_stem_length2 = 1.25 * \interline;
+minimum_stem_length3 = 1.0 * \interline;
+
 % stems in unnatural (forced) direction should be shortened,
 % according to [Roush & Gourlay].  Their suggestion to knock off
-% a whole staffspace seems a bit drastical though?
+% a whole staffspace seems a bit drastical: we'll do half.
 %
-forced_stem_shorten = 1.0 * \interline;
+forced_stem_shorten0 = 0.5 * \interline;
+forced_stem_shorten1 = \forced_stem_shorten0;
+forced_stem_shorten2 = \forced_stem_shorten1;
+forced_stem_shorten3 = \forced_stem_shorten2;
 
-%
 % there are several ways to calculate the direction of a beam
 % 
 % * MAJORITY : number count of up or down notes
@@ -46,21 +57,11 @@ MEDIAN = 4.0;
 % [Ross]: majority
 beam_dir_algorithm = \MAJORITY;
 
-%
-%
-% some beam-stemlength settings...
-%
-%    beam_*1 : multiplicity < beam_multiple_break
-%    beam_*2 : multiplicity >= beam_multiple_break
-%
-beam_multiple_break = 3.0;
-beam_minimum_stem1 = 0.75 * \interline;
-beam_ideal_stem1 = 1.75 * \interline;
-beam_minimum_stem2 = 0.75 * \interline;
-beam_ideal_stem2 = 1.25 * \interline;
-
-% beam_slope_damp_correct_factor = 2.0;
-beam_slope_damp_correct_factor = 0.0;
+% catch suspect beam slopes, set slope to zero if
+% outer stem is lengthened more than
+beam_lengthened = 0.2 * \interline;
+% and slope is running away steeper than
+beam_steep_slope = 0.2 / 1.0;
 
 % OSU: suggested gap = ss / 5;
 slur_x_gap = \interline / 5.0;
diff --git a/input/test/beam-damp.ly b/input/test/beam-damp.ly
new file mode 100644
index 0000000000..c6f2147b9e
--- /dev/null
+++ b/input/test/beam-damp.ly
@@ -0,0 +1,19 @@
+\score{
+	\notes\relative c''{
+%		\stemup
+%		[a16 b b c]
+%		[c b b a]
+%		\stemdown
+%		[c b b a]
+%		[a b b c]
+		\stemup
+		[g16 a b c]
+		[c b a g]
+		\stemdown
+		[d' c b a]
+		[a b c d]
+	}
+	\paper{
+		linewidth=-1.;
+	}
+}
diff --git a/input/test/beam-interstaff.ly b/input/test/beam-interstaff.ly
new file mode 100644
index 0000000000..65e0a5d2c2
--- /dev/null
+++ b/input/test/beam-interstaff.ly
@@ -0,0 +1,31 @@
+\score{
+	\type GrandStaff <
+	\type Staff=one \notes\relative c'{
+		\stemup [c8 c \translator Staff=two \stemup c c]
+		r2
+		\translator Staff=one
+		\stemdown [c8 c \translator Staff=two \stemup c c]
+		r2
+		\stemdown [c8 c \translator Staff=one \stemdown c c]
+		r2
+		\translator Staff=two
+		\stemup [c8 c \translator Staff=one \stemdown c c]
+		r2
+	}
+	\type Staff=two \notes\relative c'{
+		\clef bass;
+		s1
+		s1
+		s1
+		s1
+	}
+	>
+	\paper{
+		\translator{
+			\GrandStaffContext
+			minVerticalAlign = 2.5*\staffheight;
+			maxVerticalAlign = 2.5*\staffheight;
+		}
+		linewidth=-1.;
+	}
+}
diff --git a/input/test/beam-isknee.ly b/input/test/beam-isknee.ly
new file mode 100644
index 0000000000..45a5e4bf41
--- /dev/null
+++ b/input/test/beam-isknee.ly
@@ -0,0 +1,22 @@
+\score{
+	\type GrandStaff <
+	\type Staff=one \notes\relative c'{
+		s1
+	}
+	\type Staff=two \notes\relative c'{
+		\clef bass;
+% no knee
+		\stemup [c8 \translator Staff=one \stemdown g'16 f]
+		s8
+		s2
+	}
+	>
+	\paper{
+		\translator{
+			\GrandStaffContext
+			minVerticalAlign = 2.8*\staffheight;
+			maxVerticalAlign = 2.8*\staffheight;
+		}
+		linewidth=-1.;
+	}
+}
diff --git a/input/test/beam-suspect.ly b/input/test/beam-suspect.ly
new file mode 100644
index 0000000000..cf41188dcc
--- /dev/null
+++ b/input/test/beam-suspect.ly
@@ -0,0 +1,16 @@
+\score{
+	\notes\relative c'{
+		\stemup
+		[f8 a' g f]
+		[c8 g'16 f]
+		[c8 e16 d]
+		[a16 b c d]
+		[d16 c b a]
+		\stemdown
+		[c16 b a g]
+		[g16 a b c]
+	}
+	\paper{
+		linewidth=-1.;
+	}
+}
diff --git a/input/test/wtk-huh.ly b/input/test/wtk-huh.ly
new file mode 100644
index 0000000000..3d49c18a50
--- /dev/null
+++ b/input/test/wtk-huh.ly
@@ -0,0 +1,18 @@
+\score{
+	\type Staff \notes\relative c'''{
+		< \type Voice = one {
+		\stemup
+		\voiceone
+		[g8 a g f]
+		}
+		\type Voice=two
+		{
+		\stemdown
+		\voicetwo
+		[c8 f e d]
+		}>
+	}
+	\paper{
+		linewidth=-1.;
+	}
+}
diff --git a/lily/beam.cc b/lily/beam.cc
index 40648d8353..af118cb5dd 100644
--- a/lily/beam.cc
+++ b/lily/beam.cc
@@ -37,7 +37,6 @@
 Beam::Beam ()
 {
   slope_f_ = 0;
-  solved_slope_f_ = 0;
   left_y_ = 0;
   damping_i_ = 1;
   quantisation_ = NORMAL;
@@ -78,6 +77,10 @@ Beam::do_brew_molecule_p () const
   mol_p->translate_axis (x0 
     - spanned_drul_[LEFT]->absolute_coordinate (X_AXIS), X_AXIS);
 
+  // correct if last note (and therefore reference point of beam)
+  // is on different staff
+  mol_p->translate_axis (- sinfo_.top ().interstaff_f_ * internote_f, Y_AXIS);
+
   return mol_p;
 }
 
@@ -156,18 +159,6 @@ Beam::set_default_dir ()
 
     } while (flip(&d) != DOWN);
   
-#if 0
-   /*
-     urg?  consider [b''16 a]: will get stem down!
-     i'll leave this 'fix' commented-out in case something breaks.
-     jcn
-    */
-   do {
-    if (!total[d])
-      count[d] = 1;
-  } while (flip(&d) != DOWN);
-#endif
-  
   /* 
      [Ross] states that the majority of the notes dictates the
      direction (and not the mean of "center distance")
@@ -214,164 +205,159 @@ Beam::set_default_dir ()
  */
 
 void
-Beam::solve_slope (Array<Stem_info>& sinfo)
+Beam::solve_slope ()
 {
   /*
     should use minimum energy formulation (cf linespacing)
   */
-  assert (sinfo.size () > 1);
+  assert (sinfo_.size () > 1);
   DOUT << "Beam::solve_slope: \n";
 
-  Real staffline_f = paper ()->rule_thickness ();
-  Real epsilon_f = staffline_f / 8;
-
-  Real leftx = sinfo[0].x_;
   Least_squares l;
-  for (int i=0; i < sinfo.size (); i++)
+  for (int i=0; i < sinfo_.size (); i++)
     {
-      sinfo[i].x_ -= leftx;
-      l.input.push (Offset (sinfo[i].x_, sinfo[i].idealy_f_));
+      l.input.push (Offset (sinfo_[i].x_, sinfo_[i].idealy_f_));
     }
-
-  // l.input[0].y () += left_y_;
-  l.input[0].y () += left_y_ / 2;
   l.minimise (slope_f_, left_y_);
-
-  solved_slope_f_ = dir_ * slope_f_;
-
-  /*
-    This neat trick is by Werner Lemberg, damped = tanh (slope_f_) corresponds
-    with some tables in [Wanske]
-    */
-  if (damping_i_)
-    slope_f_ = 0.6 * tanh (slope_f_) / damping_i_;
-
-  /* 
-    [TODO]
-    think
-
-    dropping lq for stemlengths solves [d d d] [d g d] "bug..."
-
-    but may be a bit too crude, and result in lots of 
-    too high beams...
-
-    perhaps only if slope = 0 ?
-    */
-
-  if (abs (slope_f_) < epsilon_f)
-    left_y_ = (sinfo[0].idealy_f_ + sinfo.top ().idealy_f_) / 2;
-  else
-    /* 
-      symmetrical, but results often in having stemlength = minimal 
-
-    left_y_ = sinfo[0].dir_ == dir_ ? sinfo[0].miny_f_ : sinfo[0].maxy_f_;
-
-      what about
-    */
-    {
-      Real dx = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
-      if (sinfo[0].dir_ == sinfo.top ().dir_)
-	left_y_ = sinfo[0].idealy_f_ >? sinfo.top ().idealy_f_ - slope_f_ * dx; 
-      // knee
-      else
-	left_y_ = sinfo[0].idealy_f_;
-    }
 }
 
 Real
-Beam::check_stemlengths_f (Array<Stem_info>& sinfo)
+Beam::check_stemlengths_f (bool set_b)
 {
-  /*
-   find shortest stem and adjust left_y accordingly
-   */
-  Real dy = 0.0;
-  for (int i=0; i < sinfo.size (); i++)
+  Real interbeam_f = paper ()->interbeam_f (multiple_i_);
+  Real internote_f = paper ()->internote_f (); 
+  Real beam_f = paper ()->beam_thickness_f ();
+  Real staffline_f = paper ()->rule_thickness ();
+  Real epsilon_f = staffline_f / 8;
+  Real dy_f = 0.0;
+  for (int i=0; i < sinfo_.size (); i++)
     {
-      Real y = sinfo[i].x_ * slope_f_ + left_y_;
-      Real my = sinfo[i].miny_f_;
+      Real y = sinfo_[i].x_ * slope_f_ + left_y_;
 
-      if (my - y > dy)
-	dy = my -y;
+      // correct for knee
+      if (dir_ != sinfo_[i].dir_)
+	{
+	  y -= dir_ * (beam_f / 2
+		       + (sinfo_[i].mult_i_ - 1) * interbeam_f) / internote_f;
+	  if (!i && sinfo_[i].stem_l_->staff_sym_l_ !=
+	      sinfo_.top ().stem_l_->staff_sym_l_)
+	    y += dir_ * (multiple_i_ - (sinfo_[i].stem_l_->flag_i_ - 2) >? 0)
+	      * interbeam_f / internote_f;
+	}
+
+      if (set_b)
+	sinfo_[i].stem_l_->set_stemend (y - sinfo_[i].interstaff_f_);
+	
+      y *= dir_;
+      if (y > sinfo_[i].maxy_f_)
+	dy_f = dy_f <? sinfo_[i].maxy_f_ - y;
+      if (y < sinfo_[i].miny_f_)
+	{ 
+	  // when all too short, normal stems win..
+	  if (dy_f < -epsilon_f)
+	    warning (_ ("weird beam shift, check your knees"));
+	  dy_f = dy_f >? sinfo_[i].miny_f_ - y;
+	}
     }
-  return dy;
+  return dy_f;
 }
 
 void
-Beam::calculate_slope ()
+Beam::set_steminfo ()
 {
-  Real interline_f = paper ()->interline_f ();
-  Real staffline_f = paper ()->rule_thickness ();
-  Real epsilon_f = staffline_f / 8;
-
   assert (multiple_i_);
-  Array<Stem_info> sinfo;
+  int total_count_i = 0;
+  int forced_count_i = 0;
   for (int i=0; i < stems_.size (); i++)
     {
       Stem *s = stems_[i];
-
       s->mult_i_ = multiple_i_;
       s->set_default_extents ();
+      if (s->invisible_b ())
+	continue;
+      if (((int)s->chord_start_f ()) && (s->dir_ != s->get_default_dir ()))
+        forced_count_i++;
+      total_count_i++;
+    }
+
+  Real internote_f = paper ()->internote_f ();
+  int stem_max = (int)rint(paper ()->get_var ("stem_max"));
+  Real shorten_f = paper ()->get_var (String ("forced_stem_shorten"
+					      + to_str (multiple_i_ <? stem_max)))
+    / internote_f;
+    
+  Real leftx = 0;
+  for (int i=0; i < stems_.size (); i++)
+    {
+      Stem *s = stems_[i];
       if (s->invisible_b ())
 	continue;
 
       Stem_info info (s);
-      sinfo.push (info);
+      if (leftx == 0)
+	leftx = info.x_;
+      info.x_ -= leftx;
+      if (info.dir_ == dir_)
+        {
+	  if (forced_count_i == total_count_i)
+	    info.idealy_f_ -= shorten_f;
+	  else if (forced_count_i > total_count_i / 2)
+	    info.idealy_f_ -= shorten_f / 2;
+	}
+      sinfo_.push (info);
     }
+}
 
-  if (! sinfo.size ())
+void
+Beam::calculate_slope ()
+{
+  set_steminfo ();
+  if (!sinfo_.size ())
     slope_f_ = left_y_ = 0;
-  else if (sinfo.size () == 1)
+  else if (sinfo_[0].idealy_f_ == sinfo_.top ().idealy_f_)
     {
       slope_f_ = 0;
-      left_y_ = sinfo[0].idealy_f_;
+      left_y_ = sinfo_[0].idealy_f_;
+      left_y_ *= dir_;
     }
   else
     {
-      Real y;
-      Real s;
-      Array <Stem_info> local_sinfo;
-      local_sinfo = sinfo;
-      for (int i = 0; i < 5; i++)
-        {
-	  y = left_y_;
-	  solve_slope (sinfo);
-	  Real dy = check_stemlengths_f (sinfo);
-	  left_y_ += dy;
-
-	  // only consider recalculation if long stem adjustments
-	  if (!i && (left_y_ - sinfo[0].idealy_f_ < 0.5 * interline_f))
-	    break;
-	
-	  if (!i)
-	    s = slope_f_;
-	  // never allow slope to tilt the other way
-	  else if (sign (slope_f_) != sign (s))
-	    {
-	      left_y_ = 0;
-	      slope_f_ = 0;
-	      sinfo = local_sinfo;
-	      Real dy = check_stemlengths_f (sinfo);
-	      left_y_ += dy;
-	      break;
-	    }
-	  // or become steeper
-	  else if (abs (slope_f_) > abs (s))
-	    {
-	      slope_f_ = s;
-	      sinfo = local_sinfo;
-	      Real dy = check_stemlengths_f (sinfo);
-	      left_y_ += dy;
-	      break;
-	    }
-	  if (abs (dy) < epsilon_f)
-	    break;
+      solve_slope ();
+      Real solved_slope_f = slope_f_;
+
+      /*
+	steep slope running against lengthened stem is suspect
+      */
+      Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
+
+      // urg, these y internote-y-dimensions
+      Real internote_f = paper ()->internote_f ();
+      Real lengthened = paper ()->get_var ("beam_lengthened") / internote_f;
+      Real steep = paper ()->get_var ("beam_steep_slope") / internote_f;
+      if (((left_y_ - sinfo_[0].idealy_f_ > lengthened)
+	   && (slope_f_ > steep))
+	  || ((left_y_ + slope_f_ * dx_f - sinfo_.top ().idealy_f_ > lengthened)
+	      && (slope_f_ < -steep)))
+	{
+	  slope_f_ = 0;
 	}
-    }
 
-  left_y_ *= dir_;
-  slope_f_ *= dir_;
+      /*
+	This neat trick is by Werner Lemberg,
+	damped = tanh (slope_f_)
+	corresponds with some tables in [Wanske]
+      */
+      if (damping_i_)
+	slope_f_ = 0.6 * tanh (slope_f_) / damping_i_;
+      
+      quantise_dy ();
+
+      Real damped_slope_dy_f = (solved_slope_f - slope_f_) * dx_f / 2;
+      left_y_ += damped_slope_dy_f;
 
-  quantise_dy ();
+      left_y_ *= dir_;
+      slope_f_ *= dir_;
+    }
 }
 
 void
@@ -505,7 +491,7 @@ Beam::quantise_left_y (bool extend_b)
       if (test_pos == 0)
         {
 	allowed_position.push (hang);
-	cout << "hang" << hang << endl;
+	cout << "hang" << hang << "\n";
 	}
       else if (test_pos==1)
         {
@@ -524,13 +510,6 @@ Beam::quantise_left_y (bool extend_b)
 	}
     }
 
-#if 0
-  // this currently never happens
-  Real q = (dy_f / interline_f - dy_i) * interline_f;
-  if ((quantisation_ < NORMAL) && (q < interline_f / 3 - beam_f / 2))
-    allowed_position.push (inter);
-#endif
-
   Interval iv = quantise_iv (allowed_position, interline_f, dy_f);
 
   Real quanty_f = dy_f - iv.min () <= iv.max () - dy_f ? iv.min () : iv.max ();
@@ -545,88 +524,19 @@ void
 Beam::set_stemlens ()
 {
   Real staffline_f = paper ()->rule_thickness ();
-  Real interbeam_f = paper ()->interbeam_f (multiple_i_);
-  Real internote_f = paper ()->internote_f (); 
-  Real beam_f = paper ()->beam_thickness_f ();
-
   // enge floots
   Real epsilon_f = staffline_f / 8;
 
-  /* 
-
-   Damped and quantised slopes, esp. in monotone scales such as
-
-      [c d e f g a b c]
-
-   will soon produce the minimal stem-length for one of the extreme 
-   stems, which is wrong (and ugly).  The minimum stemlength should
-   be kept rather small, in order to handle extreme beaming, such as
-
-      [c c' 'c]  %assuming no knee
-      
-   correctly.
-   To avoid these short stems for normal cases, we'll correct for
-   the loss in slope, if necessary.
-
-   [TODO]
-   ugh, another hack.  who's next?
-   Writing this all down, i realise (at last) that the Right Thing to
-   do is to assign uglyness to slope and stem-lengths and then minimise
-   the total uglyness of a beam.
-   Steep slopes are ugly, shortened stems are ugly, lengthened stems
-   are ugly.
-   How to do this?
-   
-   */
-
-  Real dx_f = stems_.top ()->hpos_f () - stems_[0]->hpos_f ();
-  Real damp_correct_f = paper ()->get_var ("beam_slope_damp_correct_factor");
-  Real damped_slope_dy_f = (solved_slope_f_ - slope_f_) * dx_f
-    * sign (slope_f_);
-  damped_slope_dy_f *= damp_correct_f;
-  if (damped_slope_dy_f <= epsilon_f)
-    damped_slope_dy_f = 0;
-
   DOUT << "Beam::set_stemlens: \n";
-  Real x0 = stems_[0]->hpos_f ();
-  Real dy_f = 0;
-  // urg
-  for (int jj = 0; jj < 10; jj++)
+  Real dy_f = check_stemlengths_f (false);
+  for (int i = 0; i < 2; i++)
     { 
       left_y_ += dy_f * dir_;
       quantise_left_y (dy_f);
-      dy_f = 0;
-      for (int i=0; i < stems_.size (); i++)
-	{
-	  Stem *s = stems_[i];
-	  if (s->transparent_b_)
-	    continue;
-
-	  Real x = s->hpos_f () - x0;
-	  // urg move this to stem-info
-	  Real sy = left_y_ + slope_f_ * x;
- 	  if (dir_ != s->dir_)
- 	    sy -= dir_ * (beam_f / 2
- 	      + (s->mult_i_ - 1) * interbeam_f) / internote_f;
-	  s->set_stemend (sy);
-	  Real y = s->stem_end_f () * dir_;
-	  Stem_info info (s);
-	  if (y > info.maxy_f_)
-	    dy_f = dy_f <? info.maxy_f_ - y;
-	  if (y < info.miny_f_)
-	    { 
-	      // when all too short, normal stems win..
-	      if (dy_f < -epsilon_f)
-		warning (_ ("weird beam shift, check your knees"));
-	      dy_f = dy_f >? info.miny_f_ - y;
-	    }
-	}
-      if (damped_slope_dy_f && (dy_f >= 0))
-	dy_f += damped_slope_dy_f;
-      damped_slope_dy_f = 0;
+      dy_f = check_stemlengths_f (true);
       if (abs (dy_f) <= epsilon_f)
         {
-	  DOUT << "Beam::set_stemlens: " << jj << " iterations\n";
+	  DOUT << "Beam::set_stemlens: " << i << " iterations\n";
 	  break;
 	}
     }
diff --git a/lily/include/beam.hh b/lily/include/beam.hh
index 5c42a6ba06..a94b0eba90 100644
--- a/lily/include/beam.hh
+++ b/lily/include/beam.hh
@@ -40,7 +40,10 @@ public:
   /// maximum number of beams (for opening-up of beam-spacing)
   int multiple_i_;
 
+  /// vertical align distance between staffs
+  Real vertical_align_f_;
 
+  Array<Stem_info> sinfo_;
   
   Beam();
   void add_stem (Stem*);
@@ -53,6 +56,7 @@ protected:
   virtual Interval do_width () const;    
   Offset center () const;
   void set_default_dir ();
+  void set_steminfo ();
   virtual void do_pre_processing ();
   virtual void do_post_processing ();
   virtual void do_substitute_dependent (Score_element*, Score_element*);
@@ -62,8 +66,8 @@ protected:
   virtual void quantise_left_y (bool extend_b);
   virtual Molecule stem_beams (Stem *here, Stem *next, Stem *prev) const;
   virtual void calculate_slope ();
-  virtual Real check_stemlengths_f (Array<Stem_info>& sinfo);
-  virtual void solve_slope (Array<Stem_info>& sinfo);
+  virtual Real check_stemlengths_f (bool set_b);
+  virtual void solve_slope ();
   virtual void quantise_dy ();
   virtual Molecule*do_brew_molecule_p () const;
 };
diff --git a/lily/include/multi-measure-rest-engraver.hh b/lily/include/multi-measure-rest-engraver.hh
index 4b54fa417c..b9d47c9158 100644
--- a/lily/include/multi-measure-rest-engraver.hh
+++ b/lily/include/multi-measure-rest-engraver.hh
@@ -22,18 +22,21 @@ public:
   Multi_measure_rest_engraver ();
 
 protected:
+  virtual void acknowledge_element (Score_element_info i);
   virtual void do_process_requests ();
   virtual bool do_try_music (Music*);
   virtual void do_pre_move_processing ();
   virtual void do_post_move_processing ();
+
 private:
-  Moment rest_req_stop_mom_;
-  Moment rest_item_creation_mom_;
-  Moment req_start_mom_;
+  Moment rest_stop_mom_;
+//  Moment rest_item_creation_mom_;
+  Moment rest_start_mom_;
 
   
   int start_measure_i_;
   Multi_measure_rest_req* multi_measure_req_l_;
   Multi_measure_rest* mmrest_p_;
+  Multi_measure_rest* lastrest_p_;
 };
 #endif // MULTI_MEASURE_REST_ENGRAVER_HH
diff --git a/lily/include/multi-measure-rest.hh b/lily/include/multi-measure-rest.hh
index 8be84d3002..ed9c9769fd 100644
--- a/lily/include/multi-measure-rest.hh
+++ b/lily/include/multi-measure-rest.hh
@@ -10,19 +10,25 @@
 #ifndef MULTI_MEASURE_REST_HH
 #define MULTI_MEASURE_REST_HH
 
-#include "item.hh"
+#include "spanner.hh"
 
-class Multi_measure_rest : public Item 
+class Multi_measure_rest : public Spanner
 {
 public:
   Multi_measure_rest ();
   int measures_i_;
+  void add_column (Bar*);
 
-  
+  Link_array<Bar> column_arr_;
 
 protected:
-  virtual void do_print () const;
   virtual Molecule *do_brew_molecule_p () const;
+  VIRTUAL_COPY_CONS (Score_element);
+
+  virtual void do_add_processing ();
+  virtual void do_post_processing ();
+  virtual void do_print () const;
+  virtual void do_substitute_dependency (Score_element*,Score_element*);
 };
 
 #endif /* MULTI_MEASURE_REST_HH */
diff --git a/lily/include/score-column.hh b/lily/include/score-column.hh
index 50fd2afa89..736712abdf 100644
--- a/lily/include/score-column.hh
+++ b/lily/include/score-column.hh
@@ -42,7 +42,7 @@ public:
     
 
   Moment when() {  return when_; }
-  Score_column (Moment when);       
+  Score_column (Moment when, bool musical_b=false);
   void add_duration (Moment);
   void preprocess();
   bool musical_b() { return musical_b_; }
diff --git a/lily/include/stem-info.hh b/lily/include/stem-info.hh
index bff7cfbdb3..14d39426e3 100644
--- a/lily/include/stem-info.hh
+++ b/lily/include/stem-info.hh
@@ -20,9 +20,11 @@ struct Stem_info {
   Real miny_f_;
   Real maxy_f_;
   int mult_i_;
+  Real interstaff_f_;
+  Stem* stem_l_;
 
   Stem_info ();
-  Stem_info (Stem const *);
+  Stem_info (Stem *);
 };
 
 #endif // STEM_INFO_HH
diff --git a/lily/include/stem.hh b/lily/include/stem.hh
index 267be4f67a..81f4617bf9 100644
--- a/lily/include/stem.hh
+++ b/lily/include/stem.hh
@@ -76,7 +76,10 @@ public:
 
   /// direction of the beam
   Direction beam_dir_;
-    
+
+  /// what staff am i on?
+  Staff_symbol* staff_sym_l_;    
+
   Stem ();
     
   /// ensure that this Stem also encompasses the Notehead #n#
diff --git a/lily/include/volta-spanner.hh b/lily/include/volta-spanner.hh
index 92dc770812..cf8c1b32d5 100644
--- a/lily/include/volta-spanner.hh
+++ b/lily/include/volta-spanner.hh
@@ -9,11 +9,11 @@
 
 #include "text-def.hh"
 #include "pointer.hh"
-#include "directional-spanner.hh"
+#include "spanner.hh"
 
 /** Volta bracket with number */
 
-class Volta_spanner : public Directional_spanner
+class Volta_spanner : public Spanner
 {
 public:
   Volta_spanner ();
@@ -29,7 +29,7 @@ public:
  
 protected:
   virtual Molecule* do_brew_molecule_p () const;
-  VIRTUAL_COPY_CONS(Score_element);
+  VIRTUAL_COPY_CONS (Score_element);
 
   virtual void do_add_processing ();
   virtual void do_post_processing ();
diff --git a/lily/multi-measure-rest-engraver.cc b/lily/multi-measure-rest-engraver.cc
index ad1b82d413..f1df3cf2e3 100644
--- a/lily/multi-measure-rest-engraver.cc
+++ b/lily/multi-measure-rest-engraver.cc
@@ -11,6 +11,12 @@
 #include "multi-measure-rest-engraver.hh"
 #include "score-column.hh"
 #include "time-description.hh"
+//#include "paper-score.hh"
+//#include "p-score.hh"
+//#include "paper-def.hh"
+//#include "main.hh"
+//#include "global-translator.hh"
+#include "bar.hh"
 
 
 ADD_THIS_TRANSLATOR (Multi_measure_rest_engraver);
@@ -18,11 +24,24 @@ ADD_THIS_TRANSLATOR (Multi_measure_rest_engraver);
 Multi_measure_rest_engraver::Multi_measure_rest_engraver ()
 {
   start_measure_i_ = 0;
-  rest_item_creation_mom_ = rest_req_stop_mom_ =0;
+  rest_stop_mom_ =0;
+  // rest_item_creation_mom_ = 0;
   multi_measure_req_l_ = 0;
   mmrest_p_ = 0;
 }
 
+void
+Multi_measure_rest_engraver::acknowledge_element (Score_element_info i)
+{
+  if (Bar *c = dynamic_cast<Bar*> (i.elem_l_))
+    {
+      if (mmrest_p_) 
+	mmrest_p_->add_column (c);
+      if (lastrest_p_)
+	lastrest_p_->add_column (c);
+    }
+}
+
 bool
 Multi_measure_rest_engraver::do_try_music (Music* req_l)
 {
@@ -30,13 +49,13 @@ Multi_measure_rest_engraver::do_try_music (Music* req_l)
    {
      if (multi_measure_req_l_)
        if (!multi_measure_req_l_->equal_b (mr)
-	   || req_start_mom_ != now_moment ())
+	   || rest_start_mom_ != now_moment ())
 	 return false;
   
      multi_measure_req_l_ = mr;
-     req_start_mom_ = now_moment ();
+     rest_start_mom_ = now_moment ();
      
-     rest_req_stop_mom_ = req_start_mom_ + multi_measure_req_l_->duration_.length ();
+     rest_stop_mom_ = rest_start_mom_ + multi_measure_req_l_->duration_.length ();
      return true;
    }
  return false;
@@ -49,7 +68,7 @@ Multi_measure_rest_engraver::do_process_requests ()
     {
       Time_description const *time = get_staff_info().time_C_;
       mmrest_p_ = new Multi_measure_rest;
-      rest_item_creation_mom_ =  time->when_mom ();
+      // rest_item_creation_mom_ = time->when_mom ();
       announce_element (Score_element_info (mmrest_p_, multi_measure_req_l_));
       start_measure_i_ = time->bars_i_;
     }
@@ -59,10 +78,18 @@ void
 Multi_measure_rest_engraver::do_pre_move_processing ()
 {
   Moment now (now_moment ());
-  if (mmrest_p_ && rest_item_creation_mom_ == now)
+  //urg lily dumps core if i want to let her print all (SkipBars=0) rests...
+#if 0
+  if (mmrest_p_ && (now >= rest_start_mom_) && (mmrest_p_->column_arr_.size () >= 2))
     {
       typeset_element (mmrest_p_);
     }
+#endif
+  if (lastrest_p_)
+    {
+      typeset_element (lastrest_p_);
+      lastrest_p_ = 0;
+    }
 }
 
 void
@@ -70,13 +97,24 @@ Multi_measure_rest_engraver::do_post_move_processing ()
 {
   Time_description const *time = get_staff_info().time_C_;
   Moment now (now_moment ());
-  if (rest_req_stop_mom_ <= now)
-    multi_measure_req_l_ = 0;
 
-  if (mmrest_p_ && (!time->whole_in_measure_ || !multi_measure_req_l_))
+  /*
+   when our time's up, calculate the number of bars rest and
+   make way for new request
+   however, linger around a bit to catch this last column when
+   its announced
+   */
+  if (mmrest_p_ && (now >= rest_stop_mom_)) //&& (!time->whole_in_measure_))
     {
-      assert (rest_item_creation_mom_ < now);
-      mmrest_p_->measures_i_ = time->bars_i_ - start_measure_i_;
+      lastrest_p_ = mmrest_p_;
+      lastrest_p_->measures_i_ = time->bars_i_ - start_measure_i_;
+      //urg lily dumps core if i want to let her print all (SkipBars=0) rests...
+#if 0
+      if (lastrest_p_->column_arr_.size () >= 2)
+        lastrest_p_ = 0;
+#endif
+      multi_measure_req_l_ = 0;
       mmrest_p_ = 0;
     }
 }
+
diff --git a/lily/multi-measure-rest.cc b/lily/multi-measure-rest.cc
index 6bb3a5a6e4..77a49ca7bb 100644
--- a/lily/multi-measure-rest.cc
+++ b/lily/multi-measure-rest.cc
@@ -3,13 +3,15 @@
   
   source file of the GNU LilyPond music typesetter
   
-  (c) 1998 Jan Nieuwenhuizen <janneke@gnu.org>
+  (c) 1998, 1999 Jan Nieuwenhuizen <janneke@gnu.org>
   
  */
 
 #include "multi-measure-rest.hh"
 #include "debug.hh"
 #include "paper-def.hh"
+#include "p-col.hh" // urg
+#include "bar.hh"
 #include "lookup.hh"
 #include "rest.hh"
 #include "script.hh"
@@ -33,20 +35,26 @@ Molecule*
 Multi_measure_rest::do_brew_molecule_p () const
 {
   /*
-   [TODO]                                     3
-     * make real multi-measure rest symbol: |---|
-     * make two,four,eight-measure-rest symbols
+   [TODO]                                          17
+     * variable-sized multi-measure rest symbol: |====| ??
+     * build 3, 5, 6, 7, 8 symbols (how far, property?)
+       from whole, brevis and longa rests
    */
+  Molecule* mol_p = new Molecule;
+  if (!column_arr_.size ())
+    return mol_p;
+
   Atom s;
   if (measures_i_ == 1 || measures_i_ == 2 || measures_i_ == 4) 
     {
       s = (lookup_l ()->rest (- intlog2(measures_i_), 0));
+      s.translate_axis (-s.extent ()[X_AXIS].length () / 2, X_AXIS);
     }
   else 
     {
       s = (lookup_l ()->rest (-4, 0));
     }
-  Molecule* mol_p = new Molecule ( Atom (s));
+  mol_p->add_atom (s);
   Real interline_f = paper ()->interline_f ();
   if (measures_i_ == 1)
     {
@@ -67,3 +75,34 @@ Multi_measure_rest::do_brew_molecule_p () const
   return mol_p;
 }
 
+void
+Multi_measure_rest::do_add_processing ()
+{
+  if (column_arr_.size ())
+    {
+      set_bounds (LEFT, column_arr_[0 >? column_arr_.size () - 2]);
+      set_bounds (RIGHT, column_arr_[column_arr_.size () - 1]);
+    }
+}
+  
+void
+Multi_measure_rest::do_post_processing ()
+{
+  if (column_arr_.size ())
+    translate_axis (extent (X_AXIS).length () / 2, X_AXIS);
+}
+
+void
+Multi_measure_rest::do_substitute_dependency (Score_element* o, Score_element* n)
+{
+  if (Bar* c = dynamic_cast <Bar*> (o))
+    column_arr_.substitute (c, dynamic_cast<Bar*> (n));
+}
+  
+void
+Multi_measure_rest::add_column (Bar* c)
+{
+  column_arr_.push (c);
+  add_dependency (c);
+}
+
diff --git a/lily/score-column.cc b/lily/score-column.cc
index 54a52bf502..ab3ceb8a50 100644
--- a/lily/score-column.cc
+++ b/lily/score-column.cc
@@ -11,11 +11,11 @@
 #include "score-column.hh"
 #include "command-request.hh"
 
-Score_column::Score_column (Moment w)
+Score_column::Score_column (Moment w, bool musical_b)
 {
   break_penalty_i_ = 0;
   when_ = w;
-  musical_b_ = false;
+  musical_b_ = musical_b;
 }
 
 void
diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc
index ae32b12ba1..07998e448f 100644
--- a/lily/stem-engraver.cc
+++ b/lily/stem-engraver.cc
@@ -13,6 +13,7 @@
 #include "duration-convert.hh"
 #include "misc.hh"
 #include "abbrev.hh"
+#include "staff-info.hh"
 
 Stem_engraver::Stem_engraver()
 {
@@ -45,6 +46,7 @@ Stem_engraver::acknowledge_element(Score_element_info i)
 	  int durlog_i = r->duration_.durlog_i_;
 	  stem_p_->flag_i_ = durlog_i;
 
+	  stem_p_->staff_sym_l_ = get_staff_info ().staff_sym_l_;
 	  
 	  if (abbrev_req_l_)
 	    {
diff --git a/lily/stem-info.cc b/lily/stem-info.cc
index 20f16ea05c..a25535b8dc 100644
--- a/lily/stem-info.cc
+++ b/lily/stem-info.cc
@@ -15,111 +15,80 @@
 #include "paper-def.hh"
 #include "lookup.hh"
 #include "stem-info.hh"
+#include "beam.hh"
 
 Stem_info::Stem_info ()
 {
 }
 
-Stem_info::Stem_info (Stem const *s)
+Stem_info::Stem_info (Stem*s)
 {
-  x_ = s->hpos_f ();
-  dir_ = s->dir_;
-  beam_dir_ = s->beam_dir_;
-  mult_i_ = s->mult_i_;
-
-  /*
-    [TODO]
-    make this runtime
-
-    Breitkopf + H\"artel:
-    miny_f_ = interline + #beams * interbeam
-    ideal8 = 2 * interline + interbeam
-    ideal16,32,64,128 = 1.5 * interline + #beams * interbeam
-
-    * B\"arenreiter:
-    miny_f_ = interline + #beams * interbeam
-    ideal8,16 = 2 interline + #beams * interbeam
-    ideal32,64,128 = 1.5 interline + #beams * interbeam
-       
-    */
-
-  Real internote_f = s->paper ()->internote_f ();
-  Real interbeam_f = s->paper ()->interbeam_f (mult_i_);
-  Real beam_f = s->paper ()->beam_thickness_f ();
+  stem_l_ = s;
+  x_ = stem_l_->hpos_f ();
+  dir_ = stem_l_->dir_;
+  beam_dir_ = stem_l_->beam_dir_;
+  mult_i_ = stem_l_->mult_i_;
+  interstaff_f_ = 0;
+
+  Paper_def* paper_l = stem_l_->paper ();
+  Real internote_f = paper_l->internote_f ();
+  Real interbeam_f = paper_l->interbeam_f (mult_i_);
+  Real beam_f = paper_l->beam_thickness_f ();
          
-
   {
       static int i = 1;
       DOUT << "******" << i++ << "******\n" 
-	   << "begin_f: " << s->stem_begin_f () * dir_ 
-	   << "\nchord_f/i: " << s->chord_start_f () * dir_ / internote_f << '\n';
+	   << "begin_f: " << stem_l_->stem_begin_f () * dir_ 
+	   << "\nchord_f/i: " << stem_l_->chord_start_f () * dir_ / internote_f << '\n';
   }
 
-  /*
-    For simplicity, we'll assume dir = UP and correct if 
-    dir = DOWN afterwards.
-   */
-  idealy_f_ = s->chord_start_f () * beam_dir_ / internote_f;
+  // strangely enough, dim(chord_start_f) == pt (and not internote!)
+  idealy_f_ = stem_l_->chord_start_f () / internote_f;
+
+  // calculate using dim(y) == pt
   idealy_f_ *= internote_f;
 
-  Real break_i = (int)rint (s->paper ()->get_var ("beam_multiple_break"));
-  Real min_stem1_f = s->paper ()->get_var ("beam_minimum_stem1");
-  Real min_stem2_f = s->paper ()->get_var ("beam_minimum_stem2");
-  Real ideal_stem1_f = s->paper ()->get_var ("beam_ideal_stem1");
-  Real ideal_stem2_f = s->paper ()->get_var ("beam_ideal_stem2");
-  Real shorten_f = s->paper ()->get_var ("forced_stem_shorten");
+  // for simplicity, we calculate as if dir == UP
+  idealy_f_ *= beam_dir_;
+  
+  int stem_max = (int)rint(paper_l->get_var ("stem_max"));
+  Real min_stem_f = paper_l->get_var (String ("minimum_stem_length")
+				     + to_str (mult_i_ <? stem_max));
+  Real stem_f = paper_l->get_var (String ("stem_length")
+				 + to_str (mult_i_ <? stem_max));
 
   if (!beam_dir_ || (beam_dir_ == dir_))
+    /* normal beamed stem */
     {
-      idealy_f_ += interbeam_f * mult_i_;
+      if (mult_i_)
+	{
+	  idealy_f_ += beam_f;
+	  idealy_f_ += (mult_i_ - 1) * interbeam_f;
+	}
       miny_f_ = idealy_f_;
       maxy_f_ = INT_MAX;
 
-      if (mult_i_ < break_i)
-        {
-	  idealy_f_ += ideal_stem1_f;
-	  miny_f_ += min_stem1_f;
-	}
-      else
-        {
-	  idealy_f_ += ideal_stem2_f;
-	  miny_f_ += min_stem2_f;
-	}
-
-      /*
-        stems in unnatural (forced) direction are shortened
-        central line is never 'forced'
-       */
-      if (((int)s->chord_start_f ()) && (s->dir_ != s->get_default_dir ()))
- 	{
-	  idealy_f_ -= shorten_f;
-	  miny_f_ = miny_f_ <? idealy_f_ + internote_f;
-	}
+      idealy_f_ += stem_f;
+      miny_f_ += min_stem_f;
 
       // lowest beam of (UP) beam must never be lower than second staffline
       miny_f_ = miny_f_ >? (- 2 * internote_f - beam_f
 	+ (mult_i_ > 0) * beam_f + interbeam_f * (mult_i_ - 1));
     }
   else
+    /* knee */
     {
       idealy_f_ -= beam_f;
+      // idealy_f_ -= (mult_i_ - 1) * interbeam_f;
+      // idealy_f_ += (mult_i_ - stem_l_->flag_i_ >? 0) * interbeam_f;
       maxy_f_ = idealy_f_;
       miny_f_ = -INT_MAX;
 
-      // B"arenreiter
-      if (mult_i_ < break_i)
-        {
-	  idealy_f_ -= ideal_stem1_f;
-	  maxy_f_ -= min_stem1_f;
-	}
-      else
-        {
-	  idealy_f_ -= ideal_stem2_f;
-	  maxy_f_ -= min_stem2_f;
-	}
+      idealy_f_ -= stem_f;
+      maxy_f_ -= min_stem_f;
     }
 
-
+  // set dim(y) == internote
   idealy_f_ /= internote_f;
   miny_f_ /= internote_f;
   maxy_f_ /= internote_f;
@@ -132,5 +101,21 @@ Stem_info::Stem_info (Stem const *s)
 
   idealy_f_ = maxy_f_ <? idealy_f_;
   idealy_f_ = miny_f_ >? idealy_f_;
+
+  // interstaff beam
+  Beam* beam_l_ = stem_l_->beam_l_;
+  if (beam_l_->sinfo_.size ()
+      && stem_l_->staff_sym_l_ != beam_l_->sinfo_[0].stem_l_->staff_sym_l_)
+    {
+      // hmm, perhaps silly now to have vertical_align in Beam
+      interstaff_f_ = beam_l_->vertical_align_f_ / internote_f;
+      // urg, guess staff order:
+      // if our stem ends higher, our staff is probably lower...
+      if (idealy_f_ * beam_dir_ > beam_l_->sinfo_[0].idealy_f_ * beam_dir_)
+	interstaff_f_ *= -1;
+      idealy_f_ += interstaff_f_ * beam_dir_;
+      miny_f_ += interstaff_f_ * beam_dir_;
+      maxy_f_ += interstaff_f_ * beam_dir_;
+    }
 }
 
diff --git a/lily/stem.cc b/lily/stem.cc
index 90a12ae555..740cb41666 100644
--- a/lily/stem.cc
+++ b/lily/stem.cc
@@ -164,41 +164,32 @@ Stem::set_default_dir ()
 void
 Stem::set_default_stemlen ()
 {
-  /*
-   TODO
-   urg; this should be handled by Stem_info
-   */
-
-  Real length_f = paper ()->get_var ("stem_length");
-  Real shorten_f = paper ()->get_var ("forced_stem_shorten");
-
   Real internote_f = paper ()->internote_f ();
-  length_f /= internote_f;
-  shorten_f /= internote_f;
+  Real length_f = paper ()->get_var ("stem_length0") / internote_f;
+  Real shorten_f = paper ()->get_var ("forced_stem_shorten0") / internote_f;
 
-  Real len = length_f;
   if (!dir_)
     set_default_dir ();
   /* 
     stems in unnatural (forced) direction should be shortened, 
     accoding to [Roush & Gourlay]
    */
-  else if (dir_ != get_default_dir ())
-    len -= shorten_f / internote_f;
+  if (((int)chord_start_f ())
+      && (dir_ != get_default_dir ()))
+    length_f -= shorten_f;
 
   if (flag_i_ >= 5)
-    len += 2.0;
+    length_f += 2.0;
   if (flag_i_ >= 6)
-    len += 1.0;
+    length_f += 1.0;
   
-  set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + len :
-	       head_positions()[SMALLER] - len);
+  set_stemend ((dir_ > 0) ? head_positions()[BIGGER] + length_f:
+	       head_positions()[SMALLER] - length_f);
 
   if (dir_ * stem_end_f () < 0)
-    {
-      set_stemend (0);
-    }
+    set_stemend (0);
 }
+
 //xxx
 void
 Stem::set_default_extents ()
diff --git a/lily/timing-translator.cc b/lily/timing-translator.cc
index 71c3eb09e1..534d3f2f31 100644
--- a/lily/timing-translator.cc
+++ b/lily/timing-translator.cc
@@ -121,7 +121,7 @@ Timing_translator::do_pre_move_processing()
   /* allbars == ! skipbars */
   bool allbars = ! get_property ("SkipBars", 0).to_bool ();
 
-
+  // urg: multi bar rests: should always must process whole of first bar?
   if (!time_.cadenza_b_ && allbars)
     global_l->add_moment_to_process (time_.next_bar_moment ());
 }
diff --git a/lily/volta-spanner.cc b/lily/volta-spanner.cc
index a5b6f629a0..7513146388 100644
--- a/lily/volta-spanner.cc
+++ b/lily/volta-spanner.cc
@@ -20,14 +20,8 @@
 #include "stem.hh"
 #include "text-def.hh"
 
-/*
-   Hmm, should probably make generic Bracket_spanner,
-   or and derive Plet and volta spanner from that.
- */
-
 Volta_spanner::Volta_spanner ()
 {
-  dir_ = UP;
   last_b_ = false;
   number_p_.set_p (new Text_def);
   number_p_->align_dir_ = LEFT;
@@ -40,38 +34,38 @@ Volta_spanner::do_brew_molecule_p () const
 {
   Molecule* mol_p = new Molecule;
 
-  if (column_arr_.size ())
-    {
-      Real internote_f = paper ()->internote_f ();
-      Real dx = internote_f;
-      Real w = extent (X_AXIS).length () - 2 * dx;
-      Atom volta (lookup_l ()->volta (w, last_b_));
-      Real h = volta.dim_.y ().length ();
-      Atom num (number_p_->get_atom (paper (), LEFT));
-      Atom dot (dot_p_->get_atom (paper (), LEFT));
-      Real dy = column_arr_.top ()->extent (Y_AXIS) [dir_] > 
-	column_arr_[0]->extent (Y_AXIS) [dir_];
-      dy += 2 * h;
+  if (!column_arr_.size ())
+    return mol_p;
 
-      /*
-	UGH.  Must use extent  ()[dir_]
-       */
-      for (int i = 0; i < note_column_arr_.size (); i++)
-        dy = dy >? note_column_arr_[i]->extent (Y_AXIS).max ();
-      dy -= h;
+  Real internote_f = paper ()->internote_f ();
+  Real dx = internote_f;
+  Real w = extent (X_AXIS).length () - 2 * dx;
+  Atom volta (lookup_l ()->volta (w, last_b_));
+  Real h = volta.dim_.y ().length ();
+  Atom num (number_p_->get_atom (paper (), LEFT));
+  Atom dot (dot_p_->get_atom (paper (), LEFT));
+  Real dy = column_arr_.top ()->extent (Y_AXIS) [UP] > 
+    column_arr_[0]->extent (Y_AXIS) [UP];
+  dy += 2 * h;
 
-      Real gap = num.dim_.x ().length () / 2;
-      Offset off (num.dim_.x ().length () + gap, 
-        (h - num.dim_.y ().length ()) / internote_f - gap);
-      num.translate (off);
-      Real dotheight = dot.dim_.y ().length () / 7;
-      off -= Offset (0, dotheight);
-      dot.translate (off);
-      mol_p->add_atom (volta);
-      mol_p->add_atom (num);
-      mol_p->add_atom (dot);
-      mol_p->translate (Offset (dx, dy));
-    }
+  /*
+    UGH.  Must use extent  ()[dir_]
+   */
+  for (int i = 0; i < note_column_arr_.size (); i++)
+    dy = dy >? note_column_arr_[i]->extent (Y_AXIS).max ();
+  dy -= h;
+
+  Real gap = num.dim_.x ().length () / 2;
+  Offset off (num.dim_.x ().length () + gap, 
+    (h - num.dim_.y ().length ()) / internote_f - gap);
+  num.translate (off);
+  Real dotheight = dot.dim_.y ().length () / 7;
+  off -= Offset (0, dotheight);
+  dot.translate (off);
+  mol_p->add_atom (volta);
+  mol_p->add_atom (num);
+  mol_p->add_atom (dot);
+  mol_p->translate (Offset (dx, dy));
   return mol_p;
 }
   
@@ -91,8 +85,8 @@ Volta_spanner::do_add_processing ()
 void
 Volta_spanner::do_post_processing ()
 {
-    if (column_arr_.size())
-    	translate_axis (column_arr_[0]->extent (Y_AXIS)[dir_], Y_AXIS);
+  if (column_arr_.size())
+    translate_axis (column_arr_[0]->extent (Y_AXIS)[UP], Y_AXIS);
 }
 
 void
diff --git a/mutopia/J.S.Bach/wtk1-fugue2.ly b/mutopia/J.S.Bach/wtk1-fugue2.ly
index 9aeb030879..946ffbe4d7 100644
--- a/mutopia/J.S.Bach/wtk1-fugue2.ly
+++ b/mutopia/J.S.Bach/wtk1-fugue2.ly
@@ -45,20 +45,22 @@ dux = \notes \relative c''{
 %%10   
   as4 r8 a [bes bes16 a] [bes8 f] |
   g4 r8 g [as as g f] |
+  r8 
   \translator Staff = bass \stemup 
-   r8 [as, bes c ] r8 [as16 g] [as8 f8] |
+  [as, bes c ] r8 [as16 g] [as8 f8] |
   [bes8 c  bes as] [bes g f es] |
   [f des'  c  bes] [c  as g f] |
 %%15
   g8
-   \translator Staff = treble \stemdown
-   [g'16 fis] [g8 c,] [es g16 fis!] [g8 a] |
+  [g'16 fis] [g8 c,] 
+  [es \translator Staff = treble \stemdown g16 fis!] [g8 a] |
   [d, g16 fis] [g8 a!] [c,16 d] es4 [d16 c] |         % forced accident!
   bes8 r8 r16 [d e fis] [g a bes8] ~ [bes16 e, f g] |
   [a bes c8] ~ [c16 fis,16 g a] [bes8 es,!16 d] [es8 g, ] |
   [as  f'16 es] [f8 a,8] [bes  g'16 f] [g8 b, ] |
 %%20
-  [c16 f es d] [c bes! as g] [f8 as' g f] |
+  [c16 f \translator Staff = bass \stemup es d] [c bes! as g] 
+  [f8 \translator Staff = treble \stemdown as' g f] |
   [es d es f] [b, c d b] |
   c4 r8 e8 [f f16 e] [f8 c] |
   d4 r8 d8 [es8 es16 d] [es8 bes] |
@@ -77,8 +79,8 @@ dux = \notes \relative c''{
 
 comes = \notes \relative c''  {
   \voiceone
-  r1 |
-  r1 |
+  R1 |
+  R1 |
   r8 [g'16 fis] [g8 c,] [es g16 fis] [g8 a] |
   [d,8 g16 fis] [g8 a] [c,16 d] es4 [d16 c] |
 %%5
@@ -120,13 +122,13 @@ comes = \notes \relative c''  {
 bassdux = \notes \relative c' {
   \clef bass;
 
-  r1 |
-  r |
-  r |
-  r |
+  R1 |
+  R |
+  R |
+  R |
 %%5
-  r |
-  r1 |
+  R |
+  R1 |
   r8 [c16 b] [c8 g] [as c16 b] [c8 d] |
   [g, c16 b] [c8 d] [f,16 g] as4 [g16 f] | 
  [es c'  b a] [g f es d] [c d es d] [c bes! as! g] |
@@ -144,7 +146,8 @@ bassdux = \notes \relative c' {
   [f d'16 c ] [d8 fis,] g4 r16 [g, a b] |
   [c16 d es8~] [es16 a, bes c] [d es f8~] [f16 b,  c d] |
 %%20    
-  es8 r r e [f f, es! d] |                           % -> \classic_accidentals
+%   es8 r r e [f f, es! d] |                           % -> \classic_accidentals
+  es8 r r e \stemdown [f f, es! d] \stemboth |
   r [as' g f] [g f16 es] [f8 g] |
   [c16 d  es d] [c bes as g] [f bes' as g] [f es d c] |
   [bes c d c] [bes as g f] [es as' g f] [es d c bes] |
@@ -188,7 +191,13 @@ bassdux = \notes \relative c' {
     %hmm
 %    \translator { \BarNumberingScoreContext }
 %    \translator { \BarNumberingStaffContext }
-  \translator{ \OrchestralScoreContext }
+%  \translator{ \OrchestralScoreContext }
+    \translator{ \OrchestralScoreContext }
+    \translator{ 
+      \GrandStaffContext
+      minVerticalAlign = 3.0*\staffheight;
+      maxVerticalAlign = 3.0*\staffheight;
+    }
   }
   \header{
 	  opus = "BWV 847";
-- 
2.39.5