+void
+add_acknowledger (SCM ptr,
+ char const *func_name,
+ SCM &ack_hash)
+{
+ if (SCM_UNBNDP (ack_hash))
+ ack_hash = Scheme_hash_table::make_smob ();
+
+ string interface_name (func_name);
+
+ interface_name = replace_all (&interface_name, '_', '-');
+ interface_name += "-interface";
+
+ unsmob<Scheme_hash_table> (ack_hash)
+ ->set (ly_symbol2scm (interface_name.c_str ()), ptr);
+}
+
+SCM
+generic_get_acknowledger (SCM sym, SCM ack_hash)
+{
+ if (SCM_UNBNDP (ack_hash))
+ return SCM_UNDEFINED;
+
+ return unsmob<Scheme_hash_table> (ack_hash)->get (sym);
+}
+
+Moment
+get_event_length (Stream_event *e)
+{
+ Moment *m = unsmob<Moment> (e->get_property ("length"));
+ if (m)
+ return *m;
+ else
+ return Moment (0);
+}
+
+Moment
+get_event_length (Stream_event *e, Moment now)
+{
+ Moment len = get_event_length (e);
+
+ if (now.grace_part_)
+ {
+ len.grace_part_ = len.main_part_;
+ len.main_part_ = Rational (0);
+ }
+ return len;
+}
+
+/*
+ Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
+ simultaneous events. The helper is only useful in listen_* methods
+ of translators.
+*/
+bool
+internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
+{
+ if (*old_ev
+ && !to_boolean (scm_equal_p ((*old_ev)->self_scm (),
+ new_ev->self_scm ())))
+ {
+ /* extract event class from function name */
+ string ev_class = function;
+
+ /* This assertion fails if EVENT_ASSIGNMENT was called outside a
+ translator listener. Don't do that. */
+ const char *prefix = "listen_";
+ assert (0 == ev_class.find (prefix));
+
+ /* "listen_foo_bar" -> "foo-bar" */
+ ev_class.erase (0, strlen (prefix));
+ replace_all (&ev_class, '_', '-');
+
+ new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
+ (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
+ return false;
+ }
+ else
+ {
+ *old_ev = new_ev;
+ return true;
+ }
+}
+
+// Base class. Not instantiated. No ADD_TRANSLATOR call.