From 8dbb0048c1ac59125562d5adc1c68512eab8541b Mon Sep 17 00:00:00 2001
From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Mon, 24 Dec 2001 14:50:08 +0100
Subject: [PATCH] release: 1.5.27

---
 ChangeLog                                     |  48 +-
 Documentation/regression-test.tely            |   2 +
 Documentation/user/converters.itely           |  19 +
 Documentation/user/refman.itely               |  18 +-
 INSTALL.txt                                   |  34 +-
 VERSION                                       |   4 +-
 input/regression/spacing-accidental-staffs.ly |   7 +-
 input/regression/tie-busy-grobs.ly            |  16 +
 input/test/staff-size.ly                      |  11 +-
 lily/accidental-engraver.cc                   |  34 +-
 lily/chord-name.cc                            |   5 -
 lily/completion-note-heads-engraver.cc        |  20 +-
 lily/grob-pq-engraver.cc                      | 159 +++++
 lily/include/grob-info.hh                     |   1 -
 lily/include/lily-guile.hh                    |  10 +-
 lily/include/lyric-combine-music-iterator.hh  |   3 +-
 lily/include/note-column.hh                   |   1 +
 lily/include/note-spacing.hh                  |   6 +-
 lily/include/paper-column.hh                  |   6 +-
 lily/line-of-score.cc                         |  29 +-
 lily/lyric-combine-music-iterator.cc          |  39 +-
 lily/music-iterator.cc                        |   6 +
 lily/note-column.cc                           |  19 +-
 lily/note-heads-engraver.cc                   |   7 +-
 lily/note-spacing-engraver.cc                 |  99 ++++
 lily/note-spacing.cc                          |  79 ++-
 lily/paper-column.cc                          |  47 ++
 lily/rhythmic-column-engraver.cc              |   9 -
 lily/separating-line-group-engraver.cc        | 101 +++-
 lily/spacing-wish.cc                          |   1 +
 lily/staff-spacing.cc                         |   1 +
 lily/stem-engraver.cc                         |   4 +
 lily/text-item.cc                             |  11 +-
 lily/third-try.cc                             | 550 ++++++++++++++++--
 lily/tie-engraver.cc                          |  77 +--
 lily/translator-group.cc                      |   2 +-
 lilypond-mode.el                              |  42 +-
 ly/drumpitch-init.ly                          |  19 +-
 ly/engraver-init.ly                           |   3 +-
 make/lilypond.redhat.spec.in                  |   2 +-
 make/lilypond.suse.spec.in                    |   2 +-
 make/out/lilypond.lsm                         |   8 +-
 make/out/lilypond.mandrake.spec               |   2 +-
 make/out/lilypond.redhat.spec                 |   6 +-
 make/out/lilypond.suse.spec                   |   6 +-
 scm/font.scm                                  |   6 +-
 scm/grob-description.scm                      |   4 +-
 scm/grob-property-description.scm             |   3 +-
 scm/interface-description.scm                 |   1 +
 scm/translator-property-description.scm       |   4 +
 scripts/lilypond-book.py                      |   6 +-
 tex/lilyponddefs.tex                          |   2 +
 52 files changed, 1354 insertions(+), 247 deletions(-)
 create mode 100644 input/regression/tie-busy-grobs.ly
 create mode 100644 lily/grob-pq-engraver.cc
 create mode 100644 lily/note-spacing-engraver.cc
 create mode 100644 lily/spacing-wish.cc

diff --git a/ChangeLog b/ChangeLog
index ca802f93a5..ded1e51b59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,16 +1,56 @@
-2001-12-16  Jan Nieuwenhuizen  <janneke@gnu.org>
+2001-12-24  Han-Wen Nienhuys  <hanwen@cs.uu.nl>
+
+	* VERSION: 1.5.27 released.
+
+	* Documentation/user/refman.itely (Bar numbers): added bar number
+	documentation.
+
+	* scm/font.scm (make-style-sheet): Fixes to make staff-sizes work
+	again.
+
+2001-12-22  Mats Bengtsson  <matsb@matsb@s3.kth.se>
+
+	* tex/lilyponddefs.tex: Make sure interscorelinefill=1 doesn't
+	spread the last few lines all over the last page of a score.
+
+2001-12-24  Han-Wen  <hanwen@cs.uu.nl>
+
+	* lily/third-try.cc: 3rd try at revising spacing
+	engine. Not yet finished.
+
+	* lily/paper-column.cc (brew_molecule): print debugging marks on a
+	paper-column.
+
+	* lily/tie-engraver.cc (class Tie_engraver): Use busyGrobs for
+	collecting past note heads.
+
+	* lily/note-heads-engraver.cc (try_music): Remove end_mom_
+	stuff.
 
+	* lily/grob-pq-engraver.cc (class Grob_pq_engraver): New file, new
+	class. Keep a queue of grobs that are still playing in busyGrobs. 
+
+	* lily/lyric-combine-music-iterator.cc (get_busy_status): New
+	function. Use busyGrobs to detect playing notes.
+	
+2001-12-16  Jan Nieuwenhuizen  <janneke@gnu.org>
+ 
 	* Documentation/topdocs/INSTALL.texi: Added note about broken
 	python-2.1.  Updated note for Debian's broken (well, broken for
 	our use anyway) tex configuration.
-
+	
 	* scripts/lilypond-book.py (re_dict): python2.2 fix.
-
+	
 	* stepmake/stepmake/c++-rules.make ($(outdir)/%.hh): 
 	($(outdir)/%.cc): Adapted to bison-1.30; added bison < 1.30 fix.
-
+	
 	* scripts/lilypond-book.py (bounding_box_dimensions): Bugfix.
 	(But left margin of png's still misses a few pixels.  Arg.)
+	
+2001-12-16  Heikki Junes  <hjunes@cc.hut.fi>
+
+	* lilypond-mode.el (LilyPond-command-next-midi): Make
+	possible to kill midi-process (using "C-c C-m").
 
 2001-12-14  Han-Wen  <hanwen@cs.uu.nl>
 
diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely
index 0f7791c577..42f5aad17e 100644
--- a/Documentation/regression-test.tely
+++ b/Documentation/regression-test.tely
@@ -165,6 +165,8 @@ Grace note do weird things with timing. Fragile.
 
 @lilypondfile[printfilename]{tie.ly}
 
+@lilypondfile[printfilename]{tie-busy-grobs.ly}
+
 @lilypondfile[printfilename]{tie-chord.ly}
 
 @lilypondfile[printfilename]{tie-accidental.ly}
diff --git a/Documentation/user/converters.itely b/Documentation/user/converters.itely
index 1d1e75b1b9..dceade2638 100644
--- a/Documentation/user/converters.itely
+++ b/Documentation/user/converters.itely
@@ -16,6 +16,9 @@
 @node midi2ly
 @section midi2ly
 
+@cindex MIDI
+@cindex importing MIDI
+
 Midi2ly translates a MIDI input file to a LilyPond source file. MIDI
 (Music Instrument Digital Interface) is a standard for digital
 instruments: it specifies cabling, a serial protocol and a file format.
@@ -80,6 +83,10 @@ C to parse the MIDI files.
 @node etf2ly
 @section etf2ly
 
+@cindex ETF
+@cindex enigma
+@cindex Finale
+@cindex Coda Technology
 
 ETF (Enigma Transport Format) is a format used by Coda Music
 Technology's Finale product. This program will convert part of an ETF
@@ -117,6 +124,9 @@ etf2ly.
 ABC is a fairly simple ASCII based format. It is described at
 @uref{http://www.gre.ac.uk/~c.walshaw/abc2mtex/abc.txt}.
 
+@cindex ABC
+@cindex Importing ABC
+
 @subsection Invoking abc2ly
 
 @example
@@ -172,6 +182,9 @@ abc2ly ignores the ABC beaming.
 PMX is a MusiXTeX preprocessor written by Don Simons, see
 @uref{http://icking-music-archive.sunsite.dk/Misc/Music/musixtex/software/pmx/}.
 
+@cindex PMX
+@cindex MusiXTeX
+@cindex Simons, Don
 
 @subsection Invoking pmx2ly
 
@@ -196,6 +209,9 @@ version information
 @node musedata2ly
 @section musedata2ly
 
+@cindex Musedata
+@cindex CCARH
+
 Musedata (@uref{http://www.musedata.org/}) is an electronic library of
 classical music scores, currently comprising about 800 composition
 dating from 1700 to 1825.  The music is encoded in so-called Musedata
@@ -234,6 +250,9 @@ MUP (Music Publisher) is a shareware music notation program by Arkkra
 Enterprises.  It is also the name of the input format.  Mup2ly will
 convert part of a Mup file to a ready-to-use LilyPond file.
 
+@cindex MUP
+@cindex Arkkra
+
 @subsection Invoking mup2ly
 
 @example
diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely
index 12adf9a8c4..2dbad10f96 100644
--- a/Documentation/user/refman.itely
+++ b/Documentation/user/refman.itely
@@ -141,7 +141,7 @@ brevity we omit obligatory lint such as @code{\score} blocks and
 * Notes::                       
 * Pitches::                     
 * Rests::                       
-* Skips::
+* Skips::                       
 * Durations::                   
 * Ties::                        
 * Tuplets::                     
@@ -2512,8 +2512,20 @@ The grob is @internalsref{RehearsalMark} in @internalsref{Score} context. See
 @node Bar numbers
 @subsection Bar numbers
 
-Bar numbers (grob: @internalsref{BarNumber}) are printed at the start of the
-line. See @code{input/test/boxed-molecule.ly} for boxed bar numbers.
+
+@cindex bar numbers
+@cindex measure numbers
+@cindex currentBarNumber
+
+Bar numbers are @internalsref{BarNumber} grobs.  They are printed at the
+start of the line.  The number itself is a property that can be set by
+modifying the @code{currentBarNumber} property, i.e.
+@example
+  \property Score.currentBarNumber = #217
+@end example
+
+If you want boxed bar numbers, see the example file
+@code{input/test/boxed-molecule.ly}.
 
 @refbugs
 
diff --git a/INSTALL.txt b/INSTALL.txt
index 176a50e062..058e0d97e7 100644
--- a/INSTALL.txt
+++ b/INSTALL.txt
@@ -27,6 +27,7 @@ INSTALL - compiling and installing GNU LilyPond
     Debian GNU/Linux
   Problems
     FLex-2.5.4a and gcc-3.0
+    Python-2.1[.1]
     Linux-2.4.0, Guile-1.4 -with-threads
     NetBSD
     Solaris:
@@ -128,9 +129,10 @@ Compilation
    * A reasonably new C++ compiler:  EGCS 1.1, GCC 2.95.2 or newer.
      Check out the gcc site (ftp://ftp.gnu.org/gnu/gcc/).
 
-   * Python 1.5, Check out the python website (http://www.python.org).
+   * Python (version 1.5 or newer; not 2.1.x) Check out the python
+     website (http://www.python.org).
 
-   * GUILE 1.3.4 or newer,  check out the GUILE webpage
+   * GUILE 1.4 or newer,  check out the GUILE webpage
      (http://www.gnu.org/software/guile/guile.html).  Version 1.4 is
      recommended for better performance.
 
@@ -388,18 +390,28 @@ running `apt-get' as root:
 
    Debian's TeX installation is a bit short on memory, you may want to
 increase it like this:
-     --- /etc/texmf/texmf.cnf.dpkg	Sun Jan 28 14:12:14 2001
-     +++ /etc/texmf/texmf.cnf	Fri Apr 27 11:09:35 2001
-     @ -384,8 +384,8 @
+     --- texmf.cnf.orig	Sun Dec 16 23:47:07 2001
+     +++ texmf.cnf	Sun Dec 16 23:46:34 2001
+     @ -411,8 +411,8 @
       main_memory.context = 1500000
       main_memory.mpost = 1000000
       main_memory = 263000 % words of inimemory available; also applies to inimf&mp
      -extra_mem_top = 0    % extra high memory for chars, tokens, etc.
      -extra_mem_bot = 0    % extra low memory for boxes, glue, breakpoints, etc.
-     +extra_mem_top = 100000    % extra high memory for chars, tokens, etc.
-     +extra_mem_bot = 100000    % extra low memory for boxes, glue, breakpoints, etc.
+     +extra_mem_top = 1000000    % extra high memory for chars, tokens, etc.
+     +extra_mem_bot = 1000000    % extra low memory for boxes, glue, breakpoints, etc.
      
-      obj_tab_size.context = 256000
+      obj_tab_size.context = 300000
+     
+     @ -430,7 +430,7 @
+      % Max number of characters in all strings, including all error messages,
+      % help texts, font names, control sequences.  These values apply to TeX and MP.
+      pool_size.context = 750000
+     -pool_size = 125000
+     +pool_size = 250000
+      % Minimum pool space after TeX/MP's own strings; must be at least
+      % 25000 less than pool_size, but doesn't need to be nearly that large.
+      string_vacancies.context = 45000
 
    You could also export `extra_mem_top' and `extra_mem_bot' as
 environment variables if you do not want to or cannot modify
@@ -507,6 +519,12 @@ LilyPond with gcc-3.0 you may do:
 
    Note that this is fixed in Debian/unstable for flex >= 2.5.4a-13.
 
+Python-2.1[.1]
+--------------
+
+   Regular expressions are broken in Python 2.1.[.1], either upgrade or
+downgrade python.
+
 Linux-2.4.0, Guile-1.4 -with-threads
 ------------------------------------
 
diff --git a/VERSION b/VERSION
index 8c2c4cc485..c939db38f5 100644
--- a/VERSION
+++ b/VERSION
@@ -1,8 +1,8 @@
 PACKAGE_NAME=LilyPond
 MAJOR_VERSION=1
 MINOR_VERSION=5
-PATCH_LEVEL=26
-MY_PATCH_LEVEL=jcn1
+PATCH_LEVEL=27
+MY_PATCH_LEVEL=
 
 # use the above to send patches: MY_PATCH_LEVEL is always empty for a
 # released version.
diff --git a/input/regression/spacing-accidental-staffs.ly b/input/regression/spacing-accidental-staffs.ly
index 58d1ecf1c9..175be7bade 100644
--- a/input/regression/spacing-accidental-staffs.ly
+++ b/input/regression/spacing-accidental-staffs.ly
@@ -4,13 +4,14 @@ texidoc = "Accidentals in different staffs don't effect the
 spacing of the quarter notes here."
 }
 
-\score { \notes \relative c'' < \context Staff = SA {
+\score { \notes \relative c'' < \context Staff = SA { \time 8/4
+
 c4 c4 cis4 cis4
-c4 c4 c4 c
+cis4 cis4 cis4 cis
 
 
  }
-   { \key d \major c2 c2 c2 cis2  } >
+   { \key d \major cis2 cis2 cis2 cis!2  } >
 
    \paper { linewidth = -1. } 
  }
diff --git a/input/regression/tie-busy-grobs.ly b/input/regression/tie-busy-grobs.ly
new file mode 100644
index 0000000000..719d196f2c
--- /dev/null
+++ b/input/regression/tie-busy-grobs.ly
@@ -0,0 +1,16 @@
+\header {
+
+texidoc = "Tie engraver uses @code{busyGrobs} to keep track of
+note heads. Test if this queue works by throwing many  mixed tuplets at it." 
+
+}
+
+\score
+{
+\notes \context Staff \relative c'' 
+ <
+  \context Voice { \voiceOne \times 2/3 { c'8~  c8~ c8~ c8~ c8~ c8 } }
+  \context Voice= VII { \voiceThree  { b,8 ~ b8 ~ b8 ~  b8 }}
+  \context Voice = VIII { \voiceTwo \times 2/5 { a,4 ~a4 ~a4~ a4~ a4 }}
+ >
+}
diff --git a/input/test/staff-size.ly b/input/test/staff-size.ly
index 854d6cc4ab..3dbe63ee08 100644
--- a/input/test/staff-size.ly
+++ b/input/test/staff-size.ly
@@ -1,16 +1,19 @@
 \version "1.3.146"
 \score {
   \notes \relative c' < \context Voice {
-	\property Staff.staffSpace = #10
+   \context Staff \outputproperty #(make-type-checker 'staff-symbol-interface)
+       #'staff-space = #(/ 16 20)
+
 	\property Staff.fontSize = #-1
 	\property Voice.fontSize = #-1
 	
-	\property Voice . dynamicDirection = \up \stemDown
-%\key gis \major
+	\dynamicUp\stemDown
+
+	%\key gis \major
 	c8 d [e f g a] b c \ff
   }
 
-\context Staff = VB {  \property Voice . dynamicDirection = \down c,,4 \ff c c c  }
+\context Staff = VB {  \dynamicDown c,,4 \ff c c c  }
 
 >
 \paper { linewidth = -1. }
diff --git a/lily/accidental-engraver.cc b/lily/accidental-engraver.cc
index 015b515e66..0f9b126eb3 100644
--- a/lily/accidental-engraver.cc
+++ b/lily/accidental-engraver.cc
@@ -54,7 +54,7 @@ public:
   Link_array<Grob> arpeggios_;
   
   Link_array<Note_req> mel_l_arr_;
-  Link_array<Grob> support_l_arr_;
+  Link_array<Grob> head_l_arr_;
   Link_array<Item> forced_l_arr_;
   Link_array<Grob> tie_l_arr_;
 
@@ -155,19 +155,20 @@ Accidental_engraver::create_grobs ()
       SCM barnum = get_property ("currentBarNumber");
 
       bool extra_natural_b = get_property ("extraNatural")==SCM_BOOL_T;
-
       for (int i=0; i  < mel_l_arr_.size (); i++) 
 	{
-	  Grob * support_l = support_l_arr_[i];
+	  Grob * support_l = head_l_arr_[i];
 	  Note_req * note_l = mel_l_arr_[i];
 
 	  int num = number_accidentals(localsig,note_l,accidentals_l,barnum);
 	  int num_caut = number_accidentals(localsig,note_l,cautionaries_l,barnum);
 	  bool cautionary = to_boolean (note_l->get_mus_property ("cautionary"));
-	  if (abs(num_caut)>abs(num)) {
-	    num=num_caut;
-	    cautionary=true;
-	  }
+	  if (abs(num_caut)>abs(num))
+	    {
+	      num=num_caut;
+	      cautionary=true;
+	    }
+	  
 	  bool different=num<0;
 	  num=abs(num);
 
@@ -200,7 +201,6 @@ Accidental_engraver::create_grobs ()
 		  key_item_p_ = new Item (get_property ("Accidentals"));
 		  Local_key_item::set_interface (key_item_p_);
 
-		  
 		  Staff_symbol_referencer::set_interface (key_item_p_);
 		  SCM c0 = get_property ("centralCPosition");
 		  if (gh_number_p (c0))
@@ -215,6 +215,8 @@ Accidental_engraver::create_grobs ()
 					 num==2 && extra_natural_b,
 					 tie_break_reminder);
 	      Side_position_interface::add_support (key_item_p_,support_l);
+	      
+	      support_l->set_grob_property ("accidentals", key_item_p_->self_scm ());
 	    }
 	  
 
@@ -258,11 +260,9 @@ Accidental_engraver::create_grobs ()
   if (key_item_p_)
     {
       /*
-	Hmm. Which one has to be on the left?
-
-	On which left, code or paper?
-
- (Arpeggios are engraved left of accidentals, of course.)
+	We add the accidentals to the support of the arpeggio, so it is put left of the
+	accidentals. 
+	
        */
       for (int i=0;  i < arpeggios_.size ();  i++)
 	Side_position_interface::add_support (arpeggios_[i], key_item_p_);
@@ -282,8 +282,8 @@ Accidental_engraver::stop_translation_timestep ()
 {
   if (key_item_p_)
     {
-      for (int i=0; i < support_l_arr_.size (); i++)
-	Side_position_interface::add_support (key_item_p_,support_l_arr_[i]);
+      for (int i=0; i < head_l_arr_.size (); i++)
+	Side_position_interface::add_support (key_item_p_,head_l_arr_[i]);
 
       typeset_grob (key_item_p_);
       key_item_p_ =0;
@@ -293,7 +293,7 @@ Accidental_engraver::stop_translation_timestep ()
   mel_l_arr_.clear ();
   arpeggios_.clear ();
   tie_l_arr_.clear ();
-  support_l_arr_.clear ();
+  head_l_arr_.clear ();
   forced_l_arr_.clear ();	
 }
 
@@ -305,7 +305,7 @@ Accidental_engraver::acknowledge_grob (Grob_info info)
   if (note_l && Rhythmic_head::has_interface (info.grob_l_))
     {
       mel_l_arr_.push (note_l);
-      support_l_arr_.push (info.grob_l_);
+      head_l_arr_.push (info.grob_l_);
     }
   else if (Tie::has_interface (info.grob_l_))
     {
diff --git a/lily/chord-name.cc b/lily/chord-name.cc
index 5595759236..2c0e717a89 100644
--- a/lily/chord-name.cc
+++ b/lily/chord-name.cc
@@ -27,11 +27,6 @@ Chord_name::after_line_breaking (SCM smob)
   if (to_boolean (s))
     {
       if (Paper_column::rank_i (me->column_l ()) -
-	  /*
-	    hmm, what's my column number in this line?
-	    why doesn't this work?
-	    me->line_l ()->rank_i_ > 2)
-	  */
 	  me->line_l ()->spanned_rank_iv ()[LEFT] > 1)
 	me->suicide ();
     }
diff --git a/lily/completion-note-heads-engraver.cc b/lily/completion-note-heads-engraver.cc
index 85609c295a..6d1157560d 100644
--- a/lily/completion-note-heads-engraver.cc
+++ b/lily/completion-note-heads-engraver.cc
@@ -16,9 +16,22 @@
 #include "score-engraver.hh"
 #include "warn.hh"
 
-/**
-  make balls and rests
+/*
+
+  How does this work?
+
+  When we catch the note, we predict the end of the note. We keep the
+  requests living until we reach the predicted end-time.
+
+  Every time process_music() is called and there are note requests, we
+  figure out how long the note to typeset should be. It should be no
+  longer than what's specified, than what is left to do and it should
+  not cross barlines.
+  
+  We copy the reqs into scratch note reqs, to make sure that we get
+  all durations exactly right.
  */
+
 class Completion_heads_engraver : public Engraver
 {
   Link_array<Item> note_p_arr_;
@@ -72,8 +85,9 @@ Completion_heads_engraver::try_music (Music *m)
     }
   else if (dynamic_cast<Busy_playing_req*> (m))
     {
-      return now_mom () < note_end_mom_;
+      return note_req_l_arr_.size ();
     }
+  
   return false;
   
 }
diff --git a/lily/grob-pq-engraver.cc b/lily/grob-pq-engraver.cc
new file mode 100644
index 0000000000..fad29ac48d
--- /dev/null
+++ b/lily/grob-pq-engraver.cc
@@ -0,0 +1,159 @@
+/*   
+  grob-pq-engraver.cc --  implement Grob_pq_engraver
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
+
+#include "translator-group.hh"
+#include "engraver.hh"
+#include "grob.hh"
+#include "warn.hh"
+
+struct Grob_mom
+{
+  Grob * grob_ ;
+  Moment end_;
+  Grob_mom () {}
+  Grob_mom (Grob*gr, Moment e)
+  {
+    grob_ = gr;
+    end_ = e;
+  }
+};
+
+int compare  (Grob_mom const &a, Grob_mom const &b)
+{
+  return Moment::compare (a.end_, b.end_);
+}
+
+class Grob_pq_engraver: public Engraver
+{
+public:
+  TRANSLATOR_DECLARATIONS(Grob_pq_engraver);
+
+  Array<Grob_mom> current_grobs_;
+protected:
+  virtual void initialize ();
+  virtual void acknowledge_grob (Grob_info);
+  virtual void start_translation_timestep ();
+  virtual void stop_translation_timestep ();
+};
+
+
+Grob_pq_engraver::Grob_pq_engraver()
+{
+}
+
+
+void
+Grob_pq_engraver::initialize ()
+{
+  daddy_trans_l_->set_property ("busyGrobs", SCM_EOL); 
+}
+
+void
+Grob_pq_engraver::acknowledge_grob (Grob_info gi)
+{
+  Music  * m = gi.music_cause ();
+
+  if (m)
+    {
+      Moment n = now_mom ();
+      Moment l = m->length_mom ();
+
+      if (!l.to_bool ())
+	return ;
+      
+      if (n.grace_part_)
+	{
+	  l.grace_part_ = l.main_part_;
+	  l.main_part_ = 0;
+	}
+
+      current_grobs_.push (Grob_mom (gi.grob_l_, n + l));
+    }
+}
+
+void
+Grob_pq_engraver::stop_translation_timestep ()
+{
+  Moment now = now_mom();
+
+  current_grobs_.sort (&compare);
+
+  SCM busy = get_property ("busyGrobs");
+  while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) == now)
+    {
+      busy = gh_cdr (busy);
+    }
+  
+  SCM start = busy;
+  SCM * current_cell = &start;
+
+  int  i = 0; 
+  while (i  < current_grobs_.size ())
+    {
+      Moment stop;
+      stop.set_infinite (1);
+      
+      if (gh_pair_p (busy))
+	{
+	  SCM h = gh_car (busy);
+	  stop = *unsmob_moment (gh_car (h));
+	}
+
+      Moment current_stop = current_grobs_[i].end_;
+      if (current_stop <= stop)
+	{
+	  SCM new_entry = gh_cons (current_stop.smobbed_copy(),
+				   current_grobs_[i].grob_->self_scm ());
+
+	  /*
+	    Insert before BUSY.
+	   */
+	  i ++;
+	  *current_cell = gh_cons (new_entry, busy);
+	  current_cell = SCM_CDRLOC(*current_cell);
+	}
+      else
+	{
+	  /*
+	    if current_stop > stop, then stop != infty, and we
+	    apparently have a next entry */
+	  busy = gh_cdr (busy);
+	  current_cell = SCM_CDRLOC(*current_cell);
+	}
+    }
+
+  current_grobs_.clear ();
+  daddy_trans_l_->set_property ("busyGrobs", start);
+}
+
+void
+Grob_pq_engraver::start_translation_timestep ()
+{
+ Moment now = now_mom();
+
+  SCM start_busy = get_property ("busyGrobs");
+  SCM busy = start_busy;
+  while (gh_pair_p (busy) && *unsmob_moment (gh_caar (busy)) < now)
+    {
+      programming_error ("Skipped something ?!");
+      
+      busy = gh_cdr (busy);
+    }
+
+  if (start_busy != busy)
+    daddy_trans_l_->set_property ("busyGrobs", busy);
+}
+
+
+ENTER_DESCRIPTION(Grob_pq_engraver,
+/* descr */       "Administrate when certain grobs (eg. note heads) stop playing.
+",
+/* creats*/       "",
+/* acks  */       "grob-interface",
+/* reads */       "busyGrobs",
+/* write */       "busyGrobs");
diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh
index 6d8868214c..578c20730a 100644
--- a/lily/include/grob-info.hh
+++ b/lily/include/grob-info.hh
@@ -30,7 +30,6 @@ struct Grob_info {
     GC errors if you don't use music or grobs as a cause.
   */
   SCM cause_;
-
 public:
   Music * music_cause ();
   Link_array<Translator> origin_trans_l_arr (Translator*) const;
diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh
index 26c2a8a300..7788833f4b 100644
--- a/lily/include/lily-guile.hh
+++ b/lily/include/lily-guile.hh
@@ -92,7 +92,15 @@ SCM ly_write2scm (SCM s);
 SCM ly_deep_copy (SCM);
 SCM ly_truncate_list (int k, SCM l );
 
+
+#if (__GNUC__ > 2)
+/*
+  todo: should add check for x86 as well
+ */
 #define CACHE_SYMBOLS
+#endif
+
+
 #ifdef CACHE_SYMBOLS
 
 
@@ -103,8 +111,6 @@ SCM ly_truncate_list (int k, SCM l );
  */
 SCM my_gh_symbol2scm (const char* x);
 
-// #warning: CACHE_SYMBOLS
-
 /*
   Using this trick we cache the value of gh_symbol2scm ("fooo") where
   "fooo" is a constant string. This is done at the cost of one static
diff --git a/lily/include/lyric-combine-music-iterator.hh b/lily/include/lyric-combine-music-iterator.hh
index dae14c81dc..8544673a21 100644
--- a/lily/include/lyric-combine-music-iterator.hh
+++ b/lily/include/lyric-combine-music-iterator.hh
@@ -25,11 +25,12 @@ protected:
   virtual Moment pending_moment () const;
   virtual void process (Moment);
   virtual Music_iterator *try_music_in_children (Music *) const;
-
+  
   virtual bool ok () const;
   virtual ~Lyric_combine_music_iterator ();
 
 private:
+  bool get_busy_status ()const ;
   Music_iterator * music_iter_p_;
   Music_iterator * lyric_iter_p_;
 };
diff --git a/lily/include/note-column.hh b/lily/include/note-column.hh
index 5f24f7284e..647ac34cb7 100644
--- a/lily/include/note-column.hh
+++ b/lily/include/note-column.hh
@@ -29,6 +29,7 @@ public:
     JUNKME.
     */
 
+  static Grob * accidentals (Grob*me);
   static Direction dir (Grob*me);
   static Slice head_positions_interval (Grob* me);
   static Direction static_dir (Grob*);
diff --git a/lily/include/note-spacing.hh b/lily/include/note-spacing.hh
index ed92e06519..1905c72e85 100644
--- a/lily/include/note-spacing.hh
+++ b/lily/include/note-spacing.hh
@@ -15,7 +15,11 @@ source file of the GNU LilyPond music typesetter
 class Note_spacing
 {
 public:
-  static bool has_interface (Grob*);  
+  static bool has_interface (Grob*);
+
+  static Real get_spacing (Grob *me);
+
+  DECLARE_SCHEME_CALLBACK(before_line_breaking,(SCM));
 };
 
 #endif /* NOTE_SPACING_HH */
diff --git a/lily/include/paper-column.hh b/lily/include/paper-column.hh
index 507ba6f0fe..4a21edaffc 100644
--- a/lily/include/paper-column.hh
+++ b/lily/include/paper-column.hh
@@ -19,9 +19,6 @@ class Paper_column : public Item
 public:
   VIRTUAL_COPY_CONS (Grob);
 
-  /*
-    Not (yet) in scm, because of messy effects when a column commits suicide.
-   */
   int  rank_i_;
   virtual void do_break_processing ();
   virtual Paper_column *column_l () const;
@@ -30,9 +27,10 @@ public:
   /// if lines are broken then this column is in #line#
   Line_of_score *line_l_;
 
-  /// which  one (left =0)
   static int rank_i (Grob*);
 
+  DECLARE_SCHEME_CALLBACK(brew_molecule, (SCM));
+  
   Paper_column (SCM);
   static bool musical_b (Grob *);
   static Moment when_mom (Grob*);
diff --git a/lily/line-of-score.cc b/lily/line-of-score.cc
index 96f00ce5ba..eaadc08fa5 100644
--- a/lily/line-of-score.cc
+++ b/lily/line-of-score.cc
@@ -127,13 +127,16 @@ Line_of_score::output_lines ()
     }
 }
 
+
+
+
 /*
   Find the loose columns in POSNS, and drape them around the columns
   specified in BETWEEN-COLS.  */
 void
 set_loose_columns (Line_of_score* which, Column_x_positions const *posns)
 {
-  for (int i = 0; i<posns->loose_cols_.size (); i++)
+  for (int i = 0; i < posns->loose_cols_.size (); i++)
     {
       int divide_over = 1;
       Item *loose = dynamic_cast<Item*> (posns->loose_cols_[i]);
@@ -145,24 +148,30 @@ set_loose_columns (Line_of_score* which, Column_x_positions const *posns)
       
       Item * left = 0;
       Item * right = 0;
-      while (1)
+      do
 	{
 	  SCM between = loose->get_grob_property ("between-cols");
 	  if (!gh_pair_p (between))
 	    break;
 
-	  if (!left)
+
+	  Item * l=dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
+	  Item * r=dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
+
+	  if (!(l && r))
+	    break ;
+	  
+	  if (!left && l)
 	    {
-	      left = dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
-	      left = left->column_l ();
+	      left = l->column_l ();
 	    }
-	  divide_over ++;	
-	  loose = dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
-	  loose = loose->column_l ();
-	}
 
-      right = loose;
+	  divide_over ++;
 
+	  loose = right = r->column_l ();
+	}
+      while (1);
+      
       Real rx = right->relative_coordinate (right->get_parent (X_AXIS), X_AXIS);
       Real lx = left->relative_coordinate (left->get_parent (X_AXIS), X_AXIS);
 
diff --git a/lily/lyric-combine-music-iterator.cc b/lily/lyric-combine-music-iterator.cc
index 6052b89ffd..e7e7901e87 100644
--- a/lily/lyric-combine-music-iterator.cc
+++ b/lily/lyric-combine-music-iterator.cc
@@ -11,6 +11,9 @@
 #include "lyric-combine-music-iterator.hh"
 #include "lyric-combine-music.hh"
 #include "musical-request.hh"
+#include "note-head.hh"
+#include "grob.hh"
+
 
 /*
   Ugh, why static?
@@ -59,6 +62,37 @@ Lyric_combine_music_iterator::construct_children ()
   lyric_iter_p_ = get_iterator_p (m->lyrics_l ());
 }
 
+bool
+Lyric_combine_music_iterator::get_busy_status () const
+{
+  /*
+    We have to use both the request and the busyGrobs queue.  The
+    busyGrobs queue doesn't contain any notes that have started this
+    instant.  */
+  if (try_music (busy_req))
+    return true;
+  
+  Translator_group * tr = music_iter_p_->report_to_l ();
+
+  SCM grobs = tr->get_property ("busyGrobs");
+  Moment now = tr->now_mom();
+  for (; gh_pair_p (grobs); grobs = gh_cdr (grobs))
+    {
+      SCM grob = gh_cdar (grobs);
+      Moment end  =*unsmob_moment (gh_caar (grobs));
+
+      
+      /*
+	This is slightly ugh: we are now confunding the frontend
+	(iterators) and the backend (note heads) */
+      if (end > now
+	  && Note_head::has_interface (unsmob_grob (grob)))
+	return true;
+    }
+
+  return false;
+}
+
 void
 Lyric_combine_music_iterator::process (Moment m)
 {
@@ -68,8 +102,7 @@ Lyric_combine_music_iterator::process (Moment m)
   
   music_iter_p_->process (m);
 
-  bool busy = try_music (busy_req);
-  if (busy)
+  if ( get_busy_status ())
     {
       bool melisma_b = try_music (melisma_playing_req);
       if (!melisma_b)
@@ -101,10 +134,10 @@ Lyric_combine_music_iterator::~Lyric_combine_music_iterator ()
 Lyric_combine_music_iterator::Lyric_combine_music_iterator (Lyric_combine_music_iterator const & src)
     : Music_iterator (src)
 {
-
   lyric_iter_p_ = src.lyric_iter_p_ ? src.lyric_iter_p_->clone () : 0;
   music_iter_p_ = src.music_iter_p_ ? src.music_iter_p_->clone () : 0;  
 }
+
 Music_iterator*
 Lyric_combine_music_iterator::try_music_in_children (Music *m) const
 {
diff --git a/lily/music-iterator.cc b/lily/music-iterator.cc
index f27f2f0d77..4135a6c988 100644
--- a/lily/music-iterator.cc
+++ b/lily/music-iterator.cc
@@ -161,6 +161,12 @@ Music_iterator::get_iterator_p (Music *m) const
   return p;
 }
 
+/*
+  TODO: rename to prevent confusion between Translator::try_music and
+  Iterator::try_music
+  
+ */
+
 Music_iterator*
 Music_iterator::try_music (Music *m) const
 {
diff --git a/lily/note-column.cc b/lily/note-column.cc
index 56a29d08a3..95b2cd67ed 100644
--- a/lily/note-column.cc
+++ b/lily/note-column.cc
@@ -37,7 +37,6 @@ Note_column::shift_compare (Grob *const &p1, Grob *const&p2)
 void
 Note_column::set_interface (Grob* me)
 {
-  me->set_grob_property ("note-heads", SCM_EOL);  
   me->set_interface (ly_symbol2scm ("note-column-interface"));
   
   Axis_group_interface::set_interface (me);
@@ -140,3 +139,21 @@ Note_column::has_interface (Grob*me)
 {
   return me && me->has_interface (ly_symbol2scm ("note-column-interface"));
 }
+
+/*
+  Return the first Accidentals grob that we find in a note-head. 
+ */
+Grob* 
+Note_column::accidentals (Grob *me)
+{
+  SCM heads = me->get_grob_property ("note-heads");
+  for (;gh_pair_p (heads); heads =gh_cdr (heads))
+    {
+      Grob * h = unsmob_grob (gh_car (heads));
+      Grob *a = h ? unsmob_grob(h->get_grob_property ("accidentals")) : 0;
+      if (a)
+	return a;
+    }
+
+  return 0;
+}
diff --git a/lily/note-heads-engraver.cc b/lily/note-heads-engraver.cc
index 2a9b5e49e4..96938212e4 100644
--- a/lily/note-heads-engraver.cc
+++ b/lily/note-heads-engraver.cc
@@ -24,7 +24,7 @@ class Note_heads_engraver : public Engraver
   
   Link_array<Item> dot_p_arr_;
   Link_array<Note_req> note_req_l_arr_;
-  Moment note_end_mom_;
+
 public:
   TRANSLATOR_DECLARATIONS(Note_heads_engraver);
 
@@ -47,14 +47,13 @@ Note_heads_engraver::try_music (Music *m)
   if (Note_req * n =dynamic_cast <Note_req *> (m))
     {
       note_req_l_arr_.push (n);
-      note_end_mom_  = note_end_mom_ >? now_mom () + m->length_mom ();
-      
       return true;
     }
   else if (dynamic_cast<Busy_playing_req*> (m))
     {
-      return now_mom () < note_end_mom_;
+      return note_req_l_arr_.size ();
     }
+  
   return false;
 }
 
diff --git a/lily/note-spacing-engraver.cc b/lily/note-spacing-engraver.cc
new file mode 100644
index 0000000000..47b11ae5ac
--- /dev/null
+++ b/lily/note-spacing-engraver.cc
@@ -0,0 +1,99 @@
+#if 0
+/*   
+  note-spacing-engraver.cc --  implement  Note_spacing_engraver.
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+
+*/
+
+#include "grob.hh"
+#include "moment.hh"
+#include "engraver.hh"
+#include "note-spacing.hh"
+#include "note-column.hh"
+
+/*
+  Originally, we tried to have this functionality at Staff_level
+  
+  - by simply using the sequence of Separation-item as
+  spacing-sequences. Unfortunately, this fucks up if there are
+  different kinds of tuplets combined (8th and 8ths triplets combined
+  made the program believe there were 1/12 th notes.).
+
+
+  - We also created them from Rhythmic_column_engraver, but this has
+  the problem that voices can appear and disappear at will, leaving
+  lots of loose ends (the StaffSpacing don't know where to connect the
+  last note of the voice on the right with)
+  
+ */
+
+struct Grob_moment_tuple
+{
+  Link_array<Grob> current_heads_;
+  Link_array<Grob> todo_heads_;
+  
+  Moment length_;
+  
+  static int time_compare (Grob_moment_tuple const &a, Grob_moment_tuple const &b)
+  {
+    return Moment::compare (a.length_, b.length_);
+  }
+};
+
+class Note_spacing_engraver : public Engraver
+{
+public:
+  TRANSLATOR_DECLARATIONS(Note_spacing_engraver);
+
+
+protected:
+  Array<Grob_moment_tuple> lengths_found_;
+
+  virtual void acknowledge_grob (Grob_info);
+};
+
+Note_spacing_engraver::Note_spacing_engraver()
+{
+}
+
+
+void
+Note_spacing_engraver::acknowledge_grob (Grob_info gi)
+{
+  if (Note_head::has_interface (gi.grob_l_))
+    {
+      Music *m = gi.music_cause();
+      Moment now = now_mom ();
+      Moment len = m->length_mom(); 
+      if (now.grace_part_ && len.main_part_)
+	{
+	  len.grace_part_ += len.main_part_;
+	  len.main_part_ = 0;
+	}
+      
+      for (int  i=0; i <  
+    }
+  Note_column::has_interface (gi.grob_l_))
+    {
+      Grob *head  =Note_column::first_head (gi.grob_l_);
+
+      head->
+    }
+}
+
+
+
+ENTER_DESCRIPTION(Note_spacing_engraver,
+/* descr */       "This engraver creates spacing objects. It should be placed at staff
+level, but will also function at voice level.
+
+",
+/* creats*/       "NoteSpacing",
+/* acks  */       "rhythmic-column-interface",
+/* reads */       "",
+/* write */       "");
+
+#endif
diff --git a/lily/note-spacing.cc b/lily/note-spacing.cc
index 81eb2aa03b..0628ffab82 100644
--- a/lily/note-spacing.cc
+++ b/lily/note-spacing.cc
@@ -1,17 +1,88 @@
 /*   
-note-spacing.cc --  implement 
+  note-spacing.cc -- implement Note_spacing
 
-source file of the GNU LilyPond music typesetter
+  source file of the GNU LilyPond music typesetter
 
-(c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+*/
 
- */
 
+#include "paper-column.hh"
+#include "item.hh"
+#include "moment.hh"
 #include "note-spacing.hh"
 #include "grob.hh"
+#include "note-column.hh"
+#include "warn.hh"
 
 bool
 Note_spacing::has_interface (Grob* g)
 {
   return g && g->has_interface (ly_symbol2scm ("note-spacing-interface"));
 }
+
+
+
+Real
+Note_spacing::get_spacing (Grob *me)
+{
+  Drul_array<SCM> props(me->get_grob_property ("left-items"),
+			me->get_grob_property ("right-items"));
+  Direction d = LEFT;
+  Drul_array<Interval> extents;
+  do
+    {
+      for (SCM  s = props[d]; gh_pair_p (s); s = gh_cdr (s))
+	{
+	  Item * it= dynamic_cast<Item*> (unsmob_grob (gh_car(s)));
+	  extents[d].unite (it->extent (it->column_l (), X_AXIS));
+
+	  if (d == RIGHT)
+	    {
+	      Grob * accs = Note_column::accidentals (it);
+	      if (accs)
+		extents[d].unite (accs->extent (it->column_l (), X_AXIS));
+	    }
+	}
+
+      if (extents[d].empty_b ())
+	extents[d] = Interval (0,0);
+    }
+  while (flip (&d) != LEFT);
+
+  /*
+    
+    What's sticking out at the left of the right side has less
+    influence.
+
+  */
+  Real dx= extents[LEFT][RIGHT] - 0.5 * extents[RIGHT][LEFT];
+  return dx;
+}
+
+
+MAKE_SCHEME_CALLBACK(Note_spacing, before_line_breaking, 1)
+SCM
+Note_spacing::before_line_breaking (SCM g)
+{
+  Grob * me = unsmob_grob (g);
+  SCM right = me->get_grob_property ("right-items");
+
+  if (gh_pair_p (right))
+    right = gh_car (right);
+  
+  Grob *right_grob = unsmob_grob (right);
+
+  Item * ri = dynamic_cast<Item*> (right_grob);
+  if (!ri)
+    {
+      int r = Paper_column::rank_i (dynamic_cast<Item*>(me)->column_l ());
+      programming_error (_f("Spacing wish column %d has no right item.", r));
+    }
+  else
+    {
+      me->set_grob_property ("right-column", ri->column_l ()->self_scm());
+    }
+  
+  return SCM_UNSPECIFIED;
+}
diff --git a/lily/paper-column.cc b/lily/paper-column.cc
index 14774ed651..789a9cfa73 100644
--- a/lily/paper-column.cc
+++ b/lily/paper-column.cc
@@ -5,12 +5,32 @@
 
   (c)  1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
 */
+
 #include "moment.hh"
 #include "paper-column.hh"
 #include "paper-score.hh"
 #include "debug.hh"
 #include "axis-group-interface.hh"
 #include "spaceable-grob.hh"
+#include "molecule.hh"
+#include "text-item.hh"
+#include "lookup.hh"
+#include "font-interface.hh"
+
+
+/*
+  Paper_columns form the top-most item parent. (The Paper_columns X
+  parent is Line_of_score, which is a spanner.)
+
+  Paper_columns form the units for the spacing engine. They are
+  numbered, the first (leftmost) is column 0. Numbering happens before
+  line-breaking, and columns are not renumbered after line breaking.
+
+  Since many columns go unused, you should only use the rank field to
+  get ordering information.  Two adjacent columns may have
+  non-adjacent numbers.
+  
+ */
 
 void
 Paper_column::do_break_processing ()
@@ -73,6 +93,7 @@ Paper_column::musical_b (Grob *me)
   
 }
   
+
 bool
 Paper_column::used_b (Grob*me)
 {
@@ -80,3 +101,29 @@ Paper_column::used_b (Grob*me)
     || gh_pair_p (me->get_grob_property ("bounded-by-me"))
     ;
 }
+
+/*
+  Print a vertical line and  the rank number, to aid debugging.  
+ */
+
+MAKE_SCHEME_CALLBACK(Paper_column,brew_molecule,1);
+SCM
+Paper_column::brew_molecule (SCM p)
+{
+  Grob *me = unsmob_grob (p);
+
+  String r = to_str (Paper_column::rank_i (me));
+  SCM properties = Font_interface::font_alist_chain (me);
+  
+  Molecule t = Text_item::text2molecule (me, ly_str02scm (r.ch_C()),
+					 properties);
+  t.align_to (X_AXIS, CENTER);
+  t.align_to (Y_AXIS, DOWN);
+  
+  Molecule l = Lookup::filledbox (Box (Interval (-0.01, 0.01),
+				       Interval (-2, -1)));
+
+  t.add_molecule (l);
+  return t.smobbed_copy ();						
+}
+
diff --git a/lily/rhythmic-column-engraver.cc b/lily/rhythmic-column-engraver.cc
index c87409c450..84bd2ae16c 100644
--- a/lily/rhythmic-column-engraver.cc
+++ b/lily/rhythmic-column-engraver.cc
@@ -58,15 +58,6 @@ Rhythmic_column_engraver::create_grobs ()
 	  note_column_ = new Item (get_property ("NoteColumn"));
 	  Note_column::set_interface (note_column_);
 	  announce_grob (note_column_, 0);
-
-	  spacing_ = new Item (get_property ("NoteSpacing"));
-	  spacing_->set_grob_property ("left-item", note_column_->self_scm ());
-	  announce_grob (spacing_, 0);
-
-	  if (last_spacing_)
-	    {
-	      last_spacing_->set_grob_property ("right-item" , note_column_->self_scm ());
-	    }
 	}
 
       for (int i=0; i < rhead_l_arr_.size (); i++)
diff --git a/lily/separating-line-group-engraver.cc b/lily/separating-line-group-engraver.cc
index fc8679494f..57100c952e 100644
--- a/lily/separating-line-group-engraver.cc
+++ b/lily/separating-line-group-engraver.cc
@@ -15,6 +15,27 @@
 #include "axis-group-interface.hh"
 #include "note-spacing.hh"
 
+
+struct Spacings
+{
+  Item * staff_spacing_;
+  Link_array<Item> note_spacings_;
+
+  Spacings ()
+  {
+    staff_spacing_ = 0;
+  }
+
+  bool empty( )const
+  {
+    return !staff_spacing_ && !note_spacings_.size (); 
+  }
+  void clear () {
+    staff_spacing_ = 0;
+    note_spacings_.clear();
+  }
+};
+
 class Separating_line_group_engraver : public Engraver
 {
 protected:
@@ -22,9 +43,8 @@ protected:
   Item * musical_malt_p_;
   Item * last_musical_malt_p_;
 
-  Item * last_note_spacing_;
-  Item * current_note_spacing_;
-  Item * staff_spacing_;
+  Spacings current_spacings_;
+  Spacings last_spacings_;
   
   Spanner * sep_span_p_;
   
@@ -32,16 +52,13 @@ protected:
   virtual void initialize ();
   virtual void finalize ();
   virtual void stop_translation_timestep ();
+  virtual void start_translation_timestep ();  
 public:
   TRANSLATOR_DECLARATIONS(Separating_line_group_engraver);
 };
 
 Separating_line_group_engraver::Separating_line_group_engraver ()
 {
-  last_note_spacing_ = 0;
-  current_note_spacing_ = 0;
-  staff_spacing_ =0;
-  
   sep_span_p_ = 0;
   break_malt_p_ = 0;
   musical_malt_p_ =0;
@@ -59,9 +76,21 @@ Separating_line_group_engraver::initialize ()
 void
 Separating_line_group_engraver::finalize ()
 {
-  sep_span_p_->set_bound (RIGHT, unsmob_grob (get_property ("currentCommandColumn")));
+  SCM ccol = get_property ("currentCommandColumn");
+  sep_span_p_->set_bound (RIGHT, unsmob_grob (ccol));
   typeset_grob (sep_span_p_);
   sep_span_p_ =0;
+
+  for  (int i= 0 ; i < last_spacings_.note_spacings_.size(); i++)
+    {
+      last_spacings_.note_spacings_[i]->set_grob_property ("right-items", gh_cons (ccol, SCM_EOL));
+    }
+
+  if(last_spacings_.staff_spacing_
+     && last_spacings_.staff_spacing_->column_l () == unsmob_grob (ccol))
+    {
+      last_spacings_.staff_spacing_->suicide ();
+    }
 }
 
 void
@@ -77,7 +106,7 @@ Separating_line_group_engraver::acknowledge_grob (Grob_info i)
 
   if (Note_spacing::has_interface (it)) 
     {
-      current_note_spacing_ =  it;
+      current_spacings_.note_spacings_.push (it);
       return ;
     }
   
@@ -95,19 +124,38 @@ Separating_line_group_engraver::acknowledge_grob (Grob_info i)
 
       if (p_ref_ == break_malt_p_)
 	{
-	  staff_spacing_ = new Item (get_property ("StaffSpacing"));
-	  staff_spacing_->set_grob_property ("left-item", break_malt_p_->self_scm ());
-	  announce_grob (staff_spacing_, 0);
-
-	  if (last_note_spacing_)
-	    last_note_spacing_->set_grob_property ("right-item",
-						   break_malt_p_->self_scm ());
+	  Item *it  = new Item (get_property ("StaffSpacing"));
+	  current_spacings_.staff_spacing_ = it;
+	  it->set_grob_property ("left-items", gh_cons (break_malt_p_->self_scm (), SCM_EOL));
+	  
+	  announce_grob (it, 0);
+
+	  if (int i = last_spacings_.note_spacings_.size ())
+	    {
+	      SCM break_malt = gh_cons (break_malt_p_->self_scm (), SCM_EOL);
+	      for (; i--;)
+		last_spacings_.note_spacings_[i]
+		  ->set_grob_property ("right-items",break_malt);
+				     
+	    }
+	  else if (last_spacings_.staff_spacing_)
+	    {
+	      
+	      last_spacings_.staff_spacing_->set_grob_property ("right-items",
+								gh_cons (break_malt_p_->self_scm(), SCM_EOL));
+	    }
 	}
     }
 
   Separation_item::add_item (p_ref_,it);
 }
 
+void
+Separating_line_group_engraver::start_translation_timestep ()
+{
+
+}
+
 void
 Separating_line_group_engraver::stop_translation_timestep ()
 {
@@ -119,23 +167,30 @@ Separating_line_group_engraver::stop_translation_timestep ()
       break_malt_p_ =0;
     }
 
-  if (staff_spacing_)
+  if (Item * sp = current_spacings_.staff_spacing_)
     {
+      /*
+	TODO: should really look at the left-items of following
+	note-spacing grobs.
+       */
       if (musical_malt_p_)
-	staff_spacing_->set_grob_property ("right-item", musical_malt_p_->self_scm());
+	sp->set_grob_property ("right-items", musical_malt_p_->self_scm());
+
+      typeset_grob (sp);
+    }
 
-      typeset_grob (staff_spacing_);
-      staff_spacing_ = 0;
+  if (!current_spacings_.empty ())
+    {
+      last_spacings_ = current_spacings_;
     }
+
+  current_spacings_.clear ();
   
   if (musical_malt_p_)
     {
       Separating_group_spanner::add_spacing_unit (sep_span_p_, musical_malt_p_);
       typeset_grob (musical_malt_p_);
     }
-
-  last_note_spacing_ = current_note_spacing_ ;
-  current_note_spacing_ =0 ;
   
   musical_malt_p_ =0;
 }
diff --git a/lily/spacing-wish.cc b/lily/spacing-wish.cc
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/lily/spacing-wish.cc
@@ -0,0 +1 @@
+
diff --git a/lily/staff-spacing.cc b/lily/staff-spacing.cc
index 771760ca52..a662f54133 100644
--- a/lily/staff-spacing.cc
+++ b/lily/staff-spacing.cc
@@ -15,3 +15,4 @@ Staff_spacing::has_interface (Grob* g)
 {
   return g && g->has_interface (ly_symbol2scm ("staff-spacing-interface"));
 }
+
diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc
index 5ab49f9227..aba73c027f 100644
--- a/lily/stem-engraver.cc
+++ b/lily/stem-engraver.cc
@@ -105,6 +105,10 @@ Stem_engraver::acknowledge_grob (Grob_info i)
 						gh_int2scm (tremolo_flags));
 		}
 	    }
+
+	  /*
+	    We announce the cause of the head as cause of the stem.
+	    The stem needs a rhythmic structure to fit it into a beam.  */
 	  announce_grob (stem_p_, i.music_cause ());
 	}
 
diff --git a/lily/text-item.cc b/lily/text-item.cc
index e4320a3daf..1f83982d06 100644
--- a/lily/text-item.cc
+++ b/lily/text-item.cc
@@ -122,9 +122,18 @@ Text_item::lookup_text (Grob *me, Font_metric*fm, SCM text)
   return Molecule (fm->text_dimension (ly_scm2string (text)), list);
 }
 
+/*
+  TODO:
+
+  DOCME.
+
+
+  MARKUP_TEXT must be compound (may not be simple string.)
+  
+ */
 Molecule
 Text_item::markup_text2molecule (Grob *me, SCM markup_text,
-			       SCM alist_chain)
+				 SCM alist_chain)
 {
   SCM sheet = me->paper_l ()->style_sheet_;
   SCM f = ly_cdr (scm_assoc (ly_symbol2scm ("markup-to-properties"), sheet));
diff --git a/lily/third-try.cc b/lily/third-try.cc
index b66e5f6129..bfc1a34ac8 100644
--- a/lily/third-try.cc
+++ b/lily/third-try.cc
@@ -6,103 +6,545 @@
   (c) 1999--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
   
  */
+#include "line-of-score.hh"
+#include "paper-score.hh"
+#include "paper-column.hh"
+#include "item.hh"
+#include "moment.hh"
+#include "note-spacing.hh"
+#include "misc.hh"
+#include "warn.hh"
 
+/*
+  paper-column:
 
-#include "paper-column.hh"
+    right-neighbors = List of spacing-wish grobs that are close to the
+    current column.
+  
+ */
 
 
 class Third_spacing_spanner
 {
 public:
-  void find_loose_columns () {}
-  void prune_loose_colunms (Link_array<Grob> *cols);
-  void find_loose_columns (Link_array<Grob> cols);
+  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   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);
+  DECLARE_SCHEME_CALLBACK (set_springs, (SCM ));
 };
 
 
 
+/*
+  Return whether COL is fixed to its neighbors by some kind of spacing
+  constraint.
+*/
 static bool
-fixed_neighbor (Grob *col, SCM nm)
+loose_column (Grob *l, Grob *c, Grob *r) 
 {
-  SCM l = col->internal_get_grob_property (nm);
+  SCM rns = c->get_grob_property ("right-neighbors");
+  SCM lns = c->get_grob_property ("left-neighbors");
+
+ /*
+    If this column doesn't have a proper neighbor, we should really
+    make it loose, but spacing it correctly is more than we can
+    currently can handle.
+
+    (this happens in the following situation:
+
+       |
+       |    clef G 
+      *
+
+       |               |      ||
+       |               |      || 
+      O               O       ||
+
+
+    the column containing the clef is really loose, and should be
+    attached right to the first column, but that is a lot of work for
+    such a border line case.
 
-  if (!gh_pair_p (l))
+    )
+    
+  */  
+  if (!gh_pair_p (lns) || !gh_pair_p (rns))
     return false;
 
-  Item * left = dynamic_cast<Item*>  (unsmob_grob (gh_car (l)));
-  return abs (Paper_column::rank_i (left->column_l ()) - Paper_column::rank_i (col)) == 1 ;
+  Item * l_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (lns)));
+  Item * r_neighbor = dynamic_cast<Item*>  (unsmob_grob (gh_car (rns)));
+
+  if (!l_neighbor || !r_neighbor)
+    return false;
+
+  l_neighbor = l_neighbor->column_l();
+  r_neighbor = r_neighbor->column_l();
+
+  if (l == l_neighbor && r == r_neighbor)
+    return false;
+
+
+  /*
+    Only declare loose if the bounds make a little sense.  This means
+    some cases (two isolated, consecutive clef changes) won't be
+    nicely folded, but hey, then don't do that.
+  */
+  if( (Paper_column::musical_b (l_neighbor) || Item::breakable_b (l_neighbor))
+      && (Paper_column::musical_b (r_neighbor) || Item::breakable_b (r_neighbor)))
+    {
+      return true;
+    }
+
+
+  /*
+    If in doubt: we're not loose; the spacing engine should space for
+    it, risking suboptimal spacing.
+
+    (Otherwise, we might risk core dumps, and other weird stuff.)
+
+
+  */
+  return false;
 }
 
+/*
+  Remove columns that are not tightly fitting from COLS. In the
+  removed columns, set 'between-cols to the columns where it is in
+  between.
+*/
 void
 Third_spacing_spanner::prune_loose_colunms (Link_array<Grob> *cols)
 {
-   for (int i=cols->size ();  i--; )
-     {
-
-       if (Item::breakable_b (cols->elem(i)))
-	 continue;
-       
-       if (!fixed_neighbor (cols->elem(i), ly_symbol2scm ("left-neighbors"))
-	   || !fixed_neighbor (cols->elem(i), ly_symbol2scm ("right-neighbors")))
-	 cols->del (i);
-     }
+  Link_array<Grob> newcols;
+  
+  for (int i=0; i < cols->size ();  i++)
+    {
+      if (Item::breakable_b (cols->elem(i)) || Paper_column::musical_b (cols->elem (i)))
+	{
+	  newcols.push (cols->elem(i));
+	  continue;
+	}
+
+      Grob *c = cols->elem(i);
+      if (loose_column (cols->elem (i-1), c, cols->elem (i+1)))
+	{
+	  SCM lns = c->get_grob_property ("left-neighbors");
+	  lns = gh_pair_p (lns) ? gh_car (lns) : SCM_BOOL_F;
+
+	  SCM rns = c->get_grob_property ("right-neighbors");
+	  rns = gh_pair_p (rns) ? gh_car (rns) : SCM_BOOL_F;
+
+	  /*
+	    Either object can be non existent, if the score ends
+	    prematurely.
+	   */
+	  rns = gh_car (unsmob_grob (rns)->get_grob_property ("right-items"));
+	  c->set_grob_property ("between-cols", gh_cons (lns,
+							 rns));
+	}
+      else
+	{
+	  newcols.push (c);
+	}
+    }
+
+  *cols = newcols;
 }
 
+/*
+  Set neighboring columns determined by the spacing-wishes grob property.  
+*/
 void
-Third_spacing_spanner::find_loose_columns (Link_array<Grob> cols)
+Third_spacing_spanner::set_explicit_neighbor_columns (Link_array<Grob> cols)
 {
-  for (int i=0; i< cols.size(); i++)
+  for (int i=0; i < cols.size(); i++)
     {
       SCM right_neighbors = SCM_EOL;
       int min_rank = 100000;	// inf.
-      
-      for (SCM s = cols[i]-> get_grob_property ("spacing-wishes");
-	   gh_pair_p (s); s = gh_cdr (s))
-	{
-	  Grob * wish = unsmob_grob (gh_car (s));
 
-	  Grob * left = unsmob_grob (wish->get_grob_property ("left-item"));
-	  Grob * right = unsmob_grob (wish->get_grob_property ("right-item"));
 
-	  Item * li = dynamic_cast<Item*> (left);
-	  Item * ri = dynamic_cast<Item*> (right);	  
 
-	  assert (li->column_l () == cols[i]);
+      SCM wishes=  cols[i]-> get_grob_property ("spacing-wishes");
+      for (SCM s =wishes; gh_pair_p (s); s = gh_cdr (s))
+	{
+	  Item * wish = dynamic_cast<Item*> (unsmob_grob (gh_car (s)));
+
+	  Item * lc = wish->column_l ();
+	  Grob * right = unsmob_grob (wish->get_grob_property ("right-column"));
+
+	  if (!right)
+	    continue;
 
-	  Item * rc = ri->column_l ();
-	  Item * lc = li->column_l ();
-	  int newrank = Paper_column::rank_i (lc);
+	  Item * rc = dynamic_cast<Item*> (right);
 
-	  SCM neighbors = rc->get_grob_property ("left-neighbors");
-	  Item  * left_neighbor = gh_pair_p (neighbors)
-	    ? dynamic_cast<Item*> (unsmob_grob (gh_car (neighbors))) : 0;
+	  int right_rank = Paper_column::rank_i (rc);
+	  int left_rank = Paper_column::rank_i (lc);	  
 
-	  left_neighbor = left_neighbor->column_l ();
-	  if (left_neighbor)
+	  /*
+	    update the left column.
+	   */
+	  if (right_rank <= min_rank)
 	    {
-	      int oldrank = Paper_column::rank_i (left_neighbor->column_l ());
+	      if (right_rank < min_rank)
+		right_neighbors  =SCM_EOL;
+	      
+	      min_rank = right_rank;
+	      right_neighbors = gh_cons (wish->self_scm (), right_neighbors);
+	    }
 
-	      if (newrank > oldrank)
-		{
-		  neighbors= gh_cons (wish->self_scm (), SCM_EOL);
-		}
-	      else if (newrank == oldrank)
-		{
-		  neighbors = gh_cons (wish->self_scm (), neighbors); 
-		}
+	  /*
+	    update the right column of the wish.
+	   */
+	  int maxrank = 0;
+	  SCM left_neighs = rc->get_grob_property ("left-neighbors");
+	  if (gh_pair_p (left_neighs)
+	      && unsmob_grob (gh_car (left_neighs)))
+	    {
+	      Item * it = dynamic_cast<Item*> (unsmob_grob (gh_car (left_neighs)));
+	      maxrank = Paper_column::rank_i (it->column_l());
 	    }
 
-	  if (newrank < min_rank)
+	  if (left_rank >= maxrank)
 	    {
-	      right_neighbors = gh_cons (wish->self_scm(), SCM_EOL);
-	      min_rank = newrank;
+	      if (left_rank > maxrank)
+		left_neighs = SCM_EOL;
+
+	      left_neighs = gh_cons (wish->self_scm (), left_neighs);
+	      rc->set_grob_property ("left-neighbors", right_neighbors);
 	    }
-	  else if (newrank == min_rank)
+	}
+
+      if (gh_pair_p (right_neighbors))
+	{
+	  cols[i]->set_grob_property ("right-neighbors", right_neighbors);
+	}
+    }
+}
+
+/*
+  Set neighboring columns that have no left/right-neighbor set
+  yet. Only do breakable non-musical columns, and musical columns. 
+*/
+void
+Third_spacing_spanner::set_implicit_neighbor_columns (Link_array<Grob> cols)
+{
+  for (int i = 0; i < cols.size (); i++)
+    {
+      Item * it = dynamic_cast<Item*>(cols[i]);
+      if (!Item::breakable_b (it) && !Paper_column::musical_b (it))
+	continue;
+
+      // it->breakable || it->musical
+      SCM ln = cols[i] ->get_grob_property ("left-neighbors");
+      if (!gh_pair_p (ln) && i ) 
+	{
+	  cols[i]->set_grob_property ("left-neighbors", cols[i-1]->self_scm());
+	}
+
+      SCM rn = cols[i] ->get_grob_property ("right-neighbors");
+      if (!gh_pair_p (rn) && i < cols.size () - 1) 
+	{
+	  cols[i]->set_grob_property ("right-neighbors", cols[i + 1]->self_scm());
+	}
+    }
+}
+
+
+MAKE_SCHEME_CALLBACK (Third_spacing_spanner, set_springs,1);
+SCM
+Third_spacing_spanner::set_springs (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+
+  Link_array<Grob> all (me->pscore_l_->line_l_->column_l_arr ()) ;
+
+  set_explicit_neighbor_columns (all);
+  prune_loose_colunms (&all);
+  set_implicit_neighbor_columns (all);
+  
+  int j = 0;
+  for (int i = 1; i < all.size (); i++)
+    {
+      Grob *sc = all[i];
+      if (Item::breakable_b (sc))
+        {
+	  Link_array<Grob> measure (all.slice (j, i+1));	  
+          do_measure (me, &measure);
+	  j = i;
+        }
+    }
+
+  return SCM_UNSPECIFIED;
+}
+
+
+void
+Third_spacing_spanner::do_measure (Grob*me, Link_array<Grob> *cols) 
+{
+  Moment shortest_in_measure;
+
+  /*
+    space as if this duration  is present. 
+  */
+  Moment base_shortest_duration = *unsmob_moment (me->get_grob_property ("maximum-duration-for-spacing"));
+  shortest_in_measure.set_infinite (1);
+
+  for (int i =0 ; i < cols->size (); i++)  
+    {
+      if (Paper_column::musical_b (cols->elem (i)))
+	{
+	  Moment *when = unsmob_moment (cols->elem (i)->get_grob_property  ("when"));
+
+	  /*
+	    ignore grace notes for shortest notes.
+	  */
+	  if (when && when->grace_part_)
+	    continue;
+	  
+	  SCM  st = cols->elem (i)->get_grob_property ("shortest-starter-duration");
+	  Moment this_shortest = *unsmob_moment (st);
+	  shortest_in_measure = shortest_in_measure <? this_shortest;
+	}
+    }
+  
+  Array<Spring> springs;
+
+  for (int i= 0; i < cols->size () - 1; i++)
+    {
+      Item * l = dynamic_cast<Item*> (cols->elem (i));
+      Item * r =  dynamic_cast<Item*> (cols->elem (i+1));
+
+      Paper_column * lc = dynamic_cast<Paper_column*> (l);
+      Paper_column * rc = dynamic_cast<Paper_column*> (r);
+
+      if (!Paper_column::musical_b (l))
+	{
+	  breakable_column_spacing (l, r);
+
+	  /*
+	    
+	    The case that the right part is broken as well is rather
+	    rare, but it is possible, eg. with a single empty measure,
+	    or if one staff finishes a tad earlier than the rest.
+	    
+	   */
+	  Item *lb = l->find_prebroken_piece (RIGHT);
+	  Item *rb = r->find_prebroken_piece (LEFT);
+	  
+	  if (lb)
+	    breakable_column_spacing (lb,r);
+
+	  if (rb)
+	    breakable_column_spacing (l, rb);
+	  if (lb && rb)
+	    breakable_column_spacing (lb, rb);
+	  
+	  continue ; 
+	}
+      
+      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");
+
+      Moment dt = Paper_column::when_mom (r) - Paper_column::when_mom (l);
+      
+      /*
+	hinterfleisch = hind-meat = amount of space following a note.
+
+	
+	We adjust the space following a note only if the next note
+	happens after the current note (this is set in the grob
+	property SPACING-SEQUENCE.  */
+
+      Real stretch_distance = note_space;
+      if (shortest_in_measure <= dt)
+	{
+	  /*
+	    currently SPACING-SEQUENCE is set in
+	    Separating_group_spanner::find_musical_sequences (), which
+	    works neatly for one-voice-per staff, however,
+
+	    it can't find out the actual duration of the notes on a
+	    staff, so when putting tuplets and normal patterns it gets
+	    confused, (ie. believes that < { c8 c8 } { d8 d8 d8 }*2/3
+	    > contains 1/12 notes. ).
+
+	    here we kludge, by checking if the distance we're spacing
+	    for is less than the shortest note.
+
+	    TODO:
+
+	    Move SPACING-SEQUENCE detection into a voice
+	    level-engraver --or-- make sure that every column has
+	    access to the note head.
+
+	  */
+	  for (SCM s = seq; gh_pair_p (s); s = ly_cdr (s))
 	    {
-	      right_neighbors = gh_cons (wish->self_scm (), right_neighbors); 
+	      Grob * wish = unsmob_grob (gh_car (s));
+
+	      // TODO; configgable.
+	      if (Note_spacing::has_interface (wish))
+		{
+		  hinterfleisch += -headwid + Note_spacing::get_spacing (wish);
+		}
+
+	      // should move into Note_spacing
+	      // hinterfleisch += stem_dir_correction (me, l, r);
 	    }
+
+	  // ? why.
+	  if (gh_pair_p (seq))
+	    stretch_distance -= headwid;
+	}      
+      Spring s;
+      s.distance_f_ = hinterfleisch;
+      s.strength_f_ = 1 / stretch_distance;
+
+      s.item_l_drul_[LEFT] = l;
+      s.item_l_drul_[RIGHT] = r;
+
+      s.add_to_cols();
+      if (r->find_prebroken_piece (LEFT))
+	{
+	  s.item_l_drul_[RIGHT] = r->find_prebroken_piece(LEFT);
+	  s.add_to_cols();
 	}
+    }
+
+}
+
+
+/*
+  Read hints from L (todo: R) and generate springs.
+ */
+void
+Third_spacing_spanner::breakable_column_spacing (Item* l, Item *r)
+{
+  Spring s;
 
-      cols[i]->set_grob_property ("right-neighbors", right_neighbors);
+  Real break_dist = 0.0;
+  SCM espace = l->get_grob_property ("extra-space");
+  if (gh_pair_p (espace))
+    break_dist += gh_scm2double (ly_cdr (espace));
+
+  if (!break_dist)
+    break_dist = 1.0;
+
+  Real break_stretch = 0.0;
+
+  // todo: naming of "distance"
+  espace = l->get_grob_property ("stretch-distance");
+  if (gh_pair_p (espace))
+    break_stretch += gh_scm2double (ly_cdr (espace));
+
+  if (!break_stretch)
+    break_stretch = 1.0;
+  
+  s.distance_f_ = break_dist;
+  s.strength_f_ = 1/break_stretch;
+  s.item_l_drul_[LEFT] = l;
+  s.item_l_drul_[RIGHT] = r;
+
+  s.add_to_cols ();
+}
+
+
+/**
+  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
+Third_spacing_spanner::get_duration_space (Grob*me, Moment d, Moment shortest) 
+{
+  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
+Third_spacing_spanner::note_spacing (Grob*me, Grob *lc, Grob *rc,
+				   Moment shortest) 
+{
+  Moment shortest_playing_len = 0;
+  SCM s = lc->get_grob_property ("shortest-playing-duration");
+
+
+  if (unsmob_moment (s))
+    shortest_playing_len = *unsmob_moment (s);
+  
+  if (! shortest_playing_len.to_bool ())
+    {
+      programming_error ("can't find a ruling note at " + Paper_column::when_mom (lc).str ());
+      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 *= (double) (delta_t.main_part_ / shortest_playing_len.main_part_);
+    }
+  else if (delta_t.grace_part_)
+    {
+      dist = get_duration_space (me, shortest, shortest);
+
+      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; 
+    }
+
+#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/tie-engraver.cc b/lily/tie-engraver.cc
index 227761a82d..b725b64a4b 100644
--- a/lily/tie-engraver.cc
+++ b/lily/tie-engraver.cc
@@ -8,39 +8,40 @@
  */
 
 #include "command-request.hh"
-#include "rhythmic-head.hh"
 #include "musical-request.hh"
 #include "tie.hh"
 #include "translator-group.hh"
 #include "spanner.hh"
 #include "tie-column.hh"
-#include "pqueue.hh"
 #include "engraver.hh"
 #include "item.hh"
 #include "grob-pitch-tuple.hh"
-
+#include "note-head.hh"
 
 /**
    Manufacture ties.  Acknowledge noteheads, and put them into a
    priority queue. If we have a Tie_req, connect the notes that finish
    just at this time, and note that start at this time.
 
-   TODO: junk the pq; the PQ is overkill if we assume that no
-   different durations occur in parallel.
-
    TODO: Remove the dependency on musical info. We should tie on the
    basis of position and duration-log of the heads (not of the reqs).
 
+
+   TODO: figure this out: currently, this engravers ties note heads
+   that have the same Y-position (and does not look at pitch). This
+   means that we will fuck up with a clef-change. How should
+   clef-changes during ties be handled, or should they not?
+
+   
 */
 class Tie_engraver : public Engraver
 {
-  PQueue<Grob_pitch_tuple> past_notes_pq_;
   Moment end_mom_;
   Moment next_end_mom_;
 
   Tie_req *req_l_;
-  Array<Grob_pitch_tuple> now_heads_;
-  Array<Grob_pitch_tuple> stopped_heads_;
+  Link_array<Grob> now_heads_;
+  Link_array<Grob> stopped_heads_;
   Link_array<Grob> tie_p_arr_;
 
   Spanner * tie_column_p_;
@@ -96,23 +97,26 @@ Tie_engraver::set_melisma (bool m)
 void
 Tie_engraver::acknowledge_grob (Grob_info i)
 {
-  if (Rhythmic_head::has_interface (i.grob_l_))
+  if (Note_head::has_interface (i.grob_l_))
     {
-      Note_req * m = dynamic_cast<Note_req* > (i.music_cause ());
-      if (!m)
-	return;
-      now_heads_.push (Grob_pitch_tuple (i.grob_l_, m, now_mom () + m->length_mom ()));
+      now_heads_.push (i.grob_l_);
     }
 }
 
+int
+head_position_compare (Grob  *const&a,Grob  *const&b)
+{
+  return sign (gh_scm2double (a->get_grob_property ("staff-position"))
+	       - gh_scm2double (b->get_grob_property ("staff-position")));
+}
 
 void
 Tie_engraver::create_grobs ()
 {
   if (req_l_)
     {
-      now_heads_.sort (Grob_pitch_tuple::pitch_compare);
-      stopped_heads_.sort (Grob_pitch_tuple::pitch_compare);
+      now_heads_.sort (&head_position_compare);
+      stopped_heads_.sort (&head_position_compare);
 
       SCM head_list = SCM_EOL;
       
@@ -122,21 +126,19 @@ Tie_engraver::create_grobs ()
       while (i >= 0 && j >=0)
 	{
 	  int comp
-	    = Pitch::compare (now_heads_[i].pitch_,
-			      stopped_heads_[j].pitch_);
+	    = head_position_compare (now_heads_[i], stopped_heads_[j]);
 
 	  if (comp)
 	    {
- (comp < 0) ? j -- : i--;
+	      (comp < 0) ? j -- : i--;
 	      continue;
 	    }
 	  else
 	    {
-	      head_list  = gh_cons (gh_cons (stopped_heads_[j].head_l_->self_scm (),
-					     now_heads_[i].head_l_->self_scm ()),
+	      head_list  = gh_cons (gh_cons (stopped_heads_[j]->self_scm (),
+					     now_heads_[i]->self_scm ()),
 				    head_list);
 
-	      past_notes_pq_. insert (now_heads_[i]);
 	      now_heads_.del (i);
 	      stopped_heads_.del (j);
 	      i--;
@@ -192,10 +194,7 @@ void
 Tie_engraver::stop_translation_timestep ()
 {
   req_l_ = 0;
-  for (int i=0; i < now_heads_.size (); i++)
-    {
-      past_notes_pq_.insert (now_heads_[i]);
-    }
+
   now_heads_.clear ();
 
   /*
@@ -244,16 +243,24 @@ Tie_engraver::start_translation_timestep ()
       set_melisma (false);
     }
 
-  Moment now = now_mom ();
-  while (past_notes_pq_.size () && past_notes_pq_.front ().end_ < now)
-    past_notes_pq_.delmin ();
-
-
+  SCM grobs = get_property ("busyGrobs");
+  Moment now = now_mom();
   stopped_heads_.clear ();
-  while (past_notes_pq_.size ()
-	 && past_notes_pq_.front ().end_ == now)
-    stopped_heads_.push (past_notes_pq_.get ());
-
+  
+  for (; gh_pair_p (grobs); grobs = gh_cdr (grobs))
+    {
+      Grob * grob  = unsmob_grob (gh_cdar (grobs));
+      Moment end  =*unsmob_moment (gh_caar (grobs));
+      
+      /*
+	This is slightly ugh: we are now confunding the frontend
+	(iterators) and the backend (note heads) */
+      if (end > now)
+	break;
+      else if (end == now
+	       && Note_head::has_interface (grob))
+	stopped_heads_.push (grob);
+    }
 }
 
 
diff --git a/lily/translator-group.cc b/lily/translator-group.cc
index aac575c38b..34e8d0c63e 100644
--- a/lily/translator-group.cc
+++ b/lily/translator-group.cc
@@ -247,7 +247,7 @@ static void
 static_each (SCM list, Method_pointer method)
 {
   for (SCM p = list; gh_pair_p (p); p = ly_cdr (p))
- (unsmob_translator (ly_car (p))->*method) ();
+    (unsmob_translator (ly_car (p))->*method) ();
   
 }
 
diff --git a/lilypond-mode.el b/lilypond-mode.el
index 57c60489d6..eefc34282e 100644
--- a/lilypond-mode.el
+++ b/lilypond-mode.el
@@ -85,6 +85,11 @@ in LilyPond-include-path."
   (and process
        (eq (process-status process) 'run))))
 
+(defun Midi-running ()
+  (let ((process (get-process "midi")))
+  (and process
+       (eq (process-status process) 'run))))
+
 (defun LilyPond-kill-job ()
   "Kill the currently running LilyPond job."
   (interactive)
@@ -281,6 +286,12 @@ Must be the car of an entry in `LilyPond-command-alist'."
   (LilyPond-command (LilyPond-command-query (LilyPond-master-file))
 		    'LilyPond-master-file))
 
+(defun LilyPond-command-lilypond ()
+  "Run lilypond for the current document."
+  (interactive)
+  (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file)
+)
+
 (defun LilyPond-command-formatdvi ()
   "Format the dvi output of the current document."
   (interactive)
@@ -339,20 +350,20 @@ Must be the car of an entry in `LilyPond-command-alist'."
 (defun LilyPond-command-next-midi ()
   "Play next midi score of the current document."
   (interactive)
-  (LilyPond-compile-file 
-   (let ((allscores (count-midi-words))
-	 (scores (count-midi-words-backwards))
-	 (fname (LilyPond-master-file)))
-     (let ((count (string-to-number (substring scores 0 (+ (length scores) -12)))))
+  (if (Midi-running)
+      (quit-process (get-process "midi") t)
+    (LilyPond-compile-file 
+     (let ((fname (LilyPond-master-file))
+	   (allcount (string-to-number (substring (count-midi-words) 0 -12)))
+	   (count (string-to-number (substring (count-midi-words-backwards) 0 -12))))
        (concat  LilyPond-midi-command " "
-		(substring fname 0 (+ (length fname) -3)) ; suppose ".ly"
-		(if (not (string= "1 occurrences" allscores)) ; only one score
-		    (if (not (eq count 0))                    ; first score
-			(if (string= scores allscores)        ; last score
-			    (concat "-" (number-to-string (+ count -1)))
-			  (concat "-" (number-to-string count)))))
-		".midi")))
-   "Midi"))
+		(substring fname 0 -3) ; suppose ".ly"
+		(if (and (> allcount 1) (> count 0)) ; not first score
+		    (if (eq count allcount)          ; last score
+			(concat "-" (number-to-string (+ count -1)))
+		      (concat "-" (number-to-string count))))
+		".midi"))
+     "Midi")))
 
 ;; FIXME, this is broken
 (defun LilyPond-region-file (begin end)
@@ -459,6 +470,7 @@ command."
 (if LilyPond-mode-map
     ()
   (setq LilyPond-mode-map (make-sparse-keymap))
+  (define-key LilyPond-mode-map "\C-c\C-l" 'LilyPond-command-lilypond)
   (define-key LilyPond-mode-map "\C-c\C-r" 'LilyPond-command-region)
   (define-key LilyPond-mode-map "\C-c\C-b" 'LilyPond-command-buffer)
   (define-key LilyPond-mode-map "\C-c\C-k" 'LilyPond-kill-job)
@@ -540,7 +552,7 @@ command."
 ;	  (let ((file 'LilyPond-command-on-current))
 ;	    (mapcar 'LilyPond-command-menu-entry LilyPond-command-alist))
 ;;; Some kind of mapping which includes :keys might be more elegant
-	  '([ "LilyPond" (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file) ])
+	  '([ "LilyPond" (LilyPond-command (LilyPond-command-menu "LilyPond") 'LilyPond-master-file) :keys "C-c C-l"])
 	  '([ "TeX" (LilyPond-command (LilyPond-command-menu "TeX") 'LilyPond-master-file) ])
 	  '([ "2Dvi" (LilyPond-command (LilyPond-command-menu "2Dvi") 'LilyPond-master-file) :keys "C-c C-d"])
 	  '([ "2PS" (LilyPond-command (LilyPond-command-menu "2PS") 'LilyPond-master-file) :keys "C-c C-f"])
@@ -549,7 +561,7 @@ command."
 	  '([ "SmartView" (LilyPond-command (LilyPond-command-menu "SmartView") 'LilyPond-master-file) :keys "C-c C-s"])
 	  '([ "View" (LilyPond-command (LilyPond-command-menu "View") 'LilyPond-master-file) :keys "C-c C-v"])
 	  '([ "ViewPS" (LilyPond-command (LilyPond-command-menu "ViewPS") 'LilyPond-master-file) :keys "C-c C-p"])
-	  '([ "Midi" (LilyPond-command-next-midi) :keys "C-c C-m"])
+	  '([ "Midi (off)" (LilyPond-command-next-midi) :keys "C-c C-m"])
 	  ))
 
 (defconst LilyPond-imenu-generic-re "^\\([a-zA-Z_][a-zA-Z0-9_]*\\) *="
diff --git a/ly/drumpitch-init.ly b/ly/drumpitch-init.ly
index 211246f081..c70b18e0fe 100644
--- a/ly/drumpitch-init.ly
+++ b/ly/drumpitch-init.ly
@@ -116,7 +116,7 @@
 #(define timbales `(
 	(losidestick	  cross		,#f	  ,(make-pitch -1 6 0))
 	(lotimbale	  default	,#f	  ,(make-pitch -1 6 0))
-	(cowbell	  triangle	,#f	  ,(make-pitch 0 0 0))
+	(cowbell	  triangle	,#f	  ,(make-pitch 0 2 0))
 	(hisidestick	  cross		,#f	  ,(make-pitch 0 1 0))
 	(hitimbale	  default	,#f	  ,(make-pitch 0 1 0))
  ))
@@ -137,20 +137,23 @@
 	(hibongo	  default	,#f	  ,(make-pitch 0 1 0))
  ))
 
-#(define guiro `(
-	(shortguiro	  default	"staccato",(make-pitch 0 0 0))
-	(longguiro	  default	"tenuto"  ,(make-pitch 0 0 0))
-	(guiro		  default	,#f	  ,(make-pitch 0 0 0))
- ))
 
-#(define triangle `(
+#(define percussion `(
 	(opentriangle	  cross		"open"	  ,(make-pitch 0 0 0))
 	(mutetriangle	  cross		"stopped" ,(make-pitch 0 0 0))
 	(triangle	  cross		,#f	  ,(make-pitch 0 0 0))
+	(shortguiro	  default	"staccato",(make-pitch 0 0 0))
+	(longguiro	  default	"tenuto"  ,(make-pitch 0 0 0))
+	(guiro		  default	,#f	  ,(make-pitch 0 0 0))
+	(cowbell	  triangle	,#f	  ,(make-pitch 0 0 0))
+	(claves		  default	,#f	  ,(make-pitch 0 0 0))
+	(tambourine	  default	,#f	  ,(make-pitch 0 0 0))
+	(cabasa		  cross		,#f	  ,(make-pitch 0 0 0))
+	(maracas	  default	,#f	  ,(make-pitch 0 0 0))
+	(handclap	  default	,#f	  ,(make-pitch 0 0 0))
  ))
 
 
-
 \pitchnames
 #(append (map (lambda (x) (cons (car x) (caddr x))) drum-pitch-names)
 	 (map (lambda (x) (cons (cadr x) (caddr x))) drum-pitch-names)
diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly
index 003d380d3f..0e1f1e7181 100644
--- a/ly/engraver-init.ly
+++ b/ly/engraver-init.ly
@@ -31,7 +31,8 @@ StaffContext=\translator {
 	\consists "Accidental_engraver"
 	\consists "Piano_pedal_engraver"
 	\consists "Instrument_name_engraver"
-
+	\consists "Grob_pq_engraver"
+	
 	\consistsend "Axis_group_engraver"
 	
 	MinimumVerticalExtent = #'(-4 . 4)
diff --git a/make/lilypond.redhat.spec.in b/make/lilypond.redhat.spec.in
index 1489a8cc53..c75f25b10f 100644
--- a/make/lilypond.redhat.spec.in
+++ b/make/lilypond.redhat.spec.in
@@ -54,7 +54,7 @@ make web-doc top-web
 rm -rf $RPM_BUILD_ROOT
 mkdir -p $RPM_BUILD_ROOT/tmp/lilypond-rpm-doc
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %if info=="yes"
diff --git a/make/lilypond.suse.spec.in b/make/lilypond.suse.spec.in
index 4c3253f95b..1eec5b418b 100644
--- a/make/lilypond.suse.spec.in
+++ b/make/lilypond.suse.spec.in
@@ -118,7 +118,7 @@ cp tex/titledefs.tex scripts/share/lilypond/tex
 ## end of hack
 
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %{INSTALL_DIR} $RPM_BUILD_ROOT/usr/share/texmf/fonts/source/public/lilypond
diff --git a/make/out/lilypond.lsm b/make/out/lilypond.lsm
index e9bc7e9f71..7a3ad6a10d 100644
--- a/make/out/lilypond.lsm
+++ b/make/out/lilypond.lsm
@@ -1,15 +1,15 @@
 Begin3
 Title: LilyPond
-Version: 1.5.26
-Entered-date: 14DEC01
+Version: 1.5.27
+Entered-date: 24DEC01
 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.26.tar.gz 
+	1000k lilypond-1.5.27.tar.gz 
 Original-site: ftp.cs.uu.nl /pub/GNU/LilyPond/development/
-	1000k lilypond-1.5.26.tar.gz 
+	1000k lilypond-1.5.27.tar.gz 
 Copying-policy: GPL
 End
diff --git a/make/out/lilypond.mandrake.spec b/make/out/lilypond.mandrake.spec
index 0bfd672632..b8784354e3 100644
--- a/make/out/lilypond.mandrake.spec
+++ b/make/out/lilypond.mandrake.spec
@@ -1,5 +1,5 @@
 %define name lilypond
-%define version 1.5.26
+%define version 1.5.27
 %define release 1mdk
 
 Name: %{name}
diff --git a/make/out/lilypond.redhat.spec b/make/out/lilypond.redhat.spec
index 3f62515f68..7d16d85b7d 100644
--- a/make/out/lilypond.redhat.spec
+++ b/make/out/lilypond.redhat.spec
@@ -1,11 +1,11 @@
 %define info yes
 
 Name: lilypond
-Version: 1.5.26
+Version: 1.5.27
 Release: 1
 License: GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.26.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.27.tar.gz
 Summary: Create and print music notation 
 URL: http://www.lilypond.org/
 BuildRoot: /tmp/lilypond-install
@@ -54,7 +54,7 @@ make web-doc top-web
 rm -rf $RPM_BUILD_ROOT
 mkdir -p $RPM_BUILD_ROOT/tmp/lilypond-rpm-doc
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %if info=="yes"
diff --git a/make/out/lilypond.suse.spec b/make/out/lilypond.suse.spec
index 35b61fe56b..afe1711f6a 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.26
+Version: 1.5.27
 Release: 2
 Copyright:    GPL
 Group: Applications/Publishing
-Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.26.tar.gz
+Source0: ftp.cs.uu.nl:/pub/GNU/LilyPond/development/lilypond-1.5.27.tar.gz
 # music notation software for.. ?
 Summary: A program for printing sheet music.
 URL: http://www.lilypond.org/
@@ -118,7 +118,7 @@ cp tex/titledefs.tex scripts/share/lilypond/tex
 ## end of hack
 
 
-strip lily/out/lilypond midi2ly/out/midi2ly
+strip lily/out/lilypond 
 make prefix="$RPM_BUILD_ROOT%{_prefix}" install
 
 %{INSTALL_DIR} $RPM_BUILD_ROOT/usr/share/texmf/fonts/source/public/lilypond
diff --git a/scm/font.scm b/scm/font.scm
index d1813de9a1..ffdae61043 100644
--- a/scm/font.scm
+++ b/scm/font.scm
@@ -205,10 +205,10 @@
 	(tuplet . ((font-family . roman) (font-shape . italic) (font-relative-size . -1)))
 
 	(timesig . ((font-family . number) ))
-	(timesig-symbol . ((font-family . music) (font-relative-size . 0)))
+	(timesig-symbol . ((font-family . music) ))
 	
-	(mmrest . ((font-family . number) (font-relative-size . 1)))
-	(mmrest-symbol . ((font-family . music) (font-relative-size . 0)))
+	(mmrest . ((font-family . number) ))
+	(mmrest-symbol . ((font-family . music) ))
 
 	(mark . ((font-family . number) (font-relative-size . 1)))
 	(script . ((font-family . roman) (font-relative-size . -1)))
diff --git a/scm/grob-description.scm b/scm/grob-description.scm
index fd68506d0d..3938da7413 100644
--- a/scm/grob-description.scm
+++ b/scm/grob-description.scm
@@ -529,7 +529,9 @@
 		 ))
 	      
 	(SpacingSpanner . (
-		(spacing-procedure . ,Spacing_spanner::set_springs)
+		(spacing-procedure . ;; ,Third_spacing_spanner::set_springs
+				        ,Spacing_spanner::set_springs
+				   )
 		(stem-spacing-correction . 0.5)
 		(grace-space-factor . 0.8)
 
diff --git a/scm/grob-property-description.scm b/scm/grob-property-description.scm
index 0df5480c15..0d018c3d97 100644
--- a/scm/grob-property-description.scm
+++ b/scm/grob-property-description.scm
@@ -248,7 +248,8 @@ FIXME: also pair? (cons LEFT RIGHT)
 (grob-property-description 'non-default boolean? "not set because of existence of a bar?.")
 (grob-property-description 'note-character string? "character to print in a note head.")
 (grob-property-description 'note-width number? "unit for horizontal translation, measured in staff-space.")
-(grob-property-description 'number-gap number? "size of the gap for the number in a tuplet.")
+(grob-property-description 'note-heads list? "List of note head grobs")
+(grob-property-description 'number-gap number? "size of the gap for tohe number in a tuplet.")
 (grob-property-description 'old-accidentals list? "list of (pitch, accidental) pairs.")
 (grob-property-description 'origin ly-input-location? "location in input file of the definition.")
 (grob-property-description 'outer-stem-length-limit number? "catch
diff --git a/scm/interface-description.scm b/scm/interface-description.scm
index 1e2fda7b37..ce5f960c3f 100644
--- a/scm/interface-description.scm
+++ b/scm/interface-description.scm
@@ -122,6 +122,7 @@
  'note-column-interface
  "Stem and noteheads combined"
  '(
+   note-heads
    horizontal-shift 
    force-hshift 
    ))
diff --git a/scm/translator-property-description.scm b/scm/translator-property-description.scm
index f5b1adaf40..93aabd8cdd 100644
--- a/scm/translator-property-description.scm
+++ b/scm/translator-property-description.scm
@@ -141,6 +141,10 @@ key signatures after the bar lines:
 	)
 @end example
 ")
+(translator-property-description 'busyGrobs list? "
+a queue of (END-MOMENT . GROB) conses. This is for internal (C++) use only.
+Use at your own risk. 
+")
 (translator-property-description 'centralCPosition number? "Place of the central C. Usually determined by looking at clefPosition and clefGlyph.")
 (translator-property-description 'changeMoment moment-pair? "duration that voices are examined for differences, when part-combining.  Usually unset or zero when combining threads into one voice, and 1 (or the duration of one measure) when combining voices into one staff.")
 (translator-property-description 'chordChanges boolean? "Only show changes in chords scheme?")
diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py
index 8befc79dae..4e431b030f 100644
--- a/scripts/lilypond-book.py
+++ b/scripts/lilypond-book.py
@@ -468,8 +468,10 @@ re_dict = {
 		 'lilypond-file': '(?m)^(?!@c)(?P<match>@lilypondfile(\[(?P<options>.*?)\])?{(?P<filename>[^}]+)})',
 		 'lilypond' : '(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?{(?P<code>.*?)})',
 # pyton2.2b2 barfs on this
-#		 'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
-		 'lilypond-block': r"""(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s)""",
+		 'lilypond-block': r"""(?m)^(?!@c)(?P<match>(?s)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s))""",
+
+# 1.5.2 barfs on this. 
+# 'lilypond-block': r"""(?m)^(?!@c)(?P<match>@lilypond(\[(?P<options>.*?)\])?\s(?P<code>.*?)@end lilypond\s)""",
 		  'option-sep' : ',\s*',
 		  'intertext': r',?\s*intertext=\".*?\"',
 		  'multiline-comment': r"(?sm)^\s*(?!@c\s+)(?P<code>@ignore\s.*?@end ignore)\s",
diff --git a/tex/lilyponddefs.tex b/tex/lilyponddefs.tex
index bc30d54039..c47267cead 100644
--- a/tex/lilyponddefs.tex
+++ b/tex/lilyponddefs.tex
@@ -46,6 +46,8 @@
 \fi
 \ifundefined{lilypondpaperinterscorelinefill}
         \def\lilypondpaperinterscorelinefill{0}
+\else
+        \def\lilypondpaperinterscorelinefill{1}
 \fi
 
 \def\interscoreline{\vskip\lilypondpaperinterscoreline pt plus %
-- 
2.39.5