From ffb89b3950fa34c69679ce11e38243f7258c1c34 Mon Sep 17 00:00:00 2001
From: janneke <janneke>
Date: Sat, 10 Apr 2004 17:03:21 +0000
Subject: [PATCH] * scripts/lilypond.py: Remove LaTeX titling kludge.  Remove
 page layout tweaking.

* input/les-nereides.ly (theScore): Add \book.

* input/test/title-markup.ly: Add \book.

* scm/page-layout.scm (ly:optimal-page-breaks): Debugging output
only if 'verbose.

* lily/include/paper-book.hh (PAGE_LAYOUT): Remove.

* lily/paper-outputter.cc (output_line): Remove PAGE_LAYOUT check.

* tex/lilyponddefs.tex (lilypondstart, lybox, lyitem):
* scm/output-tex.scm (start-system): Update for page layout by
LilyPond.

* scm/output-ps.scm (start-system): Previously (new-start-system).

* lily/paper-outputter.cc (output_header): Uniquify list of fonts
passed to define-fonts.

* lily/paper-column.cc:
* lily/system.cc (get_line):
* ly/property-init.ly (newpage):
* scm/define-grob-properties.scm:
* scm/output-ps.scm:
* scm/output-tex.scm: Remove between-system-string kludge.

* scm/output-ps.scm (define-fonts, font-command,
font-load-encoding): Handle ENCODING = #f.

* scm/output-tex.scm (output-scopes): Check if variable is bound.
---
 ChangeLog                                  |  32 +++
 Documentation/topdocs/NEWS.texi            |  24 +-
 Documentation/user/changing-defaults.itely |   1 +
 input/les-nereides.ly                      |   9 +-
 input/test/title-markup.ly                 |  60 ++---
 lily/include/lily-guile.hh                 |   5 +-
 lily/include/paper-book.hh                 |   5 +-
 lily/include/paper-outputter.hh            |   6 +-
 lily/lily-guile.cc                         |  39 ++++
 lily/paper-book.cc                         |  12 +-
 lily/paper-column.cc                       |   2 +-
 lily/paper-def.cc                          |  76 +++----
 lily/paper-outputter.cc                    | 192 +++++++---------
 lily/parse-scm.cc                          |   3 +-
 lily/system.cc                             | 133 +++--------
 ly/property-init.ly                        |   8 +-
 scm/define-grob-properties.scm             |   2 -
 scm/font.scm                               |   2 +-
 scm/output-ps.scm                          |   7 +-
 scm/output-tex.scm                         |  71 +++---
 scm/page-layout.scm                        |  14 +-
 scripts/lilypond-book.py                   |   4 +-
 scripts/lilypond.py                        | 247 ++++++---------------
 tex/lilyponddefs.tex                       | 211 +++++++-----------
 24 files changed, 480 insertions(+), 685 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index e262bcecb6..865ab566ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,37 @@
 2004-04-10  Jan Nieuwenhuizen  <janneke@gnu.org>
 
+	Page layout for SCOREs enclosed in a BOOK:
+
+	* scripts/lilypond.py: Remove LaTeX titling kludge.  Remove page
+	layout tweaking.
+
+	* input/les-nereides.ly (theScore): Add \book.
+	
+	* input/test/title-markup.ly: Add \book.
+
+	* scm/page-layout.scm (ly:optimal-page-breaks): Debugging output
+	only if 'verbose.
+
+	* lily/include/paper-book.hh (PAGE_LAYOUT): Remove.
+
+	* lily/paper-outputter.cc (output_line): Remove PAGE_LAYOUT check.
+
+	* tex/lilyponddefs.tex (lilypondstart, lybox, lyitem):
+	* scm/output-tex.scm (start-system): Update for page layout by
+	LilyPond.
+
+	* scm/output-ps.scm (start-system): Previously (new-start-system).
+
+	* lily/paper-outputter.cc (output_header): Uniquify list of fonts
+	passed to define-fonts.
+
+	* lily/paper-column.cc: 
+	* lily/system.cc (get_line):
+	* ly/property-init.ly (newpage): 
+	* scm/define-grob-properties.scm:
+	* scm/output-ps.scm: 
+	* scm/output-tex.scm: Remove between-system-string kludge.
+
 	* scm/output-ps.scm (define-fonts, font-command,
 	font-load-encoding): Handle ENCODING = #f.
 
diff --git a/Documentation/topdocs/NEWS.texi b/Documentation/topdocs/NEWS.texi
index 03e075e1d2..2232d7c471 100644
--- a/Documentation/topdocs/NEWS.texi
+++ b/Documentation/topdocs/NEWS.texi
@@ -4,10 +4,32 @@
 
 @node Top, , , 
 @top
-@unnumbered New features in 2.2 since 2.0
+@unnumbered New features in 2.3 since 2.2
 
 @itemize @bullet
 
+@item The toplevel block @code{book} introduces page layout.
+A @code{book} groups @code{score} blocks into one page layout entity.
+Page layout consists of markup titles, headers and footers, and page
+breaking.  Two page breaking algorithms are available, the classic
+ragged pages (the default), and optimal page breaking
+
+@example
+\paper @{
+    %% Select page breaking function.
+    %% #(define page-breaking ly:ragged-page-breaks)
+    #(define page-breaking ly:optimal-page-breaks)
+@}
+\book @{
+     \score @{ ... @}
+     \score @{ ... @}
+@}
+@end example
+
+The @code{lilypond} program does not generate La@TeX{} titles or page
+layout.  If you need La@TeX{} titles, you can use the
+@code{lilypond-book} program.
+
 @item The meaning of the @code{|} in the input can be redefined, by
  assigning a music expression to @code{pipeSymbol}.
  
diff --git a/Documentation/user/changing-defaults.itely b/Documentation/user/changing-defaults.itely
index 4ccff14182..8f244a7c8e 100644
--- a/Documentation/user/changing-defaults.itely
+++ b/Documentation/user/changing-defaults.itely
@@ -2047,6 +2047,7 @@ After the last system LilyPond emits a stronger variant of
 to the top of the page).  You can avoid that by setting the variable
 @code{lastpagefill} in LilyPond's @code{\paper} block.
 
+@c FIXME: broken by page layout
 It is possible to fine-tune the vertical offset further by defining the
 macro @code{\lilypondscoreshift}:
 
diff --git a/input/les-nereides.ly b/input/les-nereides.ly
index 6c2dbe6bdb..a5f6142583 100644
--- a/input/les-nereides.ly
+++ b/input/les-nereides.ly
@@ -262,8 +262,7 @@ middleDynamics = \notes{
     s8\!
 }
 
-
-\score{
+theScore = \score{
     \context PianoStaff <<
         \context Staff=treble <<
 	    \treble
@@ -309,7 +308,11 @@ middleDynamics = \notes{
         }
     }
 }
-
+			   
+\book{
+    \score { \theScore }
+}
+    
 %%% Local variables:
 %%% LilyPond-indent-level:4
 %%% End:
diff --git a/input/test/title-markup.ly b/input/test/title-markup.ly
index 6cc1f21b3d..bc0641e5f7 100644
--- a/input/test/title-markup.ly
+++ b/input/test/title-markup.ly
@@ -1,13 +1,12 @@
 \version "2.2.0"
 
 %{
-   Experimental markup titles are available in direct PostScript output:
+   Markup titles also available for direct PostScript output:
 
    export GS_LIB=$(pwd)/mf/out:/usr/share/texmf/fonts/type1/bluesky/cm
    lilypond-bin -fps input/title/title-markup.ly
 
-
-PostScript fonts: WIP.
+  PostScript fonts: WIP.
 
   * Nonstandardised install directory / how to locate a ps font?
   * Nonstandardised filenames?
@@ -28,7 +27,8 @@ For century schoolbook font:
 
 \paper{
     #(define page-breaking ly:optimal-page-breaks)
-	fonts = #(make-century-schoolbook-tree 1.0)
+    %% Ughr, this breaks TeX output...
+    %% fonts = #(make-century-schoolbook-tree 1.0)
     inputencoding = #"latin1"
 }
 
@@ -85,30 +85,32 @@ spaceTest = \markup { "two space chars" }
     %% bookTitle = \markup { \fill-line < \huge\bold \title > > }
 }
 
-\score {
-    \context Staff \notes \relative c' {
-	c2-\sizeTest c2-\spaceTest
-    }
-    \paper {
-	%% #(paper-set-staff-size (* 11.0 pt)) 
-    }
-}
-
-\header {
-    %% Override automatic score title
-    %% scoreTitle = \markup { "Tweetje" }
-    opus = "opus 1"
-    piece = "Second"
-}
-
-\score {
-    \context Staff \notes \relative c' {
-	%% stress page breaking:
-	%% 35 keep on 3 pages
-	%% 36 spread evenly over 4 pages
-	\repeat unfold 36 { a b c d \break }
-	c1
+\book {
+    
+    \score {
+	\context Staff \notes \relative c' {
+	    c2-\sizeTest c2-\spaceTest
+	}
+	\paper {
+	    %% #(paper-set-staff-size (* 11.0 pt)) 
+	}
     }
-    \paper {
+    
+    \score {
+	\context Staff \notes \relative c' {
+	    %% stress page breaking:
+	    %% 35 keep on 3 pages
+	    %% 36 spread evenly over 4 pages
+	    \repeat unfold 36 { a b c d \break }
+	    c1
+	}
+	\header {
+	    %% Override automatic score title
+	    %% scoreTitle = \markup { "Tweetje" }
+	    opus = "opus 1"
+	    piece = "Second"
+	}
+	\paper {
+	}
     }
-}
+}
\ No newline at end of file
diff --git a/lily/include/lily-guile.hh b/lily/include/lily-guile.hh
index 48563f7d72..bad4d43e2e 100644
--- a/lily/include/lily-guile.hh
+++ b/lily/include/lily-guile.hh
@@ -256,8 +256,9 @@ SCM index_get_cell (SCM cell, Direction d);
 SCM index_set_cell (SCM cell, Direction d, SCM val);
 
 SCM ly_snoc (SCM s, SCM list);
-SCM ly_split_list (SCM s, SCM list);
-SCM ly_unique (SCM list);
+SCM ly_split_list (SCM s, SCM lst);
+SCM ly_unique (SCM lst);
+SCM ly_list_qsort_uniq_x (SCM lst);
 
 
 
diff --git a/lily/include/paper-book.hh b/lily/include/paper-book.hh
index 24dab4e061..91cb699028 100644
--- a/lily/include/paper-book.hh
+++ b/lily/include/paper-book.hh
@@ -14,10 +14,10 @@
 #include "protected-scm.hh"
 #include "smobs.hh"
 
-#define PAGE_LAYOUT "ps"
-
 class Paper_book
 {
+  DECLARE_SMOBS (Paper_book, )
+
 public:
   Array<SCM> headers_;
   Array<SCM> global_headers_;
@@ -35,7 +35,6 @@ public:
   Stencil* title (int);
   void output (String);
   void classic_output (String);
-  DECLARE_SMOBS (Paper_book, )
 };
 
 DECLARE_UNSMOB (Paper_book, paper_book)
diff --git a/lily/include/paper-outputter.hh b/lily/include/paper-outputter.hh
index 4f2ea7b4cc..b90408ba47 100644
--- a/lily/include/paper-outputter.hh
+++ b/lily/include/paper-outputter.hh
@@ -27,18 +27,16 @@
 class Paper_outputter
 {
   bool verbatim_scheme_b_;
-public:
 
-  SCM output_func_;
+public:
   SCM output_module_;
   Protected_scm file_;
-  
   String basename_;
+
   Paper_outputter (String nm);
   ~Paper_outputter ();
   
   void dump_scheme (SCM);
-
   void output_metadata (Paper_def*, SCM);
   void output_music_output_def (Music_output_def* odef);
   void output_scheme (SCM scm);
diff --git a/lily/lily-guile.cc b/lily/lily-guile.cc
index d993c066f3..3df914a86f 100644
--- a/lily/lily-guile.cc
+++ b/lily/lily-guile.cc
@@ -634,6 +634,45 @@ ly_unique (SCM list)
   return scm_reverse_x (unique, SCM_EOL);
 }
 
+
+static int
+scm_default_compare (void const *a, void const *b)
+{
+  SCM pa = *(SCM*) a;
+  SCM pb = *(SCM*) b;
+  if (pa == pb)
+    return 0;
+  return pa < pb ? -1 : 1;
+}
+
+/*  Modify LST in place: qsort it.  */
+SCM
+ly_list_qsort_uniq_x (SCM lst)
+{
+  int len = scm_ilength (lst);
+  SCM *arr = new SCM[len];
+  int k = 0;
+  for (SCM s = lst; SCM_NNULLP (s); s = SCM_CDR (s))
+    arr[k++] = SCM_CAR (s);
+
+  assert (k == len);
+  qsort (arr, len, sizeof (SCM), &scm_default_compare);
+
+  SCM *tail = &lst;
+  for (int i = 0; i < len; i++)
+    if (!i || arr[i] != arr[i - 1])
+      {
+	SCM_SETCAR (*tail, arr[i]);
+	tail = SCM_CDRLOC (*tail);
+      }
+
+  *tail = SCM_EOL;
+  delete[] arr;
+
+  return lst; 
+}
+
+
 /* tail add */
 SCM
 ly_snoc (SCM s, SCM list)
diff --git a/lily/paper-book.cc b/lily/paper-book.cc
index 1a844ab7e6..eaa8acd5be 100644
--- a/lily/paper-book.cc
+++ b/lily/paper-book.cc
@@ -258,13 +258,10 @@ Paper_book::output (String outname)
 
   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
 
-  /*
-    Ugh
-   */
-  for (int i =pages->size (); i--;)
-    delete pages->elem(i);
+  /* Ugh.  */
+  for (int i = pages->size (); i--;)
+    delete pages->elem (i);
   delete pages;
-
   
   progress_indication ("\n");
 }
@@ -313,10 +310,11 @@ Paper_book::classic_output (String outname)
   Paper_outputter *out = papers_.top ()->get_paper_outputter (outname);
   out->output_header (papers_.top (), scopes (count - 1), 0);
 
+  Offset o (0, 0);
   int line_count = SCM_VECTOR_LENGTH ((SCM) scores_.top ());
   for (int i = 0; i < line_count; i++)
     out->output_line (scm_vector_ref ((SCM) scores_.top (), scm_int2num (i)),
-		      0, i == line_count - 1);
+		      &o, i == line_count - 1);
   
   out->output_scheme (scm_list_1 (ly_symbol2scm ("end-output")));
   progress_indication ("\n");
diff --git a/lily/paper-column.cc b/lily/paper-column.cc
index 0314006cb7..6b8d7a4364 100644
--- a/lily/paper-column.cc
+++ b/lily/paper-column.cc
@@ -35,7 +35,7 @@ ADD_INTERFACE (Paper_column, "paper-column-interface",
 	       "  non-adjacent numbers.\n"
 	       "\n"
 	       ,
-	       "between-cols between-system-string when bounded-by-me "
+	       "between-cols when bounded-by-me "
 	       "shortest-playing-duration shortest-starter-duration");
 
 void
diff --git a/lily/paper-def.cc b/lily/paper-def.cc
index 96497b964b..98b46180de 100644
--- a/lily/paper-def.cc
+++ b/lily/paper-def.cc
@@ -30,27 +30,23 @@
 
 Paper_def::Paper_def ()
 {
+  /* Do not remove this statement, scm_make_hash_table may trigger GC.  */
   scaled_fonts_ = SCM_EOL;
-  /*
-    don't remove above statement,  scm_make_hash_table may trigger GC.
-   */
   scaled_fonts_ = scm_c_make_hash_table (11);
 }
 
-Paper_def::~Paper_def ()
-{
-}
-
 Paper_def::Paper_def (Paper_def const&src)
   : Music_output_def (src)
 {
+  /* Do not remove this statement, scm_make_hash_table may trigger GC.  */
   scaled_fonts_ = SCM_EOL;
-  /*
-    don't remove above statement,  scm_make_hash_table may trigger GC.
-   */
   scaled_fonts_ = scm_c_make_hash_table (11);
 }
 
+Paper_def::~Paper_def ()
+{
+}
+
 void
 Paper_def::derived_mark ()
 {
@@ -67,10 +63,8 @@ Paper_def::get_dimension (SCM s) const
   return ly_scm2double (val) / sc;
 }
 
-/*
-  FIXME. This is broken until we have a generic way of
-  putting lists inside the \paper block.
- */
+/* FIXME.  This is broken until we have a generic way of
+   putting lists inside the \paper block.  */
 Interval
 Paper_def::line_dimensions_int (int n) const
 {
@@ -80,16 +74,11 @@ Paper_def::line_dimensions_int (int n) const
   return Interval (ind, lw);
 }
 
-
-
-
 Paper_outputter*
-Paper_def::get_paper_outputter (String outname)  const
+Paper_def::get_paper_outputter (String outname) const
 {
   progress_indication (_f ("paper output to `%s'...",
 			   outname == "-" ? String ("<stdout>") : outname));
-  progress_indication("\n");
-
   global_input_file->target_strings_.push (outname);
   Paper_outputter * po = new Paper_outputter (outname);
   Path p = split_path (outname);
@@ -98,9 +87,7 @@ Paper_def::get_paper_outputter (String outname)  const
   return po;
 }
 
-
-
-Font_metric *
+Font_metric*
 Paper_def::find_scaled_font (Font_metric *f, Real m, SCM input_enc_name)
 {
   SCM sizes = scm_hashq_ref (scaled_fonts_, f->self_scm (), SCM_BOOL_F);
@@ -111,40 +98,32 @@ Paper_def::find_scaled_font (Font_metric *f, Real m, SCM input_enc_name)
 	return unsmob_metrics (ly_cdr (met));
     }
   else
-    {
-      sizes = SCM_EOL;
-    }
+    sizes = SCM_EOL;
   
-
-  /*
-    Hmm. We're chaining font - metrics. Should consider wether to merge
-    virtual-font and scaled_font.
-  */
+  /* Hmm. We're chaining font - metrics.  Should consider whether to
+     merge virtual-font and scaled_font.  */
   SCM val = SCM_EOL;
   if (Virtual_font_metric * vf = dynamic_cast<Virtual_font_metric*> (f))
     {
-      /*
-	For fontify_atom (), the magnification and name must be known
-	at the same time. That's impossible for
+      /* For fontify_atom (), the magnification and name must be known
+	 at the same time. That's impossible for
 
 	  Scaled (Virtual_font (Font1,Font2))
 
 	so we replace by
 
-	  Virtual_font (Scaled (Font1), Scaled (Font2))
-	
-       */
-      SCM l = SCM_EOL;
-      SCM *t =  &l;
+	  Virtual_font (Scaled (Font1), Scaled (Font2))  */
+      SCM lst = SCM_EOL;
+      SCM *t = &lst;
       for (SCM s = vf->get_font_list (); is_pair (s); s = ly_cdr (s))
 	{
-	  Font_metric*scaled
-	    = find_scaled_font (unsmob_metrics (ly_car (s)), m, input_enc_name);
+	  Font_metric *scaled = find_scaled_font (unsmob_metrics (ly_car (s)),
+						  m, input_enc_name);
 	  *t = scm_cons (scaled->self_scm (), SCM_EOL);
 	  t = SCM_CDRLOC(*t);
 	}
 
-      vf = new Virtual_font_metric (l);
+      vf = new Virtual_font_metric (lst);
       val = vf->self_scm ();
     }
   else
@@ -157,22 +136,19 @@ Paper_def::find_scaled_font (Font_metric *f, Real m, SCM input_enc_name)
 	  input_enc_name = scm_variable_ref (var);
 	}
       m /= ly_scm2double (scm_variable_ref (scale_var));
-      val = Modified_font_metric::make_scaled_font_metric (input_enc_name, f, m);
+      val = Modified_font_metric::make_scaled_font_metric (input_enc_name,
+							   f, m);
     }
 
   sizes = scm_acons (scm_make_real (m), val, sizes);
   scm_gc_unprotect_object (val);
-
   scm_hashq_set_x (scaled_fonts_, f->self_scm (), sizes);
-  
   return unsmob_metrics (val);
 }
 
 
-
-/*
-  Return alist to translate internally used fonts back to real-world
-  coordinates.  */
+/* Return alist to translate internally used fonts back to real-world
+   coordinates.  */
 SCM
 Paper_def::font_descriptions () const
 {
@@ -201,7 +177,7 @@ unsmob_paper (SCM x)
   
 
 LY_DEFINE (ly_paper_def_p, "ly:paper-def?",
-	   1, 0,0, (SCM def),
+	   1, 0, 0, (SCM def),
 	   "Is @var{def} a paper definition?")
 {
   Paper_def *op = dynamic_cast<Paper_def*> (unsmob_music_output_def (def));
diff --git a/lily/paper-outputter.cc b/lily/paper-outputter.cc
index 94003c5b08..56d4e9b378 100644
--- a/lily/paper-outputter.cc
+++ b/lily/paper-outputter.cc
@@ -4,106 +4,97 @@
   source file of the GNU LilyPond music typesetter
 
   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
-  Jan Nieuwenhuizen <janneke@gnu.org>
+                 Jan Nieuwenhuizen <janneke@gnu.org>
 */
 
-#include <time.h>
 #include <math.h>
+#include <time.h>
 
-#include "dimensions.hh"
-#include "virtual-methods.hh"
-#include "paper-outputter.hh"
-#include "stencil.hh"
 #include "array.hh"
-#include "string-convert.hh"
-#include "warn.hh"
+#include "dimensions.hh"
 #include "font-metric.hh"
-#include "main.hh"
-#include "scm-hash.hh"
-#include "lily-version.hh"
-#include "paper-def.hh"
 #include "input-file-results.hh"
+#include "input-smob.hh"
+#include "lily-guile.hh"
+#include "lily-version.hh"
 #include "ly-module.hh"
+#include "main.hh"
 #include "paper-book.hh"
+#include "paper-def.hh"
 #include "paper-line.hh"
-#include "input-smob.hh"  // output_expr
+#include "paper-outputter.hh"
+#include "scm-hash.hh"
+#include "stencil.hh"
+#include "string-convert.hh"
+#include "warn.hh"
 
 
-Paper_outputter::Paper_outputter (String name)
+Paper_outputter::Paper_outputter (String filename)
 {
   if (safe_global_b)
     scm_define (ly_symbol2scm ("safe-mode?"), SCM_BOOL_T);      
   
-  file_ = scm_open_file (scm_makfrom0str (name.to_str0 ()),
+  file_ = scm_open_file (scm_makfrom0str (filename.to_str0 ()),
 			 scm_makfrom0str ("w"));
 
-  if (output_format_global == PAGE_LAYOUT)
+  String module_name = "scm output-" + output_format_global;
+  if (safe_global_b)
     {
-      output_func_ = SCM_EOL;
-      String name = "scm output-" + output_format_global;
-      if (safe_global_b)
-	{
-	  /* In safe mode, start from a GUILE safe-module and import
-	     all symbols from the output module.  */
-	  scm_c_use_module ("ice-9 safe");
-	  SCM msm = scm_primitive_eval (ly_symbol2scm ("make-safe-module"));
- 	  output_module_ = scm_call_0 (msm);
-	  ly_import_module (output_module_,
-			    scm_c_resolve_module (name.to_str0 ()));
-	}
-      else
-	output_module_ = scm_c_resolve_module (name.to_str0 ());
-
-      /* FIXME: output-lib should be module, that can be imported.  */
+      /* In safe mode, start from a GUILE safe-module and import
+	 all symbols from the output module.  */
+      scm_c_use_module ("ice-9 safe");
+      SCM msm = scm_primitive_eval (ly_symbol2scm ("make-safe-module"));
+      output_module_ = scm_call_0 (msm);
+      ly_import_module (output_module_,
+			scm_c_resolve_module (module_name.to_str0 ()));
+    }
+  else
+    output_module_ = scm_c_resolve_module (module_name.to_str0 ());
+  
+  /* FIXME: output-lib should be module, that can be imported.  */
 #define IMPORT_LESS 1 // only import the list of IMPORTS
 #if IMPORT_LESS
-      scm_c_use_module ("lily");
-      scm_c_use_module ("ice-9 regex");
-      scm_c_use_module ("srfi srfi-13");
+  scm_c_use_module ("lily");
+  scm_c_use_module ("ice-9 regex");
+  scm_c_use_module ("srfi srfi-1");
+  scm_c_use_module ("srfi srfi-13");
 #endif
-      char const *imports[] = {
-	"lilypond-version",          /* from lily */
-	"ly:output-def-scope",
-	"ly:gulp-file",
-	"ly:number->string",
-	"ly:ragged-page-breaks",
-	"ly:optimal-page-breaks",
-	
-	"ly:number-pair->string",    /* output-lib.scm */
-	"ly:numbers->string",
-	"ly:inexact->string",
-	
-	"assoc-get",
+  char const *imports[] = {
+    "lilypond-version",          /* from lily */
+    "ly:output-def-scope",
+    "ly:gulp-file",
+    "ly:number->string",
+    "ly:ragged-page-breaks",
+    "ly:optimal-page-breaks",
+    
+    "ly:number-pair->string",    /* output-lib.scm */
+    "ly:numbers->string",
+    "ly:inexact->string",
+    
+    "assoc-get",
 #if IMPORT_LESS	
-	"string-index",              /* from srfi srfi-13 */
-	"string-join",
-	"regexp-substitute/global",  /* from (ice9 regex) */
+    "remove",                    /* from srfi srfi-1 */
+    "string-index",              /* from srfi srfi-13 */
+    "string-join",
+    "regexp-substitute/global",  /* from (ice9 regex) */
 #endif	
-	0,
-      };
+    0,
+  };
       
-      for (int i = 0; imports[i]; i++)
-	{
-	  SCM s = ly_symbol2scm (imports[i]);
-	  scm_module_define (output_module_, s, scm_primitive_eval (s));
-	}
-#ifndef IMPORT_LESS  // rather crude, esp for safe-mode let's not
-      SCM m = scm_set_current_module (output_module_);
-      /* not present in current module*/
-      scm_c_use_module ("ice-9 regex");
-      scm_c_use_module ("srfi srfi-13");
-      /* Need only a few of these, see above
-	 scm_c_use_module ("lily"); */
-      scm_set_current_module (m);
-#endif
-    }
-  else
+  for (int i = 0; imports[i]; i++)
     {
-      output_func_
-	= scm_call_1 (ly_scheme_function ("find-dumper"),
-		      scm_makfrom0str (output_format_global.to_str0 ()));
-      output_module_ = SCM_EOL;
+      SCM s = ly_symbol2scm (imports[i]);
+      scm_module_define (output_module_, s, scm_primitive_eval (s));
     }
+#ifndef IMPORT_LESS  // rather crude, esp for safe-mode let's not
+  SCM m = scm_set_current_module (output_module_);
+  /* not present in current module*/
+  scm_c_use_module ("ice-9 regex");
+  scm_c_use_module ("srfi srfi-13");
+  /* Need only a few of these, see above
+     scm_c_use_module ("lily"); */
+  scm_set_current_module (m);
+#endif
 }
 
 Paper_outputter::~Paper_outputter ()
@@ -115,10 +106,7 @@ Paper_outputter::~Paper_outputter ()
 void
 Paper_outputter::output_scheme (SCM scm)
 {
-  if (output_format_global == PAGE_LAYOUT)
-    scm_display (scm_eval (scm, output_module_), file_);
-  else
-    scm_call_2 (output_func_, scm, file_);
+  scm_display (scm_eval (scm, output_module_), file_);
 }
 
 void
@@ -156,15 +144,15 @@ Paper_outputter::output_header (Paper_def *paper, SCM scopes, int page_count)
 
   output_scheme (scm_list_1 (ly_symbol2scm ("header-end")));
 
-  /*
-    TODO: maybe have Scheme extract the fonts directly from \paper?
-
-    Alternatively, we could simply load the fonts on demand in the
-    output, and do away with this define-fonts step.
-   */
+  /* TODO: maybe have Scheme extract the fonts directly from \paper ?
+          
+     Alternatively, we could simply load the fonts on demand in the
+     output, and do away with this define-fonts step.  */
+  SCM fonts = paper->font_descriptions ();
   output_scheme (scm_list_3 (ly_symbol2scm ("define-fonts"),
 			     paper->self_scm (),
-			     ly_quote_scm (paper->font_descriptions ())));
+			     //FIXME:
+			     ly_quote_scm (ly_list_qsort_uniq_x (fonts))));
 }
 
 void
@@ -178,37 +166,17 @@ Paper_outputter::output_line (SCM line, Offset *origin, bool is_last)
       dim[Y_AXIS] = 50 CM;
     }
 
-  if (output_format_global != PAGE_LAYOUT)
-    output_scheme (scm_list_3 (ly_symbol2scm ("start-system"),
-			       scm_make_real (dim[X_AXIS]),
-			       scm_make_real (dim[Y_AXIS])));
-  else
-    {
-      output_scheme (scm_list_3 (ly_symbol2scm ("new-start-system"),
-				 ly_quote_scm (ly_offset2scm (*origin)),
-				 ly_quote_scm (ly_offset2scm (dim))));
-      (*origin)[Y_AXIS] += dim[Y_AXIS];
-    }
+  output_scheme (scm_list_3 (ly_symbol2scm ("start-system"),
+			     ly_quote_scm (ly_offset2scm (*origin)),
+			     ly_quote_scm (ly_offset2scm (dim))));
 
-  SCM between = SCM_EOL;
   for (SCM s = pl->stencils (); is_pair (s); s = ly_cdr (s))
-    {
-      Stencil *stil = unsmob_stencil (ly_car (s));
-      if (stil)
-	output_expr (stil->get_expr (), Offset (0,0));
-      /* Only if !PAGE_LAYOUT */
-      else if (ly_caar (s) == ly_symbol2scm ("between-system-string"))
-	between = ly_cdar (s);
-    }
+    output_expr (unsmob_stencil (ly_car (s))->get_expr (), Offset (0, 0));
 
-  if (is_last)
-    output_scheme (scm_list_1 (ly_symbol2scm ("stop-last-system")));
-  else
-    {
-      output_scheme (scm_list_1 (ly_symbol2scm ("stop-system")));
-      if (output_format_global != PAGE_LAYOUT && between != SCM_EOL)
-	output_scheme (between);
-    }
+  output_scheme (scm_list_2 (ly_symbol2scm ("stop-system"),
+			     ly_bool2scm (is_last)));
+
+  (*origin)[Y_AXIS] += dim[Y_AXIS];
 }
 
 void
diff --git a/lily/parse-scm.cc b/lily/parse-scm.cc
index fa6098a9dc..bd183b2bf2 100644
--- a/lily/parse-scm.cc
+++ b/lily/parse-scm.cc
@@ -35,8 +35,7 @@ internal_ly_parse_scm (Parse_start * ps, bool safe)
 	  if (!safe_module)
 	    {
 	      safe_module = scm_primitive_eval (ly_symbol2scm ("safe-module"));
-	      if (output_format_global == PAGE_LAYOUT)
-		ly_import_module (safe_module, scm_c_resolve_module ("lily"));
+	      ly_import_module (safe_module, scm_c_resolve_module ("lily"));
 	    }
 	  answer = scm_eval (form, safe_module);
 	}
diff --git a/lily/system.cc b/lily/system.cc
index b13d4d0866..e727f1323f 100644
--- a/lily/system.cc
+++ b/lily/system.cc
@@ -38,63 +38,11 @@ System::element_count () const
 int
 System::spanner_count () const
 {
-  int k =0;
-  for (SCM s = get_property ("all-elements");
-       is_pair (s); s = ly_cdr (s))
-    {
-      if (dynamic_cast<Spanner*> (unsmob_grob (ly_car (s))))
-	k++;
-    }
-
-  return k;
-}
-  
-
-int
-scm_default_compare (const void * a, const void *b)
-{
-  SCM pa = *(SCM *)a;
-  SCM pb = *(SCM *)b;
-
-  if (pa < pb)
-    return -1;
-  else if (pa > pb)
-    return 1;
-  else
-    return 0;
-}
-
-/*
-  modify L in place: sort it 
-*/
-SCM
-uniquify_list (SCM l)
-{
-  int len = scm_ilength (l);
-  SCM  * arr = new SCM[len];
   int k = 0;
-  for (SCM s = l; SCM_NNULLP (s); s = SCM_CDR (s))
-    arr[k++] = SCM_CAR (s);
-
-  assert (k == len);
-  qsort (arr, len, sizeof (SCM), &scm_default_compare);
-
-  k = 0;
-  SCM *tail = &l;
-  
-  for (int i = 0; i < len ; i++)
-    {
-      if (i && arr[i] == arr[i-1])
-	continue;
-
-      SCM_SETCAR (*tail, arr[i]);
-      tail = SCM_CDRLOC(*tail);
-    }
-
-  *tail = SCM_EOL;
-  delete[] arr;
-  
-  return l; 
+  for (SCM s = get_property ("all-elements"); is_pair (s); s = ly_cdr (s))
+    if (dynamic_cast<Spanner*> (unsmob_grob (ly_car (s))))
+      k++;
+  return k;
 }
 
 void
@@ -168,12 +116,12 @@ System::get_lines ()
   /* Because the this->get_property (all-elements) contains items in 3
      versions, handle_broken_dependencies () will leave duplicated
      items in all-elements.  Strictly speaking this is harmless, but
-     it leads to duplicated symbols in the output.  uniquify_list ()
+     it leads to duplicated symbols in the output.  ly_list_qsort_uniq_x ()
      makes sure that no duplicates are in the list.  */
   for (int i = 0; i < line_count; i++)
     {
       SCM all = broken_intos_[i]->get_property ("all-elements");
-      all = uniquify_list (all); 
+      all = ly_list_qsort_uniq_x(all); 
     }
 #endif
   
@@ -201,10 +149,9 @@ System::get_lines ()
 
 
 
-/*
-  Find the loose columns in POSNS, and drape them around the columns
-  specified in BETWEEN-COLS.  */
-void
+/* Find the loose columns in POSNS, and drape them around the columns
+   specified in BETWEEN-COLS.  */
+static void
 set_loose_columns (System* which, Column_x_positions const *posns)
 {
   for (int i = 0; i < posns->loose_cols_.size (); i++)
@@ -225,64 +172,53 @@ set_loose_columns (System* which, Column_x_positions const *posns)
 	    break;
 
 
-	  Item * l=dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
-	  Item * r=dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
+	  Item *le = dynamic_cast<Item*> (unsmob_grob (ly_car (between)));
+	  Item *re = dynamic_cast<Item*> (unsmob_grob (ly_cdr (between)));
 
-	  if (!(l && r))
+	  if (!(le && re))
 	    break ;
 	  
-	  if (!left && l)
+	  if (!left && le)
 	    {
-	      left = l->get_column ();
+	      left = le->get_column ();
 	      if (!left->get_system ())
 		left = left->find_prebroken_piece (RIGHT);
 	    }
 
 	  divide_over ++;
-	  loose = right = r->get_column ();
+	  loose = right = re->get_column ();
 	}
       while (1);
 
       if (!right->get_system ())
 	right = right->find_prebroken_piece (LEFT);
       
-      /*
-	We divide the remaining space of the column over the left and
-	right side. At the moment, we  
-	
-      */
-      Grob * common = right->common_refpoint (left, X_AXIS);
+      /* Divide the remaining space of the column over the left and
+	right side.  At the moment,  FIXME  */
+      Grob *common = right->common_refpoint (left, X_AXIS);
       
       Real rx =	right->extent (common, X_AXIS)[LEFT];
       Real lx = left->extent (common, X_AXIS)[RIGHT];
       Real total_dx = rx - lx;
       Interval cval =col->extent (col, X_AXIS);
 
-      /*
-	
-	We put it in the middle. This is not an ideal solution -- the
-	break alignment code inserts a fixed space before the clef
-	(about 1 SS), while the space following the clef is
-	flexible. In tight situations, the clef will almost be on top
-	of the following note. 
-	
-      */
-      Real dx = rx-lx - cval.length ();
+      /* Put it in the middle.  This is not an ideal solution -- the
+	 break alignment code inserts a fixed space before the clef
+	 (about 1 SS), while the space following the clef is flexible.
+	 In tight situations, the clef will almost be on top of the
+	 following note.  */
+      Real dx = rx - lx - cval.length ();
       if (total_dx < 2* cval.length ())
 	{
-	  /*
-	    todo: this is discontinuous. I'm too tired to
-	    invent a sliding mechanism. Duh.
-
-	    TODO.
-	   */
+	  /* TODO: this is discontinuous. I'm too tired to
+	    invent a sliding mechanism.  Duh. */
 	  dx *= 0.25;
 	}
       else
 	dx *= 0.5;
 
       col->system_ = which;
-      col->translate_axis (- col->relative_coordinate (common, X_AXIS), X_AXIS);
+      col->translate_axis (-col->relative_coordinate (common, X_AXIS), X_AXIS);
       col->translate_axis (lx + dx - cval[LEFT], X_AXIS); 
     }
 }
@@ -376,7 +312,7 @@ System::post_processing ()
      This might seem inefficient, but Stencils are cached per grob
      anyway. */
   SCM all = get_property ("all-elements");
-  all = uniquify_list (all);
+  all = ly_list_qsort_uniq_x (all);
 
   this->get_stencil ();
   for (SCM s = all; is_pair (s); s = ly_cdr (s))
@@ -430,17 +366,6 @@ System::get_line ()
 	stencils = scm_cons (my_stencil, stencils);
       }
 
-  if (output_format_global != PAGE_LAYOUT)
-    {
-      SCM lastcol = ly_car (get_property ("columns"));
-      Grob *g = unsmob_grob (lastcol);
-      
-      SCM between = ly_symbol2scm ("between-system-string");
-      SCM inter = g->internal_get_property (between);
-      if (is_string (inter))
-	stencils = scm_cons (scm_cons (between, inter), stencils);
-    }
-
   Interval x (extent (this, X_AXIS));
   Interval y (extent (this, Y_AXIS));
   Paper_line *pl = new Paper_line (Offset (x.length (), y.length ()),
@@ -507,4 +432,4 @@ System::columns ()const
 ADD_INTERFACE (System,"system-interface",
 	       "This is the toplevel object: each object in a score "
 	       "ultimately has a System object as its X and Y parent. ",
-	       "between-system-string all-elements columns")
+	       "all-elements columns")
diff --git a/ly/property-init.ly b/ly/property-init.ly
index 4d11d8ff68..0c554b4b9f 100644
--- a/ly/property-init.ly
+++ b/ly/property-init.ly
@@ -80,10 +80,10 @@ cadenzaOff = {
 newpage = \notes
 {
   \break
-  % urg, only works for TeX output
-  \context Score \applyoutput
-  #(outputproperty-compatibility (make-type-checker 'paper-column-interface)
-    'between-system-string "\\newpage")
+  %% FIXME: page break penalty should tickle into Paper_line
+  %% \context Score \applyoutput
+  %%#(outputproperty-compatibility (make-type-checker 'paper-column-interface)
+  %%  'between-system-string "\\newpage")
 }
 
 % dynamic ly:dir?  text script, articulation script ly:dir?	
diff --git a/scm/define-grob-properties.scm b/scm/define-grob-properties.scm
index 2890451ba5..e604fbd6a9 100644
--- a/scm/define-grob-properties.scm
+++ b/scm/define-grob-properties.scm
@@ -105,8 +105,6 @@ beaming patterns from stem to stem inside a beam.")
 called before line breaking, but after splitting breakable items at
 potential line breaks.")
      (between-cols ,pair? "Where to attach a loose column to")
-     (between-system-string ,string? "string
- to dump between two systems. Useful for forcing page breaks.")
      (bracket-thick ,number? "width of a system start bracket.")
      (break-align-symbol ,symbol? "This key is used for aligning and
 spacing breakable items.")
diff --git a/scm/font.scm b/scm/font.scm
index cb772c2ff4..0badebc011 100644
--- a/scm/font.scm
+++ b/scm/font.scm
@@ -203,7 +203,7 @@
   (add-font
    node
    '((font-encoding . math))
-   `((* factor 10) . #(,(delay (ly:font-load "msam10")))))
+   `(,(* factor 10) . #(,(delay (ly:font-load "msam10")))))
   
   (for-each
    (lambda (x)
diff --git a/scm/output-ps.scm b/scm/output-ps.scm
index 8e0a148643..0e75869197 100644
--- a/scm/output-ps.scm
+++ b/scm/output-ps.scm
@@ -50,7 +50,6 @@
 	     tuplet
 	     polygon
 	     draw-line
-	     between-system-string
 	     define-origin
 	     no-origin
 	     start-page
@@ -384,7 +383,7 @@
     (ly:numbers->string
      (list x y width height blotdiam)) " draw_round_box"))
 
-(define (new-start-system origin dim)
+(define (start-system origin dim)
   (string-append
    "\n" (ly:number-pair->string origin) " start-system\n"
    "{\n"
@@ -395,11 +394,9 @@
    (ly:numbers->string (list breapth width depth height))
    " draw_box" ))
 
-(define (stop-system)
+(define (stop-system last?)
   "} stop-system\n")
 
-(define stop-last-system stop-system)
-
 (define (symmetric-x-triangle thick w h)
   (string-append
    (ly:numbers->string (list h w thick))
diff --git a/scm/output-tex.scm b/scm/output-tex.scm
index 6c529914c4..d9c87df9ca 100644
--- a/scm/output-tex.scm
+++ b/scm/output-tex.scm
@@ -42,13 +42,11 @@
 	     tuplet
 	     polygon
 	     draw-line
-	     between-system-string
 	     define-origin
 	     no-origin
 	     start-page
 	     stop-page
-	     )
-  )
+	     ))
 
 (use-modules (ice-9 regex)
 	     (ice-9 string-fun)
@@ -82,14 +80,24 @@
   (regexp-substitute/global
    #f "_" (output-tex-string (symbol->string sym)) 'pre "X" 'post) )
 
+(define (string->param string)
+  (string-append "{" string "}"))
+
+(define (number->param number)
+  (string->param (ly:number->string number)))
+
+(define (number-pair->param o)
+  (string-append (number->param (car o)) (number->param (cdr o))))
+
 (define (tex-string-def prefix key str)
   (if (equal? "" (sans-surrounding-whitespace (output-tex-string str)))
       (string-append "\\let\\" prefix (symbol->tex-key key) "\\undefined%\n")
-      (string-append "\\def\\" prefix (symbol->tex-key key) "{"  (output-tex-string str) "}%\n")
-      ))
+      (string-append "\\def\\" prefix (symbol->tex-key key)
+		     "{" (output-tex-string str) "}%\n")))
 
 (define (tex-number-def prefix key number)
-  (string-append "\\def\\" prefix (symbol->tex-key key) "{" number "}%\n"))
+  (string-append
+   "\\def\\" prefix (symbol->tex-key key) (string->param number) "%\n"))
 
 (define (output-paper-def pd)
   (apply
@@ -270,28 +278,23 @@
    (ly:number->string x) " \\outputscale "))
 
 (define (placebox x y s) 
-  (string-append "\\lyitem{"
-		 (ly:number->string y) "}{"
-		 (ly:number->string x) "}{"
-		 s "}%\n"))
+  (string-append
+   "\\lyitem" (number->param x) (number->param y) (string->param s) "%\n"))
 
 (define (bezier-sandwich l thick)
   (embedded-ps (list 'bezier-sandwich  `(quote ,l) thick)))
 
-(define (start-system wd ht)
-  (string-append "\\leavevmode\n"
-		 "\\scoreshift = " (number->dim (* ht 0.5)) "\n"
-		 "\\lilypondifundefined{lilypondscoreshift}%\n"
-		 "  {}%\n"
-		 "  {\\advance\\scoreshift by -\\lilypondscoreshift}%\n"
-		 "\\lybox{"
-		 (ly:number->string wd) "}{"
-		 (ly:number->string ht) "}{%\n"))
-
-(define (stop-system) 
-  "}%\n%\n\\interscoreline\n%\n")
-(define (stop-last-system)
-  "}%\n")
+(define (start-system origin dim)
+  (string-append
+   "\\leavevmode\n"
+   "\\lybox" (number-pair->param origin) (number-pair->param dim)
+  "{%\n"))
+
+(define (stop-system last?)
+  (if last?
+      "}%\n"
+      ;; FIXME: still used by lilypond.py for --preview
+      "}%\n%\n\\interscoreline\n%\n"))
 
 (define (horizontal-line x1 x2 th)
   (filledbox (- x1)  (- x2 x1) (* .5 th)  (* .5 th )))
@@ -314,11 +317,11 @@
   (let*
       ((mapping #f))
 
-      ;; TODO: we'd better do this for PS only
-      ;; LaTeX gets in the way, and we need to remap
-      ;; nonprintable chars.
-
-       ; (assoc-get  'char-mapping (ly:font-encoding-alist font))))
+    ;; TODO: we'd better do this for PS only
+    ;; LaTeX gets in the way, and we need to remap
+    ;; nonprintable chars.
+    
+    ;; (assoc-get  'char-mapping (ly:font-encoding-alist font))))
 
     (string-append "\\hbox{\\" (font-command font) "{}"
 		   (output-tex-string
@@ -337,10 +340,6 @@
 (define (draw-line thick fx fy tx ty)
   (embedded-ps (list 'draw-line thick fx fy tx ty)))
 
-;; TODO: this should be a default, which is overriden in PS
-(define (between-system-string string)
-  string
-  )
 (define (define-origin file line col)
   (if (procedure? point-and-click)
       (string-append "\\special{src:" ;;; \\string ? 
@@ -352,9 +351,9 @@
 (define (no-origin) "")
 
 (define (start-page)
-  "\n%\\vbox{\n")
+  "\n\\vbox to 0pt{\n")
 
 (define (stop-page last?)
   (if last?
-      "\n%}\n"
-      "\n%}\n\\newpage\n"))
+      "\\vss\n}\n\\vfill\n"
+      "\\vss\n}\n\\vfill\\newpage\n"))
diff --git a/scm/page-layout.scm b/scm/page-layout.scm
index 80270ec48f..d706f418dc 100644
--- a/scm/page-layout.scm
+++ b/scm/page-layout.scm
@@ -274,10 +274,12 @@
 	 ;; CDR: junk dummy node
 	 (breaks (cdr (reverse (map robust-line-number path)))))
 
-    (format (current-error-port) "ESTIMATE: ~S\n"
-	    (/ book-height text-height))
-    (format (current-error-port) "breaks: ~S\n" breaks)
-    ;; TODO: if solution is bad return no breaks and revert to
-    ;;       ragged bottom
-    (force-output (current-error-port))
+    (if (ly:get-option 'verbose)
+	(begin
+	  (format (current-error-port) "Estimated page count: ~S\n"
+		  (/ book-height text-height))
+	(format (current-error-port) "breaks: ~S\n" breaks)
+	(force-output (current-error-port))))
+	;; TODO: if solution is bad return no breaks and revert to
+	;;       ragged bottom
     (list->vector breaks)))
diff --git a/scripts/lilypond-book.py b/scripts/lilypond-book.py
index 1cec868aa0..d1afc82560 100644
--- a/scripts/lilypond-book.py
+++ b/scripts/lilypond-book.py
@@ -296,8 +296,8 @@ output = {
 	},
 	}
 
-PREAMBLE_LY = r'''%% Generated by %(program_name)s
-%% Options: [%(option_string)s]
+PREAMBLE_LY = r'''%%%% Generated by %(program_name)s
+%%%% Options: [%(option_string)s]
 %(preamble_string)s
 \paper {%(paper_string)s
 }
diff --git a/scripts/lilypond.py b/scripts/lilypond.py
index eb4e959e52..bb9930c6d8 100644
--- a/scripts/lilypond.py
+++ b/scripts/lilypond.py
@@ -1,18 +1,19 @@
 #!@PYTHON@
+# lilypond.py -- frontend for lilypond-bin
 #
-# lilypond.py -- Run LilyPond, add titles to bare score, generate printable
-#              document
-#              Invokes: lilypond-bin, latex (or pdflatex), dvips, ps2pdf, gs
-# 
 # source file of the GNU LilyPond music typesetter
 # 
 # (c) 1998--2004  Han-Wen Nienhuys <hanwen@cs.uu.nl>
 #                 Jan Nieuwenhuizen <janneke@gnu.org>
+#
+# Run lilypond-bin, generate printable document
+# Invokes: lilypond-bin, latex (or pdflatex), dvips, ps2pdf, gs
+# 
 
-# This is the third incarnation of ly2dvi, now renamed lilypond.
+# This is the third incarnation of ly2dvi, renamed to lilypond.
 #
-# Earlier incarnations of lilypond were written by
-# Jeffrey B. Reed<daboys@austin.rr.com> (Python version)
+# Earlier incarnations of ly2dvi were written by
+# Jeffrey B. Reed<daboys@austin.rr.com> (Python versioan)
 # Jan Arne Fagertun <Jan.A.Fagertun@@energy.sintef.no> (Bourne shell script)
 #
 
@@ -24,6 +25,8 @@
 '''
 TODO:
 
+  * cleanup
+
   * figure out which set of command line options should make lilypond:
 
       na: create tex only?  
@@ -37,34 +40,9 @@ TODO:
 
      etc.
 
-  * move versatile taglines, 
-  
-     \header {
-        beginfooter=\mutopiaPD
-        endfooter=\tagline  -> 'lily was here <version>'
-     }
-
-     lilytagline (->lily was here), usertagline, copyright, lily-version
-     etc.
-
-  * head/header tagline/endfooter
-
   * dvi from lilypond .tex output?  This is hairy, because we create dvi
     from lilypond .tex *and* header output.
 
-  * multiple \score blocks?
-
-  * Introduce verbosity levels
-  
-     0  = QUIET: mute all command output, no lilypond progress
-     1  = BRIEF: mute all command output, only lilypond progress
-     2a = NORMAL: show only LilyPond command output, show lilypond progress
-     2b = NORMAL: show command output, show lilypond progress
-     3  = VERBOSE: show command output, run lilypond --verbose
-     4  = DEBUGGING: show all command output, run lilypond --verbose, print
-                   environment and all kinds of client side debugging stuff
-
-     Currently, we only have 1 and 4, but we kludge to have 2a and 4.
 '''
 
 import operator
@@ -114,10 +92,13 @@ keep_temp_dir_p = 0
 preview_resolution = 90
 debug_p = 0
 
+TEX_PREAMBLE = '%%%% Generated by %(program_name)s (v%(program_version)s)' \
+	       % vars ()
+
 ## FIXME
 ## do -P or -p by default?
 ##help_summary = _ ("Run LilyPond using LaTeX for titling")
-help_summary = _ ("Run LilyPond, add titles, generate printable document.")
+help_summary = _ ("Run LilyPond, generate printable document.")
 copyright = ('Han-Wen Nienhuys <hanwen@cs.uu.nl',
 	     'Jan Nieuwenhuizen <janneke@gnu.org')
 
@@ -174,32 +155,18 @@ if '@bindir@' == ('@' + 'bindir@') or not os.path.exists (lilypond_binary):
 	lilypond_binary = 'lilypond-bin'
 
 
-layout_fields = ['dedication', 'title', 'subtitle', 'subsubtitle',
-	  'footer', 'head', 'composer', 'arranger', 'instrument',
-	  'opus', 'piece', 'metre', 'meter', 'poet', 'texttranslator']
-
-
-# init to empty; values here take precedence over values in the file
-
-## TODO: change name.
+## Init to empty; values here take precedence over values in the file
 extra_init = {
 	'language' : [],
 	'latexheaders' : [],
-	'latexpackages' :  ['geometry'],
-
-	# for geometry v3
-	'latexoptions' : ['compat2'],
-	
-	'papersize' : [],
-	'pagenumber' : [1],
-	'textheight' : [], 
-	'linewidth' : [],
+	'latexoptions' : [],
+	'latexpackages' :  [],
 	'orientation' : [],
+	'papersize' : [],
 	'unit' : ['pt'],
 }
 
-extra_fields = extra_init.keys ()
-fields = layout_fields + extra_fields
+header_fields = extra_init.keys ()
 
 include_path = ['.']
 lily_p = 1
@@ -238,27 +205,25 @@ def set_setting (dict, key, val):
 def escape_shell (x):
 	return re.sub ("(\s|[`'\"\\\\])", r'\\\1',x)
 
-
 def run_lilypond (files, dep_prefix):
+	
 	def make_include_option (x):
 		return '-I %s' %   escape_shell (x)
-
-	opts = ''
-	opts = opts + ' ' + string.join (map (make_include_option, include_path))
+	
+	opts = ' ' + string.join (map (make_include_option, include_path))
+	
+	## UGHr
 	if pseudo_filter_p:
-		opts = opts + ' --output=lelie'
+		opts += ' --output=lelie'
 	if paper_p:
-		opts = opts + ' ' + string.join (map (lambda x : '-H ' + x,
-						      fields))
+		opts += ' ' + string.join (map (lambda x : '--header=' + x,
+						header_fields))
 	else:
 		opts = opts + ' --no-paper'
-
 	if pdftex_p:
 		opts = opts + ' -f pdftex'		
-
 	if safe_mode_p:
 		opts = opts + ' --safe-mode'
-
 	if track_dependencies_p:
 		opts = opts + " --dependencies"
 		if dep_prefix:
@@ -308,32 +273,23 @@ def analyse_lilypond_output (filename, extra):
 
 	# search only the first 10k
 	s = s[:10240]
-	for x in extra_fields:
+	for x in header_fields:
 		m = re.search (r'\\def\\lilypondpaper%s{([^}]*)}'%x, s)
 		if m:
 			set_setting (extra, x, m.group (1))
 	ly.progress ('\n')
 
 def find_tex_files_for_base (base, extra):
-	'''
-	Find the \header fields dumped from BASE.
-	'''
-	
-	headerfiles = {}
-	for f in layout_fields:
-		fn = base + '.' + f
-		if os.path.exists (fn):
-			headerfiles[f] = fn
 
 	if os.path.exists (base  +'.dep'):
 		dependency_files.append (base + '.dep')
 
-	for f in extra_fields:
+	for f in header_fields:
 		fn =base + '.' + f
 		if os.path.exists (fn):
 			extra[f].append (open (fn).read ())
 	
-	return (base + tex_extension, headerfiles)
+	return (base + tex_extension, {})
 	 
 
 def find_tex_files (files, extra):
@@ -366,136 +322,82 @@ def find_tex_files (files, extra):
 
 def one_latex_definition (defn, first):
 	s = '\n'
-	for (k,v) in defn[1].items ():
+	for (k, v) in defn[1].items ():
 		val = open (v).read ()
 		if (string.strip (val)):
-			s = s + r'''\def\lilypond%s{%s}''' % (k, val)
+			s += r'''\def\lilypond%s{%s}''' % (k, val)
 		else:
-			s = s + r'''\let\lilypond%s\relax''' % k
-		s = s + '\n'
+			s += r'''\let\lilypond%s\relax''' % k
+		s += '\n'
 
-	if first:
-		s = s + '\\def\\mustmakelilypondtitle{}\n'
-	else:
-		s = s + '\\def\\mustmakelilypondpiecetitle{}\n'
-		
-	s = s + '\\input %s\n' % defn[0] # The final \n seems important here. It ensures that the footers and taglines end up on the right page.
+	s += '%%PREVIEW%%\n'
+	s += '\\input %s\n' % defn[0]
 	return s
 
-
-ly_paper_to_latexpaper =  {
-	'letter' : 'letterpaper', 
-	'a3' : 'a3paper',
-	'a4' : 'a4paper',
-	'a5' : 'a5paper',
-	'a6' : 'a6paper',
-	'legal' : 'legalpaper', 
-	'tabloid' : 'papersize={11in,17in}', 
-}
-
-#TODO: should set textheight (enlarge) depending on papersize. 
 def global_latex_preamble (extra):
 	'''construct preamble from EXTRA,'''
-	s = ""
-	s = s + '% generation tag\n'
+	
+	s = TEX_PREAMBLE
+	s += '\n'
 
 	options = ''
 
 	if extra['latexoptions']:
 		options = options + ',' + extra['latexoptions'][-1]
 
-	s = s + '\\documentclass[%s]{article}\n' % options
+	s += '\\documentclass[%s]{article}\n' % options
 
 	if safe_mode_p:
-		s = s + '\\nofiles\n'
+		s += '\\nofiles\n'
 
 	if extra['language']:
-		s = s + r'\usepackage[%s]{babel}' \
+		s += r'\usepackage[%s]{babel}' \
 		    % extra['language'][-1] + '\n'
 
-	s = s + '\\usepackage{%s}\n' \
+	s += '\\usepackage{%s}\n' \
 		% string.join (extra['latexpackages'], ',')
 
 	if extra['latexheaders']:
-		s = s + '\\include{%s}\n' \
+		s += '\\include{%s}\n' \
 			% string.join (extra['latexheaders'], '}\n\\include{')
 
  	unit = extra['unit'][-1]
 
-
-	papersize = ''
-	if extra['papersize']:
-		try:
-			papersize = ly_paper_to_latexpaper[extra['papersize'][0]] + ','
-		except KeyError:
-			ly.warning (_ ("invalid value: `%s'") % `extra['papersize'][0]`)
-			pass
-
-	textheight = ''
-	if extra['textheight']:
-		textheight = ',textheight=%f%s' % (extra['textheight'][0], unit)
-
-	orientation = 'portrait'
-	if extra['orientation']:
-		orientation = extra['orientation'][0]
-
- 	# set sane geometry width (a4-width) for linewidth = -1.
-	maxlw = max (extra['linewidth'] + [-1])
-	if maxlw < 0:
-	        # who the hell is 597 ?
-		linewidth = '597pt'
-	else:
-		linewidth = '%d%s' % (maxlw, unit)
-	s = s + '\geometry{%swidth=%s%s,bottom=11mm,headsep=2mm,top=12mm,headheight=2mm,footskip=5mm,%s}\n' % (papersize, linewidth, textheight, orientation)
-
-
-	if 'twoside' in  extra['latexoptions'] :
-		s = s + '\geometry{twosideshift=4mm}\n'
-
-	s = s + r'''
+	# FIXME, must (only) from lilypond-bin
+	s += r'''
 \usepackage[latin1]{inputenc}
-\input{titledefs}
+\pagestyle{empty}
+%%PREVIEW%%
+%% Nullify [La]TeX page layout settings, page layout by LilyPond.
+\pagestyle{empty}
+\topmargin-1in
+%% FIXME: empirical computer science: page is ca 5mm too low.
+\advance\topmargin-5mm
+\headheight0pt\headsep0pt
+\oddsidemargin-1in
+\evensidemargin\oddsidemargin
+\parindent 0pt
 '''
-	
-	if extra['pagenumber'] and extra['pagenumber'][-1] and extra['pagenumber'][-1] != 'no':
-		s = s + '\setcounter{page}{%d}\n' % (extra['pagenumber'][-1])
-                s = s + '\\pagestyle{plain}\n'
-	else:
-		s = s + '\\pagestyle{empty}\n'
-
-
 	return s
 
 	
 def global_latex_definition (tfiles, extra):
 	'''construct preamble from EXTRA, dump Latex stuff for each
 lily output file in TFILES after that, and return the Latex file constructed.  '''
-
-	
 	s = global_latex_preamble (extra) + '\\begin{document}\n'
-	s = s + '\\parindent 0pt\n'
-	s = s + '\\thispagestyle{firstpage}\n'
+	s += '\\parindent 0pt'
 
 	first = 1
 	for t in tfiles:
-		s = s + one_latex_definition (t, first)
+		s += one_latex_definition (t, first)
 		first = 0
-
-
-	s = s + '\n\\thispagestyle{lastpage}\n'
-	s = s + '\\end{document}'
-
+	s += '\\end{document}\n'
 	return s
 
 def run_latex (files, outbase, extra):
-
 	'''Construct latex file, for FILES and EXTRA, dump it into
-OUTBASE.latex. Run LaTeX on it.
-
-RETURN VALUE
-
-None
-	'''
+OUTBASE.latex.  Run LaTeX on it.
+'''
 
 	latex_fn = outbase + '.latex'
 	
@@ -538,12 +440,8 @@ None
 			preview_base = ly.strip_extension (score[0], '.tex')
 			preview_fn = preview_base + '.preview.tex'
 			s = global_latex_definition ((score,), extra)
-			s = re.sub ('thispagestyle{firstpage}',
-				    r'''thispagestyle{empty}%
-				    \\def\\interscoreline{\\endinput}''', s)
-			s = re.sub ('thispagestyle{lastpage}',
-				    r'''thispagestyle{empty}%
-				    \\def\\interscoreline{\\endinput}''', s)
+			s = re.sub ('%%PREVIEW%%',
+				    r'''\def\interscoreline{\endinput}''', s)
 			f = open (preview_fn, 'w')
 			f.write (s)
 			f.close ()
@@ -553,23 +451,14 @@ None
 
 
 def run_dvips (outbase, extra):
-
-
 	'''Run dvips using the correct options taken from EXTRA,
 leaving a PS file in OUTBASE.ps
-
-RETURN VALUE
-
-None.
 '''
-	opts = ''
-	if extra['papersize']:
-		opts = opts + ' -t%s' % extra['papersize'][0]
-
+	#FIXME: papersize, orientation must come from lilypond-bin
+	opts = ' -t%s' % extra['papersize'][0]
 	if extra['orientation'] and extra['orientation'][0] == 'landscape':
 		opts = opts + ' -tlandscape'
 
-
 	if 'PDF' in targets:
 		where = ly.read_pipe ('kpsewhich feta20.pfa').strip()
 
@@ -625,10 +514,8 @@ def find_file_in_path (path, name):
 		if name in os.listdir (d):
 			return os.path.join (d, name)
 
-# Added as functionality to lilypond, because lilypond may well need to do this
-# in future too.
-PS = '%!PS-Adobe'
 def find_pfa_fonts (name):
+	PS = '%!PS-Adobe'
 	s = open (name).read ()
 	if s[:len (PS)] != PS:
 		# no ps header?
diff --git a/tex/lilyponddefs.tex b/tex/lilyponddefs.tex
index 5cc6d4ffcf..2ed92bbe2a 100644
--- a/tex/lilyponddefs.tex
+++ b/tex/lilyponddefs.tex
@@ -1,37 +1,35 @@
-% lilyponddefs.tex
-%
-% Include file for LilyPond.
-%
-% This file defines various macros to acommodate lilypond output.
-%
-% It should run with plain TeX, LaTeX, pdftex, and texinfo.
-%
-% To avoid interferences, lilyponddefs.tex should be loaded within a group.
-% To load it only once, most of the definitions must be global.
-%
-% The overall structure of a file created by LilyPond is as follows:
-%
-%   <lilypond parameter definitions>
-%   \ifx\lilypondstart \undefined
-%     \input lilyponddefs
-%   \fi
-%   \lilypondstart
-%   <font setup and note output>
-%   \lilypondend
-%
-% No footers and headers are provided for the stand-alone run (i.e., for
-% directly saying `latex <LilyPond output>'.
-%
-%
-% Avoid \par while reading this file.
+%%% lilyponddefs.tex -- TeX macros for LilyPond output.
+%%%
+%%%  source file of the GNU LilyPond music typesetter
+%%% 
+%%% (c)  1998--2004 Jan Nieuwenhuizen <janneke@gnu.org>
+%%%                 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+%%%                 Mats Bengtsson <mats.bengtsson@s3.kth.se>
+%%%
+%% Avoid \par while reading this file.
 \edef\lilyponddefsELC{\the\endlinechar}%
 \endlinechar -1\relax
 
-% the next three macros are taken from LaTeX
-\long\gdef\lilypondfirst#1#2{#1}
+%% This runs with plain TeX, LaTeX, pdftex, and texinfo.
+%%
+%% To avoid interferences, lilyponddefs.tex must be loaded within a group.
+%% It is loaded only once, so the definitions must be global.
+%%
+%% The overall structure of a file created by LilyPond is as follows:
+%%
+%%   <lilypond parameter definitions>
+%%   \ifx\lilypondstart \undefined
+%%     \input lilyponddefs
+%%   \fi
+%%   \lilypondstart
+%%   <font setup and note output>
+%%   \lilypondend
 
-\long\gdef\lilypondsecond#1#2{#2}
+\newdimen\outputscale
 
+%% Handy macros from the LaTeX manual.
+\long\gdef\lilypondfirst#1#2{#1}
+\long\gdef\lilypondsecond#1#2{#2}
 \gdef\lilypondifundefined#1{
   \expandafter\ifx\csname#1\endcsname\relax
     \expandafter\lilypondfirst
@@ -43,72 +41,46 @@
 \gdef\lilypondstart{
   \begingroup
   \catcode `\@=11\relax
-  % \@nodocument is defined as \relax after `\begin{document}'
+  %% \@nodocument is defined as \relax after `\begin{document}'
   \lilypondifundefined{@nodocument}
     {
-      % either plain TeX or texinfo or not at the beginning of LaTeX input
-      \def\x{\endgroup}
-    }
+      %% either plain TeX or texinfo or not at the beginning of LaTeX input
+      \def\x{\endgroup}}
     {
-      % provide a proper LaTeX preamble (for A4 paper format)
+      %% FIXME: a4
+      %% provide a proper LaTeX preamble (for A4 paper format)
       \def\x{
         \endgroup
         \def\lilyponddocument{}
         \documentclass[a4paper]{article}
-	\nofiles
+        %% safe-mode
+        \nofiles
+        %% Nullify [La]TeX page layout settings, page layout by LilyPond.
         \pagestyle{empty}
-        % \begin is defined as \outer in texinfo, thus we use \csname
-        \csname begin\endcsname{document}
-        % center staves horizontally on page
-        \ifdim\lilypondpaperlinewidth\lilypondpaperunit > 0pt
-          \hsize\lilypondpaperlinewidth\lilypondpaperunit
-          % we abuse \scoreshift temporarily
-          \scoreshift \paperwidth
-          \advance\scoreshift -\the\hsize
-          \scoreshift 0.5\scoreshift
-          \advance\scoreshift -1in
-          \oddsidemargin \scoreshift
-          \evensidemargin \scoreshift
-        \fi
+        \topmargin-1in
+        %% FIXME: empirical computer science: page is ca 5mm too low.
+        \advance\topmargin-5mm
+        \headheight0pt\headsep0pt
+        \oddsidemargin-1in
+        \evensidemargin\oddsidemargin
         \parindent 0pt
-      }
-    }
-
-  \x
-
-  \lilypondifundefined{mustmakelilypondtitle}
-    {}
-    {\makelilypondtitle}
-
-  \lilypondifundefined{mustmakelilypondpiecetitle}
-    {}
-    {\makelilypondpiecetitle}
-}
+        %% TEXINFO workaround: \begin is defined as \outer, use \csname.
+        \csname begin\endcsname{document}}}
+  \x}
 
 \gdef\lilypondend{
   \lilypondifundefined{lilypondbook}
-    {\lilypondifundefined{lilypondpaperlastpagefill}
-      {\vskip 0pt plus \lilypondpaperinterscorelinefill00 fill}
-      {}
-    }
-    {}
-
+  {\lilypondifundefined{lilypondpaperlastpagefill}
+    {\vskip 0pt plus\lilypondpaperinterscorelinefill00 fill}
+    {}}
+  {}
   \begingroup
   \lilypondifundefined{lilyponddocument}
-    {
-      \def\x{\endgroup}
-    }
-    {
-      \def\x{
-        \endgroup
-        \csname end\endcsname{document}
-      }
-    }
-
-  \x
-}
+    {\def\x{\endgroup}}
+    {\def\x{\endgroup\csname end\endcsname{document}}}
+  \x}
 
-% this is an inversed \loop ... \repeat macro
+%% Inversed \loop ... \repeat macro
 \def\lilypondloop#1\lilypondrepeat{
   \def\lilypondbody{#1}
   \lilyponditerate
@@ -124,82 +96,59 @@
   \lilypondnext
 }
 
-% the following macro is executed only once
+%% Include \special only once.
 \gdef\lilypondspecial{
   \special{header=music-drawing-routines.ps}
   \gdef\lilypondspecial{}
 }
 
-% the feta characters
+%% The feta characters.
 \input feta20
 
 \global\font\fetasixteen = feta16
 \gdef\fetafont{\fetasixteen}
 \gdef\fetachar#1{\hbox{\fetasixteen#1}}
 
-\gdef\botalign#1{
-  \vbox to 0pt{\vss #1}
-}
-\gdef\leftalign#1{
-  \hbox to 0pt{#1\hss}
-}
+\gdef\topalign#1{\vbox to 0pt{\hbox{#1}\vss}}
+\gdef\leftalign#1{\hbox to 0pt{#1\hss}}
 
 \gdef\lyitem#1#2#3{
-  \botalign{
-    \hbox{\raise #1\outputscale
-          \leftalign{\kern #2\outputscale #3}}
-  }
-}
+  \topalign{\raise#2\outputscale\leftalign{\kern#1\outputscale#3}}}
 
-\gdef\lybox#1#2#3{
-  \hbox to #1\outputscale {
-    \lower\scoreshift \vbox to #2\outputscale {
-      \hbox{#3}
-      \vss
-    }
-    \hss
-  }
-}
+\gdef\XXXlybox#1#2#3#4#5{
+  \vbox to #4\outputscale{
+    \hbox to #3\outputscale{
+      \leftalign{\kern#1\outputscale\lower#2\outputscale\topalign{#5}}}
+    \hss}\vss}
 
-\gdef\lyvrule#1#2#3#4{
-  \kern #1\outputscale
-  \vrule width #2\outputscale depth #3\outputscale height #4\outputscale
-}
+%% FIXME: no dimensions, should fix at toplevel
+\gdef\lybox#1#2#3#4#5{
+  \leftalign{\kern#1\outputscale\lower#2\outputscale\topalign{#5}}}
 
-% Attempt to keep lilypiecetitle together with the piece:
-%
-% TODO: figure this out.
-\gdef\myfilbreak{}%\par\vfil\penalty200\vfilneg}
+\gdef\lyvrule#1#2#3#4{
+  \kern#1\outputscale
+  \vrule width #2\outputscale depth #3\outputscale height #4\outputscale}
 
 \lilypondifundefined{lilypondpaperinterscorelinefill}
   {\gdef\lilypondpaperinterscorelinefill{0}}
   {\gdef\lilypondpaperinterscorelinefill{1}}
 
-%% Allow overriding of interscoreline, eg for lilypond --preview
+%% Allow overriding of interscoreline, e.g. for lilypond.py's --preview
 \lilypondifundefined{interscoreline}
-{\gdef\interscoreline{
-  \vskip \lilypondpaperinterscoreline \lilypondpaperunit
-    plus \lilypondpaperinterscorelinefill fill
-}}{}
+{\gdef\interscoreline{}}{}
 
-% Are we using PDFTeX?  If so, use pdf definitions.
-% MiKTeX checks \pdfoutput the wrong way, thus we use \csname.
+%% Include postscript definitions unless using PDFTeX,
+%% in that case use pdf definitions.
+%% MiKTeX workaround: use \csname.
 \lilypondifundefined{lilypondpostscript}
-  {
-    \lilypondifundefined{pdfoutput}
-      {\input lily-ps-defs }
-      {
-        \pdfoutput = 1
-        \input lily-pdf-defs %
-      }
-  }
-  {}
-
-\newdimen\outputscale
-\newdimen\scoreshift
+{\lilypondifundefined{pdfoutput}
+  {\input lily-ps-defs }
+  {\pdfoutput = 1
+    \input lily-pdf-defs }}
+{}
 
-% Restore newline functionality (disabled to avoid \par).
+%% Restore newline functionality (disabled to avoid \par).
 \endlinechar \lilyponddefsELC
 \endinput
 
-% EOF
+%% end lilyponddefs.tex
-- 
2.39.5