From: Jan Nieuwenhuizen <janneke@gnu.org>
Date: Sat, 24 Mar 2001 15:20:14 +0000 (+0100)
Subject: patch::: 1.3.141.jcn3
X-Git-Tag: release/1.3.142~3
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=d4e71555e7e093a4da32d92378f8f475fa0d6aaa;p=lilypond.git

patch::: 1.3.141.jcn3

1.3.141.jcn3
============

* some mup2ly progress.

* Bugfix: ly2dvi: don't include empty set fo latexheaders, don't use
python-1.5.2 abspath func.
---

diff --git a/CHANGES b/CHANGES
index 2bb1994a46..9996f1fa38 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+1.3.141.jcn3
+============
+
+* some mup2ly progress.
+
+* Bugfix: ly2dvi: don't include empty set fo latexheaders, don't use
+python-1.5.2 abspath func.
+
 1.3.141.jcn2
 ============
 
@@ -5,17 +13,26 @@
 
 * Bugfix: lilypond-book: accept \documentclass{article}.
 
-1.3.141.jcn1
-============
-
 * scripts/update-lily.py: fancy source rebuild update tool that we're
 probably not going to use on www.lilypond.org.  Check it out!
 
 * Bugfix: building of topdocs.
 
-1.3.140.jcn6
+1.3.141.hwn1
 ============
 
+* doco fixes.
+
+* Beat repeats, double measure repeats; removed repeat sign character
+from the font (WARNING: FONT CHANGED).
+
+* cleanups in (de)crescendo code, fixed continued (de)crescendi.
+
+* German chords (Rune Zedler)
+
+1.3.141
+=======
+
 * po update.
 
 * Renamed remaining mudela -> lilypond (except for old change logs).
diff --git a/Documentation/regression-test.tely b/Documentation/regression-test.tely
index 53d356514c..2b89bd8ab7 100644
--- a/Documentation/regression-test.tely
+++ b/Documentation/regression-test.tely
@@ -57,6 +57,8 @@ and documenting bugfixes.
 
 @lilypondfile[printfilename]{dynamics-line.ly}
 
+@lilypondfile[printfilename]{dynamics-broken-hairpin.ly}
+
 @lilypondfile[printfilename]{arpeggio.ly}
 
 @lilypondfile[printfilename]{glissando.ly}
diff --git a/Documentation/topdocs/INSTALL.texi b/Documentation/topdocs/INSTALL.texi
index 9d7e01ad9d..66141d6c21 100644
--- a/Documentation/topdocs/INSTALL.texi
+++ b/Documentation/topdocs/INSTALL.texi
@@ -257,6 +257,27 @@ everything will be compiled, but nothing will be installed.  The
 resulting binaries can be found in the subdirectories @file{out/} (which
 contain all files generated during compilation).
 
+
+@section Emacs mode
+
+
+An emacs mode for LilyPond is included with the source archive as
+@file{lilypond-mode.el} and @file{lilypond-font-lock.el}.  If you have
+an RPM, it is in @file{/usr/share/doc/lilypond-X/}.  You have to install
+it yourself.
+
+Add this to your ~/.emacs or ~/.emacs.el:
+@example 
+    (load-library "lilypond-mode.el")
+    (setq auto-mode-alist
+      (cons '("\\.ly$" . LilyPond-mode) auto-mode-alist))
+    (add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
+@end example
+
+If you have the latest LilyPond-1.3.x Debian package, LilyPond-mode
+is automatically loaded, so you need not modify your ~/.emacs file.
+
+
 @section Configuring for multiple platforms
 
 If you want to build multiple versions of LilyPond with different
@@ -330,6 +351,13 @@ in addition to the those needed for running:
 @item tetex-devel
 @end itemize
 
+@section SuSE
+
+[TODO: document this]
+
+Install @code{tetex}, @code{te_mpost}, @code{te_kpath}.
+
+
 @section Debian GNU/Linux
 
 A Debian package is also available.  You may install it easily by using
diff --git a/Documentation/user/lilypond.tely b/Documentation/user/lilypond.tely
index 25830f909d..d0034f88a7 100644
--- a/Documentation/user/lilypond.tely
+++ b/Documentation/user/lilypond.tely
@@ -15,7 +15,7 @@
 @titlepage
 @title GNU LilyPond
 @subtitle The music typesetter
-@author Han-Wen Nienhuys, Jan Nieuwenhuizen, Adrian Mariano,  Tom Cato Amundsen
+@author    
 
 
 Copyright @copyright{} 1999--2001 by the authors
@@ -33,7 +33,8 @@ Copyright @copyright{} 1999--2001 by the authors
 @ifinfo
 This file documents GNU LilyPond.
 
-Copyright 1999 Han-Wen Nienhuys, Jan Nieuwenhuizen and Adrian Mariano
+Copyright 1999 Han-Wen Nienhuys, Jan Nieuwenhuizen, Adrian Mariano
+Tom Cato Amundsen.
 
   Permission is granted to copy, distribute and/or modify this document
   under the terms of the GNU Free Documentation License, Version 1.1
diff --git a/Documentation/user/refman.itely b/Documentation/user/refman.itely
index 3ec6395039..ee400db07a 100644
--- a/Documentation/user/refman.itely
+++ b/Documentation/user/refman.itely
@@ -41,7 +41,6 @@ revision of this document was for LilyPond 1.3.141.
 * Page layout::                 
 * Sound::                       
 * Music entry::                 
-* Using LilyPond::              
 * Interpretation context::      
 * Syntactic details::           
 * Lexical details::             
@@ -1367,11 +1366,9 @@ want to get several marks during one note, you must use spacer notes.
 
 @lilypond[fragment,verbatim,center]
   c'' \< \! c''   d'' \decr e'' \rced 
-  < f''1 { s4 \< \! s2 \> \! s4 } >
+  < f''1 { s4 s4 \< \! s4 \> \! s4 } >
 @end lilypond
 
-[BUG in \> ! ]
-
 You can also use a text saying @emph{cresc.} instead of hairpins. Here
 is an example how to do it:
 
@@ -1384,7 +1381,11 @@ is an example how to do it:
 @end lilypond
 
 
+@refbugs
 
+When using spacer notes to subdivide note dynamics and @code{linewidth =
+-1}, starting a hairpin on the first spacer note (the one coinciding
+with the real note) exposes an embarassing bug.
 
 
 
@@ -1583,10 +1584,15 @@ In the @code{percent} style, a note pattern can be repeated. It is
 printed once, and then the pattern is replaced with a special sign.
 
 @lilypond[verbatim,singleline]
- \context Voice { \repeat  "percent" 5  { c'1 } }  
+ \context Voice { \repeat  "percent" 4  { c'4 }
+    \repeat "percent" 2 { c'2 es'2 f'4 fis'4 g'4 c''4 }
+}
 @end lilypond
 
-At present, only repeats of whole measures are supported.
+@refbugs
+
+You can not nest percent repeats, filling in the first measure with
+slashes, and repeating that measure with percents.
 
 @node Rhythmic music
 @section Rhythmic music
@@ -2169,7 +2175,7 @@ scheme = \notes {
 
 \score {
   <
-    \context ChordNamesVoice \scheme
+    \context ChordNames \scheme
     \context Staff \scheme
   >
 }
@@ -2611,6 +2617,29 @@ Formally the syntax for these constructions is
 Here @var{symbol} is a Scheme expression of symbol type, @var{context}
 and @var{grobname} are strings and @var{value} is a Scheme expression.
 
+If you want to be
+Correct nesting of @code{\override}, @code{\set}, @code{\revert} is as
+follows
+
+@example 
+\override \set \set \set \set
+\revert
+@end example
+
+This is always correct, but if you know the default value, you can also use 
+@example
+\set \set \set \set
+\set @var{to default value}
+@end example
+
+If there is no default (i.e. by default, the grob property is unset),
+then you can use
+@example
+\set \set \set \set \set
+\revert
+@end example
+
+
 @refbugs
 
 LilyPond will hang or crash if @var{value} contains cyclic references.
@@ -3338,107 +3367,6 @@ will complain about not finding @code{src:X:Y} files. Those complaints are
 harmless, and can be ignored.
 
 
-@c . {Using LilyPond}
-@node Using LilyPond
-@section Using LilyPond
-@cindex Using LilyPond
-@cindex Generating output
-
-@c slaat dit ergens op?
-
-@c direct postscript?
-
-@table @code
-@item plain lilypond
-@example
-lilypond foo.ly
-@end example
-For more information on how to use lilypond see
-@ifnottex
-@ref{Invoking LilyPond}.
-@end ifnottex
-@iftex
-the online manual.
-@end iftex
-
-@item ly2dvi
-Ly2dvi produces titling from @code{\header} fields.
-@example
-ly2dvi foo.ly
-@end example
-For more information on how to use ly2dvi see
-@ifnottex
-@ref{ly2dvi}.
-@end ifnottex
-@iftex
-the online manual.
-@end iftex
-
-@item lilypond-book
-Lilypond-book supports interleaving text and music.
-@example
-lilypond-book foo.doc
-@end example
-For more information on how to use lilypond-book see
-@ifnottex
-@ref{lilypond-book}.
-@end ifnottex
-@iftex
-the online manual.
-@end iftex
-@end table
-
-
-An emacs mode for LilyPond is included with the source archive as
-@file{lilypond-mode.el} and @file{lilypond-font-lock.el}.  If you have
-an RPM, it is in @file{/usr/share/doc/lilypond-X/}.  You have to install
-it yourself.
-
-Add this to your ~/.emacs or ~/.emacs.el:
-@example 
-    (load-library "lilypond-mode.el")
-    (setq auto-mode-alist
-      (cons '("\\.ly$" . LilyPond-mode) auto-mode-alist))
-    (add-hook 'LilyPond-mode-hook (lambda () (turn-on-font-lock)))
-@end example
-
-If you have the latest LilyPond-1.3.x Debian package, LilyPond-mode
-is automatically loaded, so you need not modify your ~/.emacs file.
-
-@menu
-* Pre-cooked makefile::         
-@end menu
-
-@node Pre-cooked makefile
-@subsection Pre-cooked makefile
-
-@c waar deze info?  is uiteindelijk wel handig, schat ik.
-[TODO: cut blabla]
-If you have a big music project, or just a lot of LilyPond input files,
-all generated output from LilyPond, @TeX{} and metafont will clutter
-your working directory.  LilyPond comes with a one-size-fits-all
-pre-cooked makefile that helps you manage producing ouptut.  It will
-produce all output in @file{out}, generate and track dependencies.
-Also, it helps in preparing your submission to the @ref{Mutopia
-project}.
-
-@file{make/ly.make}
-@example
-mkdir my-project
-cd my-project
-cp /usr/share/lilypond/make/ly.make GNUmakefile
-cp /usr/share/doc/lilypond/examples/input/tutorial/menuet.ly .
-make menuet
-[..]
-Generated out/menuet.ps for target menuet.
-@end example
-
-Type @samp{make help} to see possible targets.
-
-[TODO]
-@file{/usr/share/lilypond/doc/lilypond/examples/input/mutopia-header.ly}
-
-
 @node Interpretation context
 @section Interpretation context
 
diff --git a/Documentation/user/tutorial.itely b/Documentation/user/tutorial.itely
index 04265373c0..415d95ac8c 100644
--- a/Documentation/user/tutorial.itely
+++ b/Documentation/user/tutorial.itely
@@ -1827,3 +1827,40 @@ files in @file{input} and @file{input/test}.  You can also look at Real
 Music (TM), have a look at the @ref{Mutopia project}.
 
 
+
+[TODO figure out what to do with this: ]
+
+@menu
+* Pre-cooked makefile::         
+@end menu
+
+@node Pre-cooked makefile
+@subsection Pre-cooked makefile
+
+@c waar deze info?  is uiteindelijk wel handig, schat ik.
+[TODO: cut blabla]
+
+If you have a big music project, or just a lot of LilyPond input files,
+all generated output from LilyPond, @TeX{} and metafont will clutter
+your working directory.  LilyPond comes with a one-size-fits-all
+pre-cooked makefile that helps you manage producing ouptut.  It will
+produce all output in @file{out}, generate and track dependencies.
+Also, it helps in preparing your submission to the @ref{Mutopia
+project}.
+
+@file{make/ly.make}
+@example
+mkdir my-project
+cd my-project
+cp /usr/share/lilypond/make/ly.make GNUmakefile
+cp /usr/share/doc/lilypond/examples/input/tutorial/menuet.ly .
+make menuet
+[..]
+Generated out/menuet.ps for target menuet.
+@end example
+
+Type @samp{make help} to see possible targets.
+
+[TODO]
+@file{/usr/share/lilypond/doc/lilypond/examples/input/mutopia-header.ly}
+
diff --git a/VERSION b/VERSION
index 1eeef491e1..959790eb7e 100644
--- a/VERSION
+++ b/VERSION
@@ -2,7 +2,7 @@ PACKAGE_NAME=LilyPond
 MAJOR_VERSION=1
 MINOR_VERSION=3
 PATCH_LEVEL=141
-MY_PATCH_LEVEL=jcn2
+MY_PATCH_LEVEL=jcn3
 
 # use the above to send patches: MY_PATCH_LEVEL is always empty for a
 # released version.
diff --git a/input/bugs/crescendo-squash.ly b/input/bugs/crescendo-squash.ly
new file mode 100644
index 0000000000..b143968366
--- /dev/null
+++ b/input/bugs/crescendo-squash.ly
@@ -0,0 +1,9 @@
+
+
+ % < becomes | 
+\score {\notes { \context Staff < f''1
+   { s4 \< \! s4 } > }
+
+  \paper { linewidth = -1.;  }
+  }
+
diff --git a/input/regression/dynamics-broken-hairpin.ly b/input/regression/dynamics-broken-hairpin.ly
new file mode 100644
index 0000000000..2aef2493fe
--- /dev/null
+++ b/input/regression/dynamics-broken-hairpin.ly
@@ -0,0 +1,12 @@
+\header{
+texidoc = "Broken crescendi should look be open on one side.";
+}
+
+\score { \notes \relative c'' { 
+    c1 \< \break \! c1  \> \break \! c1 
+  }
+  \paper {
+    linewidth = 10.\cm;
+  }
+}
+  
diff --git a/input/regression/dynamics-line.ly b/input/regression/dynamics-line.ly
index 95f6b6068c..9ab480cb62 100644
--- a/input/regression/dynamics-line.ly
+++ b/input/regression/dynamics-line.ly
@@ -1,7 +1,8 @@
 \header{
 texidoc=" Dynamics appear below or above the staff.  If multiple
 dynamics are linked with (de)crescendi, they should be on the same
-line. Isolated dynamics may be forced up or down.  ";
+line. Isolated dynamics may be forced up or down.
+ ";
 }
 
 
diff --git a/input/regression/percent-repeat.ly b/input/regression/percent-repeat.ly
new file mode 100644
index 0000000000..2080187b99
--- /dev/null
+++ b/input/regression/percent-repeat.ly
@@ -0,0 +1,18 @@
+\header {
+texidoc = "Measure and beat repeats are supported.";
+}
+	
+\score { \notes \relative c' \context Voice { \time 4/4;
+   \repeat "percent" 2 { c2 }
+
+   % the chairman dances
+   \repeat "percent" 2 { g'8 g c, c  }   
+   \repeat "percent" 4 { b8 b8  }
+   \repeat "percent" 2 { c8 d es f g4 r4  }   
+   
+   % riff
+   \repeat "percent" 2 { r8. a16 g8. a16 bes8. a16 f8 d |  a c8 ~ c8 d8 ~ d8 r8 r4 }
+   
+
+
+     }}
diff --git a/input/star-spangled-banner.ly b/input/star-spangled-banner.ly
index c72646beff..4f79f9dafb 100644
--- a/input/star-spangled-banner.ly
+++ b/input/star-spangled-banner.ly
@@ -1,7 +1,7 @@
 %{
-Converted from star.mup with the aid of mup2ly.py
-http://www.Arkkra.com/doc/star.html
-http://www.Arkkra.com/doc/star.ps
+Converted from star.mup with the aid of the old mup2ly.py
+http://www.arkkra.com/doc/star.html
+http://www.arkkra.com/doc/star.ps
 %}
 
 
diff --git a/input/test/test-german-chords.ly b/input/test/test-german-chords.ly
new file mode 100644
index 0000000000..0df2a1a39d
--- /dev/null
+++ b/input/test/test-german-chords.ly
@@ -0,0 +1,14 @@
+\include "german-chords.ly"
+% #(set! german-Bb #t)
+
+ch = \chords { beses1/+beses bes/+bes b/+b bis/+bis ases/+ases as/+as a/+a ais/+ais fisis/+fisis}
+
+
+\score {
+   <
+   \context ChordNames=ch {\ch}
+   \context Staff=st \chords {\ch}
+   >
+   \paper {}
+}
+
diff --git a/input/tricks/follow-thread.ly b/input/tricks/follow-thread.ly
index 30dfa9d1fc..c09efe2075 100644
--- a/input/tricks/follow-thread.ly
+++ b/input/tricks/follow-thread.ly
@@ -2,14 +2,14 @@
 \header{
 texidoc="
 Theads can be traced automagically when they switch staffs by setting
-property @code{followThread}.
+property @code{followVoice}.
 ";
 }
 % followThread: connect note heads with line when thread switches staff 
 
 fragment = \notes {
   \context PianoStaff <
-    \property PianoStaff.followThread = ##t
+    \property PianoStaff.followVoice = ##t
     \context Staff \context Voice {
       c'1
       \translator Staff=two
diff --git a/lily/hairpin.cc b/lily/hairpin.cc
index 23de3362d4..4fc4bce8d3 100644
--- a/lily/hairpin.cc
+++ b/lily/hairpin.cc
@@ -76,16 +76,33 @@ Hairpin::brew_molecule (SCM smob)
   bool continued = broken[Direction (-grow_dir)];
   Real height = gh_scm2double (me->get_grob_property ("height"));
   Real thick = line * gh_scm2double (me->get_grob_property ("thickness"));
+
+  Real starth, endh;
+  if (grow_dir < 0)
+    {
+      starth = height;
+      endh = continued ? height/2 : 0.0;
+    }
+  else
+    {
+      starth = continued ? height/2 : 0.0;
+      endh = height;
+    }
   
-  const char* type = (grow_dir < 0) ? "decrescendo" :  "crescendo";
-  SCM hairpin = gh_list (ly_symbol2scm (type),
-		    gh_double2scm (thick),
-		    gh_double2scm (width),
-		    gh_double2scm (height),
-		    gh_double2scm (continued ? height/2 : 0.0),
-		    SCM_UNDEFINED);
-
-  Box b (Interval (0, width), Interval (-2*height, 2*height));
+  /*
+    TODO: junk this and, make a general
+
+    Lookup::line  (XY1, XY2).
+  */
+  SCM hairpin = gh_list (ly_symbol2scm ("hairpin"),
+			 gh_double2scm (thick),
+			 gh_double2scm (width),
+			 gh_double2scm (starth),
+			 gh_double2scm (endh),
+			 SCM_UNDEFINED);
+
+  Interval yext = 2* height  * Interval (-1,1);
+  Box b (Interval (0, width), yext);
   Molecule mol (b, hairpin);
   mol.translate_axis (broken_left + extra_off[LEFT], X_AXIS);
 
diff --git a/lily/include/lookup.hh b/lily/include/lookup.hh
index 4a3dea7e0f..8f954757df 100644
--- a/lily/include/lookup.hh
+++ b/lily/include/lookup.hh
@@ -24,7 +24,8 @@ struct Lookup
   static Molecule beam (Real, Real, Real) ;
   static Molecule dashed_slur (Bezier, Real thick, Real dash) ;
   static Molecule blank (Box b) ;
-  static Molecule filledbox (Box b) ;  
+  static Molecule filledbox (Box b) ;
+  static Molecule repeat_slash( Real w, Real slope, Real th);
 };
 
 #endif // LOOKUP_HH
diff --git a/lily/include/percent-repeat-item.hh b/lily/include/percent-repeat-item.hh
new file mode 100644
index 0000000000..057144c5d7
--- /dev/null
+++ b/lily/include/percent-repeat-item.hh
@@ -0,0 +1,25 @@
+/*   
+  percent-repeat-item.hh -- declare Percent_repeat_item_interface
+  
+  source file of the GNU LilyPond music typesetter
+  
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  
+ */
+
+#ifndef PERCENT_REPEAT_ITEM_HH
+#define PERCENT_REPEAT_ITEM_HH
+
+#include "grob.hh"
+
+class Percent_repeat_item_interface
+{
+public:
+  DECLARE_SCHEME_CALLBACK (beat_slash, (SCM ));  
+  DECLARE_SCHEME_CALLBACK (double_percent, (SCM ));
+  static Molecule x_percent (Grob*,int,Real,Real );
+  static Molecule brew_slash (Grob*);
+};
+
+#endif /* PERCENT_REPEAT_ITEM_HH */
+
diff --git a/lily/lookup.cc b/lily/lookup.cc
index f2e89466b6..b01db45413 100644
--- a/lily/lookup.cc
+++ b/lily/lookup.cc
@@ -355,3 +355,21 @@ Lookup::accordion (SCM s, Real staff_space, Font_metric *fm)
   return m;  
 }
 
+/*
+  TODO: should use slope instead?  Angle gives nasty rad <-> degree
+  conversions.
+*/
+Molecule
+Lookup::repeat_slash (Real w, Real s, Real t)
+{
+  SCM wid = gh_double2scm (w);
+  SCM sl = gh_double2scm (s);
+  SCM thick = gh_double2scm (t);
+  SCM slashnodot = gh_list (ly_symbol2scm ("repeat-slash"),
+			    wid, sl, thick, SCM_UNDEFINED);
+
+  Box b (Interval (0, w + sqrt (sqr(t/s) + sqr (t))),
+	 Interval (0, w * s));
+
+  return Molecule (b, slashnodot);
+}
diff --git a/lily/multi-measure-rest.cc b/lily/multi-measure-rest.cc
index f216aeac8a..890c0d1562 100644
--- a/lily/multi-measure-rest.cc
+++ b/lily/multi-measure-rest.cc
@@ -19,6 +19,8 @@
 #include "spanner.hh"
 #include "staff-symbol-referencer.hh"
 #include "text-item.hh"
+#include "percent-repeat-item.hh"
+
 
 void
 Multi_measure_rest::set_interface (Grob*me)
@@ -36,12 +38,13 @@ MAKE_SCHEME_CALLBACK (Multi_measure_rest,percent,1);
 SCM
 Multi_measure_rest::percent (SCM smob)
 {
+  
   Grob *me = unsmob_grob (smob);
   Spanner *sp = dynamic_cast<Spanner*> (me);
   
   Font_metric *musfont = Font_interface::get_default_font (me);
 			
-  Molecule r (musfont->find_by_name ("scripts-repeatsign"));
+  Molecule r = Percent_repeat_item_interface::x_percent (me, 1,  0.75, 1.6);
 
   // ugh copy & paste.
   
diff --git a/lily/percent-repeat-engraver.cc b/lily/percent-repeat-engraver.cc
index b063ad4660..994288da64 100644
--- a/lily/percent-repeat-engraver.cc
+++ b/lily/percent-repeat-engraver.cc
@@ -16,6 +16,10 @@
 #include "spanner.hh"
 #include "item.hh"
 #include "percent-repeat-iterator.hh"
+#include "bar.hh"
+
+#include "score-engraver.hh"
+#include "translator-group.hh"
 
 /**
   This acknowledges repeated music with "percent" style.  It typesets
@@ -52,7 +56,9 @@ protected:
     MEASURE,
     DOUBLE_MEASURE,
   } repeat_sign_type_ ;
-  
+
+  Item * beat_slash_;
+  Item * double_percent_;
   Spanner * perc_p_;
   Spanner * finished_perc_p_;
   Item * stem_tremolo_;
@@ -70,6 +76,9 @@ Percent_repeat_engraver::Percent_repeat_engraver ()
   perc_p_  = finished_perc_p_ = 0;
   repeat_ =0;
   stem_tremolo_ = 0;
+
+  beat_slash_ = 0;
+  double_percent_ = 0;
 }
 
 bool
@@ -89,25 +98,25 @@ Percent_repeat_engraver::try_music (Music * m)
       stop_mom_ = start_mom_ + Moment (count) * body_length_;
       next_moment_ = start_mom_ + body_length_;
 
-      SCM m = get_property ("timeSignatureFraction");
-      Moment mlen (1,
-		  gh_scm2int (gh_cdr (m)));
+      SCM m = get_property ("measureLength");
+      Moment meas_len;
+      if (unsmob_moment (m))
+	meas_len = *unsmob_moment (m);
 
-      if (mlen == body_length_)
+      if (body_length_ < meas_len &&
+	  meas_len.mod_rat (body_length_) == Moment (0,0))
 	repeat_sign_type_ = BEAT;
+      else if (meas_len == body_length_)
+	repeat_sign_type_ = MEASURE;
+      else if (Moment (2)* meas_len == body_length_)
+	{
+	  repeat_sign_type_ = DOUBLE_MEASURE;
+	  next_moment_ += meas_len ;
+	}
       else
 	{
-	  mlen *= gh_scm2int (gh_car (m));
-	  if (mlen == body_length_)
-	    repeat_sign_type_ = MEASURE;
-	  else if (Moment (2)* mlen == body_length_)
-	    repeat_sign_type_ = DOUBLE_MEASURE;
-
-	  if (repeat_sign_type_ != MEASURE)
-	    {
-	      warning (_ ("Don't know yet how to handle this percent repeat."));
-	      return false;
-	    }
+	  warning (_ ("Don't know how to handle a percent repeat of this length."));
+	  return false;
 	}
 
       repeat_ = rp;
@@ -138,7 +147,8 @@ Percent_repeat_engraver::process_music ()
     {
       if (repeat_sign_type_ == BEAT)
 	{
-	  ;
+	  beat_slash_ = new Item (get_property ("RepeatSlash"));
+	  announce_grob (beat_slash_, repeat_);
 	}
       else if (repeat_sign_type_ == MEASURE)
 	{
@@ -149,10 +159,31 @@ Percent_repeat_engraver::process_music ()
 	  perc_p_->set_bound (LEFT, unsmob_grob (col));
 	  announce_grob (perc_p_, repeat_);
 	}
+      else if (repeat_sign_type_ == DOUBLE_MEASURE)
+	
+	{
+	  double_percent_ = new Item (get_property ("DoublePercentRepeat"));
+	  announce_grob (double_percent_, repeat_);
+
+      /*
+	forbid breaks on a % line. Should forbid all breaks, really.
+       */
+	  Score_engraver * e = 0;
+	  Translator * t  =  daddy_grav_l ();
+	  for (; !e && t;  t = t->daddy_trans_l_)
+	    {
+	      e = dynamic_cast<Score_engraver*> (t);
+	    }
 
+	  if (!e)
+	    programming_error ("No score engraver!");
+	  else
+	    e->forbid_breaks ();	// guh. Use properties!      
+	}
       next_moment_ = next_moment_ + body_length_;
     }
 }
+
 void
 Percent_repeat_engraver::finalize ()
 {
@@ -174,22 +205,38 @@ Percent_repeat_engraver::typeset_perc ()
       typeset_grob (finished_perc_p_);
       finished_perc_p_ = 0;
     }
+
+  if (beat_slash_)
+    {
+      typeset_grob (beat_slash_);
+      beat_slash_ = 0;
+    }
+
+  if (double_percent_)
+    {
+      typeset_grob (double_percent_);
+      double_percent_ = 0;
+    }
 }
 
 
 void
 Percent_repeat_engraver::acknowledge_grob (Grob_info info)
 {
+
 }
 
 
 void
 Percent_repeat_engraver::start_translation_timestep ()
 {
-  if (perc_p_ && stop_mom_ == now_mom ())
+  if (stop_mom_ == now_mom ())
     {
-      finished_perc_p_ = perc_p_;
-      typeset_perc ();
+      if (perc_p_)
+	{
+	  finished_perc_p_ = perc_p_;
+	  typeset_perc ();
+	}
       repeat_ = 0;
       perc_p_ = 0;
       repeat_sign_type_ = UNKNOWN;
diff --git a/lily/percent-repeat-item.cc b/lily/percent-repeat-item.cc
new file mode 100644
index 0000000000..373404428d
--- /dev/null
+++ b/lily/percent-repeat-item.cc
@@ -0,0 +1,85 @@
+/*   
+  percent-repeat-item.cc --  implement Percent_repeat_item_interface
+  
+  source file of the GNU LilyPond music typesetter
+  
+  (c) 2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
+  
+ */
+#include <math.h>
+
+#include "grob.hh"
+#include "lookup.hh"
+#include "molecule.hh"
+#include "font-interface.hh"
+#include "font-metric.hh" 
+#include "percent-repeat-item.hh"
+
+
+Molecule
+Percent_repeat_item_interface::brew_slash ( Grob *me)
+{
+  Real slope = gh_scm2double (me->get_grob_property ("slope"));
+  Real wid = 2.0 / slope;
+
+  /*
+    todo: check out if in staff-rule thickness normally.
+   */
+  Real thick = gh_scm2double (me->get_grob_property ("thickness"));
+  Molecule m = Lookup::repeat_slash (wid, slope, thick);
+  m.translate_axis (-m.extent (Y_AXIS).center (), Y_AXIS);
+  return m;
+}
+
+/*
+  todo: use grob props for dot_neg_kern, slash_neg_kern?
+ */
+Molecule
+Percent_repeat_item_interface::x_percent (Grob *me, int count,
+					  Real dot_neg_kern,
+					  Real slash_neg_kern)
+{
+  Molecule m ;
+  Molecule s = brew_slash (me);
+
+  for (int i  = count; i--;)
+    {
+      m.add_at_edge (X_AXIS, RIGHT, s, -slash_neg_kern);
+    }
+  Molecule d1 = Font_interface::get_default_font (me)->find_by_name ("dots-dot");
+  Molecule d2  =  d1;
+  d1.translate_axis (0.5, Y_AXIS );
+  d2.translate_axis (-0.5, Y_AXIS);
+  
+  m.add_at_edge (X_AXIS, LEFT, d1, -dot_neg_kern);
+  m.add_at_edge (X_AXIS, RIGHT, d2, -dot_neg_kern);
+
+  return m;
+}
+
+MAKE_SCHEME_CALLBACK(Percent_repeat_item_interface,double_percent,1);
+SCM
+Percent_repeat_item_interface::double_percent (SCM grob)
+{
+  Grob *me = unsmob_grob (grob);
+  Molecule m = x_percent (me, 2, 0.75, 1.6);
+  m.translate_axis (- m.extent (X_AXIS).center (), X_AXIS);
+  return m.smobbed_copy ();
+}
+
+MAKE_SCHEME_CALLBACK(Percent_repeat_item_interface,beat_slash,1);
+SCM
+Percent_repeat_item_interface::beat_slash (SCM grob)
+{
+  Grob *me = unsmob_grob (grob);
+  Molecule m = brew_slash (me);
+
+  return m.smobbed_copy ();
+}
+
+
+
+
+
+
+
diff --git a/lily/system-start-delimiter-engraver.cc b/lily/system-start-delimiter-engraver.cc
index 1f4504a733..27ee99dc86 100644
--- a/lily/system-start-delimiter-engraver.cc
+++ b/lily/system-start-delimiter-engraver.cc
@@ -53,6 +53,14 @@ System_start_delimiter_engraver::acknowledge_grob (Grob_info inf)
       if (gh_symbol_p (gl) && gl  == ly_symbol2scm ("brace")
 	  && gh_symbol_p (my_gl) && my_gl == ly_symbol2scm ("bracket"))
 	inf.elem_l_->translate_axis (-1.0, X_AXIS); // ugh
+      else if (gh_symbol_p (gl) && gl  == ly_symbol2scm ("bracket")
+	       && gh_symbol_p (my_gl) && my_gl == ly_symbol2scm ("bracket"))
+	{
+	  inf.elem_l_->translate_axis ( -0.8, X_AXIS); // ugh
+          inf.elem_l_->set_grob_property ("arch-height",
+	  gh_double2scm(gh_scm2double(inf.elem_l_->get_grob_property
+				      ("arch-height"))+0.5));
+        }
     }
 
 }
diff --git a/lily/system-start-delimiter.cc b/lily/system-start-delimiter.cc
index 39bd68040e..5d4cb3d67a 100644
--- a/lily/system-start-delimiter.cc
+++ b/lily/system-start-delimiter.cc
@@ -32,6 +32,25 @@ System_start_delimiter::staff_bracket (Grob*me,Real height)
 		    me->get_grob_property ("bracket-thick"),
 		    SCM_UNDEFINED);
 
+  /*
+TODO: sort this out.
+    
+Another thing:
+In system-start-delimiter.cc I see the line
+
+  Real h = height + 2 * arc_height;
+
+But I really think that you mean
+
+ Real h = height + 2 * arc_width;
+
+(arc_height changes the x-axis-size of arc ; arc_width changes the
+y-axis-size)
+Will not fix it since I'm not sure.
+
+-Rune
+  
+   */
   Real h = height + 2 * arc_height;
   Box b (Interval (0, 1.5), Interval (-h/2, h/2));
   Molecule mol (b, at);
diff --git a/lily/tuplet-engraver.cc b/lily/tuplet-engraver.cc
index 7568a08679..0e7d238247 100644
--- a/lily/tuplet-engraver.cc
+++ b/lily/tuplet-engraver.cc
@@ -110,6 +110,16 @@ Tuplet_engraver::acknowledge_grob (Grob_info i)
     }
   else if (Beam::has_interface (i.elem_l_))
     {
+      /*
+	TODO:
+	
+	ugh, superfluous. Should look at
+
+	tuplet -> note-column -> stem -> beam
+
+	to find the beam(s) of a tuplet
+       */
+      
       for (int j = 0; j < started_span_p_arr_.size (); j++)
 	if (started_span_p_arr_[j]) 
 	  Tuplet_bracket::add_beam (started_span_p_arr_[j],i.elem_l_);
diff --git a/ly/german-chords.ly b/ly/german-chords.ly
new file mode 100644
index 0000000000..e158592b34
--- /dev/null
+++ b/ly/german-chords.ly
@@ -0,0 +1,39 @@
+
+%  german-chords.ly:
+% german/norwegian/danish?
+
+% To get Bb instead of B, use
+% \include "german-chords.ly"
+% #(set! german-Bb #t)
+
+#(define german-Bb #f)
+
+#(define (pitch->chord-name-text-banter pitch)
+   (if (equal? (cdr pitch) '(6 -1))
+     (if german-Bb
+       (cons "B" (accidental->text -1))
+       '("B")
+     )
+     (cons
+       (list-ref '("C" "D" "E" "F" "G" "A" "H") (cadr pitch))
+       (accidental->text (caddr pitch))
+     )
+   )
+ )   
+
+
+#(define (pitch->note-name-text-banter pitch)
+   (if (equal? (cdr pitch) '(6 -1))
+     '("b")
+     (cons
+       (string-append
+	  (list-ref '("c" "d" "e" "f" "g" "a" "h") (cadr pitch))
+	  (if (or (equal? (cadr pitch) 2) (equal? (cadr pitch) 5))
+	    (list-ref '( "ses"  "s" "" "is" "isis") (+ 2 (caddr pitch)))
+	    (list-ref '("eses" "es" "" "is" "isis") (+ 2 (caddr pitch)))
+	  )
+       )
+       '()
+     )
+   )
+ )
diff --git a/mf/feta-schrift.mf b/mf/feta-schrift.mf
index f4fc744a27..8ddcc5d1d6 100644
--- a/mf/feta-schrift.mf
+++ b/mf/feta-schrift.mf
@@ -585,25 +585,6 @@ fet_beginchar("Flageolet", "flageolet", "flageolet")
 	draw z1..z2..z3..z4..cycle;
 fet_endchar;
 
-fet_beginchar("Repeatsign", "repeatsign", "repeatsign")
-	set_char_box(staff_space#, staff_space#, staff_space#, staff_space#);
-
-	save dot_diam;
-	2 dot_diam# = staff_space# - stafflinethickness#;
-	define_pixels(dot_diam);
-
-	penpos1(dot_diam,0);
-	z1l=(-b,-d);
-	penpos2(dot_diam,0);
-	z2r=(w,h);
-	filldraw z1l--z2l{right}--z2r{down}--z1r{right}--cycle;
-        penlabels (1,2);
-
-	pickup pencircle scaled dot_diam;
-        draw (-staff_space/2, staff_space/2);
-        draw (staff_space/2, -staff_space/2);
-fet_endchar;
-
 fet_beginchar("Segno", "segno", "segno")
 	save thin, thick, ball_diam, darkness, pointheight;
 	save wd, ht, thick_nibangle, ball_nib_thick;
diff --git a/ps/lily.ps b/ps/lily.ps
index de0f845dd0..b5406ca0ac 100644
--- a/ps/lily.ps
+++ b/ps/lily.ps
@@ -5,6 +5,11 @@
 % round cappings 
 1 setlinecap
 
+/euclidean_length  
+{ 
+	1 copy mul exch 1 copy mul add sqrt 
+} bind def 
+
 /draw_beam % width slope thick 
 { 
         2 div /beam_thick exch def 
@@ -18,40 +23,34 @@
         closepath fill 
 } bind def 
 
-/draw_decrescendo %  width height cons thick 
-{ 
-	setlinewidth 
-	/cresc_cont exch def 
-	/cresc_ht exch def 
-	/cresc_wd exch def 
-
-	cresc_wd cresc_cont moveto 
-	0 cresc_ht lineto 
-	stroke 
-	cresc_wd cresc_cont neg moveto 
-	0 cresc_ht neg lineto 
-	stroke 
-} bind def 
-
-/draw_crescendo % width height cons thick 
-{ 
-	setlinewidth 
-	/cresc_cont exch def 
-	/cresc_ht exch def 
-	/cresc_wd exch def 
-
-	0 cresc_cont moveto 
-	cresc_wd cresc_ht lineto 
-	stroke 
-	0 cresc_cont neg moveto 
-	cresc_wd cresc_ht neg lineto 
-	stroke 
-} bind def 
+/draw_repeat_slash % width slope thick
+{
+  /beamthick exch def
+  /slope exch def
+  /width exch def
+  beamthick beamthick slope div euclidean_length
+    /xwid exch def 
+  0 0 moveto
+  xwid 0  rlineto
+  width slope width mul rlineto
+  xwid neg 0 rlineto
+%  width neg width angle sin mul neg rlineto
+  closepath fill
+} bind def
 
-/lily_distance  
-{ 
-	1 copy mul exch 1 copy mul add sqrt 
-} bind def 
+/draw_hairpin % width start_h end_h thick
+{
+  setlinewidth
+  /end_h exch def 
+  /start_h exch def
+  /wid exch def
+  0 start_h moveto
+  wid end_h lineto
+  stroke
+  0 start_h neg moveto
+  wid end_h neg lineto
+  stroke
+} bind def
 
 /draw_tuplet % height gap dx dy thick dir 
 { 
@@ -101,6 +100,7 @@
 } bind def
 
 % simple, but does it work everywhere?
+% explain ? --hwn
 /draw_ez_ball % ch letter_col ball_col font
 {
 	% font
diff --git a/scm/chord-name.scm b/scm/chord-name.scm
index bcdf7aaa1f..5bbb2017e4 100644
--- a/scm/chord-name.scm
+++ b/scm/chord-name.scm
@@ -253,11 +253,9 @@
 
 (define (pitch->note-name pitch)
   (cons (cadr pitch) (caddr pitch)))
-  
-(define (pitch->text pitch)
-  (cons
-    (make-string 1 (integer->char (+ (modulo (+ (cadr pitch) 2) 7) 65)))
-    (if (= (caddr pitch) 0)
+
+(define (accidental->text acc)
+    (if (= acc 0)
       '()
       (list
        (append '(music)
@@ -268,7 +266,15 @@
 				(list (append '((raise . 0.6))
 				  (list
 				   (string-append "accidentals-" 
-						  (number->string (caddr pitch)))))))))))))))
+						  (number->string acc))))))))))))
+)
+
+(define (pitch->text pitch)
+  (cons
+    (make-string 1 (integer->char (+ (modulo (+ (cadr pitch) 2) 7) 65)))
+    (accidental->text (caddr pitch))
+  )
+)
 
 ;;; Hooks to override chord names and note names, 
 ;;; see input/tricks/german-chords.ly
diff --git a/scm/grob-description.scm b/scm/grob-description.scm
index d12715908c..a1fdc784cf 100644
--- a/scm/grob-description.scm
+++ b/scm/grob-description.scm
@@ -9,7 +9,18 @@
 ; staffspace (distances)
 
 (define all-grob-descriptions
-  `((Arpeggio . (
+  `(
+    (Accidentals . (
+		(molecule-callback . ,Local_key_item::brew_molecule)
+		(X-offset-callbacks . (,Side_position_interface::aligned_side))
+		(after-line-breaking-callback . ,Local_key_item::after_line_breaking)
+		(direction . -1)
+		(left-padding . 0.2)
+		(right-padding . 0.4)
+		(meta . ,(grob-description "Accidentals"  accidentals-interface font-interface side-position-interface))
+	))
+
+    (Arpeggio . (
 	       (X-extent-callback . ,Arpeggio::width_callback)
 	       (Y-extent-callback . #f)	       
 	       (molecule-callback . ,Arpeggio::brew_molecule)
@@ -139,21 +150,6 @@
                (meta . ,(grob-description "Custos" custos-interface staff-symbol-referencer-interface break-aligned-interface) )
        ))
 	
-	(Hairpin . (
-		(molecule-callback . ,Hairpin::brew_molecule)
-		(thickness . 1.0)
-		(height . 0.6666)
-		(spacing-procedure . ,Spanner::set_spacing_rods)
-		(minimum-length . 2.0)
-		(if-text-padding . 1.0)
-		(width-correct . -1.0)
-		
-		(dash-thickness . 1.2)
-		(dash-length . 4.0)
-		(self-alignment-Y . 0)
-		(Y-offset-callbacks . (,Side_position_interface::aligned_on_self))
-		(meta . ,(grob-description "Hairpin" hairpin-interface dynamic-interface))
-	))
 
 	(DotColumn . (
 		(axes 0 )
@@ -167,6 +163,17 @@
 		(Y-offset-callbacks  . (,Dots::quantised_position_callback ,Staff_symbol_referencer::callback))
 		(meta . ,(grob-description "Dots"  font-interface dots-interface ))
 	))
+	(DoublePercentRepeat
+	 . ((molecule-callback . ,Percent_repeat_item_interface::double_percent)
+	    (breakable . #t)
+	    (slope . 1.0)
+	    (font-family . music)
+	    (width . 2.0)
+	    (thickness . 0.48)
+	    (break-align-symbol . Staff_bar)
+	    (visibility-lambda . ,begin-of-line-invisible)
+	    (meta . ,(grob-description "DoublePercentRepeat" font-interface percent-repeat-interface))
+	    ))
 	
 	(DynamicText . (
 		(Y-offset-callbacks . (,Side_position_interface::aligned_on_self))
@@ -220,14 +227,20 @@
 		(axes 1)
 		(meta . ,(grob-description "HaraKiriVerticalGroup" axis-group-interface hara-kiri-group-interface))
 	))
-
-	(LyricHyphen . (
+	(Hairpin . (
+		(molecule-callback . ,Hairpin::brew_molecule)
 		(thickness . 1.0)
-		(height . 0.4)
-		(minimum-length .  0.5) 
-		(molecule-callback . ,Hyphen_spanner::brew_molecule)
-		(Y-extent-callback . ,Grob::point_dimension_callback)
-		(meta . ,(grob-description "LyricHyphen" lyric-hyphen-interface ))
+		(height . 0.6666)
+		(spacing-procedure . ,Spanner::set_spacing_rods)
+		(minimum-length . 2.0)
+		(if-text-padding . 1.0)
+		(width-correct . -1.0)
+		
+		(dash-thickness . 1.2)
+		(dash-length . 4.0)
+		(self-alignment-Y . 0)
+		(Y-offset-callbacks . (,Side_position_interface::aligned_on_self))
+		(meta . ,(grob-description "Hairpin" hairpin-interface dynamic-interface))
 	))
 	
 	(InstrumentName . (
@@ -253,14 +266,14 @@
 	  (meta . ,(grob-description "KeySignature" key-signature-interface  font-interface  break-aligned-interface))
 	))
 	
-	(Accidentals . (
-		(molecule-callback . ,Local_key_item::brew_molecule)
-		(X-offset-callbacks . (,Side_position_interface::aligned_side))
-		(after-line-breaking-callback . ,Local_key_item::after_line_breaking)
-		(direction . -1)
-		(left-padding . 0.2)
-		(right-padding . 0.4)
-		(meta . ,(grob-description "Accidentals"  accidentals-interface font-interface side-position-interface))
+
+	(LyricHyphen . (
+		(thickness . 1.0)
+		(height . 0.4)
+		(minimum-length .  0.5) 
+		(molecule-callback . ,Hyphen_spanner::brew_molecule)
+		(Y-extent-callback . ,Grob::point_dimension_callback)
+		(meta . ,(grob-description "LyricHyphen" lyric-hyphen-interface ))
 	))
 	
 	(LineOfScore . (
@@ -415,15 +428,20 @@
 	(PercentRepeat . (
 		(spacing-procedure . ,Multi_measure_rest::set_spacing_rods)
 		(molecule-callback . ,Multi_measure_rest::percent)
-		(staff-position . 0)
-		(expand-limit . 10)
-		(padding . 2.0) ; staffspace
+		(slope . 1.0)
+		(thickness . 0.48)
 		(minimum-width . 12.5) ; staffspace
 		(font-family . music)
-		(meta . ,(grob-description "PercentRepeat" multi-measure-rest-interface  font-interface))
+		(meta . ,(grob-description "PercentRepeat" multi-measure-rest-interface  font-interface percent-repeat-interface))
 	))
 
 	
+	(RepeatSlash . (
+			(molecule-callback . , Percent_repeat_item_interface::beat_slash)
+			(thickness . 0.48)
+			(slope . 1.7)
+			(meta . ,(grob-description "RepeatSlash" percent-repeat-interface))
+			))
 	(Rest . (
 		(after-line-breaking-callback . ,Rest::after_line_breaking)
 		(X-extent-callback . ,Rest::extent_callback)
diff --git a/scm/interface-description.scm b/scm/interface-description.scm
index 3116029953..61f746d6f0 100644
--- a/scm/interface-description.scm
+++ b/scm/interface-description.scm
@@ -6,7 +6,7 @@
 ;;;;                 Jan Nieuwenhuizen <janneke@gnu.org>
 
 
-; should include default value?
+					; should include default value?
 
 
 ;;; FIXME: naming.
@@ -27,18 +27,18 @@
 (define (grob-description name . interfaces)
   (let* ((ifs (cons general-grob-interface interfaces))
 	 (props (map caddr ifs))
-;	 (prop-typep-pairs (map (lambda (x) (cons (car x) (cadr x)))
-;					(apply append props)))
+					;	 (prop-typep-pairs (map (lambda (x) (cons (car x) (cadr x)))
+					;					(apply append props)))
 	 (syms (map car ifs))
-	)
+	 )
     (list (cons 'separator "\n\n\n")	;easy printing.
 	  (cons 'name name)
 	  (cons 'interfaces syms)
 	  (cons 'interface-descriptions ifs)
-	  ; (cons 'interface-descriptions (cadr merged))
+					; (cons 'interface-descriptions (cadr merged))
 	  ;; description of the grob itself?
-;	  (cons 'properties prop-typep-pairs)
-  )))
+					;	  (cons 'properties prop-typep-pairs)
+	  )))
 
 
 (lily-interface
@@ -190,7 +190,7 @@
  '(
    left-padding 
    right-padding 
- ))
+   ))
 
 
 
@@ -758,22 +758,26 @@ direction = Forced direction for all ties"
    '(direction
    ))
 
+(lily-interface
+ 'percent-repeat-interface
+ "Repeats that look like percent signs"
+ '(angle thickness))
 
-  (lily-interface
-   'volta-bracket-interface
-   "Volta bracket with number"
-   '(
-    bars  
-    thickness  
-    height  
-    ))
+(lily-interface
+ 'volta-bracket-interface
+ "Volta bracket with number"
+ '(
+   bars  
+   thickness  
+   height  
+   ))
 
 
-  (lily-interface
-   'span-bar-interface
-   "A bar line that spans other barlines (typically used to get cross-staff barlines."
-   '(
-    ))
+(lily-interface
+ 'span-bar-interface
+ "A bar line that spans other barlines (typically used to get cross-staff barlines."
+ '(
+   ))
 
 
 (eval (cons
@@ -784,3 +788,4 @@ direction = Forced direction for all ties"
 
 (define (interface-names) (map (lambda (x) (symbol->string (car x))) all-interfaces))
 
+
diff --git a/scm/ps.scm b/scm/ps.scm
index d17843731e..0f8011bf6d 100644
--- a/scm/ps.scm
+++ b/scm/ps.scm
@@ -67,11 +67,12 @@
   (define (char i)
     (invoke-char " show" i))
 
-  (define (crescendo thick w h cont )
-    (string-append 
-     (numbers->string (list w h (inexact->exact cont) thick))
-     " draw_crescendo"))
 
+  (define (hairpin thick width starth endh )
+    (string-append 
+     (numbers->string (list width starth endh thick))
+     " draw_hairpin"))
+  
   ;; what the heck is this interface ?
   (define (dashed-slur thick dash l)
     (string-append 
@@ -95,13 +96,11 @@
      " "
      (ly-number->string off)
      " ] 0 draw_dashed_line"))
-
-  (define (decrescendo thick w h cont)
-    (string-append 
-     (numbers->string (list w h (inexact->exact cont) thick))
-     " draw_decrescendo"))
-
-
+  
+  (define (repeat-slash wid slope thick)
+   (string-append (numbers->string (list wid slope thick))
+    " draw_repeat_slash"))
+  
   (define (end-output)
     "\nshowpage\n")
   
@@ -208,12 +207,11 @@ lilypondpaperoutputscale lilypondpaperoutputscale scale
 	    (define tuplet ,tuplet)
 	    (define bracket ,bracket)
 	    (define char ,char)
-	    (define crescendo ,crescendo)
+	    (define hairpin ,hairpin)
 	    (define volta ,volta)
 	    (define bezier-sandwich ,bezier-sandwich)
 	    (define dashed-line ,dashed-line) 
 	    (define dashed-slur ,dashed-slur) 
-	    (define decrescendo ,decrescendo) 
 	    (define end-output ,end-output)
 	    (define experimental-on ,experimental-on)
 	    (define filledbox ,filledbox)
@@ -231,20 +229,21 @@ lilypondpaperoutputscale lilypondpaperoutputscale scale
 	    (define stem ,stem)
 	    (define stop-line ,stop-line)
 	    (define stop-last-line ,stop-line)
+	    (define repeat-slash ,repeat-slash)
 	    (define text ,text)
 	    (define no-origin ,no-origin)
 	    (define define-origin ,define-origin)
 	    (define ez-ball ,ez-ball)
 	    ))
+	((eq? action-name 'repeat-slash) repeat-slash)
 	((eq? action-name 'tuplet) tuplet)
 	((eq? action-name 'beam) beam)
 	((eq? action-name 'bezier-sandwich) bezier-sandwich)
 	((eq? action-name 'bracket) bracket)
 	((eq? action-name 'char) char)
-	((eq? action-name 'crescendo) crescendo)
 	((eq? action-name 'dashed-line) dashed-line) 
 	((eq? action-name 'dashed-slur) dashed-slur) 
-	((eq? action-name 'decrescendo) decrescendo)
+	((eq? action-name 'hairpin) hairpin)
 	((eq? action-name 'experimental-on) experimental-on)
 	((eq? action-name 'filledbox) filledbox)
 	((eq? action-name 'ez-ball) ez-ball)	
diff --git a/scm/tex.scm b/scm/tex.scm
index 6f0e0e69f6..5e358449f9 100644
--- a/scm/tex.scm
+++ b/scm/tex.scm
@@ -47,8 +47,8 @@
   (define (dashed-slur thick dash l)
     (embedded-ps ((ps-scm 'dashed-slur)  thick dash l)))
 
-  (define (crescendo thick w h cont)
-    (embedded-ps ((ps-scm 'crescendo) thick w h cont)))
+  (define (hairpin thick w sh eh)
+    (embedded-ps ((ps-scm 'hairpin) thick w sh eh)))
 
   (define (char i)
     (string-append "\\char" (inexact->string i 10) " "))
@@ -56,9 +56,6 @@
   (define (dashed-line thick on off dx dy)
     (embedded-ps ((ps-scm 'dashed-line) thick on off dx dy)))
 
-  (define (decrescendo thick w h cont)
-    (embedded-ps ((ps-scm 'decrescendo) thick w h cont)))
-
   (define (font-load-command name-mag command)
     (string-append
      "\\font\\" command "="
@@ -86,6 +83,9 @@
   (define (experimental-on)
     "")
 
+  (define (repeat-slash w a t)
+    (embedded-ps ((ps-scm 'repeat-slash) w a t)))
+  
   (define (font-switch i)
     (string-append
      "\\" (font i) "\n"))
@@ -201,10 +201,9 @@
 	    (define bezier-sandwich ,bezier-sandwich)
 	    (define bracket ,bracket)
 	    (define char ,char)
-	    (define crescendo ,crescendo)
 	    (define dashed-line ,dashed-line) 
 	    (define dashed-slur ,dashed-slur) 
-	    (define decrescendo ,decrescendo) 
+	    (define hairpin ,hairpin) 
 	    (define end-output ,end-output)
 	    (define experimental-on ,experimental-on)
 	    (define filledbox ,filledbox)
@@ -226,15 +225,15 @@
 	    (define volta ,volta)
 	    (define define-origin ,define-origin)
 	    (define no-origin ,no-origin)
+	    (define repeat-slash ,repeat-slash)
 	    ))
 
 	((eq? action-name 'beam) beam)
 	((eq? action-name 'tuplet) tuplet)
 	((eq? action-name 'bracket) bracket)
-	((eq? action-name 'crescendo) crescendo)
+	((eq? action-name 'hairpin) hairpin)
 	((eq? action-name 'dashed-line) dashed-line) 
 	((eq? action-name 'dashed-slur) dashed-slur) 
-	((eq? action-name 'decrescendo) decrescendo) 
 	((eq? action-name 'end-output) end-output)
 	((eq? action-name 'experimental-on) experimental-on)
 	((eq? action-name 'font-def) font-def)
diff --git a/scripts/ly2dvi.py b/scripts/ly2dvi.py
index a29429947b..bb9d97188c 100644
--- a/scripts/ly2dvi.py
+++ b/scripts/ly2dvi.py
@@ -21,6 +21,8 @@ TODO:
   * dvi from lilypond .tex output?  This is hairy, because we create dvi
     from lilypond .tex *and* header output.
 
+  * windows compatibility: rm -rf, cp file... dir
+  
 '''
 
 
@@ -200,8 +202,9 @@ def setup_temp ():
 		os.mkdir (temp_dir, 0777)
 	except OSError:
 		pass
-		
-	
+	os.chdir (temp_dir)
+
+
 def system (cmd, ignore_error = 0):
 	if verbose_p:
 		progress (_ ("Invoking `%s\'") % cmd)
@@ -241,6 +244,7 @@ def set_setting (dict, key, val):
 option_definitions = [
 	('', 'h', 'help', _ ("this help")),
 	('KEY=VAL', 's', 'set', _ ("change global setting KEY to VAL")),
+	('DIR', 'I', 'include', _ ("add DIR to LilyPond\'s search path")),
 	('', 'P', 'postscript', _ ("generate PostScript output")),
 	('', 'k', 'keep', _ ("keep all output, and name the directory ly2dvi.dir")),
 	('', '', 'no-lily', _ ("don't run LilyPond")),
@@ -364,8 +368,10 @@ def global_latex_definition (tfiles, extra):
 
 	s = s + '\\usepackage{%s}\n' \
 		% string.join (extra['latexpackages'], ',')
-	
-	s = s + string.join (extra['latexheaders'], ' ')
+
+	if extra['latexheaders']:
+		s = s + '\\include{%s}\n' \
+			% string.join (extra['latexheaders'], '}\n\\include{')
 
 	textheight = ''
 	if extra['textheight']:
@@ -505,11 +511,15 @@ for opt in options:
 	elif o == '--warranty' or o == '-w':
 		warranty ()
 		sys.exit (0)
-		
-		
-include_path = map (os.path.abspath, include_path)
-files = map (os.path.abspath, files) 
-outdir = os.path.abspath (outdir)
+
+# On most platforms, this is equivalent to
+#`normpath(join(os.getcwd()), PATH)'.  *Added in Python version 1.5.2*
+def compat_abspath (path):
+	return os.path.normpath (os.path.join (os.getcwd (), path))
+
+include_path = map (compat_abspath, include_path)
+files = map (compat_abspath, files) 
+outdir = compat_abspath (outdir)
 
 def strip_ly_suffix (f):
 	(p, e) =os.path.splitext (f)
diff --git a/scripts/mup2ly.py b/scripts/mup2ly.py
index 7011a7b1e4..2808dc1b65 100644
--- a/scripts/mup2ly.py
+++ b/scripts/mup2ly.py
@@ -7,6 +7,9 @@
 
 '''
 TODO:
+
+   WIP:lots of stuff
+   
 '''
 
 import os
@@ -66,7 +69,9 @@ NO WARRANTY.'''))
 	sys.stdout.write ('\n')
 
 def progress (s):
-	sys.stderr.write (s + '\n')
+        if s[-1] != '\n':
+                s = s + '\n'
+	sys.stderr.write (s)
 
 def warning (s):
 	sys.stderr.write (_ ("warning: ") + s)
@@ -199,7 +204,7 @@ def set_setting (dict, key, val):
 #
 
 def encodeint (i):
-	return chr ( i  + ord ('A'))
+	return chr (i  + ord ('A'))
 
 	
 actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
@@ -207,7 +212,7 @@ actab = {-2: 'eses', -1: 'es', 0 : '', 1: 'is', 2:'isis'}
 def pitch_to_lily_string (tup):
 	(o,n,a) = tup
 
-	nm = chr((n + 2) % 7 + ord ('a'))
+        nm = chr((n + 2) % 7 + ord ('a'))
 	nm = nm + actab[a]
 	if o > 0:
 		nm = nm + "'" * o
@@ -321,12 +326,14 @@ class Slur:
 			sys.stderr.write ("\nOrphaned slur")
 			
 class Voice:
-	def __init__ (self):
+	def __init__ (self, n):
+                self.number = n
 		self.entries = []
 		self.chords = []
 		self.staff = None
 		self.current_slurs = []
 		self.slurs = []
+                
 	def toggle_slur (self, id):
 		
 		for s in self.current_slurs:
@@ -340,36 +347,56 @@ class Voice:
 		self.slurs.append (s)
 		
 	def last_chord (self):
-		return self.chords[-1]
+                if len (self.chords):
+                        return self.chords[-1]
+                else:
+                        ch = Chord ()
+                        ch.basic_duration = 4
+                        return ch
+                
 	def add_chord (self, ch):
 		self.chords.append (ch)
 		self.entries.append (ch)
+                
 	def add_nonchord (self, nch):
 		self.entries.append (nch)
 
 	def idstring (self):
 		return 'staff%svoice%s ' % (encodeint (self.staff.number) , encodeint(self.number))
+        
 	def dump (self):
 		str = ''
-		ln = ''
+                if not self.entries:
+                        #return '\n'
+                        #ugh ugh
+                        return '\n%s = {}\n\n' % self.idstring ()
+                ln = '  '
+                one_two = ("One", "Two")
+                if self.staff.voices [1 - self.number].entries:
+                        ln = ln + '\\voice%s\n  ' % one_two[self.number]
 		for e in self.entries:
-			next = ' ' + e.dump ()
+			next = e.dump ()
 			if next[-1] == '\n':
-				str  = str + ln + next
-				ln = ''
+				str  = str + ln + next + ' '
+				ln = '  '
 				continue
 			
 			if len (ln) +len (next) > 72:
 				str = str+ ln + '\n'
-				ln = ''
-			ln = ln + next
+				ln = '  '
+			ln = ln + next + ' '
 			
 			
 		str = str  + ln
 		id = self.idstring ()
 			
-		str = '%s =  \\notes { \n %s }\n '% (id, str)
+		str = '''%s = \\notes {
+%s
+}
+
+'''% (id, str)
 		return str
+        
 	def calculate_graces (self):
 		lastgr = 0
 		lastc = None
@@ -380,6 +407,7 @@ class Voice:
 				lastc.chord_suffix = lastc.chord_suffix + ' } '
 			lastgr = c.grace
 			lastc = c
+                        
 	def calculate (self):
 		self.calculate_graces ()
 		for s in self.slurs:
@@ -400,43 +428,54 @@ clef_table = {
 	's':'soprano',
 	't':'treble',
 	'f':'frenchviolin',
-	} 
+	}
+
 class Staff:
-	def __init__ (self): 
-		self.voices = (Voice (), Voice())
+	def __init__ (self, n):
+                # ugh
+		self.voices = (Voice (0), Voice (1))
+                
+		# self.voice_idx = 0
 		self.clef = None
 		self.instrument = 0
-		self.voice_idx = 0
-		self.number = None
+		self.number = n
 		
 		i = 0
-		for v  in self.voices:
+		for v in self.voices:
 			v.staff = self
 			v.number = i
 			i = i+1
+                        
 	def set_clef (self, letter):
 		clstr = clef_table[letter]
 		self.voices[0].add_nonchord (Clef (clstr))
 		
-	def current_voice (self):
-		return self.voices[self.voice_idx]
-	def next_voice (self):
-		self.voice_idx = (self.voice_idx + 1)%len (self.voices)
+	#def current_voice (self):
+	#	return self.voices[self.voice_idx]
+        #
+	#def next_voice (self):
+	#	self.voice_idx = (self.voice_idx + 1)%len (self.voices)
 
 	def calculate (self):
 		for v in self.voices:
 			v.calculate ()
+                        
 	def idstring (self):
 		return 'staff%s' % encodeint (self.number)
+        
 	def dump (self):
 		str = ''
 
 		refs = ''
 		for v in self.voices:
 			str = str + v.dump()
-			refs = refs + '\\' + v.idstring ()+  ' '
+			refs = refs + '\n  \\' + v.idstring ()
 		
-		str = str + '\n\n%s = \\context Staff = %s \n  < \n %s >\n\n\n'% (self.idstring (), self.idstring (), refs)
+		str = str + '''
+%s = \context Staff = %s <%s
+>
+
+''' % (self.idstring (), self.idstring (), refs)
 		return str
 
 class Tuplet:
@@ -564,6 +603,7 @@ class Parser:
 	def __init__ (self, filename):
 		self.parse_function = self.parse_context_music
 		self.staffs = []
+                self.current_voices = []
 		self.forced_duration = None
 		self.last_name = 0
 		self.last_oct = 0		
@@ -573,68 +613,140 @@ class Parser:
 
 		self.parse (filename)
 		
-	def set_staffs (self, number):
-		self.staffs = map (lambda x: Staff (), range (0, number))
+	#def set_staffs (self, number):
+	#	self.staffs = map (lambda x: Staff (x), range (0, number))
 		
-		self.staff_idx = 0
-
-		i =0
-		for s in self.staffs:
-			s.number = i
-			i = i+1
-			
-	def current_staff (self):
-		return self.staffs[self.staff_idx]
+	#def current_staff (self):
+	#	return self.staffs[self.staff_idx]
 
-	def current_voice (self):
-		return self.current_staff ().current_voice ()
+	#def current_voice (self):
+	#	return self.current_staff ().current_voice ()
 	
-	def next_staff (self):
-		self.staff_idx = (self.staff_idx + 1)% len (self.staffs)
+	#def next_staff (self):
+	#	self.staff_idx = (self.staff_idx + 1)% len (self.staffs)
 		
+        def parse_compound_location (self, line):
+                colon = string.index (line, ':')
+                s = line[:colon]
+                debug (s)
+                line = line[colon + 1:]
+                debug (line)
+                self.current_voices = []
+                ##self.current_staffs = []
+                map (self.parse_location, string.split (s, '&'))
+                return line
+
+        def parse_location (self, line):
+		m = re.match ('^([-,0-9]+) *([-,0-9]*)', string.lstrip (line))
+                
+                def range_list_to_idxs (s):
+                        
+                        # duh
+                        def flatten (l):
+                                f = []
+                                for i in l:
+                                        for j in i:
+                                                f.append (j)
+                                return f
+                                        
+                        def range_to_list (s):
+                                if string.find (s, '-') >= 0:
+                                        debug ('s: ' + s)
+                                        l = map (string.lstrip,
+                                                 string.split (s, '-'))
+                                        r = range (string.atoi (l[0]) - 1,
+                                                   string.atoi (l[1]))
+                                else:
+                                        r = (string.atoi (s) - 1,)
+                                return r
+                        
+                        ranges = string.split (s, ',')
+                        l = flatten (map (range_to_list, ranges))
+                        l.sort ()
+                        return l
+                
+                staff_idxs = range_list_to_idxs (m.group (1))
+                if m.group (2):
+                        voice_idxs = range_list_to_idxs (m.group (2))
+                else:
+                        voice_idxs = [0]
+                for s in staff_idxs:
+                        while s > len (self.staffs) - 1:
+                                self.staffs.append (Staff (s))
+                        for v in voice_idxs:
+                                self.current_voices.append (self.staffs[s].voices[v])
+                        
 	def parse_note (self, line):
-		name = line[0]
+                # FIXME: 1?
+                oct = 1
+                name = (ord (line[0]) - ord ('a') + 5) % 7
+                # FIXME: does key play any role in this?
 		alteration = 0
-		line = line[1:]
+                line = string.lstrip (line[1:])
 		while line:
-			if line[0] == '#':
+                        if len (line) > 1 and line[:2] == '//':
+                                line = 0
+                                break
+			elif line[0] == '#':
 				alteration = alteration + 1
 			elif line[0] == '&':
 				alteration = alteration - 1
-			line = line[1:]
-			# shortcut
-			line = 0
+			elif line[0] == '+':
+                                oct = oct + 1 
+			elif line[0] == '-':
+                                oct = oct - 1
+                        else:
+                                skipping (_ ("%s") % line[0])
+			line = string.lstrip (line[1:])
 		return (oct, name, alteration)
-	
 			
 	def parse_chord (self, line):
-		line = string.strip (line)
+		line = string.lstrip (line)
 		ch = Chord ()
 		if not line:
-			ch = self.current_voice ().last_chord ()
+			ch = self.current_voices[0].last_chord ()
 		else:
-			m = re.match ('([0-9]+)([.]*)', line)
+			m = re.match ('^([0-9]+)([.]*)', line)
 			if m:
 				ch.basic_duration = string.atoi (m.group (1))
-				line = line[len (m.group (1))-1:]
+				line = line[len (m.group (1)):]
 				if m.group (2):
 					ch.basic_duration = len (m.group (2))
-					line = line[len (m.group (1))-1:]
-				line = string.strip (line)
-			m = re.match ('([0-9]+)([.]*)', line)
+					line = line[len (m.group (1)):]
+                        else:
+                                ch.basic_duration = self.current_voices[0].last_chord ().basic_duration
+                                
+                        line = string.lstrip (line)
+                        if len (line) > 1 and line[:2] == '//':
+                                line = 0
+                        #ugh
+                        if not line:
+                                duration = ch.basic_duration
+                                ch = self.current_voices[0].last_chord ()
+                                ch.basic_duration = duration
+                                
 			while line:
-				c = line[0]
-				if line[:1] == 'mr':
+                                if len (line) > 1 and line[:2] == '//':
+                                        line = 0
+                                        break
+                                elif line[:1] == 'mr':
+					ch.multimeasure = 1
+                                        line = line[1:]
+                                elif line[:1] == 'ms':
 					ch.multimeasure = 1
-					line = 0
-				elif c in 'abcdefgrs':
-					pitch = parse_note (line)
-					ch.add_pitches (pitch)
-					line = 0
+                                        line = line[1:]
+				elif line[0] in 'rs':
+                                        pass
+				elif line[0] in 'abcdefg':
+					pitch = self.parse_note (line)
+                                        debug ('PITCH: ' + `pitch`)
+					ch.pitches.append (pitch)
+                                        line = 0
+                                        break
 				else:
-					progress ( _("skipping: %s") % line)
-					line = 0
-		self.current_voice ().add_chord (ch)
+					skipping (_ ("%s") % line[0])
+                                line = string.lstrip (line[1:])
+		map (lambda x, ch=ch: x.add_chord (ch), self.current_voices)
 
 	def parse_voice (self, line):
 		chords = string.split (line, ';')
@@ -644,81 +756,80 @@ class Parser:
 		self.parse_function = self.parse_context_header
 					
 	def parse_context_header (self, line):
-		sys.stderr.write ('header: ' + line)
+		debug ('header: ' + line)
 
 	def init_context_footer (self, line):
 		self.parse_function = self.parse_context_footer
 
 	def parse_context_footer (self, line):
-		sys.stderr.write ('footer: ' + line)
+		debug ('footer: ' + line)
 
 	def init_context_header2 (self, line):
 		self.parse_function = self.parse_context_header2
 
 	def parse_context_header2 (self, line):
-		sys.stderr.write ('header2: ' + line)
+		debug ('header2: ' + line)
 
 	def init_context_footer2 (self, line):
 		self.parse_function = self.parse_context_footer2
 
 	def parse_context_footer2 (self, line):
-		sys.stderr.write ('footer2: ' + line)
+		debug ('footer2: ' + line)
 
 	def init_context_score (self, line):
 		self.parse_function = self.parse_context_score
 
 	def parse_context_score (self, line):
-		sys.stderr.write ('score: ' + line)
+		debug ('score: ' + line)
 
 	def init_context_staff (self, line):
 		self.parse_function = self.parse_context_staff
 
 	def parse_context_staff (self, line):
-		sys.stderr.write ('staff: ' + line)
+		debug ('staff: ' + line)
 
 	def init_context_voice (self, line):
 		self.parse_function = self.parse_context_voice
 
 	def parse_context_voice (self, line):
-		sys.stderr.write ('voice: ' + line)
+		debug ('voice: ' + line)
 
 	def init_context_grids (self, line):
 		self.parse_function = self.parse_context_line
 
 	def parse_context_grids (self, line):
-		sys.stderr.write ('grids: ' + line)
+		debug ('grids: ' + line)
 
 	def init_context_music (self, line):
 		self.parse_function = self.parse_context_music
 
 	def parse_context_music (self, line):
-		sys.stderr.write ('music: ' + line)
-		m = re.match ('^([0-9]+):([0-9]*) ', line)
-		if m:
-			self.staff_idx = string.atoi (m.group (1))
-			line = line[len (m.group (1)):]
-			if m.group (2):
-				self.current_staff ().voice_idx = string.atoi (m.group (2)) - 1
-				line = line[len (m.group (2))-1:]
-			else:
-				self.current_staff ().voice_idx = 0
-			self.parse_voice (line)
+		debug ('music: ' + line)
+                line = string.lstrip (line)
+                if line and line[0] in '0123456789':
+                        line = string.lstrip (self.parse_compound_location (line))
+                        self.parse_voice (line)
 		else:
-			progress ( _("skipping: %s") % line)
+			skipping (_ ("%s") % line)
 	
 	def parse (self, file):
 		# shortcut: set to official mup maximum (duh)
 		# self.set_staffs (40)
 		lines = open (file).readlines ()
 		for line in lines:
-			m = re.match ('^([a-z2]+)', line)
+                        debug ('LINE: ' + line)
+			m = re.match ('^([a-z]+2?)', line)
 			
 			if m:
 				word = m.group (1)
 				if word in contexts:
 					eval ('self.init_context_%s (line)' % word)
 					continue
+                                else:
+                                        warning (_ ("no such context: %s") % word)
+                                        skipping (line)
 			else:
+                                debug ('FUNC: ' + `self.parse_function`)
 				self.parse_function (line)
 				
 		for c in self.staffs:
@@ -730,13 +841,20 @@ class Parser:
 		refs = ''
 		for s in self.staffs:
 			str = str +  s.dump ()
-			refs = '\\' + s.idstring() + refs
+			refs = refs + '\n    \\' + s.idstring ()
+
+		str = str + '''
 
-		str = str + "\n\n\\score { <\n %s\n > }" % refs 
+\score {
+  <%s
+   >
+}
+''' % refs 
 		return str
 
 		
 option_definitions = [
+	('', 'd', 'debug', _ ("debug")),
 	('', 'h', 'help', _ ("this help")),
 	('FILE', 'o', 'output', _ ("write output to FILE")),
 	('', 'V', 'verbose', _ ("verbose")),
@@ -744,7 +862,13 @@ option_definitions = [
 	('', 'w', 'warranty', _ ("show warranty and copyright")),
 	]
 
-
+debug_p = 0
+def debug (s):
+        if debug_p:
+                progress ('DEBUG: ' + s)
+def skipping (s):
+        if debug_p:
+                progress ('SKIPPING: ' + s)
 
 (sh, long) = getopt_args (__main__.option_definitions)
 try:
@@ -757,13 +881,19 @@ except:
 for opt in options:
 	o = opt[0]
 	a = opt[1]
-	if o== '--help' or o == '-h':
+        if 0:
+                pass
+	elif o== '--debug' or o == '-d':
+                debug_p = 1
+	elif o== '--help' or o == '-h':
 		help ()
 		sys.exit (0)
-	if o == '--version' or o == '-v':
+	elif o== '--verbose' or o == '-V':
+                verbose_p = 1
+	elif o == '--version' or o == '-v':
 		identify ()
 		sys.exit (0)
-	if o == '--output' or o == '-o':
+	elif o == '--output' or o == '-o':
 		output = a
 	else:
 		print o
@@ -793,7 +923,7 @@ for f in files:
 	progress (_ ("Writing %s...") % output)
 
 	tag = '%% Lily was here -- automatically converted by %s from %s' % ( program_name, f)
-	ly = tag + e.dump ()
+	ly = tag + '\n' + e.dump ()
 
 	o = open (output, 'w')
 	o.write (ly)
diff --git a/scripts/pmx2ly.py b/scripts/pmx2ly.py
index b8d289b861..c260b06819 100644
--- a/scripts/pmx2ly.py
+++ b/scripts/pmx2ly.py
@@ -407,7 +407,9 @@ class Parser:
 			str = str[1:]
 		else:
 			ch = Chord ()
-			self.current_voice().add_chord (ch)			
+			self.current_voice().add_chord (ch)
+
+		# what about 's'?
 		if str[0] <> 'r':
 			name = (ord (str[0]) - ord('a') + 5) % 7