]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-iterator.cc
*** empty log message ***
[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,
46     TOGETHER,
47     SOLO1,
48     SOLO2,
49     UNISONO,
50     UNISILENCE,
51   };
52   Status state_;
53   Status playing_state_;
54
55   /*
56     Should be SOLO1 or SOLO2
57    */
58   Status last_playing_;
59
60   /*
61     TODO: this is getting of hand... 
62    */
63   Interpretation_context_handle one_;
64   Interpretation_context_handle two_;
65   Interpretation_context_handle null_;
66   Interpretation_context_handle shared_;
67   Interpretation_context_handle solo_;
68   
69   void substitute_both (Context * to1,
70                         Context * to2);
71
72   void kill_mmrest (Context *);
73   void chords_together ();
74   void solo1 ();
75   void solo2 ();
76   void apart (bool silent);
77   void unisono (bool silent);
78 };
79
80
81 static Music *busy_playing_event;
82
83 void
84 Part_combine_iterator::do_quit ()
85 {
86   if (first_iter_)
87     first_iter_->quit ();
88   if (second_iter_)
89     second_iter_->quit ();
90
91   null_.set_translator (0);
92   one_ .set_translator (0);
93   two_.set_translator (0);
94   shared_.set_translator (0);
95   solo_.set_translator (0);
96
97 }
98
99 Part_combine_iterator::Part_combine_iterator ()
100 {
101   first_iter_ = 0;
102   second_iter_ = 0;
103   split_list_ = SCM_EOL;
104   state_ = APART;
105   playing_state_ = APART;
106   
107   if (!busy_playing_event)
108     {
109       busy_playing_event
110         = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
111     }
112 }
113
114 void
115 Part_combine_iterator::derived_mark () const
116 {
117   if (first_iter_)
118     scm_gc_mark (first_iter_->self_scm ());
119   if (second_iter_)
120     scm_gc_mark (second_iter_->self_scm ());
121 }
122
123 void
124 Part_combine_iterator::derived_substitute (Context *f,
125                                      Context *t)
126 {
127   if (first_iter_)
128     first_iter_->substitute_outlet (f,t);
129
130 }
131
132 Moment
133 Part_combine_iterator::pending_moment () const
134 {
135   Moment p;
136   p.set_infinite (1);
137   if (first_iter_->ok ())
138     p = p <? first_iter_->pending_moment ();
139
140   if (second_iter_->ok ())
141     p = p <? second_iter_->pending_moment ();
142   return p;
143 }
144
145 bool
146 Part_combine_iterator::ok () const
147 {
148   return first_iter_->ok () || second_iter_->ok ();
149 }
150
151 void
152 Part_combine_iterator::chords_together ()
153 {
154   if (state_ == TOGETHER)
155     return;
156   else
157     {
158       playing_state_ = TOGETHER;
159       state_ = TOGETHER;
160
161       substitute_both (shared_.get_outlet (), shared_.get_outlet ());
162     }
163 }
164
165
166 void
167 Part_combine_iterator::kill_mmrest (Context * tg)
168 {
169   static Music * mmrest;
170   if (!mmrest)
171     {
172       mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
173       mmrest->set_property ("duration", SCM_EOL);
174     }
175
176   tg->try_music (mmrest);
177 }
178
179 void
180 Part_combine_iterator::solo1 ()
181 {
182   if (state_ == SOLO1)
183     return;
184   else
185     {
186       state_ = SOLO1;
187       substitute_both (solo_.get_outlet (),
188                        null_.get_outlet ());
189       
190       kill_mmrest (two_.get_outlet ());
191       kill_mmrest (shared_.get_outlet ());
192
193       if (playing_state_ != SOLO1)
194         {
195           static Music* event;
196           if (!event)
197             event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
198
199           first_iter_-> try_music_in_children (event);
200         }
201       playing_state_ = SOLO1;
202     }
203 }
204
205 void
206 Part_combine_iterator::substitute_both (Context * to1,
207                                         Context * to2)
208 {
209   Context *tos[]  = {to1,to2};
210   Music_iterator *mis[] = {first_iter_, second_iter_}; 
211   Interpretation_context_handle *hs[] = {
212     &null_,
213     &one_, &two_,
214     &shared_,  &solo_,
215     0
216   };
217   
218   for (int i = 0; i < 2 ; i++)
219     {
220       for (int j =  0; hs[j]; j++)
221         if (hs[j]->get_outlet () != tos[i])
222           mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]); 
223     }
224
225   for (int j =  0; hs[j]; j++)
226     {
227       Context * t = hs[j]->get_outlet ();
228       if (t != to1 && t != to2)
229         kill_mmrest (t);
230     }
231 }
232
233
234 void
235 Part_combine_iterator::unisono (bool silent)
236 {
237   Status newstate = (silent) ? UNISILENCE : UNISONO;
238   
239   if (newstate == state_)
240     return; 
241   else
242     {
243       /*
244         If we're coming from SOLO2 state, we might have kill mmrests
245         in the 1st voice, so in that case, we use the second voice 
246         as a basis for events.
247        */
248       Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet();
249       Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet();
250       substitute_both (c1, c2);
251       kill_mmrest ((last_playing_ == SOLO2)
252                    ? one_.get_outlet () : two_.get_outlet ());
253       kill_mmrest (shared_.get_outlet ());
254
255       if (playing_state_ != UNISONO
256           && newstate == UNISONO)
257         {
258           static Music* event;
259           if (!event)
260             event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
261
262           (last_playing_ == SOLO2 ? second_iter_ : first_iter_)
263             ->try_music_in_children (event);      
264           playing_state_ = UNISONO;
265         }
266       state_ = newstate;
267     }
268 }
269
270 void
271 Part_combine_iterator::solo2 ()
272 {
273   if (state_ == SOLO2)
274     return;
275   else
276     {
277       state_ = SOLO2;
278       
279       substitute_both (null_.get_outlet (), solo_.get_outlet ());
280       
281       if (playing_state_ != SOLO2)
282         {
283           static Music* event;
284           if (!event)
285             event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
286
287           second_iter_-> try_music_in_children (event);
288           playing_state_ = SOLO2;
289         }
290     }
291 }
292
293 void
294 Part_combine_iterator::apart (bool silent)
295 {
296   if (!silent)
297     playing_state_ = APART;
298
299   if (state_ == APART)
300     return;
301   else
302     {
303       state_ = APART;
304       substitute_both (one_.get_outlet (), two_.get_outlet ());
305     }
306 }
307
308
309 void
310 Part_combine_iterator::construct_children ()
311 {
312   start_moment_ = get_outlet ()->now_mom ();
313   split_list_ =  get_music ()->get_property ("split-list");
314   SCM lst =  get_music ()->get_property ("elements");
315
316   SCM props = scm_list_n (/*
317                             used to have tweaks here.
318                            */
319                           
320                           SCM_UNDEFINED);
321
322   Context *tr
323     =  get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
324                                              "shared",props);
325
326   shared_.set_translator (tr);
327
328   /*
329     If we don't, we get a new staff for every Voice.
330    */
331   set_translator (tr);
332
333   Context *solo_tr
334     =  get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
335                                               "solo",props);
336
337   solo_ .set_translator (solo_tr);
338
339   Context *null
340     =  get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
341                                              "", SCM_EOL);
342
343   if (!null)
344     programming_error ("No Devnull found?");
345   
346   null_.set_translator (null);
347
348   Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
349                                                       "one", props);
350
351   one_.set_translator (one);
352
353   set_translator (one);
354   first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst))));
355
356
357   Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
358                                                       "two", props);
359   two_.set_translator (two);
360   set_translator (two);
361   second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst))));
362
363
364   set_translator (tr);
365
366
367   char const * syms[] = {
368     "Stem",
369     "DynamicLineSpanner",
370     "Tie",
371     "Dots",
372     "Rest",
373     "Slur",
374     "TextScript",
375     "Script",
376     0
377   };
378   
379   for (char const**p = syms; *p; p++)
380     {
381       SCM sym = ly_symbol2scm (*p);
382       execute_pushpop_property (one, sym,
383                                      ly_symbol2scm ("direction"), scm_int2num (1));
384
385       execute_pushpop_property (two, sym,
386                                 ly_symbol2scm ("direction"), scm_int2num (-1));
387     }
388
389 }
390
391 void
392 Part_combine_iterator::process (Moment m)
393 {
394   Moment now = get_outlet ()->now_mom ();
395   Moment *splitm = 0;
396   
397   for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_))
398     {
399       splitm = unsmob_moment (scm_caar (split_list_));
400       if (splitm && *splitm + start_moment_ > now)
401         break ;
402
403       SCM tag = scm_cdar (split_list_);
404       
405       if (tag == ly_symbol2scm ("chords"))
406         chords_together ();
407       else if (tag == ly_symbol2scm ("apart")
408                || tag == ly_symbol2scm ("apart-silence")
409                || tag == ly_symbol2scm ("apart-spanner"))
410         apart (tag == ly_symbol2scm ("apart-silence"));
411       else if (tag == ly_symbol2scm ("unisono"))
412         unisono (false);
413       else if (tag == ly_symbol2scm ("unisilence"))
414         unisono (true);
415       else if (tag == ly_symbol2scm ("solo1"))
416         solo1 ();
417       else if (tag == ly_symbol2scm ("solo2"))
418         solo2 ();
419       else if (scm_is_symbol (tag))
420         {
421           String s =  "Unknown split directive: "
422             + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol")); 
423           programming_error (s);
424         }
425     }
426
427   if (first_iter_->ok ())
428     {
429       first_iter_->process (m);
430       if (first_iter_->try_music_in_children (busy_playing_event))
431         last_playing_ = SOLO1;
432     }
433   
434   if (second_iter_->ok ())
435     {
436       second_iter_->process (m);
437       if (first_iter_->try_music_in_children (busy_playing_event))
438         last_playing_ = SOLO2;
439     }
440 }
441
442 Music_iterator*
443 Part_combine_iterator::try_music_in_children (Music *m) const
444 {
445   Music_iterator * i =  first_iter_->try_music (m);
446   if (i)
447     return i;
448   else
449     return second_iter_->try_music (m);
450 }
451
452 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);