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