]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
(PATCH_LEVEL): bump.
[lilypond.git] / lily / translator.cc
1 /*
2   translator.cc -- implement Translator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
8
9 #include "translator.hh"
10
11 #include "context-def.hh"
12 #include "dispatcher.hh"
13 #include "global-context.hh"
14 #include "international.hh"
15 #include "translator-group.hh"
16 #include "warn.hh"
17
18 #include "translator.icc"
19 #include "ly-smobs.icc"
20
21 Translator::~Translator ()
22 {
23 }
24
25 void
26 Translator::init ()
27 {
28   must_be_last_ = false;
29   self_scm_ = SCM_EOL;
30   daddy_context_ = 0;
31   smobify_self ();
32 }
33
34 void
35 Translator::process_music ()
36 {
37 }
38
39 void
40 Translator::process_acknowledged ()
41 {
42 }
43
44 Translator::Translator ()
45 {
46   init ();
47 }
48
49 Translator::Translator (Translator const &src)
50 {
51   init ();
52   must_be_last_ = src.must_be_last_;
53 }
54
55 bool
56 Translator::try_music (Music *)
57 {
58   return false;
59 }
60
61 Moment
62 Translator::now_mom () const
63 {
64   return daddy_context_->now_mom ();
65 }
66
67 Output_def *
68 Translator::get_output_def () const
69 {
70   return daddy_context_->get_output_def ();
71 }
72
73 Translator_group *
74 Translator::get_daddy_translator () const
75 {
76   return daddy_context_->implementation ();
77 }
78
79 void
80 Translator::protect_event (SCM ev)
81 {
82   get_daddy_translator ()->protect_event (ev);
83 }
84
85 SCM
86 Translator::internal_get_property (SCM sym) const
87 {
88   return daddy_context_->internal_get_property (sym);
89 }
90
91 void
92 Translator::stop_translation_timestep ()
93 {
94 }
95
96 /*
97   this function has 2 properties
98
99   - It is called before try_music ()
100
101   - It is called before any user information enters the translators.
102   (i.e. any \property or event is not processed yet.)
103 */
104 void
105 Translator::start_translation_timestep ()
106 {
107 }
108
109 void
110 Translator::initialize ()
111 {
112 }
113
114 void
115 Translator::finalize ()
116 {
117 }
118
119 void
120 Translator::connect_to_context (Context *c)
121 {
122   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
123     c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_);
124 }
125
126 void
127 Translator::disconnect_from_context (Context *c)
128 {
129   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
130     c->events_below ()->remove_listener (r->get_listener_ (this), r->event_class_);
131 }
132
133 static SCM listened_event_class_table;
134 void
135 ensure_listened_hash ()
136 {
137   if (!listened_event_class_table)
138     listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
139 }
140
141
142 LY_DEFINE (ly_get_listened_event_classes, "ly:get-listened-event-classes",
143            0, 0, 0, (),
144            "Returns a list of all event classes that some translator listens to.")
145 {
146   ensure_listened_hash ();
147   return ly_hash_table_keys (listened_event_class_table);
148 }
149
150 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
151            1, 0, 0, (SCM sym),
152            "Is @var{sym} a listened event class?")
153 {
154   ensure_listened_hash ();
155   return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
156 }
157
158 void
159 add_listened_event_class (SCM sym)
160 {
161   ensure_listened_hash ();
162
163   scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
164 }
165
166
167 /*
168   internally called once, statically, for each translator
169   listener. Connects the name of an event class with a procedure that
170   fetches the corresponding listener.
171
172   The method should only be called from the macro
173   IMPLEMENT_TRANSLATOR_LISTENER.
174  */
175 void
176 Translator::add_translator_listener (translator_listener_record **listener_list,
177                                      translator_listener_record *r,
178                                      Listener (*get_listener) (void *), 
179                                      const char *ev_class)
180 {
181   /* ev_class is the C++ identifier name. Convert to scm symbol */
182   string name = string (ev_class);
183   name = replace_all (name, '_', '-');
184   name += "-event";
185   
186   SCM class_sym = scm_str2symbol (name.c_str ());
187   
188   add_listened_event_class (class_sym);
189   r->event_class_ = class_sym;
190   r->get_listener_ = get_listener;
191   r->next_ = *listener_list;
192   *listener_list = r;
193 }
194
195 /*
196   SMOBS
197 */
198 SCM
199 Translator::mark_smob (SCM sm)
200 {
201   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
202   me->derived_mark ();
203   return SCM_EOL;
204 }
205
206 Global_context *
207 Translator::get_global_context () const
208 {
209   return daddy_context_->get_global_context ();
210 }
211
212 Context *
213 Translator::get_score_context () const
214 {
215   return daddy_context_->get_score_context ();
216 }
217
218 IMPLEMENT_SMOBS (Translator);
219 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
220 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
221
222 bool
223 Translator::must_be_last () const
224 {
225   return must_be_last_;
226 }
227
228 void
229 Translator::derived_mark () const
230 {
231 }
232
233 int
234 Translator::print_smob (SCM s, SCM port, scm_print_state *)
235 {
236   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
237   scm_puts ("#<Translator ", port);
238   scm_puts (me->class_name (), port);
239   scm_puts (" >", port);
240   return 1;
241 }
242
243 void
244 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
245                   char const *func_name,
246                   vector<Acknowledge_information> *ack_array)
247 {
248   Acknowledge_information inf;
249   inf.function_ = ptr;
250
251   string interface_name (func_name);
252
253   interface_name = replace_all (interface_name, '_', '-');
254   interface_name += "-interface";
255
256   inf.symbol_ = ly_symbol2scm (interface_name.c_str ());
257   ack_array->push_back (inf);
258 }
259
260 Engraver_void_function_engraver_grob_info
261 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
262 {
263   for (vsize i = 0; i < ack_array->size (); i++)
264     {
265       if (ack_array->at (i).symbol_ == sym)
266         return ack_array->at (i).function_;
267     }
268   return 0;
269 }
270
271 Moment
272 get_event_length (Stream_event *e)
273 {
274   Moment *m = unsmob_moment (e->get_property ("length"));
275   if (m)
276     return *m;
277   else
278     return Moment (0);
279 }
280
281 /*
282   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
283   simultaneous events. The helper is only useful in listen_* methods
284   of translators.
285 */
286 bool
287 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
288 {
289   if (*old_ev)
290     {
291       /* extract event class from function name */
292       const char *prefix = "listen_";
293       assert (!strncmp (function, "listen_", strlen (prefix)));
294       function += strlen (prefix);
295       char ev_class[strlen (function) + 1];
296       strcpy (ev_class, function);
297       for (char *c = ev_class; *c; c++)
298         if (*c == '_')
299           *c = '-';
300
301       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class));
302       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class));
303       return false;
304     }
305   else
306     {
307       *old_ev = new_ev;
308       return true;
309     }
310 }
311
312 ADD_TRANSLATOR (Translator,
313                 "Base class. Unused",
314                 "",
315                 "",
316                 "",
317                 "");