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