Hi,

The attached patch makes it possible for translators to listen to stream 
events directly.
1. Stream events are now probs, with 'class as the only immutable property.
2. Music::send_to_context now sends two stream events for each music event: 
One old-style OldMusicEvent, and one MusicEvent. The event's mutable property 
list is copied directly from the music event.
3. Some mechanisms have been added to Translator, that make it possible to 
register methods to listen directly for event-classes.
4. As a first demo, arpeggio-engraver has been rewritten to use these 
mechanisms.

The patch is attached; it compiles regression tests nicely.

Problems:
- A side-effect of (2) is that each event is sent twice; therefore, I have 
temporarily disabled a warning message.
- I think there are potential GC problems: Most translators don't seem to 
protect the try_music parameter; they trust that someone else protects it for 
them. This assumption is sufficient for Music (there's always someone higher 
up who protects incoming Music), but I don't think you can assume the same 
for Stream_events. Some possible solutions:
  A. Rewrite all translators to protect incoming events appropriately. This is 
the most efficient solution, but it requires more work when creating new 
translators. There are currently about 50 translators for which new 
derived_mark methods will have to be created.
  B. Create a dummy listener that protects all incoming events, and unprotects 
them at the end of each moment. The easiest way is probably to let 
Score-level translators take care of this. This is the easiest and safest 
solution, but also the most inefficient one.
  C. Create some macro trickery in translators, so that incoming events are 
remembered and protected automatically between try_music and 
stop_translation_timestep.
  D. Add an 'event property to Music, so that sent events are protected by 
their music origins. This is the easiest solution, but I'm nervous about 
memory errors that can happen when a different front-end is used (e.g., when 
loading music streams directly from a file)

-- 
Erik
Index: lily/arpeggio-engraver.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/arpeggio-engraver.cc,v
retrieving revision 1.42
diff -u -r1.42 arpeggio-engraver.cc
--- lily/arpeggio-engraver.cc	6 Jan 2006 09:13:27 -0000	1.42
+++ lily/arpeggio-engraver.cc	7 Jul 2006 12:55:35 -0000
@@ -13,6 +13,7 @@
 #include "stem.hh"
 #include "rhythmic-head.hh"
 #include "side-position-interface.hh"
+#include "stream-event.hh"
 #include "note-column.hh"
 
 #include "translator.icc"
@@ -28,10 +29,10 @@
 protected:
   void process_music ();
   void stop_translation_timestep ();
-  virtual bool try_music (Music *);
+  DECLARE_TRANSLATOR_LISTENER (Arpeggio_engraver, hear_arpeggio);
 private:
   Item *arpeggio_;
-  Music *arpeggio_event_;
+  Stream_event *arpeggio_event_;
 };
 
 Arpeggio_engraver::Arpeggio_engraver ()
@@ -40,12 +41,11 @@
   arpeggio_event_ = 0;
 }
 
-bool
-Arpeggio_engraver::try_music (Music *m)
+IMPLEMENT_TRANSLATOR_LISTENER (Arpeggio_engraver, hear_arpeggio, "ArpeggioEvent");
+void Arpeggio_engraver::hear_arpeggio (Stream_event *ev)
 {
-  if (!arpeggio_event_)
-    arpeggio_event_ = m;
-  return true;
+  arpeggio_event_ = ev;
+  ev->protect ();
 }
 
 void
@@ -84,7 +84,10 @@
 Arpeggio_engraver::process_music ()
 {
   if (arpeggio_event_)
-    arpeggio_ = make_item ("Arpeggio", arpeggio_event_->self_scm ());
+    {
+      arpeggio_ = make_item ("Arpeggio", arpeggio_event_->self_scm ());
+      arpeggio_event_->unprotect ();
+    }
 }
 
 void
@@ -94,13 +97,13 @@
   arpeggio_event_ = 0;
 }
 
-ADD_ACKNOWLEDGER (Arpeggio_engraver, stem)
-  ADD_ACKNOWLEDGER (Arpeggio_engraver, rhythmic_head)
-  ADD_ACKNOWLEDGER (Arpeggio_engraver, note_column)
-
-  ADD_TRANSLATOR (Arpeggio_engraver,
-		  /* doc */ "Generate an Arpeggio symbol",
-		  /* create */ "Arpeggio",
-		  /* accept */ "arpeggio-event",
-		  /* read */ "",
-		  /* write */ "");
+ADD_ACKNOWLEDGER (Arpeggio_engraver, stem);
+ADD_ACKNOWLEDGER (Arpeggio_engraver, rhythmic_head);
+ADD_ACKNOWLEDGER (Arpeggio_engraver, note_column);
+
+ADD_TRANSLATOR (Arpeggio_engraver,
+		/* doc */ "Generate an Arpeggio symbol",
+		/* create */ "Arpeggio",
+		/* accept */ "arpeggio-event",
+		/* read */ "",
+		/* write */ "");
Index: lily/dispatcher.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/dispatcher.cc,v
retrieving revision 1.3
diff -u -r1.3 dispatcher.cc
--- lily/dispatcher.cc	26 Jun 2006 22:11:38 -0000	1.3
+++ lily/dispatcher.cc	7 Jul 2006 12:55:36 -0000
@@ -80,7 +80,8 @@
   SCM class_list = scm_call_1 (ly_lily_module_constant ("ly:make-event-class"), class_symbol);
   if (!scm_is_pair (class_list))
     {
-      ev->origin ()->warning (_f ("Unknown event class %s", ly_symbol2string (class_symbol).c_str ()));
+      // TODO: Re-enable this warning when the translator cleanup is finished
+      //ev->origin ()->warning (_f ("Unknown event class %s", ly_symbol2string (class_symbol).c_str ()));
       return;
     }
   bool sent = false;
Index: lily/listener.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/listener.cc,v
retrieving revision 1.2
diff -u -r1.2 listener.cc
--- lily/listener.cc	16 May 2006 11:30:55 -0000	1.2
+++ lily/listener.cc	7 Jul 2006 12:55:36 -0000
@@ -10,6 +10,12 @@
 #include "ly-smobs.icc"
 #include "warn.hh"
 
+Listener::Listener ()
+{
+  target_ = 0;
+  type_ = 0;
+}
+
 Listener::Listener (const void *target, Listener_function_table *type)
 {
   target_ = (void *)target;
@@ -30,7 +36,8 @@
 Listener::mark_smob (SCM sm)
 {
   Listener *me = (Listener *) SCM_CELL_WORD_1 (sm);
-  (me->type_->mark_callback) (me->target_);
+  if (me->type_)
+    (me->type_->mark_callback) (me->target_);
   return SCM_EOL;
 }
 
Index: lily/lyric-combine-music-iterator.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/lyric-combine-music-iterator.cc,v
retrieving revision 1.56
diff -u -r1.56 lyric-combine-music-iterator.cc
--- lily/lyric-combine-music-iterator.cc	3 Jun 2006 12:25:27 -0000	1.56
+++ lily/lyric-combine-music-iterator.cc	7 Jul 2006 12:55:36 -0000
@@ -76,13 +76,13 @@
 {
   if (music_context_)
     {
-      music_context_->event_source()->remove_listener (GET_LISTENER (set_busy), ly_symbol2scm ("MusicEvent"));
+      music_context_->event_source()->remove_listener (GET_LISTENER (set_busy), ly_symbol2scm ("OldMusicEvent"));
       lyrics_context_->unset_property (ly_symbol2scm ("associatedVoiceContext"));
     }
   music_context_ = to;
   if (to)
     {
-      to->event_source()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("MusicEvent"));
+      to->event_source()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("OldMusicEvent"));
       lyrics_context_->set_property ("associatedVoiceContext", to->self_scm ());
     }
 }
Index: lily/music.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/music.cc,v
retrieving revision 1.152
diff -u -r1.152 music.cc
--- lily/music.cc	26 Jun 2006 22:11:38 -0000	1.152
+++ lily/music.cc	7 Jul 2006 12:55:36 -0000
@@ -21,11 +21,11 @@
 #include "warn.hh"
 
 /*
-  Music is anything that has duration and supports both time compression
-  and transposition.
+  Music is anything that has (possibly zero) duration and supports
+  both time compression and transposition.
 
   In Lily, everything that can be thought to have a length and a pitch
-  (which has a duration which can be transposed) is considered "music",
+  (which has a duration which can be transposed) is considered "music".
 */
 bool
 Music::internal_is_music_type (SCM k) const
@@ -239,8 +239,15 @@
 void
 Music::send_to_context (Context *c)
 {
-  send_stream_event (c, "MusicEvent", origin (),
+  /*
+    TODO: This is a work-in-progress solution. Send the event so it
+    can be read both by old-style translators and the new ones.
+  */
+  send_stream_event (c, "OldMusicEvent", origin (),
   		     ly_symbol2scm("music"), self_scm (), 0);
+
+  Stream_event *e = new Stream_event (get_property ("name"), mutable_property_alist_);
+  c->event_source ()->broadcast (e);
 }
 
 Music *
Index: lily/part-combine-iterator.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/part-combine-iterator.cc,v
retrieving revision 1.32
diff -u -r1.32 part-combine-iterator.cc
--- lily/part-combine-iterator.cc	26 Jun 2006 22:11:38 -0000	1.32
+++ lily/part-combine-iterator.cc	7 Jul 2006 12:55:36 -0000
@@ -373,7 +373,7 @@
   Context *contexts[] = {one, two, solo_tr, tr, 0};
   for (int i = 0; contexts[i]; i++)
     {
-      contexts[i]->event_source ()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("MusicEvent"));
+      contexts[i]->event_source ()->add_listener (GET_LISTENER (set_busy), ly_symbol2scm ("OldMusicEvent"));
     }
 
   for (char const **p = syms; *p; p++)
Index: lily/stream-event.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/stream-event.cc,v
retrieving revision 1.2
diff -u -r1.2 stream-event.cc
--- lily/stream-event.cc	26 Jun 2006 22:11:38 -0000	1.2
+++ lily/stream-event.cc	7 Jul 2006 12:55:36 -0000
@@ -13,46 +13,37 @@
 #include "input.hh"
 #include "input-smob.hh"
 
-Stream_event::~Stream_event ()
+Stream_event::Stream_event ()
+  : Prob (ly_symbol2scm ("Stream_event"), SCM_EOL)
 {
 }
 
-void
-Stream_event::init ()
+Stream_event::Stream_event (SCM event_class, SCM mutable_props)
+  : Prob (ly_symbol2scm ("Stream_event"),
+	  scm_list_1 (scm_cons (ly_symbol2scm ("class"), event_class)))
 {
-  self_scm_ = SCM_EOL;
-  property_alist_ = SCM_EOL;
-
-  smobify_self ();
-}
-
-Stream_event::Stream_event ()
-{
-  init ();
+  mutable_property_alist_ = mutable_props;
 }
 
 Stream_event::Stream_event (SCM property_alist)
+  : Prob (ly_symbol2scm ("Stream_event"), SCM_EOL)
 {
-  init ();
-  property_alist_ = property_alist;
+  mutable_property_alist_ = property_alist;
 }
 
-/*
-   Hm. Perhaps Stream_event should be a prob, with class_name as an
-   immutable property?
- */
 Stream_event::Stream_event (SCM class_name, Input *origin)
+  : Prob (ly_symbol2scm ("Stream_event"),
+	  scm_list_1 (scm_cons (ly_symbol2scm ("class"), class_name)))
 {
-  init ();
-  set_property ("class", class_name);
   if (origin)
     set_spot (origin);
 }
 
 Stream_event::Stream_event (Stream_event *ev)
+  : Prob (ly_symbol2scm ("Stream_event"), SCM_EOL)
 {
-  init ();
-  property_alist_ = scm_copy_tree (ev->property_alist_);
+  mutable_property_alist_ = scm_copy_tree (ev->mutable_property_alist_);
+  immutable_property_alist_ = ev->immutable_property_alist_;
 }
 
 Input *
@@ -67,24 +58,6 @@
   set_property ("origin", make_input (*i));
 }
 
-SCM
-Stream_event::mark_smob (SCM sm)
-{
-  Stream_event *me = (Stream_event *) SCM_CELL_WORD_1 (sm);
-  return me->property_alist_;
-}
-
-int
-Stream_event::print_smob (SCM s, SCM port, scm_print_state *)
-{
-  scm_puts ("#<Stream_event ", port);
-  scm_write (dump (s), port);
-  scm_puts (" >", port);
-  return 1;
-}
-
-IMPLEMENT_SMOBS (Stream_event);
-IMPLEMENT_DEFAULT_EQUAL_P (Stream_event);
 IMPLEMENT_TYPE_P (Stream_event, "ly:stream-event?");
 
 MAKE_SCHEME_CALLBACK (Stream_event, undump, 1);
@@ -95,28 +68,21 @@
 {
   Stream_event *ev = unsmob_stream_event (self);
   // Reversed alists look prettier.
-  return scm_reverse (ev->property_alist_);
+  return scm_cons (scm_reverse (ev->immutable_property_alist_),
+		   scm_reverse (ev->mutable_property_alist_));
 }
 
 SCM
 Stream_event::undump (SCM data)
 {
   Stream_event *obj = new Stream_event ();
-  obj->property_alist_ = scm_reverse (data);
+  obj->immutable_property_alist_ = scm_reverse (scm_car (data));
+  obj->mutable_property_alist_ = scm_reverse (scm_cdr (data));
   return obj->unprotect ();
 }
 
-SCM
-Stream_event::internal_get_property (SCM sym) const
-{
-  SCM s = scm_sloppy_assq (sym, property_alist_);
-  if (s != SCM_BOOL_F)
-    return scm_cdr (s);
-  return SCM_EOL;
-}
-
-void 
-Stream_event::internal_set_property (SCM prop, SCM val)
+Stream_event *
+unsmob_stream_event (SCM m)
 {
-  property_alist_ = scm_assq_set_x (property_alist_, prop, val);
+  return dynamic_cast<Stream_event*> (unsmob_prob (m));
 }
Index: lily/translator-group.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/translator-group.cc,v
retrieving revision 1.155
diff -u -r1.155 translator-group.cc
--- lily/translator-group.cc	26 Jun 2006 22:11:38 -0000	1.155
+++ lily/translator-group.cc	7 Jul 2006 12:55:36 -0000
@@ -48,16 +48,21 @@
     programming_error ("translator group is already connected to a context");
   context_ = c;
   c->event_source ()->add_listener (GET_LISTENER (eat_event),
-				    ly_symbol2scm ("MusicEvent"));
+				    ly_symbol2scm ("OldMusicEvent"));
   c->event_source ()->add_listener (GET_LISTENER (create_child_translator),
 				    ly_symbol2scm ("AnnounceNewContext"));
+  for (SCM tr_list = simple_trans_list_; scm_is_pair (tr_list); tr_list = scm_cdr (tr_list))
+    {
+      Translator *tr = unsmob_translator (scm_car (tr_list));
+      tr->connect_to_context (c);
+    }
 }
 
 void
 Translator_group::disconnect_from_context ()
 {
   context_->event_source ()->remove_listener (GET_LISTENER (eat_event),
-					      ly_symbol2scm ("MusicEvent"));
+					      ly_symbol2scm ("OldMusicEvent"));
   context_->event_source ()->remove_listener (GET_LISTENER (create_child_translator),
 					      ly_symbol2scm ("AnnounceNewContext"));
   context_ = 0;
@@ -169,14 +174,12 @@
 	}
     }
 
-  g->simple_trans_list_ = trans_list;
-
   /* Filter unwanted translator types. Required to make
      \with {\consists "..."} work. */
   if (dynamic_cast<Engraver_group *> (g))
-    g->simple_trans_list_ = filter_performers (g->simple_trans_list_);
+    g->simple_trans_list_ = filter_performers (trans_list);
   else if (dynamic_cast<Performer_group *> (g))
-    g->simple_trans_list_ = filter_engravers (g->simple_trans_list_);
+    g->simple_trans_list_ = filter_engravers (trans_list);
 
   // TODO: scrap Context::implementation
   new_context->implementation_ = g;
Index: lily/translator.cc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/translator.cc,v
retrieving revision 1.100
diff -u -r1.100 translator.cc
--- lily/translator.cc	11 Feb 2006 11:35:17 -0000	1.100
+++ lily/translator.cc	7 Jul 2006 12:55:36 -0000
@@ -11,6 +11,7 @@
 #include "warn.hh"
 #include "translator-group.hh"
 #include "context-def.hh"
+#include "dispatcher.hh"
 #include "global-context.hh"
 
 #include "translator.icc"
@@ -108,6 +109,28 @@
 {
 }
 
+void
+Translator::connect_to_context (Context *c)
+{
+  for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
+    {
+      if (!r->event_class_symbol_)
+	r->event_class_symbol_ = ly_symbol2scm (r->event_class_str_);
+      c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_symbol_);
+    }
+}
+
+void
+Translator::disconnect_from_context (Context *c)
+{
+  for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
+    {
+      if (!r->event_class_symbol_)
+	r->event_class_symbol_ = ly_symbol2scm (r->event_class_str_);
+      c->events_below ()->remove_listener (r->get_listener_ (this), r->event_class_symbol_);
+    }
+}
+
 /*
   SMOBS
 */
Index: lily/include/listener.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/listener.hh,v
retrieving revision 1.1
diff -u -r1.1 listener.hh
--- lily/include/listener.hh	5 May 2006 15:59:21 -0000	1.1
+++ lily/include/listener.hh	7 Jul 2006 12:55:36 -0000
@@ -63,6 +63,8 @@
 public:
   Listener (const void *target, Listener_function_table *type);
   Listener (Listener const &other);
+  Listener ();
+
   void listen (SCM ev) const;
 
   bool operator == (Listener const &other) const
@@ -72,29 +74,29 @@
 };
 DECLARE_UNSMOB (Listener, listener);
 
-#define IMPLEMENT_LISTENER(cl, method)			        \
-void								\
-cl :: method ## _callback (void *self, SCM ev)	                \
-{								\
-  cl *s = (cl *)self;						\
-  s->method (ev);					        \
-}								\
-void								\
-cl :: method ## _mark (void *self) 				\
-{								\
-  cl *s = (cl *)self;						\
-  scm_gc_mark (s->self_scm ());					\
-}								\
-Listener							\
-cl :: method ## _listener () const				\
-{								\
-  static Listener_function_table callbacks;			\
-  callbacks.listen_callback = &cl::method ## _callback;		\
-  callbacks.mark_callback = &cl::method ## _mark;		\
-  return Listener (this, &callbacks);				\
+#define IMPLEMENT_LISTENER(cl, method)			\
+void							\
+cl :: method ## _callback (void *self, SCM ev)		\
+{							\
+  cl *s = (cl *)self;					\
+  s->method (ev);					\
+}							\
+void							\
+cl :: method ## _mark (void *self)			\
+{							\
+  cl *s = (cl *)self;					\
+  scm_gc_mark (s->self_scm ());				\
+}							\
+Listener						\
+cl :: method ## _listener () const			\
+{							\
+  static Listener_function_table callbacks;		\
+  callbacks.listen_callback = &cl::method ## _callback;	\
+  callbacks.mark_callback = &cl::method ## _mark;	\
+  return Listener (this, &callbacks);			\
 }
 
-#define GET_LISTENER(proc) ( proc ## _listener ())
+#define GET_LISTENER(proc) proc ## _listener ()
 
 #define DECLARE_LISTENER(name)				\
   inline void name (SCM);		       	        \
Index: lily/include/stream-event.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/stream-event.hh,v
retrieving revision 1.3
diff -u -r1.3 stream-event.hh
--- lily/include/stream-event.hh	26 Jun 2006 22:11:39 -0000	1.3
+++ lily/include/stream-event.hh	7 Jul 2006 12:55:36 -0000
@@ -13,12 +13,8 @@
 #include "smobs.hh"
 #include "prob.hh"
 
-class Stream_event
+class Stream_event : public Prob
 {
-  void init ();
-  SCM property_alist_;
-  Input *origin_;
-
 public:
   Stream_event ();
   Input *origin () const;
@@ -28,18 +24,13 @@
   DECLARE_SCHEME_CALLBACK (dump, (SCM));
 
   // todo: remove unneeded constructors
+  Stream_event (SCM event_class, SCM mutable_props);
   Stream_event (SCM property_alist);
   Stream_event (SCM class_name, Input *);
   Stream_event (Stream_event *ev);
-
-  SCM internal_get_property (SCM) const;
-  void internal_set_property (SCM prop, SCM val);
-
-protected:
-  DECLARE_SMOBS (Stream_event,);
 };
 
-DECLARE_UNSMOB (Stream_event, stream_event);
+Stream_event *unsmob_stream_event (SCM);
 DECLARE_TYPE_P (Stream_event);
 
 #endif /* STREAM_EVENT_HH */
Index: lily/include/translator.hh
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/translator.hh,v
retrieving revision 1.100
diff -u -r1.100 translator.hh
--- lily/include/translator.hh	26 Jun 2006 22:11:39 -0000	1.100
+++ lily/include/translator.hh	7 Jul 2006 12:55:36 -0000
@@ -23,7 +23,22 @@
   Engraver_void_function_engraver_grob_info function_;
 };
 
+
+/*
+  Each translator class has a static list of listener records. Each
+  record makes one explains how to register one of the class's stream event
+  listeners to a context.
+*/
+typedef struct translator_listener_record {
+  Listener (*get_listener_) (void *);
+  const char *event_class_str_;
+  SCM event_class_symbol_;
+  struct translator_listener_record *next_;
+} translator_listener_record;
+
 #define TRANSLATOR_DECLARATIONS(NAME)					\
+private:								\
+  static translator_listener_record *listener_list_;			\
   public:								\
   NAME ();								\
   VIRTUAL_COPY_CONSTRUCTOR (Translator, NAME);				\
@@ -42,8 +57,19 @@
   } \
   static Engraver_void_function_engraver_grob_info static_get_acknowledger (SCM sym); \
   static Engraver_void_function_engraver_grob_info static_get_end_acknowledger(SCM); \
+public:									\
+  virtual translator_listener_record *get_listener_list () const	\
+  {									\
+    return listener_list_;						\
+  }									\
   /* end #define */
 
+#define DECLARE_TRANSLATOR_LISTENER(cl, m)		\
+public:							\
+inline void m (Stream_event *);				\
+static Listener get_ ## m ## _listener (void *);	\
+DECLARE_LISTENER (m ## _scm);				\
+friend class cl ## _ ## m ## _init;
 
 #define DECLARE_ACKNOWLEDGER(x) public : void acknowledge_ ## x (Grob_info); protected:
 #define DECLARE_END_ACKNOWLEDGER(x) public : void acknowledge_end_ ## x (Grob_info); protected:
@@ -84,6 +110,10 @@
   virtual void initialize ();
   virtual void finalize ();
 
+  /*should maybe be virtual*/
+  void connect_to_context (Context *c);
+  void disconnect_from_context (Context *c);
+
   void stop_translation_timestep ();
   void start_translation_timestep ();
   void process_music ();
Index: lily/include/translator.icc
===================================================================
RCS file: /sources/lilypond/lilypond/lily/include/translator.icc,v
retrieving revision 1.13
diff -u -r1.13 translator.icc
--- lily/include/translator.icc	30 May 2006 15:47:16 -0000	1.13
+++ lily/include/translator.icc	7 Jul 2006 12:55:36 -0000
@@ -9,6 +9,7 @@
 #ifndef TRANSLATOR_ICC
 #define TRANSLATOR_ICC
 
+#include "listener.hh"
 #include "std-vector.hh"
 #include "translator.hh"
 
@@ -16,6 +17,7 @@
    A macro to automate administration of translators.
 */
 #define ADD_THIS_TRANSLATOR(T)						\
+  translator_listener_record *T::listener_list_;			\
   SCM T::static_description_ = SCM_EOL;					\
   static void _ ## T ## _adder ()					\
   {									\
@@ -117,6 +119,39 @@
   }									\
   ADD_SCM_INIT_FUNC (CLASS ## NAME ## _end_ack_adder_initclass, CLASS ## NAME ## _end_ack_adder);
 
+/*
+  Implement the method cl::m, and make it hear stream events in class
+  evclass.
+*/
+#define IMPLEMENT_TRANSLATOR_LISTENER(cl, m, evclass)	\
+static class cl ## _ ## m ## _init			\
+{							\
+public:							\
+  cl ## _ ## m ## _init ()				\
+  {							\
+    static translator_listener_record r;		\
+    r.get_listener_ = cl::get_ ## m ## _listener;	\
+    r.event_class_str_ = evclass;			\
+    r.event_class_symbol_ = 0;				\
+    r.next_ = cl::listener_list_;			\
+    cl::listener_list_ = &r;				\
+  }							\
+} cl ## _ ## m ## _dummy;				\
+							\
+Listener						\
+cl :: get_ ## m ## _listener (void *me)			\
+{							\
+  cl *obj = (cl *) me;					\
+  return obj->GET_LISTENER (m ## _scm);			\
+}							\
+							\
+IMPLEMENT_LISTENER (cl, m ## _scm)			\
+void							\
+cl::m ## _scm(SCM sev)					\
+{							\
+  Stream_event *ev = unsmob_stream_event (sev);		\
+  m (ev);						\
+}
 
 #endif /* TRANSLATOR_ICC */
 
Index: scm/define-event-classes.scm
===================================================================
RCS file: /sources/lilypond/lilypond/scm/define-event-classes.scm,v
retrieving revision 1.3
diff -u -r1.3 define-event-classes.scm
--- scm/define-event-classes.scm	26 Jun 2006 22:11:39 -0000	1.3
+++ scm/define-event-classes.scm	7 Jul 2006 12:55:36 -0000
@@ -10,8 +10,10 @@
 ;; Event class hierarchy. Each line is on the form ((List of children) . Parent)
 (define event-classes
   '(((StreamEvent) . '())
-    ((RemoveContext ChangeParent Override Revert UnsetProperty SetProperty 
-      MusicEvent CreateContext Prepare OneTimeStep Finish) . StreamEvent)
+    ((RemoveContext ChangeParent Override Revert UnsetProperty
+      SetProperty MusicEvent OldMusicEvent CreateContext Prepare
+      OneTimeStep Finish) . StreamEvent)
+    ((ArpeggioEvent) . MusicEvent)
     ((Announcement) . '())
     ((AnnounceNewContext) . Announcement)
     ))
_______________________________________________
lilypond-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/lilypond-devel

Reply via email to