Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / translator.cc
blob3020006f837e21e9edfac660a720a41bb80ca2f3
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "translator.hh"
22 #include "context-def.hh"
23 #include "dispatcher.hh"
24 #include "global-context.hh"
25 #include "international.hh"
26 #include "translator-group.hh"
27 #include "warn.hh"
29 #include "translator.icc"
30 #include "ly-smobs.icc"
32 Translator::~Translator ()
36 void
37 Translator::init ()
39 self_scm_ = SCM_EOL;
40 daddy_context_ = 0;
41 smobify_self ();
44 void
45 Translator::process_music ()
49 void
50 Translator::process_acknowledged ()
54 Translator::Translator ()
56 init ();
59 Translator::Translator (Translator const &src)
61 (void) src;
62 init ();
65 Moment
66 Translator::now_mom () const
68 return daddy_context_->now_mom ();
71 Output_def *
72 Translator::get_output_def () const
74 return daddy_context_->get_output_def ();
77 Translator_group *
78 Translator::get_daddy_translator () const
80 return daddy_context_->implementation ();
83 void
84 Translator::protect_event (SCM ev)
86 get_daddy_translator ()->protect_event (ev);
89 SCM
90 Translator::internal_get_property (SCM sym) const
92 return daddy_context_->internal_get_property (sym);
95 void
96 Translator::stop_translation_timestep ()
101 this function is called once each moment, before any user
102 information enters the translators. (i.e. no \property or event has
103 been processed yet.)
105 void
106 Translator::start_translation_timestep ()
110 void
111 Translator::initialize ()
115 void
116 Translator::finalize ()
120 void
121 Translator::connect_to_context (Context *c)
123 for (translator_listener_record *r = get_listener_list (); r; r = r->next_)
124 c->events_below ()->add_listener (r->get_listener_ (this, r->event_class_),
125 r->event_class_);
128 void
129 Translator::disconnect_from_context (Context *c)
131 for (translator_listener_record *r = get_listener_list (); r; r = r->next_)
132 c->events_below ()->remove_listener (r->get_listener_ (this, r->event_class_),
133 r->event_class_);
136 static SCM listened_event_class_table;
137 void
138 ensure_listened_hash ()
140 if (!listened_event_class_table)
141 listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
145 LY_DEFINE (ly_get_listened_event_classes, "ly:get-listened-event-classes",
146 0, 0, 0, (),
147 "Return a list of all event classes that some translator listens"
148 " to.")
150 ensure_listened_hash ();
151 return ly_hash_table_keys (listened_event_class_table);
154 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
155 1, 0, 0, (SCM sym),
156 "Is @var{sym} a listened event class?")
158 ensure_listened_hash ();
159 return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
162 void
163 add_listened_event_class (SCM sym)
165 ensure_listened_hash ();
166 scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
171 internally called once, statically, for each translator
172 listener. Connects the name of an event class with a procedure that
173 fetches the corresponding listener.
175 The method should only be called from the macro
176 IMPLEMENT_TRANSLATOR_LISTENER.
178 void
179 Translator::add_translator_listener (translator_listener_record **listener_list,
180 translator_listener_record *r,
181 Listener (*get_listener) (void *, SCM),
182 const char *ev_class)
184 /* ev_class is the C++ identifier name. Convert to scm symbol */
185 string name = string (ev_class);
186 name = replace_all (&name, '_', '-');
187 name += "-event";
189 SCM class_sym = scm_from_locale_symbol (name.c_str ());
191 add_listened_event_class (class_sym);
193 r->event_class_ = class_sym;
194 r->get_listener_ = get_listener;
195 r->next_ = *listener_list;
196 *listener_list = r;
200 Helps the individual static_translator_description methods of translators.
203 Translator::static_translator_description (const char *grobs,
204 const char *desc,
205 translator_listener_record *listener_list,
206 const char *read,
207 const char *write) const
209 SCM static_properties = SCM_EOL;
211 static_properties = scm_acons (ly_symbol2scm ("grobs-created"),
212 parse_symbol_list (grobs), static_properties);
214 static_properties = scm_acons (ly_symbol2scm ("description"),
215 scm_from_locale_string (desc), static_properties);
217 SCM list = SCM_EOL;
218 for (; listener_list; listener_list = listener_list->next_)
219 list = scm_cons (listener_list->event_class_, list);
220 static_properties = scm_acons (ly_symbol2scm ("events-accepted"),
221 list, static_properties);
223 static_properties = scm_acons (ly_symbol2scm ("properties-read"),
224 parse_symbol_list (read), static_properties);
226 static_properties = scm_acons (ly_symbol2scm ("properties-written"),
227 parse_symbol_list (write), static_properties);
229 return static_properties;
233 SMOBS
236 Translator::mark_smob (SCM sm)
238 Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
239 me->derived_mark ();
240 return SCM_EOL;
243 Global_context *
244 Translator::get_global_context () const
246 return daddy_context_->get_global_context ();
249 Context *
250 Translator::get_score_context () const
252 return daddy_context_->get_score_context ();
255 IMPLEMENT_SMOBS (Translator);
256 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
257 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
259 bool
260 Translator::must_be_last () const
262 return false;
265 void
266 Translator::derived_mark () const
271 Translator::print_smob (SCM s, SCM port, scm_print_state *)
273 Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
274 scm_puts ("#<Translator ", port);
275 scm_puts (me->class_name (), port);
276 scm_puts (" >", port);
277 return 1;
280 void
281 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
282 char const *func_name,
283 vector<Acknowledge_information> *ack_array)
285 Acknowledge_information inf;
286 inf.function_ = ptr;
288 string interface_name (func_name);
290 interface_name = replace_all (&interface_name, '_', '-');
291 interface_name += "-interface";
294 this is only called during program init, so safe to use scm_gc_protect_object ()
296 inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
297 ack_array->push_back (inf);
300 Engraver_void_function_engraver_grob_info
301 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
303 for (vsize i = 0; i < ack_array->size (); i++)
305 if (ack_array->at (i).symbol_ == sym)
306 return ack_array->at (i).function_;
308 return 0;
312 Moment
313 get_event_length (Stream_event *e)
315 Moment *m = unsmob_moment (e->get_property ("length"));
316 if (m)
317 return *m;
318 else
319 return Moment (0);
322 Moment
323 get_event_length (Stream_event *e, Moment now)
325 Moment len = get_event_length (e);
327 if (now.grace_part_)
329 len.grace_part_ = len.main_part_;
330 len.main_part_ = Rational (0);
332 return len;
336 Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
337 simultaneous events. The helper is only useful in listen_* methods
338 of translators.
340 bool
341 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
343 if (*old_ev &&
344 !to_boolean (scm_equal_p ((*old_ev)->self_scm (),
345 new_ev->self_scm ())))
347 /* extract event class from function name */
348 string ev_class = function;
350 /* This assertion fails if EVENT_ASSIGNMENT was called outside a
351 translator listener. Don't do that. */
352 const char *prefix = "listen_";
353 assert (0 == ev_class.find (prefix));
355 /* "listen_foo_bar" -> "foo-bar" */
356 ev_class.erase (0, strlen (prefix));
357 replace_all (&ev_class, '_', '-');
359 new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
360 (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
361 return false;
363 else
365 *old_ev = new_ev;
366 return true;
370 ADD_TRANSLATOR (Translator,
371 /* doc */
372 "Base class. Not instantiated.",
374 /* create */
377 /* read */
380 /* write */