From ce521e79fd7669b45c8c1132e4b5693a03b5d90a Mon Sep 17 00:00:00 2001
From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Mon, 11 Mar 2002 01:49:51 +0100
Subject: [PATCH] release: 1.5.38

---
 ChangeLog                              |  63 ++++++
 Documentation/regression-test.tely     |   2 +
 Documentation/user/refman.itely        |  37 ++--
 VERSION                                |   2 +-
 flower/include/interval.hh             |  19 +-
 flower/include/interval.tcc            |   2 +-
 input/baerenreiter-sarabande.ly        | 138 +++++++++++++
 input/regression/break.ly              |   4 +-
 input/regression/spacing-bar-stem.ly   |  23 +++
 input/regression/spacing-stem-bar.ly   |  26 +++
 input/regression/spacing-tight.ly      |   8 +-
 lily/GNUmakefile                       |   1 -
 lily/afm.cc                            |   4 +
 lily/beam.cc                           |   6 +-
 lily/break-align-interface.cc          |   4 +-
 lily/collision.cc                      |   2 +-
 lily/grob.cc                           |  20 +-
 lily/hairpin.cc                        |   2 +-
 lily/include/grob.hh                   |   2 +
 lily/include/paper-column.hh           |   2 +-
 lily/include/simple-spacer.hh          |  35 +---
 lily/include/spaceable-grob.hh         |   2 +-
 lily/include/spacing-spanner.hh        |  29 ---
 lily/include/spring.hh                 |  18 +-
 lily/include/staff-spacing.hh          |   5 +
 lily/interpretation-context-handle.cc  |   2 -
 lily/line-of-score.cc                  |  12 +-
 lily/molecule.cc                       |   7 +
 lily/moment.cc                         |   4 +-
 lily/note-spacing.cc                   |  55 ++++--
 lily/parser.yy                         |  10 +-
 lily/porrectus.cc                      |  10 +-
 lily/property-iterator.cc              |  61 ++++--
 lily/score-engraver.cc                 |   2 +-
 lily/score.cc                          |  12 +-
 lily/separating-line-group-engraver.cc |   3 +-
 lily/simple-spacer.cc                  | 121 +++++++++---
 lily/slur.cc                           |   4 +-
 lily/spaceable-grob.cc                 |  23 ++-
 lily/spacing-engraver.cc               |  17 +-
 lily/spacing-spanner.cc                | 224 ++++++++++++---------
 lily/spring-smob.cc                    |  47 +++++
 lily/spring.cc                         |  55 ------
 lily/staff-spacing.cc                  | 184 ++++++++++++++---
 lily/stem.cc                           |   2 +-
 lily/text-spanner.cc                   |   2 +-
 lily/time-signature-engraver.cc        |   4 +-
 lily/time-signature.cc                 |   2 +-
 make/out/lilypond.lsm                  |   8 +-
 make/out/lilypond.mandrake.spec        |   2 +-
 make/out/lilypond.redhat.spec          |   4 +-
 make/out/lilypond.suse.spec            |   4 +-
 mf/feta-generic.mf                     |   9 +-
 mf/feta-klef.mf                        | 264 +++++++++++++++++--------
 mf/feta-macros.mf                      |   2 +
 mf/feta-toevallig.mf                   |  59 ++++--
 mf/parmesan-generic.mf                 |   1 +
 scm/grob-description.scm               |  10 +-
 scm/grob-property-description.scm      |   7 +-
 scm/interface-description.scm          |   5 +-
 scm/tex.scm                            |   2 +-
 scripts/convert-ly.py                  |   8 +
 62 files changed, 1187 insertions(+), 517 deletions(-)
 create mode 100644 input/baerenreiter-sarabande.ly
 create mode 100644 input/regression/spacing-bar-stem.ly
 create mode 100644 input/regression/spacing-stem-bar.ly
 delete mode 100644 lily/include/spacing-spanner.hh
 create mode 100644 lily/spring-smob.cc

diff --git a/ChangeLog b/ChangeLog
index 2bcad5c824..f525bd9ee3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,66 @@
+2002-03-11  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/grob.cc (warning): Use cause tracking to give more
+	meaningful errors from the backend. 
+
+	* lily/property-iterator.cc (check_grob): Warn if setting grob
+	property in unknown grob. 
+
+	* mf/feta-toevallig.mf: brushed stems for natural sign.
+
+	* lily/molecule.cc (align_to): don't translate empty molecule.
+	(this triggers a very subtle bug in time-signature.)  
+
+2002-03-10  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/spring.cc: remove file.
+
+	* input/regression/spacing-stem-bar.ly: new file
+
+	* lily/score.cc (run_translator): resurrect point-and-click
+
+	* input/baerenreiter-sarabande.ly: Copy Barenreiter beaming for
+	sarabande layout
+
+	* lily/spacing-spanner.cc (find_shortest): Shortest note for
+	spacing is now globally determined, using the most common shortest
+	note. Notes that are shorter are spaced geometrically, and with
+	expand hints. This makes spacing more even, and measures that have
+	very short notes won't be that stretched out.  
+
+	* mf/feta-klef.mf: F-clef fixes, documentation on the
+	shape. (WARNING: font changed.)
+
+2002-03-09  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/simple-spacer.cc (add_columns): support for infinitely
+	stiff springs.
+ 
+	* lily/staff-spacing.cc (get_spacing_params): space after
+	prefatory matter is fixed.
+
+2002-03-08  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/note-spacing.cc (stem_dir_correction): Correct spacing for
+	barline following an upstem.
+
+	* lily/staff-spacing.cc (extremal_break_aligned_grob): destill
+	function from next_notes_correction().
+	(bar_y_positions): idem.
+
+2002-03-04  Han-Wen Nienhuys  <hanwen@cs.uu.nl>
+
+	* input/regression/break.ly (texidoc): bugfix: escape \ in
+	strings.
+
+	* lily/staff-spacing.cc (next_notes_correction): Correct the
+	spacing of a note following a barline.
+
+
+2002-03-04  Glen Prideaux
+
+	* mf/feta-solfa.mf: Shaped note heads
+
 2002-03-03  Han-Wen  <hanwen@cs.uu.nl>
 
 	* VERSION: 1.5.37 released
diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely
index 3eef351526..36cacbfb90 100644
--- a/Documentation/regression-test.tely
+++ b/Documentation/regression-test.tely
@@ -253,6 +253,8 @@ Grace note do weird things with timing. Fragile.
 
 @lilypondfile[printfilename]{prefatory-spacing-matter.ly}
 
+@lilypondfile[printfilename]{spacing-bar-stem.ly}
+
 
 @c @l ilypondfile[printfilename]{spacing-tight.ly}
 
diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely
index c2786787ff..8a6f012082 100644
--- a/Documentation/user/refman.itely
+++ b/Documentation/user/refman.itely
@@ -3610,8 +3610,8 @@ Lilypond and @code{ly2dvi})
 @cindex breaking lines
 
 Line breaks are normally computed automatically. They are chosen such
-that the resulting spacing has low variation, and looks neither cramped
-nor loose.
+that it looks neither cramped nor loose, and that consecutive lines have
+similar density.
 
 Occasionally you might want to override the automatic breaks; you can do
 this by specifying @code{\break}. This will force a line break at this
@@ -3620,6 +3620,17 @@ are bar lines.  If you want to have a line break where there is no
 bar line, you can force an invisible bar line by entering @code{\bar
 ""}. Similarly, @code{\noBreak} forbids a line break at a certain point.
 
+If you want linebreaks at regular intervals, you can use the following:
+@example
+
+<  \repeat 7 unfold @{ s1 * 4 \break  @}
+   @emph{real music}
+> 
+@end  example
+This makes the following 28 measures (assuming 4/4 time) be broken every
+4 measures.
+
+
 @cindex @code{\penalty}
 
 The @code{\break} and @code{\noBreak} commands are defined in terms of
@@ -5082,16 +5093,16 @@ See @ref{convert-ly} for more information on @code{convert-ly}.
 
 
 
-
-@c .{Local emacs vars}
-@c Local variables:
-@c mode: texinfo
-@c minor-mode: font-lock
-@c minor-mode: outline
-@c outline-layout: (-1 : 0)
-@c outline-use-mode-specific-leader: "@c \."
-@c outline-primary-bullet: "{"
-@c outline-stylish-prefixes: nil
-@c outline-override-protect: t
+@c broken with  emacs-21
+@c {Local emac s  vars}
+@c Local varia bles:
+@c mode: texi nfo
+@c minor-mod e: font-lock
+@c minor-mo de: outline
+@c outline -layout: (-1 : 0)
+@c outlin e-use-mode-specific-leader: "@c \."
+@c outli ne-primary-bullet: "{"
+@c outli ne-stylish-prefixes: nil
+@c outli ne-override-protect: t
 @c End:
 
diff --git a/VERSION b/VERSION
index b958c5e8df..b4dfcf2045 100644
--- a/VERSION
+++ b/VERSION
@@ -1,7 +1,7 @@
 PACKAGE_NAME=LilyPond
 MAJOR_VERSION=1
 MINOR_VERSION=5
-PATCH_LEVEL=37
+PATCH_LEVEL=38
 MY_PATCH_LEVEL=
 
 # use the above to send patches: MY_PATCH_LEVEL is always empty for a
diff --git a/flower/include/interval.hh b/flower/include/interval.hh
index 5a1d3c49af..8d4d83a5dc 100644
--- a/flower/include/interval.hh
+++ b/flower/include/interval.hh
@@ -49,7 +49,8 @@ struct Interval_t : public Drul_array<T> {
     set_empty ();
   }
   Interval_t (T m, T M) : Drul_array<T> (m,M)
-    {}
+    {
+    }
   Interval_t<T> &operator -= (T r) {
     *this += -r;
     return *this;
@@ -65,11 +66,9 @@ struct Interval_t : public Drul_array<T> {
       {
 	elem (LEFT) *= r;
 	elem (RIGHT) *= r;
-	if (r < T (0)) {
-	  T t = elem (LEFT);
-	  elem (LEFT) = elem (RIGHT);
-	  elem (RIGHT) = t;
-	}
+	if (r < T (0))
+	  swap();
+
       }
     return *this;
   }
@@ -86,6 +85,14 @@ struct Interval_t : public Drul_array<T> {
     elem (LEFT) = l;
     elem (RIGHT) =r;
   }
+private:
+
+  void swap ()
+  {
+    T t = elem (LEFT);
+    elem (LEFT) = elem (RIGHT);
+    elem (RIGHT) = t;
+  }
 };
 
 
diff --git a/flower/include/interval.tcc b/flower/include/interval.tcc
index c78b476a91..7e773e2579 100644
--- a/flower/include/interval.tcc
+++ b/flower/include/interval.tcc
@@ -64,7 +64,7 @@ template<class T>
 T
 Interval_t<T>::length () const 
 {
-  if (elem (RIGHT) < elem (LEFT)) 
+  if (elem (RIGHT) <= elem (LEFT)) 
     return 0;
   else 
     return elem (RIGHT)-elem (LEFT);
diff --git a/input/baerenreiter-sarabande.ly b/input/baerenreiter-sarabande.ly
new file mode 100644
index 0000000000..450f08d173
--- /dev/null
+++ b/input/baerenreiter-sarabande.ly
@@ -0,0 +1,138 @@
+
+% #(set! point-and-click line-column-location)
+
+\header {
+title = "Solo Cello Suite II"
+piece ="Sarabande"
+composer = "J.S.Bach"
+editor = "August Wenzinger"
+source= "B\\\"arenreiter Urtext"
+
+texidoc = "The B\\\"arenreiter edition of the Cello Suites is the most
+beautifully typeset piece of music in our collection of music (we both
+own one. It is also lovely on French Horn). This piece follows the
+same beaming as the printed edition. This is done in order to
+benchmarkk the quality of the LilyPond output. As of lilypond 1.5.38,
+the spacing is almost identical. With a line-break forced before
+measure 25, we get back the linebreaking of Baerenreiter.
+
+This file used to show spacing weaknesses. Now it shows weaknesses in
+beam and slur handling.
+
+Note that the Barenreiter edition contains a mistake. The second line
+begins with measure 6, not 5.  "
+
+
+}
+
+
+\version "1.3.148"
+
+
+sarabandeA =  \context Voice \notes \relative c {
+    \property Staff.NoteCollision \set #'merge-differently-dotted = ##t
+  	< { d8. e16 e4.-\trill d16 e } \\
+	  { d4 a2 } >
+	f4.  [e8 d c] |
+	[bes g'] [f e16(f] [g a bes)d,] |
+	cis4.-\trill b8 a g |
+
+% check spacing without accs: 
+%	c4.-\trill [bes8 a g] |
+	
+	< { d'8. e16 f4.-\trill d16 e |
+	    f4. d8 e f }
+	  \\
+	  { <a,4 f> a2 <a4. d,4.>  } > |
+	%5
+
+	g8 bes16()a c()bes a()g d'8 f, |
+	<  e4.-\trill
+	   \\ <a,,4 e'> >
+	  [d8 c bes]
+	%8
+	< { f'8 g16()a a4. g16()f  |
+	     g8 a16()bes bes4. c16()d }
+	  \\
+  	  { a,4 <bes4. d4. > r8 bes4 <g2 f'2>  }
+ 	> |
+
+	% 11
+        [e,8 f] [c, g'] [f' e] |
+	f4 f,2 |
+	< {  a'4 a4.-\trill bes8 
+	     c bes16 a } \\
+	  { [f8 es] es4. r8 d4 } >
+
+	fis8.-\trill es16 d8 c |
+	[bes g'] [a, fis'] [es' d] |
+	%16
+	< bes4.-\trill d, g, > a8 g f! |
+	e bes a f' g a |
+	d, as g es' f g |
+	[cis, bes'] [a g16 f] [e!8 f16 d] |
+	cis8 e16 a a,8. g'16 f8()e |
+	%21
+	< { d e16()f f4. e16()d |
+	    e8 f16()g g4. a16()bes |
+	    a8 cis16 d d,8 e16 f32 g f8-\trill e16()d } \\
+	  { bes4 g2 |
+	    g4 <bes4. cis,> s8 |
+	    <d8 a f> r r g, a4 } >
+	|
+	d4 d,16 a'( b cis d e f )g |
+    \break
+	%25
+	< { a16(b c)b c4. b16()a |
+	    b cis d cis d4. e16()f | }
+	  \\
+	  { f,4 fis4. s8 |
+	    <d4 g,> gis4.   } >
+	d16(cis)d f,  a,8 e' d' cis |
+	d4 d,,2 |
+}
+
+
+sarabande =  \context Staff \notes<
+	\apply #voicify-music \sarabandeA
+	
+>
+
+\version "1.3.148"
+
+sarabandeCelloGlobal =  \notes{
+	\time 3/4
+	\key f \major
+	\clef bass
+	\repeat "volta" 2 {
+		s2.*12
+	} \repeat "volta" 2 {
+		s2.*16
+	}
+}
+
+sarabandeCelloScripts =  \notes{
+}
+
+sarabandeCelloStaff =  \context Staff <
+	\sarabande
+	\sarabandeCelloGlobal
+	\sarabandeCelloScripts
+>
+
+\score{
+	\sarabandeCelloStaff
+	\paper{
+	    indent = 7. \mm
+	    linewidth = 183.5 \mm
+	\translator { \ScoreContext
+%		SpacingSpanner \override #'maximum-duration-for-spacing = #(make-moment 1 16)
+
+
+}}
+	\midi{ \tempo 4 = 40 }
+	\header{
+	opus= "" 
+	piece ="Sarabande" }
+}
+
diff --git a/input/regression/break.ly b/input/regression/break.ly
index 32a48357b1..572895457d 100644
--- a/input/regression/break.ly
+++ b/input/regression/break.ly
@@ -2,8 +2,8 @@
 
 \header{
 texidoc="
-Breaks can be encouraged and discouraged using @code{\break} and
-@code{\noBreak}.  They are abbrevs for @code{\penalty} commands.
+Breaks can be encouraged and discouraged using @code{\\break} and
+@code{\\noBreak}.  They are abbrevs for @code{\\penalty} commands.
 "
 }
 
diff --git a/input/regression/spacing-bar-stem.ly b/input/regression/spacing-bar-stem.ly
new file mode 100644
index 0000000000..946628b167
--- /dev/null
+++ b/input/regression/spacing-bar-stem.ly
@@ -0,0 +1,23 @@
+\header {
+texidoc = "Downstem notes following a barline are
+printed with some extra space. This is an optical correction similar
+to juxtaposed stems.
+
+Accidentals after the barline get some space as well.
+"
+}
+
+sd = \property Voice.Stem \set #'direction = #-1
+su = \property Voice.Stem \set #'direction = #1
+\score { \notes\relative c''
+{
+
+%\property Staff.StaffSpacing \override #'stem-spacing-correction = #10
+%\property Staff.NoteSpacing \override #'stem-spacing-correction = #10
+
+\time 1/4 \sd c4 \su c4
+\sd c4 \su c4
+\sd f c,4  c'4 cis4 \stemUp c4
+}
+\paper { linewidth = -1. }
+}
diff --git a/input/regression/spacing-stem-bar.ly b/input/regression/spacing-stem-bar.ly
new file mode 100644
index 0000000000..2c93e2f37a
--- /dev/null
+++ b/input/regression/spacing-stem-bar.ly
@@ -0,0 +1,26 @@
+\header {
+
+texidoc = "Upstem notes before a barline are printed with some extra
+space. This is an optical correction similar to juxtaposed stems.
+"
+
+}
+
+sd = \property Voice.Stem \set #'direction = #-1
+su = \property Voice.Stem \set #'direction = #1
+\score { \notes\relative e'
+{
+
+%\property Staff.StaffSpacing \override #'stem-spacing-correction = #0.5
+%\property Staff.NoteSpacing \override #'stem-spacing-correction = #0.5
+
+\time 3/8
+\su
+e8 e e
+f f f
+a a a
+c c c
+e e e
+}
+\paper { linewidth = -1. }
+}
diff --git a/input/regression/spacing-tight.ly b/input/regression/spacing-tight.ly
index 4532696c9c..09f72731d6 100644
--- a/input/regression/spacing-tight.ly
+++ b/input/regression/spacing-tight.ly
@@ -2,17 +2,11 @@
 
 \header{
 texidoc="
-If there are accidentals in the music, we add space, but the space
-between note and accidentals is less than between the notes with the
-same value.  Clef changes also get extra space, but not as much as
-barlines.
-
 Even if a line is very tightly spaced, there will still be room
 between prefatory matter and the following notes.  The space after the
-prefatory is very rigid.  In contrast, the space before the barline
+prefatory is rigid.  In contrast, the space before the barline
 must stretch like the space within the measure.
 
-Tight:
 "
 }
 \score {
diff --git a/lily/GNUmakefile b/lily/GNUmakefile
index fffbc18c68..edc0c0ae6e 100644
--- a/lily/GNUmakefile
+++ b/lily/GNUmakefile
@@ -15,7 +15,6 @@ include $(depth)/make/stepmake.make
 
 default: 
 
-
 # force these: Make can't know these have to be generated in advance
 $(outdir)/my-lily-parser.o: $(outdir)/parser.hh
 $(outdir)/my-lily-lexer.o: $(outdir)/parser.hh
diff --git a/lily/afm.cc b/lily/afm.cc
index 1072990430..ddca303bc0 100644
--- a/lily/afm.cc
+++ b/lily/afm.cc
@@ -154,6 +154,10 @@ Adobe_font_metric::find_by_name (String s) const
 
   if (!cm)
     {
+      /*
+	Why don't we return empty?
+       */
+      
       Molecule m;
       m.set_empty (false);
       return m;
diff --git a/lily/beam.cc b/lily/beam.cc
index 019f985151..79d869b552 100644
--- a/lily/beam.cc
+++ b/lily/beam.cc
@@ -90,12 +90,12 @@ Beam::before_line_breaking (SCM smob)
   
   if (visible_stem_count (me) < 2)
     {
-      warning (_ ("beam has less than two visible stems"));
+      me->warning (_ ("beam has less than two visible stems"));
 
       SCM stems = me->get_grob_property ("stems");
       if (scm_ilength (stems) == 1)
 	{
-	  warning (_("Beam has less than two stems. Removing beam."));
+	  me->warning (_("Beam has less than two stems. Removing beam."));
 
 	  unsmob_grob (gh_car (stems))->remove_grob_property ("beam");
 	  me->suicide ();
@@ -657,7 +657,7 @@ Beam::check_stem_length_f (Grob*me,Real y, Real dy)
     }
 
   if (lengthen && shorten)
-    warning (_ ("weird beam vertical offset"));
+    me->warning (_ ("weird beam vertical offset"));
 
   /* when all stems are too short, normal stems win */
   return dir * ((shorten) ?  shorten : lengthen);
diff --git a/lily/break-align-interface.cc b/lily/break-align-interface.cc
index 37b27c6d2c..3a7e953811 100644
--- a/lily/break-align-interface.cc
+++ b/lily/break-align-interface.cc
@@ -74,9 +74,6 @@ Break_align_interface::set_interface (Grob*me)
   Align_interface::set_axis (me,X_AXIS);
 }
 
-
-
-
 void
 Break_align_interface::do_alignment (Grob *me)
 {
@@ -224,3 +221,4 @@ Break_align_interface::do_alignment (Grob *me)
     }
 }
 
+
diff --git a/lily/collision.cc b/lily/collision.cc
index 07b681ee2a..7a82e12193 100644
--- a/lily/collision.cc
+++ b/lily/collision.cc
@@ -283,7 +283,7 @@ Collision::automatic_shift (Grob *me)
 	{
 	  if (shift[i-1] == shift[i])
 	    {
-	      warning (_ ("Too many clashing notecolumns.  Ignoring them."));
+	      me->warning (_ ("Too many clashing notecolumns.  Ignoring them."));
 	      return tups;
 	    }
 	}
diff --git a/lily/grob.cc b/lily/grob.cc
index deea0beadf..c901e95cac 100644
--- a/lily/grob.cc
+++ b/lily/grob.cc
@@ -283,7 +283,7 @@ Grob::get_uncached_molecule ()const
   
   if (unsmob_molecule (mol))
     {
-      SCM origin =	ly_symbol2scm ("no-origin");
+      SCM origin = ly_symbol2scm ("no-origin");
       
       if (store_locations_global_b){
 	SCM cause = get_grob_property ("cause");
@@ -756,6 +756,24 @@ Grob::fixup_refpoint (SCM smob)
   return smob;
 }
 
+void
+Grob::warning (String s)
+{
+  SCM cause = self_scm();
+  while (cause != SCM_EOL && !unsmob_music (cause))
+    {
+      Grob * g = unsmob_grob (cause);
+      cause = g->get_grob_property ("cause");
+    }
+
+  if (Music *m = unsmob_music (cause))
+    {
+      m->origin()->warning (s);
+    }
+  else
+    ::warning (s);
+      
+}
 
 
 /****************************************************
diff --git a/lily/hairpin.cc b/lily/hairpin.cc
index 1e4d659f82..26518b007f 100644
--- a/lily/hairpin.cc
+++ b/lily/hairpin.cc
@@ -90,7 +90,7 @@ Hairpin::brew_molecule (SCM smob)
 
   if (width < 0)
     {
-      warning (_ ((grow_dir < 0) ? "decrescendo too small"
+      me->warning (_ ((grow_dir < 0) ? "decrescendo too small"
 		  : "crescendo too small"));
       width = 0;
     }
diff --git a/lily/include/grob.hh b/lily/include/grob.hh
index 9894f53830..98c0b7ae82 100644
--- a/lily/include/grob.hh
+++ b/lily/include/grob.hh
@@ -73,6 +73,8 @@ public:
   void set_immutable_grob_property (const char * , SCM val);
   void set_immutable_grob_property (SCM key, SCM val);
 #endif
+
+  void warning (String);
   
   void set_elt_pointer (const char*, SCM val);
   friend class Property_engraver; //  UGHUGHUGH.
diff --git a/lily/include/paper-column.hh b/lily/include/paper-column.hh
index 23223452d3..59e2c797df 100644
--- a/lily/include/paper-column.hh
+++ b/lily/include/paper-column.hh
@@ -12,7 +12,7 @@
 
 #include "item.hh"
 #include "rod.hh"
-#include "spring.hh"
+
 
 class Paper_column : public Item
 { 
diff --git a/lily/include/simple-spacer.hh b/lily/include/simple-spacer.hh
index 1b963650e0..58bd34cf7c 100644
--- a/lily/include/simple-spacer.hh
+++ b/lily/include/simple-spacer.hh
@@ -28,38 +28,6 @@ struct Spring_description
   bool sane_b () const;
 };
 
-/**
-   A simple spacing constraint solver. The approach:
-
-   Stretch the line uniformly until none of the constraints (rods)
-   block.  It then is very wide.
-
-
-      Compress until the next constraint blocks,
-
-      Mark the springs over the constrained part to be non-active.
-      
-   Repeat with the smaller set of non-active constraints, until all
-   constraints blocked, or until the line is as short as desired.
-
-   This is much simpler, and much much faster than full scale
-   Constrained QP. On the other hand, a situation like this will not
-   be typeset as dense as possible, because
-
-   c4                   c4           c4                  c4
-   veryveryverylongsyllable2         veryveryverylongsyllable2
-   " "4                 veryveryverylongsyllable2        syllable4
-
-
-   can be further compressed to
-
-
-   c4    c4                        c4   c4
-   veryveryverylongsyllable2       veryveryverylongsyllable2
-   " "4  veryveryverylongsyllable2      syllable4
-
-
-   Perhaps this is not a bad thing, because the 1st looks better anyway.  */
 struct Simple_spacer
 {
   Array<Spring_description> springs_;
@@ -70,7 +38,8 @@ struct Simple_spacer
   Real line_len_f_;
   Real default_space_f_;
   int active_count_;
-
+  bool compression_penalty_b_;
+  
   Simple_spacer ();
   
   void solve (Column_x_positions *) const;
diff --git a/lily/include/spaceable-grob.hh b/lily/include/spaceable-grob.hh
index 8260372d8b..32679ae2c5 100644
--- a/lily/include/spaceable-grob.hh
+++ b/lily/include/spaceable-grob.hh
@@ -17,7 +17,7 @@ struct Spaceable_grob
 {
   /// set a minimum distance
   static void add_rod (Grob*me, Grob * to, Real distance);
-  static void add_spring (Grob*me,Grob * to, Real dist, Real strength);
+  static void add_spring (Grob*me,Grob * to, Real dist, Real strength, bool);
   static void set_interface (Grob*);
   static void remove_interface (Grob*);
   static SCM get_minimum_distances (Grob*);
diff --git a/lily/include/spacing-spanner.hh b/lily/include/spacing-spanner.hh
deleted file mode 100644
index ec088024e2..0000000000
--- a/lily/include/spacing-spanner.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-/*   
-  spacing-spanner.hh -- declare Spacing_spanner
-  
-  source file of the GNU LilyPond music typesetter
-  
-  (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-  
- */
-
-#ifndef SPACING_SPANNER_HH
-#define SPACING_SPANNER_HH
-
-#include "spanner.hh"
-#include "spring.hh"
-
-class Spacing_spanner
-{
-public:
-  static void set_interface (Grob*);
-  static void do_measure (Grob*,Link_array<Grob> const &) ;
-  static void stretch_to_regularity (Grob*, Array<Spring> *, Link_array<Grob> const &);
-  DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
-  static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment)  ;
-  static Real note_spacing (Grob*,Grob*,Grob*,Moment)  ;
-  static Real get_duration_space (Grob*,Moment dur, Moment shortest) ;
-};
-
-#endif /* SPACING_SPANNER_HH */
-
diff --git a/lily/include/spring.hh b/lily/include/spring.hh
index 9d8f341e58..94db15a7a0 100644
--- a/lily/include/spring.hh
+++ b/lily/include/spring.hh
@@ -12,22 +12,26 @@
 
 #include "lily-proto.hh"
 #include "drul-array.hh"
+#include "smobs.hh"
 
-struct Column_spring {
-  Paper_column *other_l_;
+struct Spring_smob
+{
+  Grob *other_;
   Real distance_f_;
-
-  /*
-    TODO: make 2 strengths: one for stretching, and one for shrinking.
-  */
+  bool expand_only_b_;
   Real strength_f_;
   
-  Column_spring ();
+  DECLARE_SIMPLE_SMOBS(Spring_smob,dummy);
+public:
+  SCM smobbed_copy () const;
+  Spring_smob();
 };
+DECLARE_UNSMOB(Spring_smob, spring);
 
 struct Spring{
   Drul_array<Item*> item_l_drul_;
   Real distance_f_;
+  bool expand_only_b_;
 
   /*
     TODO: make 2 strengths: one for stretching, and one for shrinking.
diff --git a/lily/include/staff-spacing.hh b/lily/include/staff-spacing.hh
index 3d697dcc31..1c4150a250 100644
--- a/lily/include/staff-spacing.hh
+++ b/lily/include/staff-spacing.hh
@@ -15,8 +15,13 @@ source file of the GNU LilyPond music typesetter
 class Staff_spacing
 {
 public:
+  static Real next_notes_correction (Grob*, Grob*);
+  static Real next_note_correction (Grob*, Grob*, Interval);  
   static bool has_interface (Grob*);
   static void get_spacing_params (Grob*,Real*,Real*);
+
+  static Interval bar_y_positions (Grob*);
+  static  Grob*  extremal_break_aligned_grob (Grob*,Direction, Interval*);
 };
 
 #endif /* STAFF_SPACING_HH */
diff --git a/lily/interpretation-context-handle.cc b/lily/interpretation-context-handle.cc
index 6ba551c34a..176dbbe97d 100644
--- a/lily/interpretation-context-handle.cc
+++ b/lily/interpretation-context-handle.cc
@@ -1,11 +1,9 @@
 /*   
-
   interpretation-context-handle.cc --  implement Interpretation_context_handle
   
   source file of the GNU LilyPond music typesetter
   
   (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-  
  */
 
 #include "interpretation-context-handle.hh"
diff --git a/lily/line-of-score.cc b/lily/line-of-score.cc
index de47ec41d4..c65b9ac44c 100644
--- a/lily/line-of-score.cc
+++ b/lily/line-of-score.cc
@@ -277,8 +277,6 @@ ADD_SCM_INIT_FUNC (cname,cname ## _init_func);\
 GLOBAL_SYMBOL (offset_sym , "translate-molecule");
 GLOBAL_SYMBOL (placebox_sym , "placebox");
 GLOBAL_SYMBOL (combine_sym , "combine-molecule");
-GLOBAL_SYMBOL (no_origin_sym , "no-origin");
-GLOBAL_SYMBOL (define_origin_sym , "define-origin");
 
 
 
@@ -297,24 +295,24 @@ Line_of_score::output_molecule (SCM expr, Offset o)
 	  Input * ip = unsmob_input (head);
       
 
-	  pscore_l_->outputter_l_->output_scheme (scm_list_n (define_origin_sym,
+	  pscore_l_->outputter_l_->output_scheme (scm_list_n (ly_symbol2scm ("define-origin"),
 							   ly_str02scm (ip->file_str ().ch_C ()),
 							   gh_int2scm (ip->line_number ()),
 							   gh_int2scm (ip->column_number ()),
 							   SCM_UNDEFINED));
 	  expr = ly_cadr (expr);
 	}
-      else  if (head ==  no_origin_sym)
+      else  if (head ==  ly_symbol2scm ("no-origin"))
 	{
-	  pscore_l_->outputter_l_->output_scheme (scm_list_n (no_origin_sym, SCM_UNDEFINED));
+	  pscore_l_->outputter_l_->output_scheme (scm_list_n (head, SCM_UNDEFINED));
 	  expr = ly_cadr (expr);
 	}
-      else if (head == offset_sym)
+      else if (head == ly_symbol2scm ("translate-molecule"))
 	{
 	  o += ly_scm2offset (ly_cadr (expr));
 	  expr = ly_caddr (expr);
 	}
-      else if (head == combine_sym)
+      else if (head == ly_symbol2scm ("combine-molecule"))
 	{
 	  output_molecule (ly_cadr (expr), o);
 	  expr = ly_caddr (expr);
diff --git a/lily/molecule.cc b/lily/molecule.cc
index 6bb59a58a1..634ec726bd 100644
--- a/lily/molecule.cc
+++ b/lily/molecule.cc
@@ -107,6 +107,9 @@ Molecule::set_empty (bool e)
 void
 Molecule::align_to (Axis a, Direction d)
 {
+  if (empty_b())
+    return ;
+
   Interval i (extent (a));
   Real r = (d == CENTER) ? i.center () : i[d];
   translate_axis (-r, a);
@@ -237,6 +240,10 @@ molecule_init ()
 ADD_SCM_INIT_FUNC (molecule,molecule_init);
 
 
+/*
+  Hmm... maybe this is not such a good idea ; stuff can be empty,
+  while expr_ == '()
+ */
 bool
 Molecule::empty_b () const
 {
diff --git a/lily/moment.cc b/lily/moment.cc
index c305c9edc4..2be3ea129d 100644
--- a/lily/moment.cc
+++ b/lily/moment.cc
@@ -199,8 +199,8 @@ Moment
 Moment::operator - () const
 {
   Moment m;
-  m.grace_part_ = -grace_part_;
-  m.main_part_ = -main_part_;
+  m.grace_part_ = - grace_part_;
+  m. main_part_ = - main_part_ ;
   return m;
 }
 
diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc
index 905975896a..88beea3142 100644
--- a/lily/note-spacing.cc
+++ b/lily/note-spacing.cc
@@ -15,6 +15,8 @@
 #include "note-column.hh"
 #include "warn.hh"
 #include "stem.hh"
+#include "separation-item.hh"
+#include "staff-spacing.hh"
 
 bool
 Note_spacing::has_interface (Grob* g)
@@ -155,8 +157,13 @@ Note_spacing::stem_dir_correction (Grob*me)
   Drul_array<SCM> props(me->get_grob_property ("left-items"),
 			me->get_grob_property ("right-items"));
 
+  Real correction = 0.0;
+  
   stem_dirs[LEFT] = stem_dirs[RIGHT] = CENTER;
   Interval intersect;
+  Interval bar_xextent;
+  Interval bar_yextent;  
+  
   bool correct = true;
   Direction d = LEFT;
   bool acc_right = false;
@@ -172,17 +179,31 @@ Note_spacing::stem_dir_correction (Grob*me)
 	  
 	  Grob *stem = Note_column::stem_l (it);
 
-	  if (!stem || Stem::invisible_b (stem))
+	  if (!stem)
+	    {
+	      if (d == RIGHT && Separation_item::has_interface (it))
+		{
+		  Grob *last = Staff_spacing::extremal_break_aligned_grob (it, LEFT, &bar_xextent);
+
+		  if (last)
+		    bar_yextent = Staff_spacing::bar_y_positions (last);
+
+		  break;
+		}
+
+	      goto exit_func; 
+	    }
+	  if(Stem::invisible_b (stem))
 	    {
 	      correct = false;
-	      goto exit_loop ;
+	      goto exit_func ;
 	    }
 
 	  Direction sd = Stem::get_direction (stem);
 	  if (stem_dirs[d] && stem_dirs[d] != sd)
 	    {
 	      correct = false;
-	      goto exit_loop;
+	      goto exit_func;
 	    }
 	  stem_dirs[d] = sd;
 
@@ -204,9 +225,15 @@ Note_spacing::stem_dir_correction (Grob*me)
   if (acc_right)
     return 0.0;
 
+  if (!bar_yextent.empty_b())
+    {
+      stem_dirs[RIGHT] = - stem_dirs[LEFT];
+      stem_posns[RIGHT] = bar_yextent;
+    }
   
-  if (correct && stem_dirs[LEFT] *stem_dirs[RIGHT] == -1)
+  if (correct &&stem_dirs[LEFT] *stem_dirs[RIGHT] == -1)
     {
+      
       intersect = stem_posns[LEFT];  
       intersect.intersect(stem_posns[RIGHT]);
       correct = correct && !intersect.empty_b ();
@@ -214,13 +241,17 @@ Note_spacing::stem_dir_correction (Grob*me)
       if (!correct)
 	return 0.0;
       /*
-      Ugh. 7 is hardcoded.
-    */
-      Real correction = abs (intersect.length ());
+	Ugh. 7 is hardcoded.
+      */
+      correction = abs (intersect.length ());
       correction = (correction/7) <? 1.0;
       correction *= stem_dirs[LEFT] ;
       correction *= gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
-      return correction;
+
+      if (!bar_yextent.empty_b())
+	{
+	  correction *= 0.5;
+	}
     }
   else if (correct)
     {
@@ -256,11 +287,13 @@ Note_spacing::stem_dir_correction (Grob*me)
       Real corr = gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
       corr =  (delta <= 1) ? 0.0 : 0.25;
       
-      return -lowest * corr ;
+      correction=  -lowest * corr ;
     }
 
+  if (!bar_xextent.empty_b())
+    correction += - bar_xextent[LEFT];
   
- exit_loop:
-  return 0.0;
+ exit_func:
+  return correction;
 }
  
diff --git a/lily/parser.yy b/lily/parser.yy
index 3f972dcc01..dab307a3bf 100644
--- a/lily/parser.yy
+++ b/lily/parser.yy
@@ -1174,11 +1174,11 @@ command_element:
 	| TIME_T fraction  {
 		Music * p1 = set_property_music (ly_symbol2scm ( "timeSignatureFraction"), $2);
 
-  int l = gh_scm2int (ly_car ($2));
-  int o = gh_scm2int (ly_cdr ($2));
-  
-  Moment one_beat = Moment (1)/Moment (o);
-  Moment len = Moment (l) * one_beat;
+		int l = gh_scm2int (ly_car ($2));
+		int o = gh_scm2int (ly_cdr ($2));
+
+		Moment one_beat = Moment (1)/Moment (o);
+		Moment len = Moment (l) * one_beat;
 
 
 		Music *p2 = set_property_music (ly_symbol2scm ("measureLength"), len.smobbed_copy ());
diff --git a/lily/porrectus.cc b/lily/porrectus.cc
index d141b5267d..2bdbcd53d4 100644
--- a/lily/porrectus.cc
+++ b/lily/porrectus.cc
@@ -161,7 +161,7 @@ Porrectus::brew_molecule (SCM smob)
   Item *right_head = get_right_head (me);
   if (!left_head || !right_head)
     {
-      warning (_ ("junking lonely porrectus"));
+      me->warning (_ ("junking lonely porrectus"));
       me->suicide ();
       return SCM_EOL;
     }
@@ -171,7 +171,7 @@ Porrectus::brew_molecule (SCM smob)
   if ((gh_symbol_p (scm_style)) && (scm_style != SCM_EOL))
     style = ly_scm2string (scm_symbol_to_string (scm_style));
   else {
-    warning (_ ("porrectus style undefined; using mensural"));
+    me->warning (_ ("porrectus style undefined; using mensural"));
     style = "mensural";
   }
 
@@ -189,7 +189,7 @@ Porrectus::brew_molecule (SCM smob)
       // determine add_stem and stem_direction automatically from durations
     {
       if (String::compare_i (style, "mensural") != 0)
-	warning (String("auto-property should be used for\r\n") +
+	me->warning (String("auto-property should be used for\r\n") +
 		 String("mensural style porrectus only; trying anyway"));
 
       int left_duration =
@@ -219,7 +219,7 @@ Porrectus::brew_molecule (SCM smob)
 	}
       else
         {
-	  warning (String("auto-property: failed determining porrectus\r\n") +
+	  me->warning (String("auto-property: failed determining porrectus\r\n") +
 		   String("properties due to improper durations; ") +
 		   String("using user-supplied properties"));
 	}
@@ -298,7 +298,7 @@ Porrectus::brew_vaticana_molecule (Item *me,
 {
   if (interval >= 0.0)
     {
-      warning (_ ("ascending vaticana style porrectus"));
+      me->warning (_ ("ascending vaticana style porrectus"));
     }
 
   Real space = Staff_symbol_referencer::staff_space (me);
diff --git a/lily/property-iterator.cc b/lily/property-iterator.cc
index ad4452a3ee..7b2dddb1da 100644
--- a/lily/property-iterator.cc
+++ b/lily/property-iterator.cc
@@ -11,10 +11,13 @@
 #include "translator-def.hh"
 #include "translator-group.hh"
 
+
+bool check_grob(Music *mus, SCM sym);
+
 /**
-  There is no real processing to a property: just lookup the
-  translation unit, and set the property.
-  */
+   There is no real processing to a property: just lookup the
+   translation unit, and set the property.
+*/
 void
 Property_iterator::process (Moment m)
 {
@@ -35,27 +38,49 @@ void
 Property_unset_iterator::process (Moment m)
 {
   SCM sym = music_l ()->get_mus_property ("symbol");
-  if (gh_symbol_p (sym))
-    {
-      report_to_l ()->unset_property (sym);
-    }
+  type_check_assignment (sym, SCM_EOL, ly_symbol2scm ("translation-type?"));  
+  report_to_l ()->unset_property (sym);
+
   Simple_music_iterator::process (m);
 }
 
 
+SCM list_p = 0;
+
+bool
+check_grob(Music *mus, SCM sym)
+{
+  if (!list_p)
+    {
+      list_p = gh_eval_str ("list?");
+    }
+  
+  
+  SCM type_p = scm_object_property (sym, ly_symbol2scm ("translation-type?"));
+  bool ok = type_p == list_p;
+
+  if (!ok)
+    {
+      mus->origin()->warning (_f("Not a grob name, `%s'." , ly_symbol2string (sym)));
+    }
+  return  ok;
+}
+
 void
 Push_property_iterator::process (Moment m)
 {
   SCM sym = music_l ()->get_mus_property ("symbol");
-  SCM eprop = music_l ()->get_mus_property ("grob-property");
-  SCM val = music_l ()->get_mus_property ("grob-value");
+  if (check_grob (music_l (), sym))
+    {
+      SCM eprop = music_l ()->get_mus_property ("grob-property");
+      SCM val = music_l ()->get_mus_property ("grob-value");
 
-  if (to_boolean (music_l ()->get_mus_property ("pop-first")))
-    Translator_def::apply_pushpop_property (report_to_l (),
-					    sym, eprop, SCM_UNDEFINED);
+      if (to_boolean (music_l ()->get_mus_property ("pop-first")))
+	Translator_def::apply_pushpop_property (report_to_l (),
+						sym, eprop, SCM_UNDEFINED);
 
-  Translator_def::apply_pushpop_property (report_to_l (), sym, eprop, val);
-  
+      Translator_def::apply_pushpop_property (report_to_l (), sym, eprop, val);
+    }
   Simple_music_iterator::process (m);
 }
 
@@ -63,9 +88,11 @@ void
 Pop_property_iterator::process (Moment m)
 {
   SCM sym = music_l ()->get_mus_property ("symbol");
-  SCM eprop = music_l ()->get_mus_property ("grob-property");
-  Translator_def::apply_pushpop_property (report_to_l (), sym, eprop, SCM_UNDEFINED);
-  
+  if (check_grob (music_l (), sym))
+    {
+      SCM eprop = music_l ()->get_mus_property ("grob-property");
+      Translator_def::apply_pushpop_property (report_to_l (), sym, eprop, SCM_UNDEFINED);
+    }  
   Simple_music_iterator::process (m);
 }
 
diff --git a/lily/score-engraver.cc b/lily/score-engraver.cc
index 69e6ca905e..690b05af26 100644
--- a/lily/score-engraver.cc
+++ b/lily/score-engraver.cc
@@ -174,7 +174,7 @@ Score_engraver::typeset_all ()
 		if (elem_p->immutable_property_alist_ == SCM_EOL)
 		  ; // gdb hook
 		else
-		  ::warning (_f ("unbound spanner `%s'", s->name ().ch_C ()));
+		  elem_p->warning (_f ("unbound spanner `%s'", s->name ().ch_C ()));
 	      }
 	  } while (flip (&d) != LEFT);
 	}
diff --git a/lily/score.cc b/lily/score.cc
index b31c673f81..9570c267f5 100644
--- a/lily/score.cc
+++ b/lily/score.cc
@@ -32,6 +32,7 @@ Score::Score ()
   header_p_ = 0;
   music_ = SCM_EOL;
   errorlevel_i_ = 0;
+
   smobify_self ();
 }
 
@@ -48,11 +49,6 @@ Score::Score (Score const &s)
   header_p_ = 0;
   smobify_self ();
 
-  /*
-    TODO: this is not very elegant.... 
-   */
-  store_locations_global_b = (gh_eval_str ("point-and-click") !=  SCM_BOOL_F);
-
   Music * m =unsmob_music (s.music_);
   music_ =  m?m->clone ()->self_scm () : SCM_EOL;
   scm_gc_unprotect_object (music_);
@@ -76,6 +72,12 @@ Score::~Score ()
 void
 Score::run_translator (Music_output_def *odef_l)
 {
+  /*
+    TODO: this is not very elegant.... 
+   */
+  store_locations_global_b = (gh_eval_str ("point-and-click") !=  SCM_BOOL_F);
+
+  
   Cpu_timer timer;
 
   
diff --git a/lily/separating-line-group-engraver.cc b/lily/separating-line-group-engraver.cc
index 8c38cc0c26..796821254b 100644
--- a/lily/separating-line-group-engraver.cc
+++ b/lily/separating-line-group-engraver.cc
@@ -166,7 +166,7 @@ Separating_line_group_engraver::stop_translation_timestep ()
 
       break_malt_p_ =0;
     }
-
+  
   if (Item * sp = current_spacings_.staff_spacing_)
     {
       /*
@@ -180,6 +180,7 @@ Separating_line_group_engraver::stop_translation_timestep ()
       typeset_grob (sp);
     }
 
+  
   if (!current_spacings_.empty ())
     {
       last_spacings_ = current_spacings_;
diff --git a/lily/simple-spacer.cc b/lily/simple-spacer.cc
index f6052dd08c..694625bf75 100644
--- a/lily/simple-spacer.cc
+++ b/lily/simple-spacer.cc
@@ -22,8 +22,47 @@
 #include "spaceable-grob.hh"
 #include "dimensions.hh"
 
+
+/*
+   A simple spacing constraint solver. The approach:
+
+   Stretch the line uniformly until none of the constraints (rods)
+   block.  It then is very wide.
+
+      Compress until the next constraint blocks,
+
+      Mark the springs over the constrained part to be non-active.
+      
+   Repeat with the smaller set of non-active constraints, until all
+   constraints blocked, or until the line is as short as desired.
+
+   This is much simpler, and much much faster than full scale
+   Constrained QP. On the other hand, a situation like this will not
+   be typeset as dense as possible, because
+
+   c4                   c4           c4                  c4
+   veryveryverylongsyllable2         veryveryverylongsyllable2
+   " "4                 veryveryverylongsyllable2        syllable4
+
+
+   can be further compressed to
+
+
+   c4    c4                        c4   c4
+   veryveryverylongsyllable2       veryveryverylongsyllable2
+   " "4  veryveryverylongsyllable2      syllable4
+
+
+   Perhaps this is not a bad thing, because the 1st looks better anyway.  */
+
+
 Simple_spacer::Simple_spacer ()
 {
+  /*
+    Give an extra penalty for compression. Needed to avoid compressing
+    tightly spaced lines.
+  */
+  compression_penalty_b_ = false;
   active_count_ = 0;
   force_f_ = 0.;
   indent_f_ =0.0;
@@ -66,7 +105,10 @@ Simple_spacer::range_stiffness (int l, int r) const
 {
   Real den =0.0;
   for (int i=l; i < r; i++)
-    den += 1 / springs_[i].hooke_f_;
+    {
+      if (springs_[i].active_b_)
+	den += 1 / springs_[i].hooke_f_;
+    }
 
   return 1 / den;
 }
@@ -98,8 +140,7 @@ Simple_spacer::active_springs_stiffness () const
 void
 Simple_spacer::set_active_states ()
 {
-  // safe, since
-  // force is only copied.
+  /* float comparison is safe, since force is only copied.  */
   for (int i=0 ; i <springs_.size (); i++)
     if (springs_[i].active_b_
 	&& springs_[i].block_force_f_ >= force_f_)
@@ -119,14 +160,6 @@ Simple_spacer::configuration_length () const
   return l;
 }
 
-Real
-Spring_description::length (Real f) const
-{
-  if (!active_b_)
-    f = block_force_f_;
-  return ideal_f_ + f / hooke_f_ ;
-}
-
 bool
 Simple_spacer::active_b () const
 {
@@ -179,23 +212,24 @@ Simple_spacer::add_columns (Link_array<Grob> cols)
   spaced_cols_ = cols;
   for (int i=0; i < cols.size () - 1; i++)
     {
-      SCM spring_params = SCM_EOL;
+      Spring_smob *spring = 0;
+
       for (SCM s = cols[i]->get_grob_property ("ideal-distances");
-	   !gh_pair_p (spring_params) && gh_pair_p (s);
+	   !spring && gh_pair_p (s);
 	   s = ly_cdr (s))
 	{
-	  Grob *other = unsmob_grob (ly_caar (s));
-	  if (other != cols[i+1])
-	    continue;
-
-	  spring_params = ly_cdar (s);
+	  Spring_smob *sp = unsmob_spring (ly_car (s));
+	  
+	  
+	  if (sp->other_ == cols[i+1])
+	    spring = sp;
 	}
 
       Spring_description desc;
-      if (gh_pair_p (spring_params))
+      if (spring)
 	{
-	  desc.ideal_f_ = gh_scm2double (ly_car (spring_params));
-	  desc.hooke_f_ = gh_scm2double (ly_cdr (spring_params));
+	  desc.ideal_f_ = spring->distance_f_;
+	  desc.hooke_f_ = spring->strength_f_;
 	}
       else
 	{
@@ -204,6 +238,8 @@ Simple_spacer::add_columns (Link_array<Grob> cols)
 				));
 	  desc.hooke_f_ = 1.0;
 	  desc.ideal_f_ = default_space_f_;
+
+	  continue;
 	}
 
       if (!desc.sane_b ())
@@ -215,10 +251,25 @@ Simple_spacer::add_columns (Link_array<Grob> cols)
 	  desc.hooke_f_ = 1.0;
 	  desc.ideal_f_ = 1.0;
 	}
+
+      if (isinf (desc.hooke_f_))
+	{
+	  desc.active_b_ = false;
+	  springs_.push (desc);
+	}
+      else
+	{
+	  desc.block_force_f_ = - desc.hooke_f_ * desc.ideal_f_; // block at distance 0
+	  springs_.push (desc);
+      
+	  active_count_ ++;
+	}
+
+      if (spring->expand_only_b_)
+	{
+	  compression_penalty_b_ = true;
+	}
       
-      desc.block_force_f_ = - desc.hooke_f_ * desc.ideal_f_; // block at distance 0
-      springs_.push (desc);
-      active_count_ ++;
     }
   
   for (int i=0; i < cols.size () - 1; i++)
@@ -244,10 +295,17 @@ Simple_spacer::add_columns (Link_array<Grob> cols)
     my_solve_linelen ();
 }
 
+#include <stdio.h>
+
 void
 Simple_spacer::solve (Column_x_positions *positions) const
 {
   positions->force_f_ = force_f_;
+  if (compression_penalty_b_ &&  (force_f_ < 0))
+    {
+
+	positions->force_f_ *= 2; //  hmm.
+    }
   
   positions->config_.push (indent_f_);
   for (int i=0; i <springs_.size (); i++)
@@ -282,10 +340,7 @@ Simple_spacer::solve (Column_x_positions *positions) const
     positions->satisfies_constraints_b_ && break_satisfy;
 }
 
-
-
-
-
+/****************************************************************/
 
 Spring_description::Spring_description ()
 {
@@ -299,7 +354,13 @@ Spring_description::Spring_description ()
 bool
 Spring_description::sane_b () const
 {
-  return (hooke_f_ > 0) &&  ! isinf (ideal_f_) && !isnan (ideal_f_);
+  return (hooke_f_ > 0) &&  !isinf (ideal_f_) && !isnan (ideal_f_);
 }
 
-
+Real
+Spring_description::length (Real f) const
+{
+  if (!active_b_)
+    f = block_force_f_;
+  return ideal_f_ + f / hooke_f_ ;
+}
diff --git a/lily/slur.cc b/lily/slur.cc
index cf4d2897f8..f72490f872 100644
--- a/lily/slur.cc
+++ b/lily/slur.cc
@@ -45,7 +45,7 @@ void
 Slur::add_column (Grob*me, Grob*n)
 {
   if (!gh_pair_p (n->get_grob_property ("note-heads")))
-    warning (_ ("Putting slur over rest.  Ignoring."));
+    me->warning (_ ("Putting slur over rest.  Ignoring."));
   else
     {
       Pointer_group_interface::add_grob (me, ly_symbol2scm ("note-columns"), n);
@@ -390,7 +390,7 @@ Slur::encompass_offset (Grob*me,
   
   if (!stem_l)
     {
-      warning (_ ("Slur over rest?"));
+      me->warning (_ ("Slur over rest?"));
       o[X_AXIS] = col->relative_coordinate (common[X_AXIS], X_AXIS);
       o[Y_AXIS] = col->relative_coordinate (common[Y_AXIS], Y_AXIS);
       return o;  
diff --git a/lily/spaceable-grob.cc b/lily/spaceable-grob.cc
index cbef93ce5a..325efaaae8 100644
--- a/lily/spaceable-grob.cc
+++ b/lily/spaceable-grob.cc
@@ -10,6 +10,8 @@
 #include "spaceable-grob.hh"
 #include "grob.hh"
 #include "warn.hh"
+#include "spring.hh"
+#include "group-interface.hh"
 
 SCM
 Spaceable_grob::get_minimum_distances (Grob*me)
@@ -40,25 +42,28 @@ Spaceable_grob::add_rod (Grob *me , Grob * p, Real d)
 }
 
 void
-Spaceable_grob::add_spring (Grob*me, Grob * p, Real d, Real strength)
+Spaceable_grob::add_spring (Grob*me, Grob * p, Real d, Real strength, bool expand_only)
 {
+#ifndef NDEBUG
   SCM mins = me->get_grob_property ("ideal-distances");
-  
-  
-  SCM newdist= gh_double2scm (d);
   for (SCM s = mins; gh_pair_p (s); s = ly_cdr (s))
     {
-      SCM dist = ly_car (s);
-      if (ly_car (dist) == p->self_scm ())
+      Spring_smob * sp = unsmob_spring(ly_car (s));
+      if (sp->other_ == p)
 	{
 	  programming_error ("already have that spring");
 	  return ;
 	}
     }
-  SCM newstrength= gh_double2scm (strength);  
+#endif
+  
+  Spring_smob spring;
+  spring.strength_f_ = strength;
+  spring.distance_f_ = d;
+  spring.expand_only_b_ = expand_only;
+  spring.other_ = p;
   
-  mins = gh_cons (gh_cons (p->self_scm (), gh_cons (newdist, newstrength)), mins);
-  me->set_grob_property ("ideal-distances", mins);
+  Group_interface::add_thing (me, ly_symbol2scm ("ideal-distances"), spring.smobbed_copy ());
 }
 
 
diff --git a/lily/spacing-engraver.cc b/lily/spacing-engraver.cc
index f4aa7269a9..00fce0be69 100644
--- a/lily/spacing-engraver.cc
+++ b/lily/spacing-engraver.cc
@@ -9,13 +9,12 @@
 
 #include "musical-request.hh"
 #include "paper-column.hh"
-
-#include "spacing-spanner.hh"
 #include "engraver.hh"
 #include "pqueue.hh"
 #include "note-spacing.hh"
 #include "staff-spacing.hh"
 #include "group-interface.hh"
+#include "spanner.hh"
 
 struct Rhythmic_tuple
 {
@@ -123,16 +122,17 @@ Spacing_engraver::stop_translation_timestep ()
 	}
     }
   
-  Moment starter, inf;
-  inf.set_infinite (1);
-  starter=inf;
+  Moment starter;
+  starter.set_infinite (1);
+
   for (int i=0; i < now_durations_.size (); i++)
     {
       Moment m = now_durations_[i].info_.music_cause ()->length_mom ();
       if (m.to_bool ())
-	starter = starter <? m;
-
-      playing_durations_.insert (now_durations_[i]);
+	{
+	  starter = starter <? m;
+	  playing_durations_.insert (now_durations_[i]);
+	}
     }
   now_durations_.clear ();
   
@@ -141,6 +141,7 @@ Spacing_engraver::stop_translation_timestep ()
   Paper_column * sc
     = dynamic_cast<Paper_column*> (unsmob_grob (get_property ("currentMusicalColumn")));
 
+  assert (starter.to_bool ());
   SCM sh = shortest_playing.smobbed_copy ();
   SCM st = starter.smobbed_copy ();
 
diff --git a/lily/spacing-spanner.cc b/lily/spacing-spanner.cc
index 18ca3bd2fa..ffce2a7ac7 100644
--- a/lily/spacing-spanner.cc
+++ b/lily/spacing-spanner.cc
@@ -8,6 +8,7 @@
  */
 
 #include <math.h>
+#include <stdio.h>
 
 #include "line-of-score.hh"
 #include "paper-score.hh"
@@ -18,6 +19,9 @@
 #include "misc.hh"
 #include "warn.hh"
 #include "staff-spacing.hh"
+#include "spring.hh"
+#include "paper-column.hh"
+#include "spaceable-grob.hh"
 
 /*
   paper-column:
@@ -31,22 +35,20 @@
 class Spacing_spanner
 {
 public:
-  static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment)  ;
-  static Real note_spacing (Grob*,Grob*,Grob*,Moment)  ;
-  static Real get_duration_space (Grob*,Moment dur, Moment shortest) ;
-  
+  static Real default_bar_spacing (Grob*,Grob*,Grob*,Moment);
+  static Real note_spacing (Grob*,Grob*,Grob*,Moment, bool*);
+  static Real get_duration_space (Grob*,Moment dur, Rational shortest, bool*);
+  static Rational find_shortest (Link_array<Grob> const &);  
   static void breakable_column_spacing (Item* l, Item *r);
   static void find_loose_columns () {}
   static void prune_loose_colunms (Link_array<Grob> *cols);
   static void find_loose_columns (Link_array<Grob> cols);
   static void set_explicit_neighbor_columns (Link_array<Grob> cols);
   static void set_implicit_neighbor_columns (Link_array<Grob> cols);
-  static void do_measure (Grob*me,Link_array<Grob> *cols);
+  static void do_measure (Rational, Grob*me,Link_array<Grob> *cols);
   DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
 };
 
-
-
 /*
   Return whether COL is fixed to its neighbors by some kind of spacing
   constraint.
@@ -116,7 +118,6 @@ loose_column (Grob *l, Grob *c, Grob *r)
 
     (Otherwise, we might risk core dumps, and other weird stuff.)
 
-
   */
   return false;
 }
@@ -313,6 +314,8 @@ Spacing_spanner::set_springs (SCM smob)
   set_explicit_neighbor_columns (all);
   prune_loose_colunms (&all);
   set_implicit_neighbor_columns (all);
+
+  Rational global_shortest = find_shortest (all);
   
   int j = 0;
   for (int i = 1; i < all.size (); i++)
@@ -321,7 +324,7 @@ Spacing_spanner::set_springs (SCM smob)
       if (Item::breakable_b (sc))
         {
 	  Link_array<Grob> measure (all.slice (j, i+1));	  
-          do_measure (me, &measure);
+          do_measure (global_shortest, me, &measure);
 	  j = i;
         }
     }
@@ -330,22 +333,33 @@ Spacing_spanner::set_springs (SCM smob)
 }
 
 
-void
-Spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols) 
-{
-  Moment shortest_in_measure;
+/*
+  We want the shortest note that is also "common" in the piece, so we
+  find the shortest in each measure, and take the most frequently
+  found duration.
 
+  This probably gives weird effects with modern music, where every
+  note has a different duration, but hey, don't write that kind of
+  stuff, then.
+
+*/
+Rational
+Spacing_spanner::find_shortest (Link_array<Grob> const &cols)
+{
   /*
-    space as if this duration  is present. 
-  */
-  Moment base_shortest_duration = *unsmob_moment (me->get_grob_property ("maximum-duration-for-spacing"));
+    ascending in duration
+   */
+  Array<Rational> durations; 
+  Array<int> counts;
+  
+  Rational shortest_in_measure;
   shortest_in_measure.set_infinite (1);
-
-  for (int i =0 ; i < cols->size (); i++)  
+  
+  for (int i =0 ; i < cols.size (); i++)  
     {
-      if (Paper_column::musical_b (cols->elem (i)))
+      if (Paper_column::musical_b (cols[i]))
 	{
-	  Moment *when = unsmob_moment (cols->elem (i)->get_grob_property  ("when"));
+	  Moment *when = unsmob_moment (cols[i]->get_grob_property  ("when"));
 
 	  /*
 	    ignore grace notes for shortest notes.
@@ -353,14 +367,68 @@ Spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols)
 	  if (when && when->grace_part_)
 	    continue;
 	  
-	  SCM  st = cols->elem (i)->get_grob_property ("shortest-starter-duration");
+	  SCM  st = cols[i]->get_grob_property ("shortest-starter-duration");
 	  Moment this_shortest = *unsmob_moment (st);
-	  shortest_in_measure = shortest_in_measure <? this_shortest;
+	  assert (this_shortest.to_bool());
+	  shortest_in_measure = shortest_in_measure <? this_shortest.main_part_;
+	}
+      else if (!shortest_in_measure.infty_b()
+	       && Item::breakable_b (cols[i]))
+	{
+	  int j = 0;
+	  for (; j < durations.size(); j++)
+	    {
+	      if (durations[j] > shortest_in_measure)
+		{
+		  counts.insert (1, j);
+		  durations.insert (shortest_in_measure, j);
+		  break;
+		}
+	      else if (durations[j] == shortest_in_measure)
+		{
+		  counts[j]++;
+		  break;
+		}
+	    }
+
+	  if (durations.size() == j)
+	    {
+	      durations.push (shortest_in_measure);
+	      counts.push (1);
+	    }
+
+	  shortest_in_measure.set_infinite(1); 
 	}
     }
-  
-  Array<Spring> springs;
 
+  int max_idx = -1;
+  int max_count = 0;
+  for (int i =durations.size(); i--;)
+    {
+      if (counts[i] >= max_count)
+	{
+	  max_idx = i;
+	  max_count = counts[i];
+	}
+
+      //      printf ("Den %d/%d, c %d\n", durations[i].num (), durations[i].den (), counts[i]);
+    }
+
+  /*
+    TODO: 1/8 should be adjustable?
+   */
+  Rational d = Rational (1,8);
+  if (max_idx >= 0)
+    d = d <? durations[max_idx] ;
+
+  return d;
+}
+
+void
+Spacing_spanner::do_measure (Rational shortest, Grob*me, Link_array<Grob> *cols) 
+{
+
+  Real headwid =       gh_scm2double (me->get_grob_property ("spacing-increment"));
   for (int i= 0; i < cols->size () - 1; i++)
     {
       Item * l = dynamic_cast<Item*> (cols->elem (i));
@@ -393,10 +461,11 @@ Spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols)
 	  
 	  continue ; 
 	}
+      bool expand_only = false;
+      Real note_space = note_spacing (me, lc, rc, shortest, &expand_only);
       
-      Real note_space = note_spacing (me,lc, rc, shortest_in_measure <? base_shortest_duration);
       Real hinterfleisch = note_space;
-      Real headwid = gh_scm2double (me->get_grob_property ("arithmetic-multiplier"));
+
 
       SCM seq  = lc->get_grob_property ("right-neighbors");
 
@@ -446,24 +515,19 @@ Spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols)
       if (max_factor == 0.0)
 	max_factor = 1.0; 
       
-      Spring s;
-      s.distance_f_ = max_factor *  hinterfleisch;
-      s.strength_f_ = 1 / stretch_distance;
-
-      s.item_l_drul_[LEFT] = l;
-      s.item_l_drul_[RIGHT] = r;
+      Spaceable_grob::add_spring (l, r, max_factor *  hinterfleisch,  1 / stretch_distance, expand_only);
 
-      s.add_to_cols();
-      if (r->find_prebroken_piece (LEFT))
+      /*
+	TODO: we should have a separate routine determining this distance!
+       */
+      if (Item *rb = r->find_prebroken_piece (LEFT))
 	{
-	  s.item_l_drul_[RIGHT] = r->find_prebroken_piece(LEFT);
-	  s.add_to_cols();
+	  Spaceable_grob::add_spring (l, rb, max_factor *  hinterfleisch,  1 / stretch_distance, expand_only);
 	}
     }
 
 }
 
-
 /*
   Read hints from L (todo: R) and generate springs.
  */
@@ -499,48 +563,50 @@ Spacing_spanner::breakable_column_spacing (Item* l, Item *r)
       max_space = 2.0;
       max_fixed = 1.0;
     }
-  
-  Spring s;
-  s.distance_f_ = max_space;
-  s.strength_f_ = 1/(max_space - max_fixed);
-  
-  s.item_l_drul_[LEFT] = l;
-  s.item_l_drul_[RIGHT] = r;
 
-  s.add_to_cols ();
+  Spaceable_grob::add_spring (l, r, max_space,  1/(max_space - max_fixed), false);  
 }
 
 
 /**
   Get the measure wide ant for arithmetic spacing.
-
-  @see
-  John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
-  OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
-  The Ohio State University, 1987.
-
   */
 Real
-Spacing_spanner::get_duration_space (Grob*me, Moment d, Moment shortest) 
+Spacing_spanner::get_duration_space (Grob*me, Moment d, Rational shortest, bool * expand_only) 
 {
-  Real log =  log_2 (shortest.main_part_);
-  Real k = gh_scm2double (me->get_grob_property ("arithmetic-basicspace"))
-    - log;
-
-  Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
-  
-  return (log_2 (compdur) + k) * gh_scm2double (me->get_grob_property ("arithmetic-multiplier"));
+  Real k = gh_scm2double (me->get_grob_property ("shortest-duration-space"));
+    
+  if (d < shortest)
+    {
+      Rational ratio = d.main_part_ / shortest;
+      
+      *expand_only = true;
+      return (0.5 + 0.5 * double (ratio)) * k ;
+    }
+  else
+    {
+      /*
+	  @see
+  John S. Gourlay. ``Spacing a Line of Music,'' Technical Report
+  OSU-CISRC-10/87-TR35, Department of Computer and Information Science,
+  The Ohio State University, 1987.
+       */
+      Real log =  log_2 (shortest);
+      k -= log;
+      Rational compdur = d.main_part_ + d.grace_part_ /Rational (3);
+      *expand_only = false;      
+   
+      return (log_2 (compdur) + k) * gh_scm2double (me->get_grob_property ("spacing-increment"));
+    }
 }
 
-
 Real
 Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
-				   Moment shortest) 
+			       Moment shortest, bool * expand_only) 
 {
   Moment shortest_playing_len = 0;
   SCM s = lc->get_grob_property ("shortest-playing-duration");
 
-
   if (unsmob_moment (s))
     shortest_playing_len = *unsmob_moment (s);
   
@@ -550,51 +616,29 @@ Spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
       shortest_playing_len = 1;
     }
   
-  if (! shortest.to_bool ())
-    {
-      programming_error ("no minimum in measure at " + Paper_column::when_mom (lc).str ());
-      shortest = 1;
-    }
   Moment delta_t = Paper_column::when_mom (rc) - Paper_column::when_mom (lc);
   Real dist = 0.0;
 
   if (delta_t.main_part_)
     {
-      dist = get_duration_space (me, shortest_playing_len, shortest);
+      dist = get_duration_space (me, shortest_playing_len, shortest.main_part_, expand_only);
       dist *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
     }
   else if (delta_t.grace_part_)
     {
-      dist = get_duration_space (me, shortest, shortest);
+      /*
+	TODO: figure out how to space grace notes.
+      */
+      dist = get_duration_space (me, shortest, shortest.main_part_, expand_only);
 
       Real grace_fact = 1.0;
       SCM gf = me->get_grob_property ("grace-space-factor");
       if (gh_number_p (gf))
 	grace_fact = gh_scm2double (gf);
 
-      dist *= grace_fact; 
+      dist *= grace_fact;
     }
 
-#if 0
-  /*
-    TODO: figure out how to space grace notes.
-   */
-
-  dist *= 
-    +  grace_fact * (double) (delta_t.grace_part_ / shortest_playing_len.main_part_);
-
-
-  Moment *lm = unsmob_moment (lc->get_grob_property ("when"));
-  Moment *rm = unsmob_moment (rc->get_grob_property ("when"));
-
-  if (lm && rm)
-    {
-      if (lm->grace_part_ && rm->grace_part_)
-	dist *= 0.5;
-      else if (!rm->grace_part_ && lm->grace_part_)
-	dist *= 0.7;
-    }
-#endif
   
   return dist;
 }
diff --git a/lily/spring-smob.cc b/lily/spring-smob.cc
new file mode 100644
index 0000000000..b00bd9df12
--- /dev/null
+++ b/lily/spring-smob.cc
@@ -0,0 +1,47 @@
+/*   
+  spring.cc --  implement Spring
+  
+  source file of the GNU LilyPond music typesetter
+  
+  (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  
+ */
+
+#include "spring.hh"
+#include "debug.hh"
+#include "ly-smobs.icc"
+
+Spring_smob::Spring_smob()
+{
+  distance_f_ =0.;
+  strength_f_ =1.0;
+  expand_only_b_ = false;
+  other_ = 0;
+}
+
+
+IMPLEMENT_SIMPLE_SMOBS(Spring_smob);
+
+SCM
+Spring_smob::mark_smob (SCM) { return SCM_UNSPECIFIED; }
+
+int
+Spring_smob::print_smob (SCM s, SCM p, scm_print_state *)
+{
+  Spring_smob *ss = unsmob_spring (s);
+  scm_puts (_f("#<spring smob d= %f>", ss->distance_f_).ch_C(), p);
+  return 1;
+}
+
+SCM
+Spring_smob::equal_p (SCM a , SCM b)
+{
+  return a==b? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+SCM
+Spring_smob::smobbed_copy ()const
+{
+  Spring_smob *  p = new Spring_smob (*this);
+  return p->smobbed_self ();
+}
diff --git a/lily/spring.cc b/lily/spring.cc
index 6c6e9de6dc..8b13789179 100644
--- a/lily/spring.cc
+++ b/lily/spring.cc
@@ -1,56 +1 @@
-/*   
-  spring.cc --  implement Spring
-  
-  source file of the GNU LilyPond music typesetter
-  
-  (c) 1999--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-  
- */
-
-#include "spring.hh"
-#include "debug.hh"
-#include "item.hh"
-#include "spaceable-grob.hh"
-#include "paper-column.hh"
-
-Spring::Spring ()
-{
-  item_l_drul_[LEFT]  =item_l_drul_[RIGHT] =0;
-  distance_f_ =0.;
-  strength_f_ =1.0;
-}
-
-/*
-
- ugh : if we go from items to cols, we should adjust distance and strength.
- */
-
-void
-Spring::add_to_cols ()
-{
-  Spaceable_grob::add_spring (item_l_drul_[LEFT]->column_l (),
-				 item_l_drul_[RIGHT]->column_l (),
-				 distance_f_, strength_f_);
-}
-
-void
-Spring::set_to_cols( )
-{
-  Direction d = LEFT;
-  do
-    {
-      item_l_drul_[d] = item_l_drul_[d]->column_l ();
-    }
-  while (flip (&d) != LEFT);
-
-}
-
-Column_spring::Column_spring ()
-{
-  other_l_ = 0;
-  distance_f_ =0;
-  strength_f_ =1.0;
-}
-
-
 
diff --git a/lily/staff-spacing.cc b/lily/staff-spacing.cc
index aec23070d8..8493dd9326 100644
--- a/lily/staff-spacing.cc
+++ b/lily/staff-spacing.cc
@@ -1,17 +1,23 @@
 /*   
-staff-spacing.cc --  implement Staff_spacing
+     staff-spacing.cc --  implement Staff_spacing
 
-source file of the GNU LilyPond music typesetter
+     source file of the GNU LilyPond music typesetter
 
-(c) 2001--2002  Han-Wen Nienhuys <hanwen@cs.uu.nl>
+     (c) 2001--2002  Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+*/
+#include <stdio.h>
 
- */
 #include "paper-column.hh" 
 #include "separation-item.hh"
 #include "item.hh"
 #include "staff-spacing.hh"
 #include "grob.hh"
 #include "warn.hh"
+#include "bar-line.hh"
+#include "staff-symbol-referencer.hh"
+#include "note-column.hh"
+#include "stem.hh"
 
 bool
 Staff_spacing::has_interface (Grob* g)
@@ -19,43 +25,124 @@ Staff_spacing::has_interface (Grob* g)
   return g && g->has_interface (ly_symbol2scm ("staff-spacing-interface"));
 }
 
-
 /*
-*/
-void
-Staff_spacing::get_spacing_params (Grob *me, Real * space, Real * fixed)
-{
-  *space = 1.0;
-  *fixed = 1.0;
+  Insert some more space for the next note, in case it has a stem in
+  the wrong direction
 
-  
+ */
+Real
+Staff_spacing::next_note_correction (Grob * me,
+				     Grob * g,
+				     Interval bar_size)
+{
+  if (!g || !Note_column::has_interface (g))
+    return 0.0;
 
-  Grob * separation_item=0;
-  
-  for (SCM s = me->get_grob_property ("left-items");
-       gh_pair_p (s); s = gh_cdr(s))
+  Item *col =dynamic_cast<Item*> (g)->column_l ();
+  Real max_corr = 0. >? (- g->extent (col, X_AXIS)[LEFT]);
+  if (Grob * a = Note_column::accidentals (g))
     {
-      Grob * cand = unsmob_grob(gh_car (s));
-      if (cand && Separation_item::has_interface (cand))
-	separation_item = cand ;
+      max_corr = max_corr >? (- a->extent (col, X_AXIS)[LEFT]);
     }
 
-  Grob *left_col = dynamic_cast<Item*> (me)->column_l ();
+  /*
+    Let's decrease the space a little if the problem is not located
+    after a barline.
+  */
+  if (bar_size.empty_b ())
+    max_corr *= 0.75;
+  
+  if (!bar_size.empty_b())
+    if (Grob *stem = Note_column::stem_l  (g))
+      {
+	Direction d = Stem::get_direction (stem);
+	if (d == DOWN)
+	  {
+	    Real stem_start = Stem::head_positions (stem) [DOWN];
+	    Real stem_end = Stem::stem_end_position (stem); 
+	    Interval stem_posns (stem_start <? stem_end,
+				 stem_end >? stem_start);
+
+	    stem_posns.intersect (bar_size);
+
+	    Real corr = abs (stem_posns.length ()/7.) <? 1.0;
+	    corr *=
+	      gh_scm2double (me->get_grob_property ("stem-spacing-correction"));
+
+	    if (d != DOWN)
+	      corr = 0.0;
+	    max_corr = max_corr >? corr;
+	  }
+      }
+  return max_corr;
+}
 
-  Grob *last_grob = 0;
-  Interval last_ext ;
 
-  if (!separation_item)
+/*
+  Y-positions that are covered by BAR_GROB, in the case that it is a
+  barline.  */
+Interval
+Staff_spacing::bar_y_positions (Grob *bar_grob)
+{
+  Interval bar_size;
+  bar_size.set_empty();
+  if (Bar_line::has_interface (bar_grob))
     {
-      programming_error ("no sep item");
-      return;
+      SCM glyph = bar_grob->get_grob_property ("glyph");
+      
+      String glyph_str = gh_string_p (glyph) ? ly_scm2string (glyph) : "";
+      if (glyph_str.left_str (1) == "|" || glyph_str.left_str (1) == ".")
+	{
+	  SCM sz = Bar_line::get_staff_bar_size (bar_grob->self_scm());
+	  bar_size = Interval (-1,1);
+	  bar_size *= gh_scm2double (sz)
+	    / Staff_symbol_referencer::staff_space (bar_grob);
+	}
     }
+  return bar_size;
+}
+
+/*
+  Do corrections for the following notes.
+
+  This is slightly convoluted, since the staffspacing grob gets
+  pointers to the separation-items, not the note-columns or
+  note-spacings.
   
+ */
+Real
+Staff_spacing::next_notes_correction (Grob *me, Grob * last_grob)
+{
+  Interval bar_size = bar_y_positions (last_grob);
+  Real max_corr =0.0;
+  for (SCM s = me->get_grob_property ("right-items");
+       gh_pair_p (s);  s = gh_cdr (s))
+    {
+      Grob * g = unsmob_grob (gh_car (s));
+      max_corr = max_corr >?  next_note_correction (me, g,  bar_size);
+      for (SCM t = g->get_grob_property ("elements");
+	   gh_pair_p (t); t  = gh_cdr (t))
+	max_corr = max_corr >? next_note_correction (me, unsmob_grob (gh_car (t)), bar_size);
+      
+    }
+  return max_corr;
+}
+
+/*
+  Try to find the break-aligned symbol in SEPARATION_ITEM that is
+  sticking out at direction D. The x size is put in LAST_EXT
+*/
+Grob*
+Staff_spacing::extremal_break_aligned_grob (Grob *separation_item, Direction d,
+				   Interval * last_ext)
+{
+  Grob *left_col = dynamic_cast<Item*> (separation_item)->column_l ();
+  last_ext->set_empty ();
+  Grob *last_grob = 0;
   for (SCM s = separation_item->get_grob_property ("elements");
        gh_pair_p (s); s = gh_cdr (s))
     {
       Grob * break_item = unsmob_grob (gh_car (s));
-
       
       if (!gh_symbol_p (break_item->get_grob_property ("break-align-symbol")))
 	continue;
@@ -65,13 +152,45 @@ Staff_spacing::get_spacing_params (Grob *me, Real * space, Real * fixed)
       if (ext.empty_b ())
 	continue;
       if (!last_grob
-	  || (last_grob && ext[RIGHT] > last_ext[RIGHT]))
+	  || (last_grob && d * (ext[d]- (*last_ext)[d]) > 0) )
 	{
-	  last_ext = ext;
+	  *last_ext = ext;
 	  last_grob = break_item; 
 	}
     }
 
+  return last_grob;  
+}
+
+/*
+*/
+void
+Staff_spacing::get_spacing_params (Grob *me, Real * space, Real * fixed)
+{
+  *space = 1.0;
+  *fixed = 1.0;
+
+  Grob * separation_item=0;
+  
+  for (SCM s = me->get_grob_property ("left-items");
+       gh_pair_p (s); s = gh_cdr(s))
+    {
+      Grob * cand = unsmob_grob(gh_car (s));
+      if (cand && Separation_item::has_interface (cand))
+	separation_item = cand ;
+    }
+
+  //  printf ("doing col %d\n" , Paper_column::rank_i(left_col));
+
+  if (!separation_item)
+    {
+      programming_error ("no sep item");
+      return;
+    }
+
+  Interval last_ext;
+  Grob *last_grob = extremal_break_aligned_grob (separation_item, RIGHT,
+						 &last_ext);
   if (!last_grob)
     {
       programming_error ("empty break column? --fixme");
@@ -101,5 +220,14 @@ Staff_spacing::get_spacing_params (Grob *me, Real * space, Real * fixed)
     *space = *fixed + distance;
   else if (type == ly_symbol2scm("minimum-space"))
     *space = last_ext[LEFT] + (last_ext.length () >? distance);
+
+
+  *space += next_notes_correction (me, last_grob);
+
+  if (dynamic_cast<Item*> (me)-> break_status_dir () == RIGHT)
+    {
+      /* Start of line: this space is not stretchable */
+      *fixed = *space;
+    }
   
 }
diff --git a/lily/stem.cc b/lily/stem.cc
index 7ff2812ca9..d53539ec68 100644
--- a/lily/stem.cc
+++ b/lily/stem.cc
@@ -113,7 +113,7 @@ Stem::set_stemend (Grob*me, Real se)
   Direction d= get_direction (me);
   
   if (d && d * head_positions (me)[get_direction (me)] >= se*d)
-    warning (_ ("Weird stem size; check for narrow beams"));
+    me->warning (_ ("Weird stem size; check for narrow beams"));
 
   me->set_grob_property ("stem-end-position", gh_double2scm (se));
 }
diff --git a/lily/text-spanner.cc b/lily/text-spanner.cc
index 3376c8f016..0511e632b5 100644
--- a/lily/text-spanner.cc
+++ b/lily/text-spanner.cc
@@ -118,7 +118,7 @@ Text_spanner::brew_molecule (SCM smob)
   
   if (width < 0)
     {
-      warning (_ ("Text_spanner too small"));
+      me->warning (_ ("Text_spanner too small"));
       width = 0;
     }
 
diff --git a/lily/time-signature-engraver.cc b/lily/time-signature-engraver.cc
index 5e85cf3c5b..1471129cd3 100644
--- a/lily/time-signature-engraver.cc
+++ b/lily/time-signature-engraver.cc
@@ -21,7 +21,7 @@ class Time_signature_engraver : public Engraver
 
 protected:
   virtual void stop_translation_timestep ();
-  virtual void create_grobs ();
+  virtual void process_music ();
 public:
   TRANSLATOR_DECLARATIONS(Time_signature_engraver);
 };
@@ -34,7 +34,7 @@ Time_signature_engraver::Time_signature_engraver ()
 }
 
 void
-Time_signature_engraver::create_grobs ()
+Time_signature_engraver::process_music ()
 {
   /*
     not rigorously safe, since the value might get GC'd and
diff --git a/lily/time-signature.cc b/lily/time-signature.cc
index 78a1f3bbd7..1ba5fb873a 100644
--- a/lily/time-signature.cc
+++ b/lily/time-signature.cc
@@ -71,7 +71,7 @@ Time_signature::special_time_signature (Grob*me, String s, int n, int d)
   String symbolname = "timesig-" + s + to_str (n) + "/" + to_str (d);
   
   Molecule m = feta->find_by_name (symbolname);
-  if (!m.empty_b ()) 
+  if (!m.empty_b ())
     return m;
 
   /*
diff --git a/make/out/lilypond.lsm b/make/out/lilypond.lsm
index 014dadffc6..be36f34f9a 100644
--- a/make/out/lilypond.lsm
+++ b/make/out/lilypond.lsm
@@ -1,15 +1,15 @@
 Begin3
 Title: LilyPond
-Version: 1.5.37
-Entered-date: 03MRT02
+Version: 1.5.38
+Entered-date: 11MRT02
 Description: @BLURB@
 Keywords: music notation typesetting midi fonts engraving
 Author: hanwen@cs.uu.nl (Han-Wen Nienhuys)
 	janneke@gnu.org (Jan Nieuwenhuizen)
 Maintained-by: hanwen@stack.nl (Han-Wen Nienhuys)
 Primary-site: sunsite.unc.edu /pub/Linux/apps/sound/convert
-	1000k lilypond-1.5.37.tar.gz 
+	1000k lilypond-1.5.38.tar.gz 
 Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/
-	1000k lilypond-1.5.37.tar.gz 
+	1000k lilypond-1.5.38.tar.gz 
 Copying-policy: GPL
 End
diff --git a/make/out/lilypond.mandrake.spec b/make/out/lilypond.mandrake.spec
index 32005123cc..0a2dc2df67 100644
--- a/make/out/lilypond.mandrake.spec
+++ b/make/out/lilypond.mandrake.spec
@@ -1,5 +1,5 @@
 %define name lilypond
-%define version 1.5.37
+%define version 1.5.38
 %define release 1mdk
 
 Name: %{name}
diff --git a/make/out/lilypond.redhat.spec b/make/out/lilypond.redhat.spec
index 59031966cf..dae2b110c1 100644
--- a/make/out/lilypond.redhat.spec
+++ b/make/out/lilypond.redhat.spec
@@ -3,11 +3,11 @@
 %define info yes
 
 Name: lilypond
-Version: 1.5.37
+Version: 1.5.38
 Release: 1
 License: GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.37.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.38.tar.gz
 Summary: Create and print music notation 
 URL: http://www.lilypond.org/
 BuildRoot: /tmp/lilypond-install
diff --git a/make/out/lilypond.suse.spec b/make/out/lilypond.suse.spec
index c468423ae1..ae5354adc1 100644
--- a/make/out/lilypond.suse.spec
+++ b/make/out/lilypond.suse.spec
@@ -14,11 +14,11 @@
 
 Distribution: SuSE Linux 7.0 (i386)
 Name: lilypond
-Version: 1.5.37
+Version: 1.5.38
 Release: 2
 Copyright:    GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.37.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.38.tar.gz
 # music notation software for.. ?
 Summary: A program for printing sheet music.
 URL: http://www.lilypond.org/
diff --git a/mf/feta-generic.mf b/mf/feta-generic.mf
index 84e8685c03..72a00dbac0 100644
--- a/mf/feta-generic.mf
+++ b/mf/feta-generic.mf
@@ -23,6 +23,7 @@ make_picture_stack;
 input feta-params;
 
 font_x_height  staff_space#;
+font_coding_scheme "feta music";
 
 if test = 0: 
 	input feta-eindelijk;
@@ -35,16 +36,18 @@ if test = 0:
 	input feta-timesig;
 	input feta-pendaal;
 	input feta-accordion;
-
+	input feta-solfa;
+	
 else:
 %	input feta-bolletjes;	
 %	input feta-banier;
 %	input feta-eindelijk;
-	input feta-klef;
+%	input feta-klef;
 %	input feta-toevallig;
 %	input feta-schrift;
 %	input feta-haak;
-	input feta-timesig;
+%	input feta-timesig;
 %	input feta-pendaal;
 %	input feta-accordion;
+	input feta-solfa;
 fi
diff --git a/mf/feta-klef.mf b/mf/feta-klef.mf
index 1f811f1db0..5f17ff4b28 100644
--- a/mf/feta-klef.mf
+++ b/mf/feta-klef.mf
@@ -14,6 +14,9 @@ fet_begingroup("clefs");
 %
 % [Ross] says that clefs take 1 staff_space space on the left and right
 %
+% this is now handled in the lilypond spacing engine. 
+%
+
 def set_horizontal_spacing =
 	save left_space ,right_space;
 	left_space# = 0;
@@ -24,17 +27,17 @@ enddef;
 % [Wanske] says the bulbs should be positioned about 1/4 right of the
 % "arrow"
 def draw_c_clef (expr reduction) = 
-	save hair, norm, reduced_il, right_edge;
-	reduced_il#=staff_space#*reduction;
-	norm#:=2/3reduced_il#;
+	save hair, norm, reduced_ss, right_edge;
+	reduced_ss#=staff_space#*reduction;
+	norm#:=2/3reduced_ss#;
 	hair#:=1/6norm#;
 
 	set_horizontal_spacing;
 	right_edge# = 15/4norm#+2hair#;
 
 	set_char_box (left_space#, right_edge# + right_space#, 
-		2 reduced_il#, 2 reduced_il#);
-	define_pixels (hair,norm,reduced_il, right_edge);
+		2 reduced_ss#, 2 reduced_ss#);
+	define_pixels (hair,norm,reduced_ss, right_edge);
 
 	draw_block ((0,-d), (3/4norm+1/2hair,h));
 	draw_block ((3/4norm+2hair,-d), 
@@ -50,7 +53,7 @@ def draw_c_clef (expr reduction) =
 	z3=(((right_edge -xoff)/2)+xoff,2hair);
 
 	penpos4(hair,0);
-	z4=(xoff+1/2norm+1/2hair,reduced_il-hair);
+	z4=(xoff+1/2norm+1/2hair,reduced_ss-hair);
 	
 	penpos5(4hair,0);
 	z5=(xoff+5/4hair,0);
@@ -64,7 +67,6 @@ def draw_c_clef (expr reduction) =
 	p = z5l..z4l{up}..z4r{down}..z3r{right}..tension t..z2r{up}
 		..tension t..
 		flare_path(z1l,180,90,hair,norm-1/2hair, -1)
-%z1r{left}..z1l{right}
 		..tension t..z2l{down}
 		..z3l{left}..z6r..z5r{down};
 	pickup pencircle scaled 1pt#;
@@ -90,64 +92,154 @@ fet_beginchar ("C clef", "C_change", "caltoclef")
 fet_endchar;
 
 %
-% Inspired by Baerenreiter and Breitkopf
-% 
-% FIXME: dims
-% FIXME: right vertical tangent seems to be lower than the F-line
-% FIXME: bulb curve smoothly into "long curve" on the  inside
+% New bulb routine:
+%
+% Insert a brushed piece of the path, and draw a bulb separately
+%
+% The bulb is  circular form. Neat merging of the bulb and brushed path
+% is done by playing with tension.
+%
+%
+
+def new_bulb (expr outer_tangent_point, 
+    big_radius, bulb_radius, flare, direction) =
+  begingroup;
+    save p, oldpen;
+    path p;
+    pen oldpen;
+    save center;
+    pair center;
+    clearxy;
+    
+    center = outer_tangent_point +big_radius* dir(0) + big_radius* dir(-90)
+      - bulb_radius * dir (-90);
+
+    z1 = center + bulb_radius * dir 180;
+    z2 = center + bulb_radius * dir 270;
+
+    z9 = center + bulb_radius * dir (0);
+    z10 = center + bulb_radius * dir (90);
+    z3 = outer_tangent_point + flare * dir (0);
+
+    labels(1,2,3,9,10);
+
+    % tension is needed to open up the space between return path and the
+    % ball.
+    fill
+      z9 .. z10 .. tension 1.1  .. z1 .. z2 .. cycle;
+    
+    p:=    outer_tangent_point{down}
+       .. tension 0.97
+       .. {up}z9 -- z3
+     ;
+    if direction = 1:
+      p
+    else:
+      reverse p
+    fi
+  endgroup
+enddef;
+
+
+
+%
+%
+% There is  some variation is shape of bass clefs. Important points
+%
+% * the size of the swoosh tip: in some clefs, it almost reaches the
+% bottom staff line, in some it crosses the 2nd line from the bottom
+% with a small overshoot.
+%
+% The most popular design is where the X part of the tip is aligned 
+% left bulb boundary, and the Y part ends on the 2nd staffline exactly. 
+% This is what we do.
+%
+% * The size of the bulb. The diameter of the bulb is the width of the 
+% open space.
+%
+% * The y-alignment of the bulb. The center of the bulb can be on or slightly 
+% above the staff line.
+%
+% * The position of the dots. They can be symmetrical around the
+% staffline, centered in the staff space. The Baerenreiter SCS has the
+% bottom dot raised by approx. 0.1 ss.
+%
+% * uncarefully set music may have overshoots at the top. We have none. 
+%
+% * It is not exactly clear where the vertical tangent at the right
+% of the swoosh should be.
 %
 %
-% [Wanske] says that the extreme x point should be exactly between 
-% the dots, but her picture shows that the extreme is ~ 0.2 ss lower
 
 def draw_bass_clef(expr exact_center, reduction) = 
-        save reduced_il, left_tilt, left_thick, ball_to_right;
-        reduced_il# = staff_space# * reduction;
-        
+        save reduced_ss, left_tilt, left_thick, swoosh_width;
+	save right_thickness, tip_protude;
+	pair tip_protude;
+        save dot_diam;
+        reduced_ss# = staff_space# * reduction;
+
+
+        2.2 dot_diam = round reduction* (staff_space - stafflinethickness);
+	right_thickness = 0.48;
+        left_thick = .25;
+        swoosh_width# = 2.1 reduced_ss#;
+%	tip_protude := (-stafflinethickness, -.2 staff_space);
+	tip_protude := (0, 0);	
         set_horizontal_spacing;
-        ball_to_right# = 2.1 reduced_il#;
+	bulb_y_offset := 0.15 staff_space;
+	overshoot_top := 0.0;
+	%% 
+
         set_char_box(left_space# +
                 - xpart exact_center,
                 right_space# +
-                xpart exact_center + ball_to_right# + 7/12 reduced_il#, 
-                - ypart exact_center + 2.5 reduced_il#, 
-                ypart exact_center +reduced_il#);
+                xpart exact_center + swoosh_width# + 7/12 reduced_ss#, 
+                - ypart exact_center + 2.5 reduced_ss#, 
+                ypart exact_center +reduced_ss#);
 
-        define_pixels(reduced_il, ball_to_right);
+        define_pixels(swoosh_width);
+	define_whole_pixels(reduced_ss); 
         left_tilt = 5;
-        left_thick = .25  reduced_il;
 
-        x1r - x1l = left_thick;
-        z1l = (hround_pixels(xpart exact_center), 
-                vround_pixels(ypart exact_center));
+	y1 = bulb_y_offset;
+	x1 = 0;
 
-        y2 = reduced_il;
-
-        x3l - x1l =  ball_to_right;
         x2 = .5 [x1,x3];
-        x3l - x3r = .48 reduced_il;
-        y3l = -0.05 staff_space;
-        x4 = x1l - stafflinethickness;
-        y4 = -2.2  reduced_il;
-        z5 = (x3l +  1/3 reduced_il, .5 reduced_il);
-
-        penpos1(whatever, left_tilt);
-        penpos2(1.2 stafflinethickness, -90);
+	x2l = x2r = x2;
+
+	y2l := vround_pixels (reduced_ss#  + 0.5 stafflinethickness#);
+	y2l - y2r = (1.0 + overshoot_top) * stafflinethickness;
+	y2 = .5 [y2l, y2r];
+
+        x3l - x1 =  swoosh_width;
+        x3l - x3r = right_thickness * reduced_ss;
+
+	% try to correct: the top dot seems farther away if y3l = 0.
+        y3l = 0.05 staff_space;
+	
+        z4 =  - (0, 2.0 reduced_ss) + tip_protude;
+
+        z5 = (x3l +  1/3 reduced_ss, .5 reduced_ss);
+
         penpos3(whatever,  185);
         penpos4(stafflinethickness, 135);
 
-        draw_bulb(1, z1r,  z1l, .45 reduced_il, 1.0);
-
+	pickup pencircle scaled 1; 
+%	draw
+	fill
+           new_bulb (z1, 0.4 reduced_ss, 0.35 reduced_ss, 2 stafflinethickness,  1)
 
-        fill z1r{up} .. z2r{right} .. tension 1.0 .. z3r{down}  .. {curl 0} 
+{dir (90)}
+	        .. z2r{right} .. tension 1.0 .. z3r{down}  .. {curl 0} 
                 simple_serif(z4r, z4l, 90) {curl 0}
                 .. z3l{up} .. tension 0.9 .. z2l{left} 
-                .. z1l{dir (-90 + left_tilt)} -- cycle;
+                 .. cycle
+		;
         labels(2,4);
-        penlabels(1,2,3,4);
+        labels(range 1 thru 12);
+
+	penlabels(2,3,4);
 
-        save dot_diam;
-        2 dot_diam = round reduction* (staff_space - stafflinethickness);
         pickup pencircle scaled dot_diam;
         drawdot z5;
         drawdot z5 yscaled -1;
@@ -160,11 +252,11 @@ fet_beginchar("F clef ", "F", "bassclef")
 	if test = 1:
 		draw_staff(-3,1, 0.0);
 	fi;
-	draw_bass_clef((.5 staff_space#, 0), 1.0);
+	draw_bass_clef((0, 0), 1.0);
 fet_endchar;
 
 fet_beginchar("F clef (reduced)", "F_change", "cbassclef")
-	draw_bass_clef((.4 staff_space#, 0),0.8);
+	draw_bass_clef((0, 0),0.8);
 fet_endchar;
 
 
@@ -189,11 +281,11 @@ fet_endchar;
 %
 
 def draw_gclef (expr exact_center, reduction)=
-	save reduced_il, downstroke_dir, downstroke_angle, hair, center;
+	save reduced_ss, downstroke_dir, downstroke_angle, hair, center;
 	save breapth_factor, inner_thick_end, thinness, thickness, thinnib;
 	save inner_start_angle, thinness, thinpen;
-	reduced_il# = staff_space# * reduction;
-	define_pixels(reduced_il);
+	reduced_ss# = staff_space# * reduction;
+	define_pixels(reduced_ss);
 	pair downstroke_dir, center;
 
 	center := (hround_pixels(xpart exact_center), 
@@ -206,7 +298,7 @@ def draw_gclef (expr exact_center, reduction)=
 	breapth_factor = 11/7;
 	inner_thick_end = 45;
 	inner_start_angle = downstroke_angle - 43;
-	thickness = .4 reduced_il - hair;
+	thickness = .4 reduced_ss - hair;
 
 	thinnib = thinness - hair;
 	thinpen = thinness;
@@ -214,45 +306,45 @@ def draw_gclef (expr exact_center, reduction)=
 	
 	set_char_box(
 		left_space# +
-		-xpart exact_center + 1.0 * breapth_factor* reduced_il#, 
+		-xpart exact_center + 1.0 * breapth_factor* reduced_ss#, 
 		right_space# +
-		xpart exact_center + .66 breapth_factor* reduced_il#,
-		-ypart exact_center + 3 * reduced_il#,
-		ypart exact_center + 5 * reduced_il#);
+		xpart exact_center + .66 breapth_factor* reduced_ss#,
+		-ypart exact_center + 3 * reduced_ss#,
+		ypart exact_center + 5 * reduced_ss#);
 	
 	pickup pencircle scaled hair;
 	downstroke_angle = angle downstroke_dir;
 
 	z1 = center + whatever * dir (inner_start_angle);
-	x1 = xpart center -.28 reduced_il;
+	x1 = xpart center -.28 reduced_ss;
 	
-	top z2r = center + (0,reduced_il + stafflinethickness/2);
+	top z2r = center + (0,reduced_ss + stafflinethickness/2);
 	
-	x4 = xpart center - .1 reduced_il;
-	bot y4r = -(reduced_il + .5 stafflinethickness);
+	x4 = xpart center - .1 reduced_ss;
+	bot y4r = -(reduced_ss + .5 stafflinethickness);
 
 	z3 = (z4 - center) rotated inner_thick_end + center;
 	
-	z5r = (- breapth_factor, .37)* reduced_il + center;
+	z5r = (- breapth_factor, .37)* reduced_ss + center;
 	penpos5(thickness, 135);
 
 	z6 = center + whatever * downstroke_dir;
-	y6 = ypart center + 2 reduced_il;
+	y6 = ypart center + 2 reduced_ss;
 
 	z7l - z6 = whatever *(z5- z6) ;
-	y7l = 3.5 reduced_il;
+	y7l = 3.5 reduced_ss;
 	z8r = .4 [z9r, z7r] + 1.5 stafflinethickness * dir 52;
 
 	x9 = .7 [x10, x7r];
-	top y9l = 5 reduced_il;
+	top y9l = 5 reduced_ss;
 
-	y10 = 3. reduced_il;
-	y11 = -11/7 reduced_il;
+	y10 = 3. reduced_ss;
+	y11 = -11/7 reduced_ss;
 
-	y12 = ypart center - 18.5/7 reduced_il;
-	x12 = x11 - 5 /7 reduced_il;	
+	y12 = ypart center - 18.5/7 reduced_ss;
+	x12 = x11 - 5 /7 reduced_ss;	
 
-	z13 = z12 + .6 reduced_il*(-1,1);
+	z13 = z12 + .6 reduced_ss*(-1,1);
 
 	(z10r - z10l) dotprod (unitvector downstroke_dir rotated 90) = 
 		thinnib;
@@ -293,7 +385,7 @@ def draw_gclef (expr exact_center, reduction)=
 
 	filldraw z12r{left} .. z13r{up} -- z13l{down} .. z12l{right} .. cycle;
 
-	draw_bulb(-1,  z13l, lft z13r, 6/14 reduced_il, 1.0);
+	draw_bulb(-1,  z13l, lft z13r, 6/14 reduced_ss, 1.0);
 
 	pickup pencircle scaled (thinpen);
 	draw z10 --- z14 .. z11  .. tension 0.85 ..  z12{left};
@@ -319,11 +411,11 @@ fet_endchar;
 
 
 def draw_percussion_clef(expr reduction) =
-	save reduced_il;
-	reduced_il# = staff_space# * reduction;
-	define_pixels(reduced_il);
-	set_char_box(-.67reduced_il#,2.0reduced_il#,reduced_il#,reduced_il#);
-	razt := 0.45reduced_il;
+	save reduced_ss;
+	reduced_ss# = staff_space# * reduction;
+	define_pixels(reduced_ss);
+	set_char_box(-.67reduced_ss#,2.0reduced_ss#,reduced_ss#,reduced_ss#);
+	razt := 0.45reduced_ss;
 	draw_block((-b,-d),(-b+razt,h));
 	draw_block((w-razt,-d),(w,h));
 enddef;
@@ -492,23 +584,23 @@ def draw_tab_B(expr pos, siz, slant) =
 enddef;
 
 def draw_tab_clef(expr reduction) =
-        save reduced_il,vx,vy,letterheight,penw,penh;
-	reduced_il# = staff_space# * reduction;
-	letterheight# = 1.8*reduced_il#;
-	define_pixels(reduced_il,letterheight);
-	set_char_box(-.2*reduced_il#,2.8*reduced_il#,1.6*letterheight#,1.6*letterheight#);
+        save reduced_ss,vx,vy,letterheight,penw,penh;
+	reduced_ss# = staff_space# * reduction;
+	letterheight# = 1.8*reduced_ss#;
+	define_pixels(reduced_ss,letterheight);
+	set_char_box(-.2*reduced_ss#,2.8*reduced_ss#,1.6*letterheight#,1.6*letterheight#);
 
 		%draw_staff (-3,2, 0.5);
 
-	penw = .45reduced_il;
-	penh = .2reduced_il;
+	penw = .45reduced_ss;
+	penh = .2reduced_ss;
 
-	draw_tab_T((-b+.15reduced_il,h-letterheight),
-	  (2.1*reduced_il,letterheight),0.2);
-	draw_tab_A((-b-.05reduced_il,-.5letterheight +.15reduced_il),
-	  (2.2*reduced_il,letterheight),0.4);
-	draw_tab_B((-b+.025reduced_il,-d),
-	  (2.1*reduced_il,letterheight),0.25);
+	draw_tab_T((-b+.15reduced_ss,h-letterheight),
+	  (2.1*reduced_ss,letterheight),0.2);
+	draw_tab_A((-b-.05reduced_ss,-.5letterheight +.15reduced_ss),
+	  (2.2*reduced_ss,letterheight),0.4);
+	draw_tab_B((-b+.025reduced_ss,-d),
+	  (2.1*reduced_ss,letterheight),0.25);
 enddef;
 
 fet_beginchar("tab clef", "tab", "tabclef")
diff --git a/mf/feta-macros.mf b/mf/feta-macros.mf
index f709ef5413..7c12709e67 100644
--- a/mf/feta-macros.mf
+++ b/mf/feta-macros.mf
@@ -188,6 +188,8 @@ def super_curvelet(expr from, to, superness, dir) =
 enddef;
 
 
+%
+% Bulb with smooth inside curve.
 %
 % alpha = start direction.
 % beta = which side to turn to.
diff --git a/mf/feta-toevallig.mf b/mf/feta-toevallig.mf
index ed316e66f0..accc2310ac 100644
--- a/mf/feta-toevallig.mf
+++ b/mf/feta-toevallig.mf
@@ -79,13 +79,28 @@ fet_beginchar("Sharp" , "1", "sharp");
 	labels(1,2,3,4);
 	fet_endchar;
 
-fet_beginchar( "Natural", "0", "natural")
-	set_char_box(0, 8/12 staff_space#, 1.5 staff_space#, 1.5 staff_space#);
 
+%
+% The stems of the natural are brushed (at least, in Barenreiter SCS )
+%
+%
+
+fet_beginchar( "Natural", "0", "natural")
+	save height;	
 	save interbeam, interstem, beamheight, beamwidth, 
-		stemwidth;
+	stemwidth;
+	save top_stem_thick;
+
+	beamheight# = 4.0 stafflinethickness#;
+	height# = 1.5 staff_space#;
+	set_char_box(0, 2/3 staff_space#, height#, height#);
+
+	define_pixels(height);
+	define_blacker_pixels(beamheight);
+
+	% perhaps we should have a lowres fix?
+	top_stem_thick = 1.9 stafflinethickness;
 
-	beamheight = 4.5 stafflinethickness;
 	interstem + stemwidth =  w;
 	stemwidth = 1.3 stafflinethickness;
 
@@ -101,17 +116,32 @@ fet_beginchar( "Natural", "0", "natural")
 	draw z1 .. z2;
 	draw (xpart z1, -y2) .. (xpart z2, -y1);
 	beamtop = top y2;
-	
+
 	pickup pencircle scaled stemwidth;
-	xpart z3 = xpart z1;
-	xpart z4 = xpart z2;
-	top y3 = 1.5 staff_space;
+	x3 := round (xpart z1);
+	x4 := round (xpart z2);
+
+	penpos3(top_stem_thick, 0);
+	penpos5(top_stem_thick, 0);	
+	penpos4(stemwidth, 0);
+	penpos6(stemwidth, 0);	
+	
+	y3 = height;
 	top y4 = beamtop;
 
-	draw_gridline((xpart z1, -y4),z3,stemwidth);
-	draw_gridline((xpart z2, -y3),z4,stemwidth);
+	x5 = x4;
+	x6 = x3;
+	bot y6 = -beamtop;
+	y5 = - height;
 
-	labels(1,2,3,4);
+	fill simple_serif (z3l, z3r, -30) -- simple_serif(z6r, z6l, -90) -- cycle;
+	fill simple_serif (z5l, z5r, 30) -- simple_serif(z4r, z4l, 90) -- cycle;
+
+
+
+	penlabels(3,4,5,6);
+
+	labels(1,2);
 	fet_endchar;
 
 
@@ -180,12 +210,13 @@ def draw_meta_flat(expr xcenter, w, crook_fatness) =
 	x8r =  xpart center - bottom_stem_thick/2;
 	penlabels(range 0 thru 10);
 
-	z10 = (bottom_stem_thick/2, -1/5 staff_space) + center;
+	y10 = -1/5 staff_space;
+	z10 = whatever [z2r, z1r];
 
-	unfill z3r{up} .. z4r{right} .. tension .9 
+	unfill z3r .. z4r{right} .. tension .9 
 		.. z6r ---
 		z7r{left}
-		.. z10 {up} -- cycle;
+		.. z10  -- cycle;
 	fill z8r{down}
 		.. tension 0.8 ..z8l{(z9-z8)}
 		.. z7l
diff --git a/mf/parmesan-generic.mf b/mf/parmesan-generic.mf
index 53ce2688d1..4ded9c8c04 100644
--- a/mf/parmesan-generic.mf
+++ b/mf/parmesan-generic.mf
@@ -22,6 +22,7 @@ make_picture_stack;
 input feta-params;
 
 font_x_height  staff_space#;
+font_coding_scheme "parmesan music";
 
 if test = 0: 
 	input parmesan-rests;
diff --git a/scm/grob-description.scm b/scm/grob-description.scm
index cbe545bd0a..48e9722f5a 100644
--- a/scm/grob-description.scm
+++ b/scm/grob-description.scm
@@ -629,13 +629,12 @@
 	(spacing-procedure .  ,Spacing_spanner::set_springs)
 	(grace-space-factor . 0.8)
 
-	;; TODO: change naming -- unintuitive
-	(arithmetic-basicspace . 2.0)
-	(arithmetic-multiplier . ,(* 0.9 1.32))
+	(shortest-duration-space . 2.0)
+	(spacing-increment . 1.2)
 	(X-extent-callback . #f)
 	(Y-extent-callback . #f)
-	;; assume that notes at least this long are present.
-	(maximum-duration-for-spacing . ,(make-moment 1 8))
+
+
 	(meta . ,(grob-description  spacing-spanner-interface))
 	))
 
@@ -675,6 +674,7 @@
      . (
 	(breakable . #t)
 	(X-extent-callback . #f)
+	(stem-spacing-correction . 0.4)
 	(Y-extent-callback . #f)
 	(meta . ,(grob-description staff-spacing-interface))
 	))
diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm
index 0297594d73..2e63f3e81e 100644
--- a/scm/grob-property-description.scm
+++ b/scm/grob-property-description.scm
@@ -42,8 +42,11 @@ This procedure is called (using dependency resolution) after line breaking. Retu
 (grob-property-description 'arch-height number? "height of the hook of a system brace.")
 (grob-property-description 'arch-thick number? "thickness of the hook of system brace.")
 (grob-property-description 'arch-width number? "width of the hook of a system brace.")
-(grob-property-description 'arithmetic-basicspace number? "see @ref{spacing-spanner-interface}.")
-(grob-property-description 'arithmetic-multiplier number? "see @ref{spacing-spanner-interface}.")
+(grob-property-description 'shortest-duration-space number? "Start
+with this much space for the shortest duration. This is explessed in @code{spacing-increment} as unit. See also
+@ref{spacing-spanner-interface}.")
+(grob-property-description 'spacing-increment number? "Add this much space for a doubled duration. Typically, the width of a note head. See also @ref{spacing-spanner-interface}.")
+
 (grob-property-description 'arpeggio-direction dir? "If set, put an
 arrow on the arpeggio squiggly line.")
 (grob-property-description 'attachment pair? "cons of symbols, '(LEFT-TYPE . RIGHT-TYPE), where both types may be alongside-stem, stem, head or loose-end.")
diff --git a/scm/interface-description.scm b/scm/interface-description.scm
index 220a2ff457..4deb27f649 100644
--- a/scm/interface-description.scm
+++ b/scm/interface-description.scm
@@ -677,9 +677,8 @@ arithmetic_basicspace = 4.;
 
 @end example"
    '(
-  maximum-duration-for-spacing 
-    arithmetic-basicspace 
-    arithmetic-multiplier 
+spacing-increment
+shortest-duration-space
     
     ))
 
diff --git a/scm/tex.scm b/scm/tex.scm
index 4f1466880c..0ca8f300e9 100644
--- a/scm/tex.scm
+++ b/scm/tex.scm
@@ -259,7 +259,7 @@
   )
 (define (define-origin file line col)
   (if (procedure? point-and-click)
-      (string-append "\\special{src\\string:"
+      (string-append "\\special{src:" ;;; \\string ? 
 		     (point-and-click line col file)
 		     "}" )
       "")
diff --git a/scripts/convert-ly.py b/scripts/convert-ly.py
index 26e33611cd..6ae1b0e1dd 100644
--- a/scripts/convert-ly.py
+++ b/scripts/convert-ly.py
@@ -832,6 +832,14 @@ if 1:
 		return str
 	conversions.append (((1,5,33), conv, 'SystemStartDelimiter -> systemStartDelimiter'))
 
+if 1:
+	def conv (str):
+		str = re.sub ('arithmetic-multiplier', 'spacing-increment', str)
+		str = re.sub ('arithmetic-basicspace', 'shortest-duration-space', str)		
+		return str
+	
+	conversions.append (((1,5,38), conv, 'SystemStartDelimiter -> systemStartDelimiter'))
+
 
 ################################
 #	END OF CONVERSIONS	
-- 
2.39.5