]> git.donarmstrong.com Git - lilypond.git/blob - lily/translator.cc
Update source file headers. Fixes using standard GNU package conventions.
[lilypond.git] / lily / translator.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
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.
10
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.
15
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/>.
18 */
19
20 #include "translator.hh"
21
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"
28
29 #include "translator.icc"
30 #include "ly-smobs.icc"
31
32 Translator::~Translator ()
33 {
34 }
35
36 void
37 Translator::init ()
38 {
39   must_be_last_ = false;
40   self_scm_ = SCM_EOL;
41   daddy_context_ = 0;
42   smobify_self ();
43 }
44
45 void
46 Translator::process_music ()
47 {
48 }
49
50 void
51 Translator::process_acknowledged ()
52 {
53 }
54
55 Translator::Translator ()
56 {
57   init ();
58 }
59
60 Translator::Translator (Translator const &src)
61 {
62   init ();
63   must_be_last_ = src.must_be_last_;
64 }
65
66 Moment
67 Translator::now_mom () const
68 {
69   return daddy_context_->now_mom ();
70 }
71
72 Output_def *
73 Translator::get_output_def () const
74 {
75   return daddy_context_->get_output_def ();
76 }
77
78 Translator_group *
79 Translator::get_daddy_translator () const
80 {
81   return daddy_context_->implementation ();
82 }
83
84 void
85 Translator::protect_event (SCM ev)
86 {
87   get_daddy_translator ()->protect_event (ev);
88 }
89
90 SCM
91 Translator::internal_get_property (SCM sym) const
92 {
93   return daddy_context_->internal_get_property (sym);
94 }
95
96 void
97 Translator::stop_translation_timestep ()
98 {
99 }
100
101 /*
102   this function is called once each moment, before any user
103   information enters the translators.  (i.e. no \property or event has
104   been processed yet.)
105 */
106 void
107 Translator::start_translation_timestep ()
108 {
109 }
110
111 void
112 Translator::initialize ()
113 {
114 }
115
116 void
117 Translator::finalize ()
118 {
119 }
120
121 void
122 Translator::connect_to_context (Context *c)
123 {
124   for (translator_listener_record *r = get_listener_list (); r; r=r->next_)
125     c->events_below ()->add_listener (r->get_listener_ (this), r->event_class_);
126 }
127
128 void
129 Translator::disconnect_from_context (Context *c)
130 {
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 }
134
135 static SCM listened_event_class_table;
136 void
137 ensure_listened_hash ()
138 {
139   if (!listened_event_class_table)
140     listened_event_class_table = scm_permanent_object (scm_c_make_hash_table (61));
141 }
142
143
144 LY_DEFINE (ly_get_listened_event_classes, "ly:get-listened-event-classes",
145            0, 0, 0, (),
146            "Return a list of all event classes that some translator listens"
147            " to.")
148 {
149   ensure_listened_hash ();
150   return ly_hash_table_keys (listened_event_class_table);
151 }
152
153 LY_DEFINE (ly_is_listened_event_class, "ly:is-listened-event-class",
154            1, 0, 0, (SCM sym),
155            "Is @var{sym} a listened event class?")
156 {
157   ensure_listened_hash ();
158   return scm_hashq_ref (listened_event_class_table, sym, SCM_BOOL_F);
159 }
160
161 void
162 add_listened_event_class (SCM sym)
163 {
164   ensure_listened_hash ();
165   scm_hashq_set_x (listened_event_class_table, sym, SCM_BOOL_T);
166 }
167
168
169 /*
170   internally called once, statically, for each translator
171   listener. Connects the name of an event class with a procedure that
172   fetches the corresponding listener.
173
174   The method should only be called from the macro
175   IMPLEMENT_TRANSLATOR_LISTENER.
176  */
177 void
178 Translator::add_translator_listener (translator_listener_record **listener_list,
179                                      translator_listener_record *r,
180                                      Listener (*get_listener) (void *), 
181                                      const char *ev_class)
182 {
183   /* ev_class is the C++ identifier name. Convert to scm symbol */
184   string name = string (ev_class);
185   name = replace_all (&name, '_', '-');
186   name += "-event";
187   
188   SCM class_sym = scm_str2symbol (name.c_str ());
189   
190   add_listened_event_class (class_sym);
191
192   r->event_class_ = class_sym;
193   r->get_listener_ = get_listener;
194   r->next_ = *listener_list;
195   *listener_list = r;
196 }
197
198 /*
199  Helps the individual static_translator_description methods of translators.
200 */
201 SCM
202 Translator::static_translator_description (const char *grobs,
203                                            const char *desc,
204                                            translator_listener_record *listener_list,
205                                            const char *read, 
206                                            const char *write) const
207 {
208   SCM static_properties = SCM_EOL;                                      
209
210   static_properties = scm_acons (ly_symbol2scm ("grobs-created"),       
211                                  parse_symbol_list (grobs), static_properties);
212   
213   static_properties = scm_acons (ly_symbol2scm ("description"), 
214                                  scm_from_locale_string (desc), static_properties); 
215   
216   SCM list = SCM_EOL;
217   for (; listener_list; listener_list = listener_list->next_)
218     list = scm_cons (listener_list->event_class_, list);
219   static_properties = scm_acons (ly_symbol2scm ("events-accepted"),
220                                  list, static_properties);
221   
222   static_properties = scm_acons (ly_symbol2scm ("properties-read"),     
223                                  parse_symbol_list (read), static_properties); 
224   
225   static_properties = scm_acons (ly_symbol2scm ("properties-written"), 
226                                  parse_symbol_list (write), static_properties); 
227   
228   return static_properties;                                             
229 }
230   
231 /*
232   SMOBS
233 */
234 SCM
235 Translator::mark_smob (SCM sm)
236 {
237   Translator *me = (Translator *) SCM_CELL_WORD_1 (sm);
238   me->derived_mark ();
239   return SCM_EOL;
240 }
241
242 Global_context *
243 Translator::get_global_context () const
244 {
245   return daddy_context_->get_global_context ();
246 }
247
248 Context *
249 Translator::get_score_context () const
250 {
251   return daddy_context_->get_score_context ();
252 }
253
254 IMPLEMENT_SMOBS (Translator);
255 IMPLEMENT_DEFAULT_EQUAL_P (Translator);
256 IMPLEMENT_TYPE_P (Translator, "ly:translator?");
257
258 bool
259 Translator::must_be_last () const
260 {
261   return must_be_last_;
262 }
263
264 void
265 Translator::derived_mark () const
266 {
267 }
268
269 int
270 Translator::print_smob (SCM s, SCM port, scm_print_state *)
271 {
272   Translator *me = (Translator *) SCM_CELL_WORD_1 (s);
273   scm_puts ("#<Translator ", port);
274   scm_puts (me->class_name (), port);
275   scm_puts (" >", port);
276   return 1;
277 }
278
279 void
280 add_acknowledger (Engraver_void_function_engraver_grob_info ptr,
281                   char const *func_name,
282                   vector<Acknowledge_information> *ack_array)
283 {
284   Acknowledge_information inf;
285   inf.function_ = ptr;
286
287   string interface_name (func_name);
288
289   interface_name = replace_all (&interface_name, '_', '-');
290   interface_name += "-interface";
291
292   /*
293     this is only called during program init, so safe to use scm_gc_protect_object ()
294   */
295   inf.symbol_ = scm_gc_protect_object (ly_symbol2scm (interface_name.c_str ()));
296   ack_array->push_back (inf);
297 }
298
299 Engraver_void_function_engraver_grob_info
300 generic_get_acknowledger (SCM sym, vector<Acknowledge_information> const *ack_array)
301 {
302   for (vsize i = 0; i < ack_array->size (); i++)
303     {
304       if (ack_array->at (i).symbol_ == sym)
305         return ack_array->at (i).function_;
306     }
307   return 0;
308 }
309
310
311 Moment
312 get_event_length (Stream_event *e)
313 {
314   Moment *m = unsmob_moment (e->get_property ("length"));
315   if (m)
316     return *m;
317   else
318     return Moment (0);
319 }
320
321 Moment
322 get_event_length (Stream_event *e, Moment now)
323 {
324   Moment len = get_event_length (e);
325   
326   if (now.grace_part_)
327     {
328       len.grace_part_ = len.main_part_;
329       len.main_part_ = Rational (0);
330     }
331   return len;
332 }
333
334 /*
335   Helper, used through ASSIGN_EVENT_ONCE to throw warnings for
336   simultaneous events. The helper is only useful in listen_* methods
337   of translators.
338 */
339 bool
340 internal_event_assignment (Stream_event **old_ev, Stream_event *new_ev, const char *function)
341 {
342   if (*old_ev &&
343       !to_boolean (scm_equal_p ((*old_ev)->self_scm (), 
344                                new_ev->self_scm ())))
345     {
346       /* extract event class from function name */
347       string ev_class = function;
348
349       /* This assertion fails if EVENT_ASSIGNMENT was called outside a
350          translator listener. Don't do that. */
351       const char *prefix = "listen_";
352       assert (0 == ev_class.find (prefix));
353
354       /* "listen_foo_bar" -> "foo-bar" */
355       ev_class.erase (0, strlen (prefix));
356       replace_all (&ev_class, '_', '-');
357
358       new_ev->origin ()->warning (_f ("Two simultaneous %s events, junking this one", ev_class.c_str ()));
359       (*old_ev)->origin ()->warning (_f ("Previous %s event here", ev_class.c_str ()));
360       return false;
361     }
362   else
363     {
364       *old_ev = new_ev;
365       return true;
366     }
367 }
368
369 ADD_TRANSLATOR (Translator,
370                 /* doc */
371                 "Base class.  Not instantiated.",
372
373                 /* create */
374                 "",
375
376                 /* read */
377                 "",
378
379                 /* write */
380                 ""
381                 );