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