]> git.donarmstrong.com Git - lilypond.git/commitdiff
Added new system for how translators listen to events.
authorErik Sandberg <mandolaerik@gmail.com>
Fri, 14 Jul 2006 06:58:29 +0000 (06:58 +0000)
committerErik Sandberg <mandolaerik@gmail.com>
Fri, 14 Jul 2006 06:58:29 +0000 (06:58 +0000)
18 files changed:
ChangeLog
THANKS
lily/arpeggio-engraver.cc
lily/dispatcher.cc
lily/grob.cc
lily/include/listener.hh
lily/include/stream-event.hh
lily/include/translator-group.hh
lily/include/translator.hh
lily/include/translator.icc
lily/listener.cc
lily/lyric-combine-music-iterator.cc
lily/music.cc
lily/part-combine-iterator.cc
lily/stream-event.cc
lily/translator-group.cc
lily/translator.cc
scm/define-event-classes.scm

index 2d08233975c772ea6d6be10fa7c2c5d1cd455c3f..20bf175d990b7a8fc30483459b4e8ee4c9230084 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2006-07-14  Erik Sandberg  <mandolaerik@gmail.com>
+
+       * lily/music.cc: Revised MusicEvent event class. It now contains
+       event data directly instead of encapsulating it in music. The
+       previously used class is renamed to OldMusicEvent.
+
+       * lily/stream-event.cc: Stream events are now probs.
+       
+       * lily/translator-group.cc, lily/translator.cc: Translators can
+       now listen directly to stream events, by using macros
+       [DECLARE,IMPLEMENT]_TRANSLATOR_LISTENER.
+
+       * lily/arpeggio-engraver.cc: Converted to use new event system
+
+       * THANKS: Corrected spelling mistake.
+
 2006-07-12  Graham Percival  <gpermus@gmail.com>
 
        * Documentation/user/SConscript, make/lilypond-vars.make,
@@ -14,7 +30,7 @@
 
 2006-07-12  Han-Wen Nienhuys  <hanwen@lilypond.org>
 
-       * Documentation/topdocs/NEWS.tely (Top): update prop value 
+       * Documentation/topdocs/NEWS.tely (Top): update prop value
 
        * Documentation/user/basic-notation.itely (Tuplets): new property
        value.
diff --git a/THANKS b/THANKS
index 1d36a3f31cdccd98a9513c3e14dc891ca893ee5b..4ca18523bd786daddf31650d213082ff06ae762a 100644 (file)
--- a/THANKS
+++ b/THANKS
@@ -173,7 +173,7 @@ Patrick K Welton
 Paul Scott
 Ralph Little
 Richard Schoeller
-Robert Vlatasy
+Robert Vlasaty
 Roman Kurakin
 Russell Lang
 Scott Russell
@@ -407,7 +407,7 @@ Pawel D
 Pedro Kroger
 Ray McKinney
 Reuben Thomas
-Robert Vlatasy
+Robert Vlasaty
 Stef Epardaud
 Thomas Willhalm
 Thomas Scharkowski
index fd28a41e1fc4ce36a726a273e78e444572495baf..d67d9da120269ae3cd4d51de49cf962d6eb3c697 100644 (file)
@@ -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 @@ public:
 protected:
   void process_music ();
   void stop_translation_timestep ();
-  virtual bool try_music (Music *);
+  DECLARE_TRANSLATOR_LISTENER (arpeggio);
 private:
   Item *arpeggio_;
-  Music *arpeggio_event_;
+  Stream_event *arpeggio_event_;
 };
 
 Arpeggio_engraver::Arpeggio_engraver ()
@@ -40,12 +41,11 @@ Arpeggio_engraver::Arpeggio_engraver ()
   arpeggio_event_ = 0;
 }
 
-bool
-Arpeggio_engraver::try_music (Music *m)
+IMPLEMENT_TRANSLATOR_LISTENER (Arpeggio_engraver, arpeggio);
+void Arpeggio_engraver::listen_arpeggio (Stream_event *ev)
 {
-  if (!arpeggio_event_)
-    arpeggio_event_ = m;
-  return true;
+  arpeggio_event_ = ev;
+  ev->protect ();
 }
 
 void
@@ -84,7 +84,10 @@ void
 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_engraver::stop_translation_timestep ()
   arpeggio_event_ = 0;
 }
 
-ADD_ACKNOWLEDGER (Arpeggio_engraver, stem)
-  ADD_ACKNOWLEDGER (Arpeggio_engraver, rhythmic_head)
-  ADD_ACKNOWLEDGER (Arpeggio_engraver, note_column)
+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_TRANSLATOR (Arpeggio_engraver,
+               /* doc */ "Generate an Arpeggio symbol",
+               /* create */ "Arpeggio",
+               /* accept */ "arpeggio-event",
+               /* read */ "",
+               /* write */ "");
index ce6f2b71018c00fd05000365ccca3efd8adab187..9ba5fc2fc7d36b0ff254594020194b35a616e710 100644 (file)
 #include "stream-event.hh"
 #include "warn.hh"
 
-// ES todo: move to lily-guile.hh
-SCM appendable_list ();
-void appendable_list_append (SCM l, SCM elt);
-
 IMPLEMENT_SMOBS (Dispatcher);
 IMPLEMENT_TYPE_P (Dispatcher, "dispatcher");
 IMPLEMENT_DEFAULT_EQUAL_P (Dispatcher);
@@ -80,7 +76,8 @@ Dispatcher::dispatch (SCM sev)
   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 f79b266b08ee4e6f36f01cd5e22912d5b0bce838..c1545de824208cff345a3320594f057bdc720191 100644 (file)
@@ -20,6 +20,7 @@
 #include "output-def.hh"
 #include "pointer-group-interface.hh"
 #include "stencil.hh"
+#include "stream-event.hh"
 #include "system.hh"
 #include "warn.hh"
 
@@ -515,6 +516,8 @@ Grob::warning (string s) const
 
   if (Music *m = unsmob_music (cause))
     m->origin ()->warning (s);
+  else if (Stream_event *ev = unsmob_stream_event (cause))
+    ev->origin ()->warning (s);
   else
     ::warning (s);
 }
@@ -540,6 +543,8 @@ Grob::programming_error (string s) const
 
   if (Music *m = unsmob_music (cause))
     m->origin ()->message (s);
+  else if (Stream_event *ev = unsmob_stream_event (cause))
+    ev->origin ()->warning (s);
   else
     ::message (s);
 }
index fd7a7e2adfa3db21399a025581248ffc1fd74d9a..562380c5764e6967790431fc9dac8f4c8c1bea50 100644 (file)
@@ -63,6 +63,8 @@ class Listener {
 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 @@ public:
 };
 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 f2d5a960363e5ffeaadce96bc6fa5fe39c45d248..0ac1b4712fc91bf53288e9cc714b49b8b27c00c1 100644 (file)
 #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 @@ public:
   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 1c8f91ce454370eeb92377949dec337b986d74f6..2552fb4186fbf4067865b039413cef60e690e7c7 100644 (file)
@@ -47,6 +47,8 @@ private:
   Translator_group_void_method
   precomputed_self_method_bindings_[TRANSLATOR_METHOD_PRECOMPUTE_COUNT];
 
+  SCM protected_events_;
+
   DECLARE_LISTENER (create_child_translator);
   DECLARE_LISTENER (eat_event);
 
@@ -63,6 +65,8 @@ public:
   virtual void initialize ();
   virtual void finalize ();
 
+  void protect_event (SCM ev);
+
   void stop_translation_timestep ();
   void start_translation_timestep ();
 
index 442942932112066b514cf3be7985e74aff22a18f..eba2d6def4c6a76c83372aff508a11d91e607d2a 100644 (file)
@@ -23,7 +23,21 @@ struct Acknowledge_information
   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 *);
+  SCM event_class_;
+  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 +56,21 @@ struct Acknowledge_information
   } \
   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(m)                 \
+public:                                                        \
+inline void listen_ ## m (Stream_event *);             \
+/* Should be private */                                        \
+static void _internal_declare_ ## m ();                        \
+private:                                               \
+static Listener _get_ ## m ## _listener (void *);      \
+DECLARE_LISTENER (_listen_scm_ ## m);
 
 #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 +111,10 @@ public:
   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 ();
@@ -97,7 +128,9 @@ public:
 
 protected:                     // should be private.
   Context *daddy_context_;
+  void protect_event (SCM ev);
   virtual void derived_mark () const;
+  static void add_translator_listener (translator_listener_record **listener_list, translator_listener_record *r, Listener (*get_listener) (void *), const char *ev_class);
 
   friend class Translator_group;
 };
index 14ba2b62b6b022e2dcd994de4dc0b29ccc588696..bff828bcad9eafa42e4118dc7cc134093b9e7181 100644 (file)
@@ -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,34 @@ generic_get_acknowledger (SCM sym,
   }                                                                    \
   ADD_SCM_INIT_FUNC (CLASS ## NAME ## _end_ack_adder_initclass, CLASS ## NAME ## _end_ack_adder);
 
+/*
+  Implement the method cl::listen_##m, and make it listen to stream 
+  events of class m.
+ */
+#define IMPLEMENT_TRANSLATOR_LISTENER(cl, m)           \
+void                                                   \
+cl :: _internal_declare_ ## m ()                       \
+{                                                      \
+  static translator_listener_record r;                 \
+  add_translator_listener (&listener_list_, &r, _get_ ## m ## _listener, #m); \
+}                                                      \
+                                                       \
+ADD_SCM_INIT_FUNC (cl ## _declare_event_ ## m, cl::_internal_declare_ ## m);   \
+                                                       \
+Listener                                               \
+cl :: _get_ ## m ## _listener (void *me)               \
+{                                                      \
+  cl *obj = (cl *) me;                                 \
+  return obj->GET_LISTENER (_listen_scm_ ## m);                \
+}                                                      \
+                                                       \
+IMPLEMENT_LISTENER (cl, _listen_scm_ ## m)             \
+void                                                   \
+cl::_listen_scm_ ## m (SCM sev)                                \
+{                                                      \
+  Stream_event *ev = unsmob_stream_event (sev);                \
+  protect_event (sev);                                 \
+  listen_ ## m (ev);                                   \
+}
 
 #endif /* TRANSLATOR_ICC */
-
index edc96bdf1c84aed5a51c69b87ae4914a125ebe77..c8202a9d345d6ef8d9d0fabe066d688cd380a5e6 100644 (file)
 #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,12 +36,13 @@ SCM
 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;
 }
 
 int
-Listener::print_smob (SCM s, SCM p, scm_print_state*)
+Listener::print_smob (SCM, SCM p, scm_print_state*)
 {
   scm_puts ("#<Listener>", p);
   return 1;
index 8501d3f5b26e1d3f622b60f76d825cc5ed9accf2..aaccf2e2107bccd81438c580b05cc8efe612f136 100644 (file)
@@ -76,13 +76,13 @@ Lyric_combine_music_iterator::set_music_context (Context *to)
 {
   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 56b6998820c821c2a4a2917a5090cd60aca92a44..88f38f6a3899e7b69135991d49ef28f6193b4071 100644 (file)
 #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,31 @@ Music::origin () const
 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);
+
+  /* UGH. This is a temp hack for Music->Stream_event transition */
+  SCM orig_sym = get_property ("name");
+  char out[200];
+  string in = ly_symbol2string (orig_sym);
+  /* don't add '-' before first character */
+  out[0] = tolower (in[0]);
+  size_t outpos = 1;
+  for (size_t inpos = 1; inpos < in.size () && outpos < 190; inpos++)
+    {
+      if (isupper (in[inpos]))
+       out[outpos++] = '-';
+      out[outpos++] = tolower (in[inpos]);      
+    }
+  out[outpos] = 0;
+  SCM class_name = ly_symbol2scm (out);
+  
+  Stream_event *e = new Stream_event (class_name, mutable_property_alist_);
+  c->event_source ()->broadcast (e);
 }
 
 Music *
index 6f07a67be78ecdc5d256da172d980b5f03fe1629..99f36b2b74d5a9a82dee26b89bac08a5a556f2bd 100644 (file)
@@ -373,7 +373,7 @@ Part_combine_iterator::construct_children ()
   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 eb530046a0fa5fd8548484be070861f486ca9c6c..e9fe80a22fa17d60269c418763029f41a370fca5 100644 (file)
 #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 @@ void Stream_event::set_spot (Input *i)
   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::dump (SCM self)
 {
   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 172c5b2a3aed958b36c6508d89901270b0b60422..701c75ef77ab5deff023f663e0e96b90dd3fcf89 100644 (file)
@@ -48,19 +48,30 @@ Translator_group::connect_to_context (Context *c)
     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 ()
 {
+  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->disconnect_from_context (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;
+  protected_events_ = SCM_EOL;
 }
 
 void
@@ -123,6 +134,24 @@ filter_engravers (SCM ell)
   return ell;
 }
 
+/* 
+  Protects the parameter from being garbage collected. The object is
+  protected until the next disconnect_from_context call.
+
+  Whenever a child translator hears an event, the event is added to
+  this list. This eliminates the need for derived_mark methods in most
+  translators; all incoming events are instead protected by the
+  translator group.
+  TODO: Should the list also be flushed at the beginning of each new
+  moment?
+ */
+void
+Translator_group::protect_event (SCM ev)
+{
+  protected_events_ = scm_cons (ev, protected_events_);
+}
+
 /*
   Create a new translator for a newly created child context. Triggered
   by AnnounceNewContext events.
@@ -169,14 +198,12 @@ Translator_group::create_child_translator (SCM sev)
        }
     }
 
-  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;
@@ -231,9 +258,12 @@ Translator_group::try_music (Music *m)
   if (p->get_parent_context())
     // ES todo: Make Translators listeners directly instead.
     return p->implementation ()->try_music (m);
+  // 'junking event' warning is temporarily disabled during translator cleanup
+  /*
   else
     // We have tried all possible contexts. Give up.
     m->origin ()->warning (_f ("junking event: `%s'", m->name ()));
+  */
   return false;
 }
 
@@ -295,6 +325,7 @@ Translator_group::Translator_group ()
 {
   simple_trans_list_ = SCM_EOL;
   accept_hash_table_ = SCM_EOL;
+  protected_events_ = SCM_EOL;
   context_ = 0;
   smobify_self ();
 
@@ -376,5 +407,6 @@ Translator_group::mark_smob (SCM smob)
 
   me->derived_mark ();
   scm_gc_mark (me->accept_hash_table_);
+  scm_gc_mark (me->protected_events_);
   return me->simple_trans_list_;
 }
index 762fdfd2f9a7664d877e899a312a059c27137e9c..7bd0e6b47e7f19e69452e9d1e2c3e38663d7f598 100644 (file)
@@ -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"
@@ -74,6 +75,12 @@ Translator::get_daddy_translator () const
   return daddy_context_->implementation ();
 }
 
+void
+Translator::protect_event (SCM ev)
+{
+  get_daddy_translator ()->protect_event (ev);
+}
+
 SCM
 Translator::internal_get_property (SCM sym) const
 {
@@ -108,6 +115,46 @@ Translator::finalize ()
 {
 }
 
+void
+Translator::connect_to_context (Context *c)
+{
+  for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
+    c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_);
+}
+
+void
+Translator::disconnect_from_context (Context *c)
+{
+  for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
+    c->events_below ()->remove_listener (r->get_listener_ (this), r->event_class_);
+}
+
+/*
+  Internally called once, statically, for each translator
+  listener. Connects the name of an event class with a procedure that
+  fetches the corresponding listener.
+
+  The method should only be called from the macro
+  IMPLEMENT_TRANSLATOR_LISTENER.
+ */
+void
+Translator::add_translator_listener (translator_listener_record **listener_list,
+                        translator_listener_record *r,
+                        Listener (*get_listener) (void *), 
+                        const char *ev_class)
+{
+  /* ev_class is the C++ identifier name. Convert to scm symbol */
+  string name = string (ev_class);
+  name = replace_all (name, '_', '-');
+  name = name + "-event";
+  /* It's OK to use scm_gc_protect_object for protection, because r is
+     statically allocated. */
+  r->event_class_ = scm_gc_protect_object (scm_str2symbol (name.c_str ()));
+  r->get_listener_ = get_listener;
+  r->next_ = *listener_list;
+  *listener_list = r;
+}
+
 /*
   SMOBS
 */
index 3d8b1b14261d4879e756c1e9cc9af244d013760f..86245efcbbc04c1f8444b39e4337b284b3aee850 100644 (file)
 ;; 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)
+    ((arpeggio-event) . MusicEvent)
     ((Announcement) . '())
     ((AnnounceNewContext) . Announcement)
     ))