From: hanwen <hanwen>
Date: Fri, 9 Dec 2005 23:58:55 +0000 (+0000)
Subject: * ly/engraver-init.ly (AncientRemoveEmptyStaffContext): remove
X-Git-Tag: release/2.7.38^2~459
X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=8dabdcc8009e005208ca178a25caa81edc8d0211;p=lilypond.git

* ly/engraver-init.ly (AncientRemoveEmptyStaffContext): remove
Span_arpeggio_engraver, add Tweak_engraver to Score context.

* lily/parser.yy: reorganize file layout.

* ly/music-functions-init.ly: add tweak music function.

* lily/grob-info.cc (ultimate_music_cause): new function:
recursively lookup causes.

* lily/parser.yy (chord_body_element): allow music functions for
post-events, allow music functions for chord elements.

* lily/font-config-scheme.cc (display_fontset): add cast.

* python/convertrules.py (FatalConversionError.sub_syms): \tag
#'(a b) -> \tag #'a \tag #'b rule.

* python/musicexp.py (Output_printer.dump_version): new function
---

diff --git a/ChangeLog b/ChangeLog
index 82318adeb4..c89f366dac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,35 @@
-2005-12-09  Werner Lemberg  <wl@gnu.org>
+2005-12-10  Han-Wen Nienhuys  <hanwen@xs4all.nl>
 
-	* mf/feta-beugel.mf (draw_brace): Use subpaths to assure correct
-	tension values.
+	* ly/engraver-init.ly (AncientRemoveEmptyStaffContext): remove
+	Span_arpeggio_engraver, add Tweak_engraver to Score context. 
+
+	* lily/parser.yy: reorganize file layout.
+
+	* ly/music-functions-init.ly: add tweak music function.
+
+	* lily/grob-info.cc (ultimate_music_cause): new function:
+	recursively lookup causes. 
+
+	* lily/parser.yy (chord_body_element): allow music functions for
+	post-events, allow music functions for chord elements. 
+ 
+	* lily/font-config-scheme.cc (display_fontset): add cast.
+
+	* python/convertrules.py (FatalConversionError.sub_syms): \tag
+	#'(a b) -> \tag #'a \tag #'b rule.
+
+	* python/musicexp.py (Output_printer.dump_version): new function
+
+2005-12-09  Han-Wen Nienhuys  <hanwen@xs4all.nl>
+
+	* lily/parser.yy (FIXME): remove \tag
+	(FIXME): remove tag_music() function.
+
+	* lily/lily-lexer.cc: remove \tag
+
+	* ly/music-functions-init.ly: define music-function "tag"
+
+	* lily/parser.yy (chord_body_element): allow tags in chord bodies.
 
 2005-12-08  Han-Wen Nienhuys  <hanwen@xs4all.nl>
 
diff --git a/Documentation/topdocs/NEWS.tely b/Documentation/topdocs/NEWS.tely
index 6801d95811..b71f00ebce 100644
--- a/Documentation/topdocs/NEWS.tely
+++ b/Documentation/topdocs/NEWS.tely
@@ -45,6 +45,31 @@ This document is also available in @uref{NEWS.pdf,PDF}.
 
 
 @itemize @bullet
+@item With the @code{\tweak} music function, layout objects that are directly
+connected to input may be tuned,
+
+@lilypond[relative=2,fragment,raggedright]
+<
+  \tweak #'font-size #3  c
+  \tweak #'color #red  e
+  \tweak #'style #cross  g
+  \tweak #'duration-log #1  a
+>4
+@end lilypond
+
+This feature was sponsored by Sean Reed and Bertalan Fodor.
+
+@item Generic music functions may now also be used on articulations
+and chord elements, eg.
+
+@verbatim
+  < \displayMusic c
+    e-\keepWithTag #'bla -\tag #'bla ^2 >
+@end verbatim
+
+This feature was sponsored by Sean Reed and Bertalan Fodor.
+
+
 @item Spaces between lyrics and distance between syllables with
 hyphens may now be separately tuned through the
 @code{LyricSpace} grob.
diff --git a/Documentation/user/advanced-notation.itely b/Documentation/user/advanced-notation.itely
index 0433e25fad..a498d1f6d5 100644
--- a/Documentation/user/advanced-notation.itely
+++ b/Documentation/user/advanced-notation.itely
@@ -1097,10 +1097,11 @@ would yield
 
 @lilypondfile[raggedright,quote]{tag-filter.ly}
 
-The argument of the @code{\tag} command should be a symbol, or a list
-of symbols, for example,
+The argument of the @code{\tag} command should be a symbol. It's 
+possible to put multiple tags on a piece of music, with multiple
+@code{\tag} entries, 
 @example
-\tag #'(original-part transposed-part) @dots{}
+  \tag #'original-part \tag #'transposed-part @dots{}
 @end example
 
 
diff --git a/THANKS b/THANKS
index adf32cc13c..6a8d315dec 100644
--- a/THANKS
+++ b/THANKS
@@ -16,10 +16,10 @@ Bruce Fairchild
 Cameron Horsburgh
 Heikki Junes
 Joe Neeman
+Nicolas Sceaux
 Sven Axelsson
+Werner Lemberg
 Yoshinobu Ishizaki
-Nicolas Sceaux
-
 
 SPONSORS
 
@@ -36,6 +36,7 @@ Kris Shaffer
 Mark van den Borre
 Nancho Alvarez
 Nicolas Sceaux
+Sean Reed
 Steve Doonan
 Sven Axelsson
 Trent Johnston
diff --git a/input/regression/grob-tweak.ly b/input/regression/grob-tweak.ly
new file mode 100644
index 0000000000..baf6ef1d6a
--- /dev/null
+++ b/input/regression/grob-tweak.ly
@@ -0,0 +1,22 @@
+\header
+{
+
+  texidoc = "With the @code{\tweak} function, individual grobs that
+  are directly caused by events may be tuned directly."
+
+}
+
+\version "2.7.22"
+\paper {
+  raggedright = ##t
+}
+
+{
+  \set fingeringOrientations = #'(right)
+  <
+    \tweak #'font-size #3  c
+    \tweak #'color #red  d-\tweak #'font-size #8 -4
+    \tweak #'style #'cross  g
+    \tweak #'duration-log #1  a
+  >4
+}
diff --git a/lily/auto-beam-engraver.cc b/lily/auto-beam-engraver.cc
index cdf0ad31df..9609e40aa0 100644
--- a/lily/auto-beam-engraver.cc
+++ b/lily/auto-beam-engraver.cc
@@ -334,7 +334,7 @@ Auto_beam_engraver::acknowledge_stem (Grob_info info)
 {
   check_bar_property ();
   Item *stem = dynamic_cast<Item *> (info.grob ());
-  Music *m = info.music_cause ();
+  Music *m = info.ultimate_music_cause ();
   if (!m->is_mus_type ("rhythmic-event"))
     {
       programming_error ("stem must have rhythmic structure");
diff --git a/lily/beam-engraver.cc b/lily/beam-engraver.cc
index 102af1f2ac..4ba9dd7a99 100644
--- a/lily/beam-engraver.cc
+++ b/lily/beam-engraver.cc
@@ -221,52 +221,55 @@ Beam_engraver::acknowledge_rest (Grob_info info)
     }
 }
 
+
+
 void
 Beam_engraver::acknowledge_stem (Grob_info info)
 {
-  if (beam_)
+  if (!beam_)
+    return;
+  
+  Moment now = now_mom ();
+  if (!valid_start_point ())
+    return;
+
+  Item *stem = dynamic_cast<Item *> (info.grob ());
+  if (Stem::get_beam (stem))
+    return;
+
+  
+  
+  Music *m = info.ultimate_music_cause ();
+  if (!m->is_mus_type ("rhythmic-event"))
     {
-      Moment now = now_mom ();
-
-      if (!valid_start_point ())
-	return;
-
-      Item *stem = dynamic_cast<Item *> (info.grob ());
-      if (Stem::get_beam (stem))
-	return;
-
-      Music *m = info.music_cause ();
-      if (!m->is_mus_type ("rhythmic-event"))
-	{
-	  String s = _ ("stem must have Rhythmic structure");
-	  if (info.music_cause ())
-	    info.music_cause ()->origin ()->warning (s);
-	  else
-	    ::warning (s);
-
-	  return;
-	}
+      String s = _ ("stem must have Rhythmic structure");
+      if (info.music_cause ())
+	info.music_cause ()->origin ()->warning (s);
+      else
+	::warning (s);
 
-      last_stem_added_at_ = now;
-      int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
-      if (durlog <= 2)
-	{
-	  m->origin ()->warning (_ ("stem doesn't fit in beam"));
-	  prev_start_ev_->origin ()->warning (_ ("beam was started here"));
-	  /*
-	    don't return, since
+      return;
+    }
 
-	    [r4 c8] can just as well be modern notation.
-	  */
-	}
+  last_stem_added_at_ = now;
+  int durlog = unsmob_duration (m->get_property ("duration"))->duration_log ();
+  if (durlog <= 2)
+    {
+      m->origin ()->warning (_ ("stem doesn't fit in beam"));
+      prev_start_ev_->origin ()->warning (_ ("beam was started here"));
+      /*
+	don't return, since
 
-      stem->set_property ("duration-log",
-			  scm_from_int (durlog));
-      Moment stem_location = now - beam_start_mom_ + beam_start_location_;
-      beam_info_->add_stem (stem_location,
-			    max (durlog- 2, 0));
-      Beam::add_stem (beam_, stem);
+	[r4 c8] can just as well be modern notation.
+      */
     }
+
+  stem->set_property ("duration-log",
+		      scm_from_int (durlog));
+  Moment stem_location = now - beam_start_mom_ + beam_start_location_;
+  beam_info_->add_stem (stem_location,
+			max (durlog- 2, 0));
+  Beam::add_stem (beam_, stem);
 }
 
 ADD_ACKNOWLEDGER (Beam_engraver, stem);
diff --git a/lily/font-config-scheme.cc b/lily/font-config-scheme.cc
index 79b069befa..279ffb57b3 100644
--- a/lily/font-config-scheme.cc
+++ b/lily/font-config-scheme.cc
@@ -29,7 +29,7 @@ display_fontset (FcFontSet *fs)
 			      "designsize", 0, &str) == FcResultMatch)
 	printf ("designsize %s\n ", str);
       
-      printf ("%s\n", font);
+      printf ("%s\n", (const char*) font);
       free (font);
     }
 }
diff --git a/lily/grob-info.cc b/lily/grob-info.cc
index be4a41c6c2..4ffbcf9c15 100644
--- a/lily/grob-info.cc
+++ b/lily/grob-info.cc
@@ -27,7 +27,7 @@ Grob_info::Grob_info ()
 }
 
 Music *
-Grob_info::music_cause ()
+Grob_info::music_cause () const
 {
   SCM cause = grob_->get_property ("cause");
   return unsmob_music (cause);
@@ -65,3 +65,16 @@ Grob_info::item () const
 {
   return dynamic_cast<Item *> (grob_);
 }
+
+Music *
+Grob_info::ultimate_music_cause () const
+{
+  SCM cause = grob_->self_scm ();
+  while (unsmob_grob (cause))
+    {
+      cause = unsmob_grob (cause)->get_property ("cause");
+    }
+
+  return unsmob_music (cause);
+}
+
diff --git a/lily/include/grob-info.hh b/lily/include/grob-info.hh
index 9dd40fea00..61b903b64b 100644
--- a/lily/include/grob-info.hh
+++ b/lily/include/grob-info.hh
@@ -27,7 +27,8 @@ public:
   Translator *origin_translator () const { return origin_trans_; }
 
   Context *context () const;
-  Music *music_cause ();
+  Music *music_cause () const;
+  Music *ultimate_music_cause () const;
   Link_array<Context> origin_contexts (Translator *) const;
   Grob_info (Translator *, Grob *);
   Grob_info ();
diff --git a/lily/lily-lexer.cc b/lily/lily-lexer.cc
index 7a8deb6dc3..03ba282520 100644
--- a/lily/lily-lexer.cc
+++ b/lily/lily-lexer.cc
@@ -73,7 +73,6 @@ static Keyword_ent the_key_tab[]
   {"set", SET},
   {"simultaneous", SIMULTANEOUS},
   {"skip", SKIP},
-  {"tag", TAG},
   {"tempo", TEMPO},
   {"time", TIME_T},
   {"times", TIMES},
diff --git a/lily/note-head-line-engraver.cc b/lily/note-head-line-engraver.cc
index 34b6945088..a7becd06ef 100644
--- a/lily/note-head-line-engraver.cc
+++ b/lily/note-head-line-engraver.cc
@@ -97,6 +97,7 @@ Note_head_line_engraver::stop_translation_timestep ()
 }
 
 #include "translator.icc"
+
 ADD_ACKNOWLEDGER (Note_head_line_engraver, rhythmic_head);
 ADD_TRANSLATOR (Note_head_line_engraver,
 		/* doc */ "Engrave a line between two note heads, for example a glissando.  If "
diff --git a/lily/parser.yy b/lily/parser.yy
index 70f35f5000..4b250d0966 100644
--- a/lily/parser.yy
+++ b/lily/parser.yy
@@ -1,5 +1,3 @@
-%{ // -*-Fundamental-*-
-
 /*
   parser.yy -- Bison/C++ parser for LilyPond
 
@@ -9,6 +7,54 @@
                  Jan Nieuwenhuizen <janneke@gnu.org>
 */
 
+%{
+
+#define YYERROR_VERBOSE 1
+#define YYPARSE_PARAM my_lily_parser
+#define YYLEX_PARAM my_lily_parser
+#define THIS\
+	((Lily_parser *) my_lily_parser)
+
+#define yyerror THIS->parser_error
+
+/* We use custom location type: Input objects */
+#define YYLTYPE Input
+#define YYLLOC_DEFAULT(Current,Rhs,N) \
+	((Current).set_location ((Rhs)[1], (Rhs)[N]))
+
+
+%}
+
+/* We use SCMs to do strings, because it saves us the trouble of
+deleting them.  Let's hope that a stack overflow doesnt trigger a move
+of the parse stack onto the heap. */
+
+%left PREC_TOP
+%left ADDLYRICS
+%left PREC_BOT
+
+%expect 1
+
+/* One shift/reduce problem
+
+1.  \repeat
+	\repeat .. \alternative
+
+    \repeat { \repeat .. \alternative }
+
+or
+
+    \repeat { \repeat } \alternative 
+*/
+
+
+%pure_parser
+%locations
+
+
+
+%{ // -*-Fundamental-*-
+
 /*
 FIXME:
 
@@ -47,174 +93,8 @@ using namespace std;
 #include "warn.hh"
 #include "music.hh"
 
-#define MY_MAKE_MUSIC(x)  make_music_by_name (ly_symbol2scm (x))
-
-Music *property_op_to_music (SCM op);
-Music *context_spec_music (SCM type, SCM id, Music *m, SCM ops);
-SCM get_next_unique_context_id ();
-SCM get_next_unique_lyrics_context_id ();
-
-#undef _
-#if !HAVE_GETTEXT
-#define _(x) x
-#else
-#include <libintl.h>
-#define _(x) gettext (x)
-#endif
-
-#define YYERROR_VERBOSE 1
-
-#define YYPARSE_PARAM my_lily_parser
-#define YYLEX_PARAM my_lily_parser
-#define THIS\
-	((Lily_parser *) my_lily_parser)
-
-#define yyerror THIS->parser_error
-
-/* We use custom location type: Input objects */
-#define YYLTYPE Input
-#define YYLLOC_DEFAULT(Current,Rhs,N) \
-	((Current).set_location ((Rhs)[1], (Rhs)[N]))
-
-
-/* Add symbols to the TAGS field of a music object.  */
-
-void
-tag_music (Music *m, SCM tag, Input ip)
-{
-	SCM tags = m->get_property ("tags");
-	if (scm_is_symbol (tag))
-		tags = scm_cons (tag, tags);
-	else if (ly_is_list (tag))
-		tags = ly_append2 (tag, tags);
-	else
-		ip.warning (_ ("tag must be symbol or list of symbols"));
-
-	m->set_property ("tags", tags);
-}
-
-bool
-is_regular_identifier (SCM id)
-{
-  String str = ly_scm2string (id);
-  char const *s = str.to_str0 ();
-
-  bool v = true;
-#if 0
-  isalpha (*s);
-  s++;
-#endif
-  while (*s && v)
-   {
-        v = v && isalnum (*s);
-        s++;
-   }
-  return v;
-}
-
-
-SCM
-get_first_context_id (SCM type, Music *m)
-{
-	SCM id = m->get_property ("context-id");
-	if (SCM_BOOL_T == scm_equal_p (m->get_property ("context-type"), type)
-	    && scm_is_string (m->get_property ("context-id"))
-	    && scm_c_string_length (id) > 0)
-	{
-		return id;
-	}
-	return SCM_EOL;
-}
-
-SCM
-make_simple_markup (SCM a)
-{
-	return a;
-}
-
-bool
-is_duration (int t)
-{
-  return t && t == 1 << intlog2 (t);
-}
-
-void
-set_music_properties (Music *p, SCM a)
-{
-  for (SCM k = a; scm_is_pair (k); k = scm_cdr (k))
- 	p->internal_set_property (scm_caar (k), scm_cdar (k));
-}
-
-SCM
-make_chord_step (int step, int alter)
-{
-	if (step == 7)
-		alter += FLAT;
-
-	while (step < 0)
-		step += 7;
-	Pitch m ((step -1) / 7, (step - 1) % 7, alter);
-	return m.smobbed_copy ();
-}
-
-
-SCM
-make_chord (SCM pitch, SCM dur, SCM modification_list)
-{
-	SCM chord_ctor = ly_lily_module_constant ("construct-chord");
-	SCM ch = scm_call_3 (chord_ctor, pitch, dur, modification_list);
-
-	unsmob_music (ch)->protect();	
-	return ch;
-}
-
-/* Todo: actually also use apply iso. call too ...  */
-bool
-ly_input_procedure_p (SCM x)
-{
-	return ly_is_procedure (x)
-		|| (scm_is_pair (x) && ly_is_procedure (scm_car (x)));
-}
-
-Music*
-set_property_music (SCM sym, SCM value)
-{
-	Music *p = MY_MAKE_MUSIC ("PropertySet");
-	p->set_property ("symbol", sym);
-	p->set_property ("value", value);
-	return p;
-}
-
-Music*
-make_music_relative (Pitch start, Music *music)
-{
-	Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic");
- 	relative->set_property ("element", music->self_scm ());
-	
- 	Pitch last = music->to_relative_octave (start);
- 	if (lily_1_8_relative)
- 		music->set_property ("last-pitch", last.smobbed_copy ());
-	return relative;
-}
-
-Music*
-make_lyric_combine_music (SCM name, Music *music)
-{
-	Music *combine = MY_MAKE_MUSIC ("LyricCombineMusic");
-	combine->set_property ("element", music->self_scm ());
- 	combine->set_property ("associated-context", name);
-	return combine;
-}
-
 %}
 
-/* We use SCMs to do strings, because it saves us the trouble of
-deleting them.  Let's hope that a stack overflow doesnt trigger a move
-of the parse stack onto the heap. */
-
-%left PREC_TOP
-%left ADDLYRICS
-%left PREC_BOT
 
 %union {
 	Book *book;
@@ -225,40 +105,41 @@ of the parse stack onto the heap. */
  	Score *score;
  	int i;
 }
-%{
-
-int
-yylex (YYSTYPE *s, YYLTYPE *loc, void *v)
-{
-	Lily_parser *pars = (Lily_parser*) v;
-	Lily_lexer *lex = pars->lexer_;
-
-	lex->lexval = (void*) s;
-	lex->lexloc = loc;
-	lex->prepare_for_next_token ();
-	return lex->yylex ();
-}
-
-
-%}
 
-%expect 1
+%{
 
-/* One shift/reduce problem
+#define MY_MAKE_MUSIC(x)  make_music_by_name (ly_symbol2scm (x))
 
-1.  \repeat
-	\repeat .. \alternative
+Music *property_op_to_music (SCM op);
+Music *context_spec_music (SCM type, SCM id, Music *m, SCM ops);
+SCM get_next_unique_context_id ();
+SCM get_next_unique_lyrics_context_id ();
 
-    \repeat { \repeat .. \alternative }
+#undef _
+#if !HAVE_GETTEXT
+#define _(x) x
+#else
+#include <libintl.h>
+#define _(x) gettext (x)
+#endif
 
-or
 
-    \repeat { \repeat } \alternative 
-*/
 
+Music *make_lyric_combine_music (SCM name, Music *music);
+Music *make_music_relative (Pitch start, Music *music);
+Music *run_music_function (Lily_parser *, SCM expr);
+Music *set_property_music (SCM sym, SCM value);
+SCM get_first_context_id (SCM type, Music *m);
+SCM make_chord (SCM pitch, SCM dur, SCM modification_list);
+SCM make_chord_step (int step, int alter);
+SCM make_simple_markup (SCM a);
+bool is_duration (int t);
+bool is_regular_identifier (SCM id);
+bool ly_input_procedure_p (SCM x);
+int yylex (YYSTYPE *s, YYLTYPE *loc, void *v);
+void set_music_properties (Music *p, SCM a);
 
-%pure_parser
-%locations
+%}
 
 /* The third option is an alias that will be used to display the
    syntax error.  Bison CVS now correctly handles backslash escapes.
@@ -318,7 +199,6 @@ or
 %token SET "\\set"
 %token SIMULTANEOUS "\\simultaneous"
 %token SKIP "\\skip"
-%token TAG "\\tag"
 %token TEMPO "\\tempo"
 %token TIMES "\\times"
 %token TRANSPOSE "\\transpose"
@@ -435,7 +315,6 @@ If we give names, Bison complains.
 %type <i> tremolo_type
 
 %type <music> Composite_music
-%type <music> Generic_prefix_music
 %type <music> Grouped_music_list
 %type <music> Music
 %type <music> Prefix_composite_music
@@ -459,7 +338,6 @@ If we give names, Bison complains.
 %type <music> relative_music
 %type <music> simple_element
 %type <music> string_number_event
-%type <music> tagged_post_event
 %type <music> tempo_event
 %type <music> toplevel_music
 
@@ -474,6 +352,8 @@ If we give names, Bison complains.
 %type <scm> absolute_pitch
 %type <scm> assignment_id
 %type <scm> bare_number
+%type <scm> music_function_event
+%type <scm> music_function_chord_body
 %type <scm> bass_figure
 %type <scm> figured_bass_modification
 %type <scm> br_bass_figure
@@ -1113,10 +993,7 @@ Generic_prefix_music_scm:
 	| MUSIC_FUNCTION_MARKUP full_markup {
 		$$ = scm_list_3 ($1, make_input (@$), $2);
 	}
-	| MUSIC_FUNCTION_MUSIC Music {
-		$$ = scm_list_3 ($1, make_input (@$), $2->self_scm ());
-		$2->unprotect ();
-	}
+
 	| MUSIC_FUNCTION_SCM_MUSIC embedded_scm Music {
 		$$ = scm_list_4 ($1, make_input (@$), $2, $3->self_scm ());
 		$3->unprotect ();
@@ -1127,6 +1004,10 @@ Generic_prefix_music_scm:
 	| MUSIC_FUNCTION_SCM_SCM_SCM embedded_scm embedded_scm embedded_scm {
 		$$ = scm_list_5 ($1, make_input (@$), $2, $3, $4);
 	}
+	| MUSIC_FUNCTION_MUSIC Music {
+		$$ = scm_list_3 ($1, make_input (@$), $2->self_scm ());
+		$2->unprotect ();
+	}
 	| MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm Music {
 		$$ = scm_list_5 ($1, make_input (@$), $2, $3, $4->self_scm ());
 	}
@@ -1154,46 +1035,9 @@ Generic_prefix_music_scm:
 	}
 	;
 
-Generic_prefix_music:
-	Generic_prefix_music_scm {
-		SCM func = scm_car ($1);
-		Input *loc = unsmob_input (scm_cadr ($1));
-		SCM args = scm_cddr ($1);
-		SCM sig = scm_object_property (func, ly_symbol2scm ("music-function-signature"));
-
-		SCM type_check_proc = ly_lily_module_constant ("type-check-list");
-		bool ok  = true;
-
-		if (!to_boolean (scm_call_3  (type_check_proc, scm_cadr ($1), sig, args)))
-		{
-			THIS->error_level_ = 1;
-			ok = false;
-		}
-
-		SCM m = SCM_EOL;
-  		if (ok)
-			m = scm_apply_0 (func, scm_cons (THIS->self_scm(),
-							 scm_cdr ($1)));
-
-		if (unsmob_music (m))
-			{
-			$$ = unsmob_music (m);
-			$$->protect ();
-			}
-		else
-			{
-			if (ok)
- 				loc->error (_ ("music head function must return Music object")); 
-			$$ = MY_MAKE_MUSIC ("Music");
-			}
-		$$->set_spot (*loc);
-	}
-	;
-
-
 Prefix_composite_music:
-	Generic_prefix_music {
-		$$ = $1;
+	Generic_prefix_music_scm {
+		$$ = run_music_function (THIS, $1);
 	}
 	| CONTEXT simple_string '=' simple_string optional_context_mod Music {
 		$$ = context_spec_music ($2, $4, $6, $5);
@@ -1262,10 +1106,6 @@ Prefix_composite_music:
 	}
 	| relative_music	{ $$ = $1; }
 	| re_rhythmed_music	{ $$ = $1; }
-	| TAG embedded_scm Music {
-		tag_music ($3, $2, @$);
-		$$ = $3;
-	}
 	;
 
 mode_changing_head: 
@@ -1689,8 +1529,33 @@ chord_body_element:
 		}
 		$$ = n;
 	}
+	| music_function_chord_body { 
+		$$ = run_music_function (THIS, $1);
+		$$->set_spot (@$);
+	}
+	;
+
+music_function_chord_body:
+	MUSIC_FUNCTION {
+		$$ = scm_list_2 ($1, make_input (@$));
+	}
+	| MUSIC_FUNCTION_MUSIC chord_body_element {
+		$$ = scm_list_3 ($1, make_input (@$),
+					$2->self_scm ());
+	}
+	| MUSIC_FUNCTION_SCM_MUSIC embedded_scm chord_body_element {
+		$$ = scm_list_4 ($1, make_input (@$),
+					$2, $3->self_scm ());
+	}
+	| MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm
+		chord_body_element {
+
+		$$ = scm_list_5 ($1, make_input (@$),
+					$2, $3, $4->self_scm ());
+	}
 	;
 
+
 add_quote:
 	ADDQUOTE string Music {
 		SCM adder = ly_lily_module_constant ("add-quotable");
@@ -1847,26 +1712,30 @@ post_events:
 		$$ = scm_cons ($2->self_scm (), $$);
 		$2->unprotect ();
 	}
-	| post_events tagged_post_event {
-		$2 -> set_spot (@2);
-		$$ = scm_cons ($2->self_scm (), $$);
-		$2->unprotect ();
-	}
 	;
 
-
-tagged_post_event:
-	'-' TAG embedded_scm post_event {
-		tag_music ($4, $3, @$);
-		$$ = $4;
+music_function_event:
+	MUSIC_FUNCTION_MUSIC post_event {
+		$$ = scm_list_3 ($1, make_input (@$), $2->self_scm ());
+	}
+	| MUSIC_FUNCTION_SCM_MUSIC embedded_scm post_event {
+		$$ = scm_list_4 ($1, make_input (@$), $2, $3->self_scm ());
+	}
+	| MUSIC_FUNCTION_SCM_SCM_MUSIC embedded_scm embedded_scm post_event {
+		$$ = scm_list_5 ($1, make_input (@$), $2, $3, $4->self_scm ());
 	}
 	;
 
-
+	
 post_event:
 	direction_less_event {
 		$$ = $1;
 	}
+	| '-' music_function_event {
+		Music *mus = run_music_function (THIS, $2);
+		mus->set_spot (@1);
+		$$ = mus;
+	}
 	| HYPHEN {
 		if (!THIS->lexer_->is_lyric_state ())
 			THIS->parser_error (@1, _ ("have to be in Lyric mode for lyrics"));
@@ -2834,6 +2703,174 @@ get_next_unique_lyrics_context_id ()
 {
 	static int new_context_count;
 	char s[128];
-	snprintf (s, 1024, "uniqueContext%d", new_context_count++);
+	snprintf (s, sizeof (s)-1, "uniqueContext%d", new_context_count++);
 	return scm_makfrom0str (s);
 }
+
+
+Music *
+run_music_function (Lily_parser *parser, SCM expr)
+{
+	SCM func = scm_car (expr);
+	Input *loc = unsmob_input (scm_cadr (expr));
+	SCM args = scm_cddr (expr);
+	SCM sig = scm_object_property (func, ly_symbol2scm ("music-function-signature"));
+
+	SCM type_check_proc = ly_lily_module_constant ("type-check-list");
+	bool ok  = true;
+
+	if (!to_boolean (scm_call_3  (type_check_proc, scm_cadr (expr), sig, args)))
+	{
+		parser->error_level_ = 1;
+		ok = false;
+	}
+
+	SCM m = SCM_EOL;
+	if (ok)
+		m = scm_apply_0 (func, scm_cons (parser->self_scm(),
+						 scm_cdr (expr)));
+
+
+	Music* retval = 0;
+	if (unsmob_music (m))
+		{
+		retval = unsmob_music (m);
+		retval->protect ();
+		}
+	else
+		{
+		if (ok)
+			loc->error (_ ("music head function must return Music object")); 
+		retval = MY_MAKE_MUSIC ("Music");
+		}
+	retval->set_spot (*loc);
+	return retval;
+}
+
+bool
+is_regular_identifier (SCM id)
+{
+  String str = ly_scm2string (id);
+  char const *s = str.to_str0 ();
+
+  bool v = true;
+#if 0
+  isalpha (*s);
+  s++;
+#endif
+  while (*s && v)
+   {
+        v = v && isalnum (*s);
+        s++;
+   }
+  return v;
+}
+
+
+SCM
+get_first_context_id (SCM type, Music *m)
+{
+	SCM id = m->get_property ("context-id");
+	if (SCM_BOOL_T == scm_equal_p (m->get_property ("context-type"), type)
+	    && scm_is_string (m->get_property ("context-id"))
+	    && scm_c_string_length (id) > 0)
+	{
+		return id;
+	}
+	return SCM_EOL;
+}
+
+SCM
+make_simple_markup (SCM a)
+{
+	return a;
+}
+
+bool
+is_duration (int t)
+{
+  return t && t == 1 << intlog2 (t);
+}
+
+void
+set_music_properties (Music *p, SCM a)
+{
+  for (SCM k = a; scm_is_pair (k); k = scm_cdr (k))
+ 	p->internal_set_property (scm_caar (k), scm_cdar (k));
+}
+
+
+SCM
+make_chord_step (int step, int alter)
+{
+	if (step == 7)
+		alter += FLAT;
+
+	while (step < 0)
+		step += 7;
+	Pitch m ((step -1) / 7, (step - 1) % 7, alter);
+	return m.smobbed_copy ();
+}
+
+
+SCM
+make_chord (SCM pitch, SCM dur, SCM modification_list)
+{
+	SCM chord_ctor = ly_lily_module_constant ("construct-chord");
+	SCM ch = scm_call_3 (chord_ctor, pitch, dur, modification_list);
+
+	unsmob_music (ch)->protect();	
+	return ch;
+}
+
+
+/* Todo: actually also use apply iso. call too ...  */
+bool
+ly_input_procedure_p (SCM x)
+{
+	return ly_is_procedure (x)
+		|| (scm_is_pair (x) && ly_is_procedure (scm_car (x)));
+}
+
+Music*
+set_property_music (SCM sym, SCM value)
+{
+	Music *p = MY_MAKE_MUSIC ("PropertySet");
+	p->set_property ("symbol", sym);
+	p->set_property ("value", value);
+	return p;
+}
+
+Music*
+make_music_relative (Pitch start, Music *music)
+{
+	Music *relative = MY_MAKE_MUSIC ("RelativeOctaveMusic");
+ 	relative->set_property ("element", music->self_scm ());
+	
+ 	Pitch last = music->to_relative_octave (start);
+ 	if (lily_1_8_relative)
+ 		music->set_property ("last-pitch", last.smobbed_copy ());
+	return relative;
+}
+
+Music *
+make_lyric_combine_music (SCM name, Music *music)
+{
+	Music *combine = MY_MAKE_MUSIC ("LyricCombineMusic");
+	combine->set_property ("element", music->self_scm ());
+ 	combine->set_property ("associated-context", name);
+	return combine;
+}
+
+
+int
+yylex (YYSTYPE *s, YYLTYPE *loc, void *v)
+{
+	Lily_parser *pars = (Lily_parser*) v;
+	Lily_lexer *lex = pars->lexer_;
+
+	lex->lexval = (void*) s;
+	lex->lexloc = loc;
+	lex->prepare_for_next_token ();
+	return lex->yylex ();
+}
diff --git a/lily/stem-engraver.cc b/lily/stem-engraver.cc
index 052f4d653c..019b05333f 100644
--- a/lily/stem-engraver.cc
+++ b/lily/stem-engraver.cc
@@ -51,7 +51,7 @@ Stem_engraver::make_stem (Grob_info gi)
 {
   /* Announce the cause of the head as cause of the stem.  The
      stem needs a rhythmic structure to fit it into a beam.  */
-  stem_ = make_item ("Stem", gi.music_cause ()->self_scm ());
+  stem_ = make_item ("Stem", gi.grob ()->self_scm ());
 
   /*
     we take the duration log from the Event, since the duration-log
diff --git a/lily/tweak-engraver.cc b/lily/tweak-engraver.cc
new file mode 100644
index 0000000000..da8f5375de
--- /dev/null
+++ b/lily/tweak-engraver.cc
@@ -0,0 +1,48 @@
+/*
+  tweak-engraver.cc -- implement Tweak_engraver
+
+  source file of the GNU LilyPond music typesetter
+
+  (c) 2005 Han-Wen Nienhuys <hanwen@xs4all.nl>
+
+*/
+
+#include "engraver.hh"
+
+#include "music.hh"
+#include "grob.hh"
+#include "translator.icc"
+
+class Tweak_engraver : public Engraver
+{
+  TRANSLATOR_DECLARATIONS (Tweak_engraver);
+
+protected:
+  DECLARE_ACKNOWLEDGER (grob);
+};
+
+Tweak_engraver::Tweak_engraver()
+{
+}
+
+void
+Tweak_engraver::acknowledge_grob (Grob_info info)
+{
+  if (Music *music = info.music_cause ())
+    {
+      for (SCM s = music->get_property ("tweaks");
+	   scm_is_pair (s); s = scm_cdr (s))
+	{
+	  info.grob ()->internal_set_property (scm_caar (s), scm_cdar (s));
+	}
+    }
+}
+
+ADD_ACKNOWLEDGER (Tweak_engraver, grob);
+ADD_TRANSLATOR (Tweak_engraver,
+		/* doc */ "Read the @code{tweaks} property from the originating Music event, and set properties." ,
+		
+		/* create */ "",
+		/* accept */ "",
+		/* read */ "",
+		/* write */ "");
diff --git a/ly/engraver-init.ly b/ly/engraver-init.ly
index c051a64451..6bc9228970 100644
--- a/ly/engraver-init.ly
+++ b/ly/engraver-init.ly
@@ -1,18 +1,18 @@
 \version "2.7.14"
 
 \context {
-  \name Global
+  \name "Global"
 
-  \accepts Score
+  \accepts "Score"
 
-  \defaultchild Score
+  \defaultchild "Score"
   \description "Hard coded entry point for LilyPond. Cannot be tuned."
   \grobdescriptions #all-grob-descriptions
 }
 
 \context {
   \type "Engraver_group"
-  \name Staff
+  \name "Staff"
   
   \consists "Output_property_engraver"	
   \consists "Bar_engraver"
@@ -64,8 +64,9 @@
 \context {
   \Staff
   \type "Engraver_group"
-  \name DrumStaff
-  \alias Staff
+  \name "DrumStaff"
+  \alias "Staff"
+  
   \remove "Accidental_engraver"
   \remove "Ottava_spanner_engraver"
   \remove "Key_engraver" 
@@ -74,9 +75,9 @@
   
   \description "Handles typesetting for percussion."
 
-  \denies Voice
-  \accepts DrumVoice
-  \defaultchild DrumVoice
+  \denies "Voice"
+  \accepts "DrumVoice"
+  \defaultchild "DrumVoice"
 
   clefGlyph = #"clefs.percussion"
   clefPosition = #0
@@ -86,7 +87,7 @@
 
 \context {
   \type "Engraver_group"
-  \name InnerChoirStaff
+  \name "InnerChoirStaff"
   \consists "System_start_delimiter_engraver"
   systemStartDelimiter = #'SystemStartBracket
 
@@ -416,9 +417,9 @@ AncientRemoveEmptyStaffContext = \context {
 }
 
 \context {
-  \type Score_engraver
+  \type "Score_engraver"
   \name "Score"
-
+  
   \description "This is the top level notation context.  No
     other context can contain a @code{Score} context.  This context
     handles the administration of time signatures.  It also makes sure
@@ -449,9 +450,10 @@ AncientRemoveEmptyStaffContext = \context {
   \consists "Vertical_align_engraver"
   \consists "Stanza_number_align_engraver"
   \consists "Bar_number_engraver"
-  \consists "Span_arpeggio_engraver"
-
+  \consists "Tweak_engraver"
+  
   \defaultchild "Staff"
+
   \accepts "Staff"
   \accepts "RhythmicStaff"
   \accepts "TabStaff"
@@ -468,7 +470,7 @@ AncientRemoveEmptyStaffContext = \context {
   \accepts "Devnull"
   \accepts "NoteNames"
   \accepts "FiguredBass"
-
+  
   soloText = #"Solo"
   soloIIText = #"Solo II"
   aDueText = #"a2"
diff --git a/ly/music-functions-init.ly b/ly/music-functions-init.ly
index 798f46641d..0d7aeb26c0 100644
--- a/ly/music-functions-init.ly
+++ b/ly/music-functions-init.ly
@@ -6,6 +6,43 @@
 
 #(use-modules (srfi srfi-1))  
 
+
+tweak = #(def-music-function (parser location sym val arg)
+	   (symbol? scheme? ly:music?)
+
+	   "Add @code{sym . val} to the @code{tweaks} property of @var{arg}."
+
+	   
+	   (set!
+	    (ly:music-property arg 'tweaks)
+	    (acons sym val
+		   (ly:music-property arg 'tweaks)))
+	   arg)
+
+	   
+
+tag = #(def-music-function (parser location tag arg)
+   (symbol? ly:music?)
+
+   "Add @var{tag} to the @code{tags} property of @var{arg}."
+
+   (set!
+    (ly:music-property arg 'tags)
+    (cons tag
+	  (ly:music-property arg 'tags)))
+   arg)
+
+tag = #(def-music-function (parser location tag arg)
+   (symbol? ly:music?)
+
+   "Add @var{tag} to the @code{tags} property of @var{arg}."
+
+   (set!
+    (ly:music-property arg 'tags)
+    (cons tag
+	  (ly:music-property arg 'tags)))
+   arg)
+
 applyMusic =
 #(def-music-function (parser location func music) (procedure? ly:music?)
                (func music))
diff --git a/python/convertrules.py b/python/convertrules.py
index bf0e4d1aa8..6868b4937b 100644
--- a/python/convertrules.py
+++ b/python/convertrules.py
@@ -2651,3 +2651,16 @@ def conv (str):
 
 conversions.append (((2, 7, 15), conv,
 		     '''Use grob closures iso. XY-offset-callbacks.'''))
+
+
+def conv (str):
+	def sub_syms (m):
+		syms =  m.group (1).split ()
+		tags = ["\\tag #'%s" % s for s in syms]
+		return ' '.join (tags)
+		
+	str = re.sub (r"\\tag #'\(([^)]+)\)",  sub_syms, str)
+	return str
+
+conversions.append (((2, 7, 22), conv,
+		     """\tag #'(a b) -> \tag #'a \tag #'b""" ))
diff --git a/python/musicexp.py b/python/musicexp.py
index b2b5846a6f..43c75c870f 100644
--- a/python/musicexp.py
+++ b/python/musicexp.py
@@ -25,6 +25,11 @@ class Output_printer:
 		self.output_state_stack = [Output_stack_element()]
 		self._skipspace = False
 		self.last_duration = None
+
+	def dump_version (self):
+		self.newline ()
+		self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
+		self.newline ()
 		
 	def get_indent (self):
 		return self.nesting * self.indent
diff --git a/scm/define-grobs.scm b/scm/define-grobs.scm
index c3be6e3886..28c9b1c83e 100644
--- a/scm/define-grobs.scm
+++ b/scm/define-grobs.scm
@@ -134,11 +134,8 @@
 				ledgered-interface))))))
 
     (Arpeggio
-     . (
-
-	(X-extent . ,Arpeggio::width)
+     . ((X-extent . ,Arpeggio::width)
 	(stencil . ,Arpeggio::print)
-
 	(Y-offset . ,Staff_symbol_referencer::callback)
 	(X-offset . ,Side_position_interface::x_aligned_side)
 	(direction . -1)
diff --git a/scm/define-music-properties.scm b/scm/define-music-properties.scm
index 58d7eea429..689f81180e 100644
--- a/scm/define-music-properties.scm
+++ b/scm/define-music-properties.scm
@@ -83,6 +83,9 @@ It must take a single argument, being the context.")
      (quoted-context-type ,symbol? "The name of the context to direct quotes to, eg., @code{Voice}.")
      (quoted-context-id ,string? "The id of the context to direct quotes to, eg., @code{cue}.")
      (to-relative-callback ,procedure? "How to transform a piece of music to relative pitches")
+     (tweaks ,list? "An alist of properties to override in the backend
+for the grob made of this event.")
+     
      (repeat-count  ,integer? "do a @code{\repeat} how ofen?")
      (span-direction ,ly:dir? "Does this start or stop a spanner?")
      (split-list ,list? "splitting moments for part combiner.")