]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-iterator.cc
(construct_children): add
[lilypond.git] / lily / part-combine-iterator.cc
1 /*   
2      new-part-combine-music-iterator.cc -- implement Part_combine_iterator
3
4      source file of the GNU LilyPond music typesetter
5   
6      (c) 2004 Han-Wen Nienhuys
7 */
8
9 #include "context.hh"
10 #include "event.hh"
11 #include "music-sequence.hh"
12 #include "lily-guile.hh"
13 #include "warn.hh"
14 #include "music-iterator.hh"
15 #include "interpretation-context-handle.hh"
16
17 class Part_combine_iterator : public Music_iterator
18 {
19 public:
20   Part_combine_iterator ();
21
22   DECLARE_SCHEME_CALLBACK (constructor, ()); 
23 protected:
24   virtual void derived_substitute (Context *f, Context *t) ;
25   virtual void derived_mark () const;
26   Part_combine_iterator (Part_combine_iterator const &);
27
28   virtual void construct_children ();
29   virtual Moment pending_moment () const;
30   virtual void do_quit (); 
31   virtual void process (Moment);
32
33   virtual Music_iterator *try_music_in_children (Music *) const;
34
35   virtual bool ok () const;
36
37 private:
38   Music_iterator * first_iter_;
39   Music_iterator * second_iter_;
40   Moment start_moment_;
41   
42   SCM split_list_;
43
44   enum Status  {
45     APART, TOGETHER,
46     SOLO1, SOLO2,
47     UNISONO, UNISILENCE,
48   };
49   Status state_;
50   Status playing_state_;
51
52   /*
53     TODO: this is getting of hand... 
54    */
55   Interpretation_context_handle one_;
56   Interpretation_context_handle two_;
57   Interpretation_context_handle null_;
58   Interpretation_context_handle shared_;
59   Interpretation_context_handle solo_;
60   
61   void substitute_both (Context * to1,
62                         Context * to2);
63
64   void kill_mmrest (Context *);
65   void chords_together ();
66   void solo1 ();
67   void solo2 ();
68   void apart (bool silent);
69   void unisono (bool silent);
70 };
71
72
73 Part_combine_iterator::Part_combine_iterator ()
74 {
75   first_iter_ = 0;
76   second_iter_ = 0;
77   split_list_ = SCM_EOL;
78   state_ = APART;
79   playing_state_ = APART;
80 }
81
82 void
83 Part_combine_iterator::derived_mark () const
84 {
85   if (first_iter_)
86     scm_gc_mark (first_iter_->self_scm ());
87   if (second_iter_)
88     scm_gc_mark (second_iter_->self_scm ());
89 }
90
91 void
92 Part_combine_iterator::derived_substitute (Context *f,
93                                      Context *t)
94 {
95   if (first_iter_)
96     first_iter_->substitute_outlet (f,t);
97   if (second_iter_)
98     second_iter_->substitute_outlet (f,t);
99 }
100
101 void
102 Part_combine_iterator::do_quit ()
103 {
104   if (first_iter_)
105     first_iter_->quit ();
106   if (second_iter_)
107     second_iter_->quit ();
108
109   null_.set_translator (0);
110   one_ .set_translator (0);
111   two_.set_translator (0);
112   shared_.set_translator (0);
113   solo_.set_translator (0);
114 }
115
116 Moment
117 Part_combine_iterator::pending_moment () const
118 {
119   Moment p;
120   p.set_infinite (1);
121   if (first_iter_->ok ())
122     p = p <? first_iter_->pending_moment ();
123
124   if (second_iter_->ok ())
125     p = p <? second_iter_->pending_moment ();
126   return p;
127 }
128
129 bool
130 Part_combine_iterator::ok () const
131 {
132   return first_iter_->ok () || second_iter_->ok ();
133 }
134
135 void
136 Part_combine_iterator::chords_together ()
137 {
138   if (state_ == TOGETHER)
139     return;
140   else
141     {
142       playing_state_ = TOGETHER;
143       state_ = TOGETHER;
144
145       substitute_both (shared_.get_outlet (), shared_.get_outlet ());
146     }
147 }
148
149
150 void
151 Part_combine_iterator::kill_mmrest (Context * tg)
152 {
153   static Music * mmrest;
154   if (!mmrest)
155     {
156       mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
157       mmrest->set_property ("duration", SCM_EOL);
158     }
159
160   tg->try_music (mmrest);
161 }
162
163 void
164 Part_combine_iterator::solo1 ()
165 {
166   if (state_ == SOLO1)
167     return;
168   else
169     {
170       state_ = SOLO1;
171       substitute_both (solo_.get_outlet (),
172                        null_.get_outlet ());
173       
174       kill_mmrest (two_.get_outlet ());
175       kill_mmrest (shared_.get_outlet ());
176
177       if (playing_state_ != SOLO1)
178         {
179           static Music* event;
180           if (!event)
181             event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
182
183           first_iter_-> try_music_in_children (event);
184         }
185       playing_state_ = SOLO1;
186     }
187 }
188
189 void
190 Part_combine_iterator::substitute_both (Context * to1,
191                                   Context * to2)
192 {
193   Context *tos[]  = {to1,to2};
194   Music_iterator *mis[] = {first_iter_, second_iter_}; 
195   Interpretation_context_handle *hs[] = {
196     &null_,
197     &one_, &two_,
198     &shared_,  &solo_,
199     0
200   };
201   
202   for (int i = 0; i < 2 ; i++)
203     {
204       for (int j =  0; hs[j]; j++)
205         if (hs[j]->get_outlet () != tos[i])
206           mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]); 
207     }
208
209   for (int j =  0; hs[j]; j++)
210     {
211       Context * t = hs[j]->get_outlet ();
212       if (t != to1 && t != to2)
213         kill_mmrest (t);
214     }
215 }
216
217
218 void
219 Part_combine_iterator::unisono (bool silent)
220 {
221   Status newstate = (silent) ? UNISILENCE : UNISONO;
222   
223   if (newstate == state_)
224     return; 
225   else
226     {
227       substitute_both (shared_.get_outlet (), null_.get_outlet ());
228
229       kill_mmrest (two_.get_outlet ());
230       kill_mmrest (shared_.get_outlet ());
231
232       if (playing_state_ != UNISONO
233           && newstate == UNISONO)
234         {
235           static Music* event;
236           if (!event)
237             event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
238
239           first_iter_-> try_music_in_children (event);      
240           playing_state_ = UNISONO;
241         }
242       state_ = newstate;
243     }
244 }
245
246 void
247 Part_combine_iterator::solo2 ()
248 {
249   if (state_ == SOLO2)
250     return;
251   else
252     {
253       state_ = SOLO2;
254       
255       substitute_both (null_.get_outlet (), solo_.get_outlet ());
256       
257       if (playing_state_ != SOLO2)
258         {
259           static Music* event;
260           if (!event)
261             event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
262
263           second_iter_-> try_music_in_children (event);
264           playing_state_ = SOLO2;
265         }
266     }
267 }
268
269 void
270 Part_combine_iterator::apart (bool silent)
271 {
272   if (!silent)
273     playing_state_ = APART;
274
275   if (state_ == APART)
276     return;
277   else
278     {
279       state_ = APART;
280       substitute_both (one_.get_outlet (), two_.get_outlet ());
281     }
282 }
283
284
285 void
286 Part_combine_iterator::construct_children ()
287 {
288   start_moment_ = get_outlet ()->now_mom ();
289   split_list_ =  get_music ()->get_property ("split-list");
290   SCM lst =  get_music ()->get_property ("elements");
291
292   SCM props = scm_list_n (/*
293                             used to have tweaks here.
294                            */
295                           
296                           SCM_UNDEFINED);
297
298   Context *tr
299     =  get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
300                                              "shared",props);
301
302   shared_.set_translator (tr);
303
304   /*
305     If we don't, we get a new staff for every Voice.
306    */
307   set_translator (tr);
308
309   Context *solo_tr
310     =  get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
311                                               "solo",props);
312
313   solo_ .set_translator (solo_tr);
314
315   Context *null
316     =  get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
317                                              "", SCM_EOL);
318
319   if (!null)
320     programming_error ("No Devnull found?");
321   
322   null_.set_translator (null);
323
324   Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
325                                                       "one", props);
326
327   one_.set_translator (one);
328
329   set_translator (one);
330   first_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_car (lst))));
331
332
333   Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
334                                                       "two", props);
335   two_.set_translator (two);
336   set_translator (two);
337   second_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_cadr (lst))));
338
339
340   set_translator (tr);
341
342
343   char const * syms[] = {
344     "Stem",
345     "DynamicLineSpanner",
346     "Tie",
347     "Dots",
348     "Rest",
349     "Slur",
350     "TextScript",
351     "Script",
352     0
353   };
354   
355   for (char const**p = syms; *p; p++)
356     {
357       SCM sym = ly_symbol2scm (*p);
358       execute_pushpop_property (one, sym,
359                                      ly_symbol2scm ("direction"), gh_int2scm (1));
360
361       execute_pushpop_property (two, sym,
362                                 ly_symbol2scm ("direction"), gh_int2scm (-1));
363     }
364
365 }
366
367 void
368 Part_combine_iterator::process (Moment m)
369 {
370   Moment now = get_outlet ()->now_mom ();
371   Moment *splitm = 0;
372   
373   for (; gh_pair_p (split_list_); split_list_ = gh_cdr (split_list_))
374     {
375       splitm = unsmob_moment (gh_caar (split_list_));
376       if (splitm && *splitm + start_moment_ > now)
377         break ;
378
379       SCM tag = gh_cdar (split_list_);
380       
381       if (tag == ly_symbol2scm ("chords"))
382         chords_together ();
383       else if (tag == ly_symbol2scm ("apart")
384                || tag == ly_symbol2scm ("apart-silence")
385                || tag == ly_symbol2scm ("apart-spanner"))
386         apart (tag == ly_symbol2scm ("apart-silence"));
387       else if (tag == ly_symbol2scm ("unisono"))
388         unisono (false);
389       else if (tag == ly_symbol2scm ("unisilence"))
390         unisono (true);
391       else if (tag == ly_symbol2scm ("solo1"))
392         solo1 ();
393       else if (tag == ly_symbol2scm ("solo2"))
394         solo2 ();
395       else if (gh_symbol_p (tag))
396         {
397           String s =  "Unknown split directive: "
398             + (gh_symbol_p (tag) ? ly_symbol2string (tag) : String ("not a symbol")); 
399           programming_error (s);
400         }
401     }
402   
403   if (first_iter_->ok ())
404     first_iter_->process (m);
405   
406   if (second_iter_->ok ())
407     second_iter_->process (m);
408 }
409
410 Music_iterator*
411 Part_combine_iterator::try_music_in_children (Music *m) const
412 {
413   Music_iterator * i =  first_iter_->try_music (m);
414   if (i)
415     return i;
416   else
417     return second_iter_->try_music (m);
418 }
419
420 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);