From: Han-Wen Nienhuys <hanwen@xs4all.nl>
Date: Mon, 12 Sep 2005 12:20:26 +0000 (+0000)
Subject: * Documentation/user/instrument-notation.itely (Laissez vibrer
X-Git-Tag: release/2.7.10~8
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=4bee689d7993ecf9af95d33c7f8f4ecd8d74a3cc;p=lilypond.git

* Documentation/user/instrument-notation.itely (Laissez vibrer
ties): new node.

* input/regression/laissez-vibrer-ties.ly: new file.

* lily/laissez-vibrer-engraver.cc: new file.

* lily/include/tie-column-format.hh: new file.

* lily/tie-column-format.cc: new file.

* lily/tie-column.cc (set_manual_tie_configuration): new function.

* lily/laissez-vibrer-tie.cc: new file.

* lily/include/laissez-vibrer-tie.hh: new file.

* ly/engraver-init.ly: add Laissez_vibrer_engraver

* ly/declarations-init.ly (laissezVibrer): add \laissezVibrer

* scm/define-grobs.scm (all-grob-descriptions): add
LaissezVibrerTie, LaissezVibrerTieColumn

* lily/tie-column.cc (set_tie_config_directions): new function
(final_shape_adjustment): new function.
(shift_small_ties): new function.

* scm/define-music-types.scm (music-descriptions): add LaissezVibrerEvent

* lily/include/tie.hh (struct Tie_details): add x_gap_
(struct Tie_configuration): add head_position_

* lily/tie-column.cc (set_chord_outline): new function.

* mf/cmr.enc.in:  remove file.
---

diff --git a/ChangeLog b/ChangeLog
index 4480150265..4061db9478 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2005-09-12  Han-Wen Nienhuys  <hanwen@xs4all.nl>
+
+	* Documentation/user/instrument-notation.itely (Laissez vibrer
+	ties): new node.
+
+	* input/regression/laissez-vibrer-ties.ly: new file.
+
+	* lily/laissez-vibrer-engraver.cc: new file.	
+
+	* lily/include/tie-column-format.hh: new file.
+
+	* lily/tie-column-format.cc: new file. 
+
+	* lily/tie-column.cc (set_manual_tie_configuration): new function.
+
+	* lily/laissez-vibrer-tie.cc: new file.
+
+	* lily/include/laissez-vibrer-tie.hh: new file.
+
+	* ly/engraver-init.ly: add Laissez_vibrer_engraver
+
+	* ly/declarations-init.ly (laissezVibrer): add \laissezVibrer
+
+	* scm/define-grobs.scm (all-grob-descriptions): add
+	LaissezVibrerTie, LaissezVibrerTieColumn
+
+	* lily/tie-column.cc (set_tie_config_directions): new function
+	(final_shape_adjustment): new function.
+	(shift_small_ties): new function.
+
+	* scm/define-music-types.scm (music-descriptions): add LaissezVibrerEvent
+
+	* lily/include/tie.hh (struct Tie_details): add x_gap_
+	(struct Tie_configuration): add head_position_
+
+	* lily/tie-column.cc (set_chord_outline): new function.
+
+	* mf/cmr.enc.in:  remove file.
+
 2005-09-11  Graham Percival  <gpermus@gmail.com>
 
 	* Documentation/user/examples.itely: typo fix.  Thanks, Matevž
diff --git a/Documentation/topdocs/NEWS.tely b/Documentation/topdocs/NEWS.tely
index 424d593500..03c191c2a1 100644
--- a/Documentation/topdocs/NEWS.tely
+++ b/Documentation/topdocs/NEWS.tely
@@ -46,6 +46,15 @@ This document is also available in @uref{NEWS.pdf,PDF}.
 
 @itemize @bullet
 
+@item
+Laissez vibrer ties can be created with @code{\laissezVibrer},
+
+@lilypond[fragment,raggedright,relative=1]
+  <c e g>\laissezVibrer  <d f>\laissezVibrer
+@end lilypond
+
+This feature was sponsored by Henrik Frisk.
+
 @item
 The order of words in @code{\markup} commands may now be reversed by
 setting the @code{text-direction} property. This is useful for
diff --git a/Documentation/user/instrument-notation.itely b/Documentation/user/instrument-notation.itely
index 38708358b3..59090fdaae 100644
--- a/Documentation/user/instrument-notation.itely
+++ b/Documentation/user/instrument-notation.itely
@@ -36,6 +36,7 @@ handle this cross-staffing behavior.  In this section we discuss the
 @menu
 * Automatic staff changes::     
 * Manual staff switches::       
+* Laissez vibrer ties::         
 * Pedals::                      
 * Staff switch lines::          
 * Cross staff stems::           
@@ -153,6 +154,28 @@ and the @context{Voice} is inserted afterwards
 @end example
 
 
+@node Laissez vibrer ties
+@subsection Laissez vibrer ties
+@cindex Laissez vibrer
+@cindex Ties,  laissez vibrer
+
+L.v. ties (laissez vibrer) indicate that notes must not be damped at the
+end. It is used in harp notation. They can be entered using
+@code{\laissezVibrer},
+
+@lilypond[fragment,raggedright,verbatim,relative=1]
+<c f g>\laissezVibrer 
+@end lilypond
+
+@seealso
+
+Program reference: 
+@internalsref{LaissezVibrerTie}
+@internalsref{LaissezVibrerTieColumn}
+
+Example files:
+@inputfileref{input/regression,laissez-vibrer-tie.ly}
+
 @node Pedals
 @subsection Pedals
 @cindex Pedals
@@ -217,6 +240,10 @@ of the note head
 c\sostenutoDown d e c, f g a\sostenutoUp
 @end lilypond
 
+@seealso
+
+In this manual: @ref{Laissez vibrer ties}
+
 @node Staff switch lines
 @subsection Staff switch lines
 
diff --git a/THANKS b/THANKS
index 61b7139e4f..763153aebe 100644
--- a/THANKS
+++ b/THANKS
@@ -22,6 +22,7 @@ Yoshinobu Ishizaki
 SPONSORS
 
 Aaron Mehl
+Henrik Frisk
 Jay Hamilton
 Jamie Bullock
 D. Josiah Boothby
diff --git a/input/regression/laissez-vibrer-ties.ly b/input/regression/laissez-vibrer-ties.ly
new file mode 100644
index 0000000000..b95c82d846
--- /dev/null
+++ b/input/regression/laissez-vibrer-ties.ly
@@ -0,0 +1,31 @@
+
+\header {
+
+
+  texidoc = "
+l.v. ties should avoid dots and staff lines, similar to normal ties.
+They have fixed size. Their formatting can be tuned with
+@code{tie-configuration}.
+
+"
+  }
+
+\version "2.7.10"
+\paper {
+  raggedright = ##t
+}
+
+\relative {
+  <c e g>\laissezVibrer
+  <c f g>\laissezVibrer
+  <c d f g>\laissezVibrer
+  <c d f g>4.\laissezVibrer
+
+  <c d e f>4\laissezVibrer
+  \override LaissezVibrerTieColumn #'tie-configuration
+  = #'((-7 . -1)
+       (-5 . -1)
+       (-3 . 1)
+       (-1 . 1))
+  <c d e f>4\laissezVibrer
+}
diff --git a/lily/include/laissez-vibrer-tie-column.hh b/lily/include/laissez-vibrer-tie-column.hh
new file mode 100644
index 0000000000..ea7b63c5cd
--- /dev/null
+++ b/lily/include/laissez-vibrer-tie-column.hh
@@ -0,0 +1,24 @@
+/*
+  laissez-vibrer-tie-column.hh -- declare Laissez_vibrer_tie_column
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef TIE_LAISSEZ_VIBRER_COLUMN_HH
+#define TIE_LAISSEZ_VIBRER_COLUMN_HH
+
+#include "grob-interface.hh"
+#include "lily-proto.hh"
+
+struct Laissez_vibrer_tie_column
+{
+  static bool has_interface (Grob *);
+  static void set_directions (Grob *me);
+};
+
+
+#endif /* TIE_LAISSEZ_VIBRER_COLUMN_HH */
+
diff --git a/lily/include/laissez-vibrer-tie.hh b/lily/include/laissez-vibrer-tie.hh
new file mode 100644
index 0000000000..d500f08f0c
--- /dev/null
+++ b/lily/include/laissez-vibrer-tie.hh
@@ -0,0 +1,28 @@
+/*
+  laissez-vibrer-tie.hh -- declare Laissez_vibrer_tie
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef TIE_LAISSEZ_VIBRER_HH
+#define TIE_LAISSEZ_VIBRER_HH
+
+
+#include "grob-interface.hh"
+#include "lily-guile.hh"
+
+struct Laissez_vibrer_tie
+{
+  static bool has_interface (Grob *);
+  
+  DECLARE_SCHEME_CALLBACK (print, (SCM));
+  static void set_direction (Grob *);
+  static int compare (Grob *const &s1,
+		      Grob *const &s2);
+  static int get_position (Grob *);
+};
+
+#endif /* TIE_LAISSEZ_VIBRER_HH */
diff --git a/lily/include/lily-proto.hh b/lily/include/lily-proto.hh
index 05af750dbf..1947a2b220 100644
--- a/lily/include/lily-proto.hh
+++ b/lily/include/lily-proto.hh
@@ -144,6 +144,7 @@ class Simple_spacer;
 class Simple_spacer_wrapper;
 class Simultaneous_music;
 class Simultaneous_music_iterator;
+class Skyline_entry;
 class Slur_configuration;
 class Slur_score_state;
 class Span_score_bar_engraver;
@@ -157,6 +158,8 @@ class System;
 class Tempo_performer;
 class Tex_font_metric;
 class Tie;
+class Tie_details;
+class Tie_configuration;
 class Tie_performer;
 class Time_scaled_music;
 class Time_scaled_music_iterator;
diff --git a/lily/include/tie-column-format.hh b/lily/include/tie-column-format.hh
new file mode 100644
index 0000000000..5f0c438e68
--- /dev/null
+++ b/lily/include/tie-column-format.hh
@@ -0,0 +1,39 @@
+/*
+  tie-column-format.hh -- declare
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#ifndef TIE_COLUMN_FORMAT_HH
+#define TIE_COLUMN_FORMAT_HH
+
+
+
+void set_chord_outline (Array<Skyline_entry> *skyline,
+			Link_array<Item> bounds,
+			Grob *common,
+			Direction d);
+void set_tie_config_directions (Array<Tie_configuration> *tie_configs_ptr);
+void shift_small_ties (Array<Tie_configuration> *tie_configs,
+		       Grob *staff_referencer,
+		       Tie_details const &details);
+void final_shape_adjustment (Tie_configuration &conf,
+			     Drul_array< Array<Skyline_entry> > const &skylines,
+			     Grob *staff_referencer,
+			     Tie_details const &details);
+void
+set_chord_outlines (Drul_array< Array<Skyline_entry> > *skyline_drul,
+		    Link_array<Grob> ties,
+		    Grob *common);
+
+void
+set_manual_tie_configuration (Array<Tie_configuration> *tie_configs,
+			      bool *manual_override,
+			      SCM manual_configs
+			      );
+
+
+#endif /* TIE_COLUMN_FORMAT_HH */
diff --git a/lily/include/tie.hh b/lily/include/tie.hh
index 7327dbd4c4..80501acf30 100644
--- a/lily/include/tie.hh
+++ b/lily/include/tie.hh
@@ -75,9 +75,8 @@ public:
   static int compare (Grob *const &s1,
 		      Grob *const &s2);
 
-  static
-  Interval get_default_attachments (Spanner *me, Grob *common, Real gap,
-				    int *staff_position, bool *in_between);
+  static Interval get_default_attachments (Spanner *me, Grob *common, Real gap,
+					   int *staff_position, bool *in_between);
   
 };
 
diff --git a/lily/include/translator.icc b/lily/include/translator.icc
index 6895d6890b..5db338c515 100644
--- a/lily/include/translator.icc
+++ b/lily/include/translator.icc
@@ -10,6 +10,7 @@
 #define TRANSLATOR_ICC
 
 #include "array.hh"
+#include "translator.hh"
 
 /**
    A macro to automate administration of translators.
diff --git a/lily/laissez-vibrer-engraver.cc b/lily/laissez-vibrer-engraver.cc
new file mode 100644
index 0000000000..ef3d7a6b7b
--- /dev/null
+++ b/lily/laissez-vibrer-engraver.cc
@@ -0,0 +1,86 @@
+/*
+  laissez-vibrer-engraver.cc -- implement Laissez_vibrer_engraver
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+
+#include "engraver.hh"
+#include "item.hh"
+#include "pointer-group-interface.hh"
+
+#include "translator.icc"
+
+class Laissez_vibrer_engraver : public Engraver
+{
+
+  Music *event_;
+  Grob *lv_column_;
+  Link_array<Grob> lv_ties_;
+  
+  void stop_translation_timestep (); 
+  DECLARE_ACKNOWLEDGER (note_head);
+  
+  virtual bool try_music (Music *);
+public:
+  TRANSLATOR_DECLARATIONS (Laissez_vibrer_engraver);
+};
+
+Laissez_vibrer_engraver::Laissez_vibrer_engraver ()
+{
+  event_ = 0;
+  lv_column_ = 0;
+}
+
+void
+Laissez_vibrer_engraver::stop_translation_timestep ()
+{
+  event_ = 0;
+  lv_column_ = 0;
+  lv_ties_.clear ();
+}
+
+bool
+Laissez_vibrer_engraver::try_music (Music *m)
+{
+  event_ = m;
+  return true;
+}
+
+void
+Laissez_vibrer_engraver::acknowledge_note_head (Grob_info inf)
+{
+  if (!event_)
+    return;
+
+  if (!lv_column_)
+    {
+      lv_column_ = make_item ("LaissezVibrerTieColumn", event_->self_scm ());
+    }
+  
+  Grob *lv_tie = make_item ("LaissezVibrerTie", event_->self_scm ());
+  lv_tie->set_object ("note-head", inf.grob ()->self_scm ());
+  
+  Pointer_group_interface::add_grob (lv_column_, ly_symbol2scm ("ties"),
+				     lv_tie);
+  lv_tie->set_parent (lv_column_, Y_AXIS);
+
+  lv_ties_.push (lv_tie);
+}
+
+
+
+ADD_ACKNOWLEDGER (Laissez_vibrer_engraver, note_head);
+ADD_TRANSLATOR (Laissez_vibrer_engraver, 
+		/* doc */ "Create Laissez vibrer items.",
+		
+		/* create */
+		"LaissezVibrerTie "
+		"LaissezVibrerTieColumn",
+
+		/* accept */ "laissez-vibrer-event",
+		/* read */ "",
+		/* write */ "");
diff --git a/lily/laissez-vibrer-tie-column.cc b/lily/laissez-vibrer-tie-column.cc
new file mode 100644
index 0000000000..c381905719
--- /dev/null
+++ b/lily/laissez-vibrer-tie-column.cc
@@ -0,0 +1,126 @@
+/*
+  laissez-vibrer-tie-column.cc -- implement Laissez_vibrer_tie_column
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "laissez-vibrer-tie-column.hh"
+#include "laissez-vibrer-tie.hh"
+#include "grob.hh"
+#include "tie-column.hh"
+#include "tie.hh"
+#include "directional-element-interface.hh"
+#include "pointer-group-interface.hh"
+#include "staff-symbol-referencer.hh"
+#include "item.hh"
+#include "tie-column-format.hh"
+
+
+ADD_INTERFACE(Laissez_vibrer_tie_column,
+	      "laissez-vibrer-tie-column-interface",
+	      "The interface for a column of l.v. ties.",
+
+	      /* properties */
+	      "positioning-done"
+	      "tie-configuration"
+	      );
+			   
+
+
+/*
+  Cut & paste from tie-column.cc
+ */   
+void
+Laissez_vibrer_tie_column::set_directions (Grob *me)
+{
+  if (!to_boolean (me->get_property ("positioning-done")))
+    me->set_property ("positioning-done", SCM_BOOL_T); 
+  else
+    return;
+
+
+  extract_grob_set (me, "ties", lv_ro_ties);
+  Link_array<Grob> lv_ties (lv_ro_ties);
+
+  lv_ties.sort (&Laissez_vibrer_tie::compare);
+
+  Array<Tie_configuration> tie_configs;
+  Link_array<Item> heads;
+  for (int i = 0; i < lv_ties.size (); i++)
+    {
+      Tie_configuration conf;
+      conf.dir_ = get_grob_direction (lv_ties[i]);
+      Item *head = unsmob_item (lv_ties[i]->get_object ("note-head"));
+
+      heads.push (head);
+      if (head)
+	conf.position_ = (int) Staff_symbol_referencer::get_position (head);
+      
+      tie_configs.push (conf);
+    }
+
+  bool manual_override = false;
+  SCM manual_configs = me->get_property ("tie-configuration");
+  set_manual_tie_configuration (&tie_configs,
+				&manual_override,
+				manual_configs
+				);
+
+  set_tie_config_directions (&tie_configs);
+
+  Grob *common = me;
+  for (int i = 0; i < lv_ties.size (); i++)
+    {
+      common = lv_ties[i]->common_refpoint (common, X_AXIS); 
+    }
+
+  Drul_array< Array<Skyline_entry> > skylines;
+  set_chord_outline (&skylines[LEFT],
+		     heads,
+		     common, LEFT);
+
+  Real right_most = - infinity_f;   
+  for (int i = 0; i < skylines[LEFT].size (); i++)
+    {
+      right_most = max (right_most, skylines[LEFT][i].height_);
+    }
+
+  Skyline_entry right_entry;
+  right_entry.width_.set_full ();
+  right_entry.height_ = right_most + 1.5;
+  
+  skylines[RIGHT].push (right_entry);
+
+  Tie_details details;
+  details.init (lv_ties[0]);
+
+  /*
+    Calculate final width and shape of the ties.
+   */
+  for (int i = 0; i < lv_ties.size(); i++)
+    {
+      final_shape_adjustment (tie_configs[i],
+			      skylines,
+			      lv_ties[0],
+			      details);
+    }
+  
+  /*
+    Try to shift small ties into available spaces.
+   */
+  if (!manual_override)
+    {
+      shift_small_ties (&tie_configs, lv_ties[0], details);
+    }
+  
+  for (int i = 0; i < lv_ties.size(); i++)
+    {
+      Tie::set_control_points (lv_ties[i], common, tie_configs[i],
+			       details );
+      set_grob_direction (lv_ties[i], tie_configs[i].dir_);
+    }
+}
+  
diff --git a/lily/laissez-vibrer-tie.cc b/lily/laissez-vibrer-tie.cc
new file mode 100644
index 0000000000..c63f3990e1
--- /dev/null
+++ b/lily/laissez-vibrer-tie.cc
@@ -0,0 +1,80 @@
+/*
+  laissez-vibrer-tie.cc -- implement Laissez_vibrer_tie
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "laissez-vibrer-tie-column.hh"
+#include "laissez-vibrer-tie.hh"
+#include "directional-element-interface.hh"
+#include "grob.hh"
+#include "tie.hh"
+#include "warn.hh"
+#include "staff-symbol-referencer.hh"
+
+ADD_INTERFACE(Laissez_vibrer_tie,
+	      "laissez-vibrer-tie-interface",
+	      "The interface for l.v. tie items.",
+
+	      /* properties */
+	      "control-points "
+	      "details "
+	      "thickness "
+	      "x-gap "
+	      "details "
+	      "note-head "
+	      );
+
+MAKE_SCHEME_CALLBACK (Laissez_vibrer_tie, print, 1);
+SCM
+Laissez_vibrer_tie::print (SCM smob)
+{
+  Grob *me = unsmob_grob (smob);
+  if (CENTER == get_grob_direction (me))
+    set_direction (me);
+
+  if (!get_grob_direction (me))
+    me->programming_error ("lv. tie direction not set."); 
+    
+  SCM cp = me->get_property ("control-points");
+  if (!scm_is_pair (cp))
+    if (Laissez_vibrer_tie_column::has_interface (me->get_parent (Y_AXIS)))
+      {
+	Laissez_vibrer_tie_column::set_directions (me->get_parent (Y_AXIS));
+      }
+
+  return Tie::print (smob);
+}
+
+void
+Laissez_vibrer_tie::set_direction (Grob *me)
+{
+  if (!get_grob_direction (me))
+    {
+      if (Laissez_vibrer_tie_column::has_interface (me->get_parent (Y_AXIS)))
+	Laissez_vibrer_tie_column::set_directions (me->get_parent (Y_AXIS));
+      else
+	{
+	  programming_error ("lv tie without Laissez_vibrer_tie_column"); 
+	  set_grob_direction (me, UP);
+	}
+    }
+}
+
+int
+Laissez_vibrer_tie::get_position (Grob *me)
+{
+  Grob *h = unsmob_grob (me->get_object ("note-head"));
+  return (int) rint (Staff_symbol_referencer::get_position (h));
+}
+
+int
+Laissez_vibrer_tie::compare (Grob *const &s1,
+			     Grob *const &s2)
+{
+  return sign (get_position (s1) - get_position (s2));
+}
+				 
diff --git a/lily/tie-column-format.cc b/lily/tie-column-format.cc
new file mode 100644
index 0000000000..812782ef4e
--- /dev/null
+++ b/lily/tie-column-format.cc
@@ -0,0 +1,284 @@
+/*
+  tie-column-format.cc -- implement formatting routines for Tie_column
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "stem.hh"
+#include "note-head.hh"
+#include "tie.hh"
+#include "parray.hh"
+#include "spanner.hh"
+#include "item.hh"
+#include "staff-symbol-referencer.hh"
+
+#include <set>
+
+void
+set_manual_tie_configuration (Array<Tie_configuration> *tie_configs,
+			      bool *manual_override,
+			      SCM manual_configs
+			      )
+{
+  *manual_override = false;
+  int k = 0;
+  for (SCM s = manual_configs;
+       scm_is_pair (s) && k < tie_configs->size(); s = scm_cdr (s))
+    {
+      SCM entry = scm_car (s);
+      if (!scm_is_pair (entry))
+	continue;
+
+      *manual_override = true;
+      Tie_configuration &conf = tie_configs->elem_ref (k);
+      
+      Real complete_pos = robust_scm2double (scm_car (entry),
+					     conf.position_);
+
+      conf.position_ = int (rint (complete_pos));
+      conf.delta_y_ = complete_pos - conf.position_;
+      conf.dir_ = Direction (robust_scm2int (scm_cdr (entry),
+					     conf.dir_));
+      k ++;
+    }
+}
+
+void
+set_chord_outline (Array<Skyline_entry> *skyline,
+		   Link_array<Item> bounds,
+		   Grob *common,
+		   Direction d)
+{
+  Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
+
+  Array<Box> boxes;
+  Interval x_union;
+
+  Grob *stem = 0;
+  for (int i = 0; i < bounds.size (); i++)
+    {
+      Grob *head = bounds[i];
+      if (!Note_head::has_interface (head))
+	continue;
+      
+      if (!stem)
+	stem = unsmob_grob (head->get_object ("stem"));
+	  
+      Real p = Staff_symbol_referencer::get_position (head);
+      Interval y ((p-1) * 0.5 * staff_space,
+		  (p+1) * 0.5 * staff_space);
+
+      Interval x = head->extent (common, X_AXIS);
+      boxes.push (Box (x, y));
+      x_union.unite (x);
+    }
+
+  (*skyline) = empty_skyline (-d);
+
+  if (bounds[0]->break_status_dir ())
+    {
+      Real x = robust_relative_extent (bounds[0],  common, X_AXIS)[-d];
+      skyline->elem_ref (0).height_ = x; 
+    }
+	  
+  for (int i = 0; i < boxes.size (); i++)
+    insert_extent_into_skyline (skyline,
+				boxes[i], Y_AXIS, -d);
+  if (stem
+      && !Stem::is_invisible (stem))
+    {
+      Interval x;
+      x.add_point (stem->relative_coordinate (common, X_AXIS));
+      x.widen (staff_space / 20); // ugh.
+      Interval y;
+      y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
+
+      Direction stemdir = Stem::get_direction (stem);
+      y.add_point (Stem::head_positions (stem)[-stemdir]
+		   * staff_space * .5);
+	  
+      insert_extent_into_skyline (skyline, Box (x,y), Y_AXIS, -d);
+
+
+
+      if (d == LEFT)
+	{
+	  Box flag_box = Stem::get_translated_flag (stem).extent_box ();
+	  flag_box.translate( Offset (x[RIGHT], X_AXIS));
+	  insert_extent_into_skyline (skyline, flag_box,
+				      Y_AXIS, -d);
+	}
+    }
+  
+  Direction updowndir = DOWN;
+  do
+    {
+      Interval x ;
+      Interval y;
+      if (boxes.size())
+	{
+	  Box b = boxes.boundary (updowndir, 0);
+	  x = b[X_AXIS];
+	  x[-d] =  b[X_AXIS].linear_combination (-d / 2);
+	  y[-updowndir] = b[Y_AXIS][updowndir];
+	  y[updowndir] = updowndir * infinity_f;
+	}
+
+      if (!x.is_empty ())
+	insert_extent_into_skyline (skyline,
+				    Box (x,y),
+				    Y_AXIS, -d);
+    }
+  while (flip (&updowndir) != DOWN);
+
+  for (int i = 0; i < bounds.size (); i++)
+    {
+      if (!Note_head::has_interface (bounds[i]))
+	continue;
+
+      
+      Grob *dots = unsmob_grob (bounds[i]->get_object ("dot"));
+      if (dots && d == LEFT)
+	{
+	  Interval x = dots->extent (common, X_AXIS);
+	  Real p = Staff_symbol_referencer::get_position (dots);
+	      
+	  Interval y (-1,1);
+	  y *= (staff_space /4);
+	  y.translate (p * staff_space * .5);
+
+	  insert_extent_into_skyline (skyline,
+				      Box (x,y), Y_AXIS, -d);
+	}
+    }
+}
+
+void
+set_chord_outlines (Drul_array< Array<Skyline_entry> > *skyline_drul,
+		    Link_array<Grob> ties,
+		    Grob *common)
+{
+  Direction d = LEFT;
+
+  do
+    {
+      Link_array<Item> bounds;
+      
+      for (int i = 0; i < ties.size (); i++)
+	{
+	  Item *it = dynamic_cast<Spanner*> (ties[i])->get_bound (d);
+					     
+	  bounds.push (it);
+	}
+      
+      set_chord_outline (&skyline_drul->elem_ref (d),
+			 bounds, common, d);
+    }
+  while (flip (&d) != LEFT);
+}
+
+void
+shift_small_ties (Array<Tie_configuration> *tie_configs,
+		  Grob *staff_referencer,
+		  Tie_details const &details)
+{
+  set<int> positions_taken;
+  for (int i = 0; i < tie_configs->size (); i++)
+    positions_taken.insert (int (rint (tie_configs->elem (i).position_)));
+
+  for (int i = 0; i < tie_configs->size (); i++)
+    {
+      Tie_configuration * conf = &tie_configs->elem_ref (i);
+
+      /*
+	on staff line and small enough, translate a little further 
+      */
+      Real h = conf->height (details);
+      bool next_free = positions_taken.find (int (rint (conf->position_ + conf->dir_)))
+	== positions_taken.end ();
+
+      int rounded_pos = int (rint (conf->position_ + conf->delta_y_ / details.staff_space_));
+      bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer, rounded_pos);
+      
+      if (next_free)
+	if (on_line && h < 0.4 * details.staff_space_)
+	  {
+	    positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
+	    conf->delta_y_ += 0.2 * details.staff_space_ * conf->dir_;
+	  }
+	else if (!on_line && h > 0.6 * details.staff_space_)
+	  {
+	    positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
+	    conf->delta_y_ += 0.5 * details.staff_space_ * conf->dir_;
+	  }
+    }
+}
+
+
+void
+final_shape_adjustment (Tie_configuration &conf,
+			Drul_array< Array<Skyline_entry> > const &skylines,
+			Grob *staff_referencer,
+			Tie_details const &details)
+{
+  Real line_dy = 0.0;
+  bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer,
+							int (rint (conf.position_)));
+  if (on_line)
+    line_dy = - sign (conf.height (details) - 0.6 * details.staff_space_)
+      * 0.2 * details.staff_space_ * conf.dir_;
+
+  Real y = conf.position_ * details.staff_space_ * 0.5
+    + line_dy;
+  
+  conf.attachment_x_ = get_skyline_attachment (skylines, y);
+  conf.attachment_x_.intersect (get_skyline_attachment (skylines,
+							y + conf.dir_ * details.staff_space_ * 0.5));
+
+  conf.delta_y_ += line_dy;
+  conf.attachment_x_.widen (-details.x_gap_);
+  if (!on_line
+      && Staff_symbol_referencer::staff_radius (staff_referencer) * details.staff_space_ > y)
+    conf.center_tie_vertically (details);
+}
+
+void
+set_tie_config_directions (Array<Tie_configuration> *tie_configs_ptr)
+{
+  Array<Tie_configuration> &tie_configs (*tie_configs_ptr);
+  
+  if (!tie_configs[0].dir_)
+    tie_configs[0].dir_ = DOWN;
+  if (!tie_configs.top().dir_)
+    tie_configs.top().dir_ = UP;
+
+  /*
+    Seconds
+   */
+  for (int i = 1; i < tie_configs.size(); i++)
+    {
+      if (fabs (tie_configs[i-1].position_ - tie_configs[i].position_) <= 1)
+	{
+	  if (!tie_configs[i-1].dir_)
+	    tie_configs[i-1].dir_ = DOWN;
+	  if (!tie_configs[i].dir_)
+	    tie_configs[i].dir_ = UP;
+	}
+    }
+
+  for (int i = 1; i < tie_configs.size() - 1; i++)
+    {
+      if (tie_configs[i].dir_)
+	continue;
+
+      Direction position_dir = (Direction) sign (tie_configs[i].position_);
+      if (!position_dir)
+	position_dir = DOWN;
+      
+      tie_configs[i].dir_ = position_dir;
+    }
+}
+			   
diff --git a/lily/tie-column.cc b/lily/tie-column.cc
index 70b2041067..df6b7f18c8 100644
--- a/lily/tie-column.cc
+++ b/lily/tie-column.cc
@@ -10,19 +10,15 @@
 
 #include <math.h>
 #include <map>
-#include <set>
 
-#include "note-head.hh"
-#include "stem.hh"
 #include "skyline.hh"
-#include "staff-symbol-referencer.hh"
 #include "warn.hh"
 #include "paper-column.hh"
 #include "spanner.hh"
 #include "pointer-group-interface.hh"
 #include "tie.hh"
 #include "directional-element-interface.hh"
-#include "rhythmic-head.hh"
+#include "tie-column-format.hh"
 
 void
 Tie_column::add_tie (Grob *me, Grob *tie)
@@ -52,12 +48,7 @@ Tie_column::set_directions (Grob *me)
     }
 }
 
-int
-Tie::compare (Grob *const &s1,
-	      Grob *const &s2)
-{
-  return sign (Tie::get_position (s1) - Tie::get_position (s2));
-}
+
 
 MAKE_SCHEME_CALLBACK (Tie_column, after_line_breaking, 1);
 SCM
@@ -91,243 +82,6 @@ Tie_column::before_line_breaking (SCM smob)
 }
 
 
-void
-set_chord_outline (Array<Skyline_entry> *skyline,
-		   Link_array<Item> bounds,
-		   Grob *common,
-		   Direction d)
-{
-  Real staff_space = Staff_symbol_referencer::staff_space (bounds[0]);
-
-  Array<Box> boxes;
-  Interval x_union;
-
-  Grob *stem = 0;
-  for (int i = 0; i < bounds.size (); i++)
-    {
-      Grob *head = bounds[i];
-      if (!Note_head::has_interface (head))
-	continue;
-      
-      if (!stem)
-	stem = unsmob_grob (head->get_object ("stem"));
-	  
-      Real p = Staff_symbol_referencer::get_position (head);
-      Interval y ((p-1) * 0.5 * staff_space,
-		  (p+1) * 0.5 * staff_space);
-
-      Interval x = head->extent (common, X_AXIS);
-      boxes.push (Box (x, y));
-      x_union.unite (x);
-    }
-
-  (*skyline) = empty_skyline (-d);
-
-  if (bounds[0]->break_status_dir ())
-    {
-      Real x = robust_relative_extent (bounds[0],  common, X_AXIS)[-d];
-      skyline->elem_ref (0).height_ = x; 
-    }
-	  
-  for (int i = 0; i < boxes.size (); i++)
-    insert_extent_into_skyline (skyline,
-				boxes[i], Y_AXIS, -d);
-  if (stem
-      && !Stem::is_invisible (stem))
-    {
-      Interval x;
-      x.add_point (stem->relative_coordinate (common, X_AXIS));
-      x.widen (staff_space / 20); // ugh.
-      Interval y;
-      y.add_point (Stem::stem_end_position (stem) * staff_space * .5);
-
-      Direction stemdir = Stem::get_direction (stem);
-      y.add_point (Stem::head_positions (stem)[-stemdir]
-		   * staff_space * .5);
-	  
-      insert_extent_into_skyline (skyline, Box (x,y), Y_AXIS, -d);
-
-
-
-      if (d == LEFT)
-	{
-	  Box flag_box = Stem::get_translated_flag (stem).extent_box ();
-	  flag_box.translate( Offset (x[RIGHT], X_AXIS));
-	  insert_extent_into_skyline (skyline, flag_box,
-				      Y_AXIS, -d);
-	}
-    }
-  
-  Direction updowndir = DOWN;
-  do
-    {
-      Interval x ;
-      Interval y;
-      if (boxes.size())
-	{
-	  Box b = boxes.boundary (updowndir, 0);
-	  x = b[X_AXIS];
-	  x[-d] =  b[X_AXIS].linear_combination (-d / 2);
-	  y[-updowndir] = b[Y_AXIS][updowndir];
-	  y[updowndir] = updowndir * infinity_f;
-	}
-
-      if (!x.is_empty ())
-	insert_extent_into_skyline (skyline,
-				    Box (x,y),
-				    Y_AXIS, -d);
-    }
-  while (flip (&updowndir) != DOWN);
-
-  for (int i = 0; i < bounds.size (); i++)
-    {
-      if (!Note_head::has_interface (bounds[i]))
-	continue;
-
-      
-      Grob *dots = unsmob_grob (bounds[i]->get_object ("dot"));
-      if (dots && d == LEFT)
-	{
-	  Interval x = dots->extent (common, X_AXIS);
-	  Real p = Staff_symbol_referencer::get_position (dots);
-	      
-	  Interval y (-1,1);
-	  y *= (staff_space /4);
-	  y.translate (p * staff_space * .5);
-
-	  insert_extent_into_skyline (skyline,
-				      Box (x,y), Y_AXIS, -d);
-	}
-    }
-}
-
-void
-set_chord_outlines (Drul_array< Array<Skyline_entry> > *skyline_drul,
-		    Link_array<Grob> ties,
-		    Grob *common)
-{
-  Direction d = LEFT;
-
-  do
-    {
-      Link_array<Item> bounds;
-      
-      for (int i = 0; i < ties.size (); i++)
-	{
-	  Item *it = dynamic_cast<Spanner*> (ties[i])->get_bound (d);
-					     
-	  bounds.push (it);
-	}
-      
-      set_chord_outline (&skyline_drul->elem_ref (d),
-			 bounds, common, d);
-    }
-  while (flip (&d) != LEFT);
-}
-
-void
-shift_small_ties (Array<Tie_configuration> *tie_configs,
-		  Grob *staff_referencer,
-		  Tie_details const &details)
-{
-  set<int> positions_taken;
-  for (int i = 0; i < tie_configs->size (); i++)
-    positions_taken.insert (int (rint (tie_configs->elem (i).position_)));
-
-  for (int i = 0; i < tie_configs->size (); i++)
-    {
-      Tie_configuration * conf = &tie_configs->elem_ref (i);
-
-      /*
-	on staff line and small enough, translate a little further 
-      */
-      Real h = conf->height (details);
-      bool next_free = positions_taken.find (int (rint (conf->position_ + conf->dir_)))
-	== positions_taken.end ();
-
-      int rounded_pos = int (rint (conf->position_ + conf->delta_y_ / details.staff_space_));
-      bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer, rounded_pos);
-      
-      if (next_free)
-	if (on_line && h < 0.4 * details.staff_space_)
-	  {
-	    positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
-	    conf->delta_y_ += 0.2 * details.staff_space_ * conf->dir_;
-	  }
-	else if (!on_line && h > 0.6 * details.staff_space_)
-	  {
-	    positions_taken.insert (int (rint (conf->position_ + conf->dir_)));
-	    conf->delta_y_ += 0.5 * details.staff_space_ * conf->dir_;
-	  }
-    }
-}
-
-
-void
-final_shape_adjustment (Tie_configuration &conf,
-			Drul_array< Array<Skyline_entry> > const &skylines,
-			Grob *staff_referencer,
-			Tie_details const &details)
-{
-  Real line_dy = 0.0;
-  bool on_line = Staff_symbol_referencer::on_staffline (staff_referencer,
-							int (rint (conf.position_)));
-  if (on_line)
-    line_dy = - sign (conf.height (details) - 0.6 * details.staff_space_)
-      * 0.2 * details.staff_space_ * conf.dir_;
-
-  Real y = conf.position_ * details.staff_space_ * 0.5
-    + line_dy;
-  
-  conf.attachment_x_ = get_skyline_attachment (skylines, y);
-  conf.attachment_x_.intersect (get_skyline_attachment (skylines,
-							y + conf.dir_ * details.staff_space_ * 0.5));
-
-  conf.delta_y_ += line_dy;
-  conf.attachment_x_.widen (-details.x_gap_);
-  if (!on_line
-      && Staff_symbol_referencer::staff_radius (staff_referencer) * details.staff_space_ > y)
-    conf.center_tie_vertically (details);
-}
-
-void
-set_tie_config_directions (Array<Tie_configuration> *tie_configs_ptr)
-{
-  Array<Tie_configuration> &tie_configs (*tie_configs_ptr);
-  
-  if (!tie_configs[0].dir_)
-    tie_configs[0].dir_ = DOWN;
-  if (!tie_configs.top().dir_)
-    tie_configs.top().dir_ = UP;
-
-  /*
-    Seconds
-   */
-  for (int i = 1; i < tie_configs.size(); i++)
-    {
-      if (fabs (tie_configs[i-1].position_ - tie_configs[i].position_) <= 1)
-	{
-	  if (!tie_configs[i-1].dir_)
-	    tie_configs[i-1].dir_ = DOWN;
-	  if (!tie_configs[i].dir_)
-	    tie_configs[i].dir_ = UP;
-	}
-    }
-
-  for (int i = 1; i < tie_configs.size() - 1; i++)
-    {
-      if (tie_configs[i].dir_)
-	continue;
-
-      Direction position_dir = (Direction) sign (tie_configs[i].position_);
-      if (!position_dir)
-	position_dir = DOWN;
-      
-      tie_configs[i].dir_ = position_dir;
-    }
-}
-			   
-
 void
 Tie_column::new_directions (Grob *me)
 {
@@ -355,23 +109,9 @@ Tie_column::new_directions (Grob *me)
 
   SCM manual_configs = me->get_property ("tie-configuration");
   bool manual_override = false;
-  int k = 0;
-  for (SCM s = manual_configs;
-       scm_is_pair (s) && k < tie_configs.size(); s = scm_cdr (s))
-    {
-      SCM entry = scm_car (s);
-      if (!scm_is_pair (entry))
-	continue;
-
-      manual_override = true;
-      Real complete_pos = robust_scm2double (scm_car (entry), tie_configs[k].position_);
-      
-      tie_configs[k].position_ = int (rint (complete_pos));
-      tie_configs[k].delta_y_ = complete_pos - tie_configs[k].position_;
-      tie_configs[k].dir_ = Direction (robust_scm2int (scm_cdr (entry), tie_configs[k].dir_));
-      k ++;
-    }
-
+  set_manual_tie_configuration (&tie_configs,
+				&manual_override,
+				manual_configs);
   set_tie_config_directions (&tie_configs);
 
   Grob *common = me;
@@ -438,6 +178,7 @@ Tie_column::new_directions (Grob *me)
 }
 
 
+
 ADD_INTERFACE (Tie_column, "tie-column-interface",
 	       "Object that sets directions of multiple ties in a tied chord",
 
@@ -445,3 +186,4 @@ ADD_INTERFACE (Tie_column, "tie-column-interface",
 	       "positioning-done "
 	       "tie-configuration "
 	       );
+
diff --git a/lily/tie.cc b/lily/tie.cc
index 8c812e811e..cf2c4d5a38 100644
--- a/lily/tie.cc
+++ b/lily/tie.cc
@@ -24,17 +24,12 @@
 #include "note-head.hh"
 #include "tie-column.hh"
 
-/*
-  tie: Connect two noteheads.
-
-  What if we have
-
-  c4 ~ \clef bass ; c4 or
-
-  c4 \staffchange c4
-
-  do we have non-horizontal ties then?
-*/
+int
+Tie::compare (Grob *const &s1,
+	      Grob *const &s2)
+{
+  return sign (Tie::get_position (s1) - Tie::get_position (s2));
+}
 
 void
 Tie::set_head (Grob *me, Direction d, Grob *h)
diff --git a/ly/declarations-init.ly b/ly/declarations-init.ly
index 824f0ef6fd..60e8fbabe0 100644
--- a/ly/declarations-init.ly
+++ b/ly/declarations-init.ly
@@ -65,7 +65,8 @@ escapedSmallerSymbol = #(make-span-event 'CrescendoEvent START)
 
 melisma = #(make-span-event 'ManualMelismaEvent START)
 melismaEnd = #(make-span-event 'ManualMelismaEvent STOP)
-
+laissezVibrer = #(make-music 'LaissezVibrerEvent)
+		  
 \include "grace-init.ly"
 \include "midi-init.ly"
 \include "paper-defaults.ly"
diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly
index 15e40fc446..6bd5df4365 100644
--- a/ly/engraver-init.ly
+++ b/ly/engraver-init.ly
@@ -182,7 +182,7 @@ contained staves are not connected vertically."
   \consists "Trill_spanner_engraver"
   \consists "Grob_pq_engraver"
   \consists "Forbid_line_break_engraver"
-
+  \consists "Laissez_vibrer_engraver"
   \consists "Note_head_line_engraver"
   \consists "Glissando_engraver"
   \consists "Ligature_bracket_engraver"
diff --git a/mf/GNUmakefile b/mf/GNUmakefile
index f8b18ab47c..bef84b3a59 100644
--- a/mf/GNUmakefile
+++ b/mf/GNUmakefile
@@ -43,7 +43,7 @@ $(outdir)/aybabtu.otf-gtable: $(BRACES:%=$(outdir)/feta-braces-%.otf-gtable)
 LOG_FILES = $(FETA_MF_FILES:%.mf=$(outdir)/%.log)
 LISP_FILES = $(FETA_MF_FILES:%.mf=$(outdir)/%.lisp)
 TEXTABLES = $(FETA_MF_FILES:%.mf=$(outdir)/%.tex)
-ENC_FILES = $(TEXTABLES:.tex=.enc) $(outdir)/cmr.enc
+ENC_FILES = $(TEXTABLES:.tex=.enc)
 TFM_FILES = $(FETA_MF_FILES:%.mf=$(outdir)/%.tfm)\
  $(SAUTER_FONTS:%=$(outdir)/%.tfm)
 FETA_LIST_FILES = $(FETA_MF_FILES:%.mf=$(outdir)/%list.ly)
diff --git a/mf/cmr.enc.in b/mf/cmr.enc.in
deleted file mode 100644
index fca576b7b4..0000000000
--- a/mf/cmr.enc.in
+++ /dev/null
@@ -1,36 +0,0 @@
-% Thomas Esser, Dec 2002. public domain
-%
-% Encoding for:
-%     cmb10 cmbx10 cmbx12 cmbx5 cmbx6 cmbx7 cmbx8 cmbx9 cmbxsl10
-%     cmdunh10 cmr10 cmr12 cmr17cmr6 cmr7 cmr8 cmr9 cmsl10 cmsl12 cmsl8
-%     cmsl9 cmss10cmss12 cmss17 cmss8 cmss9 cmssbx10 cmssdc10 cmssi10
-%     cmssi12 cmssi17 cmssi8cmssi9 cmssq8 cmssqi8 cmvtt10
-%
-/TeXf7b6d320Encoding [
-/Gamma /Delta /Theta /Lambda /Xi /Pi /Sigma /Upsilon /Phi /Psi /Omega
-/ff /fi /fl /ffi /ffl /dotlessi /dotlessj /grave /acute /caron /breve
-/macron /ring /cedilla /germandbls /ae /oe /oslash /AE /OE /Oslash
-/suppress /exclam /quotedblright /numbersign /dollar /percent /ampersand
-/quoteright /parenleft /parenright /asterisk /plus /comma /hyphen
-/period /slash /zero /one /two /three /four /five /six /seven /eight
-/nine /colon /semicolon /exclamdown /equal /questiondown /question /at
-/A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X
-/Y /Z /bracketleft /quotedblleft /bracketright /circumflex /dotaccent
-/quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u
-/v /w /x /y /z /endash /emdash /hungarumlaut /tilde /dieresis /suppress
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /space
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
-] def
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index fd984274e5..993cff018e 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -677,6 +677,26 @@
 		 (interfaces . (key-signature-interface
 				font-interface
 				break-aligned-interface))))))
+    (LaissezVibrerTie
+     . (
+	(print-function  . ,Laissez_vibrer_tie::print)
+	(details . ((ratio . 0.333)
+		    (height-limit . 1.0)))
+	(thickness . 1.0)
+	(meta . ((class . Item)
+		 (interfaces . (laissez-vibrer-tie-interface))
+		 ))
+	))
+    
+    (LaissezVibrerTieColumn
+     . (
+	(X-extent-callback . #f)
+	(Y-extent-callback . #f)
+	(meta . ((class . Item)
+		 (interfaces . (laissez-vibrer-tie-column-interface))
+		 ))
+	))
+    
     (LedgerLineSpanner
      . (
 	(print-function . ,Ledger_line_spanner::print)
diff --git a/scm/define-music-types.scm b/scm/define-music-types.scm
index 1bdead9056..3c9d9e2b65 100644
--- a/scm/define-music-types.scm
+++ b/scm/define-music-types.scm
@@ -221,7 +221,13 @@ Syntax: @code{\\key } @var{name} @var{scale}.")
 	(to-relative-callback . ,(lambda (x p) p))
 	(types . (general-music key-change-event event))
 	))
-    
+    (LaissezVibrerEvent
+     . ((description . "Don't damp this chord.
+
+Syntax: @var{note}\\laissezVibrer.")
+
+	(types . (general-music event laissez-vibrer-event))
+	))
     (LigatureEvent
      . (
 	(description .	"(docme).")