]> git.donarmstrong.com Git - lilypond.git/blob - lily/new-part-combine-iterator.cc
* scm/music-functions.scm (determine-split-list): further analysis.
[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 "part-combine-music-iterator.hh"
10 #include "translator-group.hh"
11 #include "event.hh"
12 #include "music-sequence.hh"
13 #include "lily-guile.hh"
14 #include "warn.hh"
15 #include "music-iterator.hh"
16 #include "interpretation-context-handle.hh"
17
18 class New_pc_iterator : public Music_iterator
19 {
20 public:
21   VIRTUAL_COPY_CONS (Music_iterator);
22   New_pc_iterator ();
23
24   DECLARE_SCHEME_CALLBACK(constructor, ()); 
25 protected:
26   virtual void derived_substitute (Translator_group*f, Translator_group*t) ;
27   virtual void derived_mark () const;
28   New_pc_iterator (New_pc_iterator const &);
29
30   virtual void construct_children ();
31   virtual Moment pending_moment () const;
32   virtual void do_quit(); 
33   virtual void process (Moment);
34
35   virtual SCM get_pending_events (Moment)const;
36   virtual Music_iterator *try_music_in_children (Music *) const;
37
38   virtual bool ok () const;
39
40 private:
41   Music_iterator * first_iter_;
42   Music_iterator * second_iter_;
43   
44   SCM split_list_;
45
46   enum Status  {
47     APART, TOGETHER,
48     SOLO1, SOLO2,
49     UNISONO, UNISILENCE,
50   };
51   Status state_;
52   Status playing_state_;
53
54   Interpretation_context_handle one_;
55   Interpretation_context_handle two_;
56   Interpretation_context_handle null_;
57   Interpretation_context_handle shared_;
58
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::solo1 ()
165 {
166   if (state_ == SOLO1)
167     return;
168   else
169     {
170       state_ = SOLO1;
171       first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
172       first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
173
174       second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
175       second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
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 void
189 New_pc_iterator::unisono (bool silent)
190 {
191   Status newstate = (silent) ? UNISILENCE : UNISONO;
192   
193   if (newstate == state_)
194     return; 
195   else
196     {
197
198       first_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
199       first_iter_->substitute_outlet (one_.report_to (), shared_.report_to ());
200
201       second_iter_->substitute_outlet (two_.report_to (), null_.report_to ());
202       second_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
203
204       if (playing_state_ != UNISONO
205           && newstate == UNISONO)
206         {
207           static Music* event;
208           if (!event)
209             event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
210
211           first_iter_-> try_music_in_children (event);      
212           playing_state_ = UNISONO;
213         }
214       state_ = newstate;
215     }
216 }
217
218 void
219 New_pc_iterator::solo2 ()
220 {
221   if (state_ == SOLO2)
222     return;
223   else
224     {
225       state_ = SOLO2;
226       
227       second_iter_->substitute_outlet (null_.report_to (), shared_.report_to ());
228       second_iter_->substitute_outlet (two_.report_to (), shared_.report_to ());
229
230       first_iter_->substitute_outlet (one_.report_to (), null_.report_to ());
231       first_iter_->substitute_outlet (shared_.report_to (), null_.report_to ());
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_.report_to (), one_.report_to ());
258       first_iter_->substitute_outlet (shared_.report_to (), one_.report_to ());
259   
260       second_iter_->substitute_outlet (null_.report_to (), two_.report_to ());
261       second_iter_->substitute_outlet (shared_.report_to (), two_.report_to ());    }
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 (scm_list_n (ly_symbol2scm ("denies"), ly_symbol2scm ("Thread"), SCM_UNDEFINED),
271                           scm_list_n (ly_symbol2scm ("consists"), ly_symbol2scm ("Rest_engraver"), SCM_UNDEFINED),
272                           scm_list_n (ly_symbol2scm ("consists"), ly_symbol2scm ("Note_heads_engraver"), SCM_UNDEFINED),
273                           SCM_UNDEFINED);
274
275   Translator_group *tr
276     =  report_to ()->find_create_translator (ly_symbol2scm ("Voice"),
277                                              "shared",props);
278
279   shared_ .set_translator (tr); 
280   set_translator (tr);
281   Translator_group *null
282     =  report_to ()->find_create_translator (ly_symbol2scm ("Devnull"),
283                                              "", SCM_EOL);
284
285   if (!null)
286     programming_error ("No Devnull found?");
287   
288   null_.set_translator (null);
289
290   Translator_group *one = tr->find_create_translator (ly_symbol2scm ("Voice"),
291                                                       "one", props);
292
293   one_.set_translator (one);
294
295   set_translator (one);
296   first_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_car (lst))));
297
298
299   Translator_group *two = tr->find_create_translator (ly_symbol2scm ("Voice"),
300                                                       "two", props);
301   two_.set_translator (two);
302   set_translator (two);
303   second_iter_ = unsmob_iterator (get_iterator (unsmob_music (gh_cadr (lst))));
304
305
306   set_translator (tr);
307
308
309   char const * syms[] = {
310     "Stem",
311     "DynamicLineSpanner",
312     "Tie",
313     "Dots",
314     "Slur",
315     "TextScript",
316     "Script",
317     0
318   };
319   
320   for (char const**p = syms; *p; p++)
321     {
322       SCM sym = ly_symbol2scm (*p);
323       one->execute_pushpop_property (sym,
324                                      ly_symbol2scm ("direction"), gh_int2scm (1));
325
326       two->execute_pushpop_property (sym,
327                                      ly_symbol2scm ("direction"), gh_int2scm (-1));
328     }
329
330 }
331
332 void
333 New_pc_iterator::process (Moment m)
334 {
335   Moment now = report_to ()->now_mom ();
336   Moment *splitm = 0;
337   
338   for (; gh_pair_p (split_list_); split_list_ = gh_cdr (split_list_))
339     {
340       splitm = unsmob_moment (gh_caar (split_list_));
341       if (*splitm > now)
342         break ;
343
344       SCM tag = gh_cdar (split_list_);
345       
346       if (tag == ly_symbol2scm ("chords"))
347         chords_together ();
348       else if (tag == ly_symbol2scm ("apart")
349                || tag == ly_symbol2scm ("apart-silence"))
350         apart (tag == ly_symbol2scm ("apart-silence"));
351       else if (tag == ly_symbol2scm ("unisono"))
352         unisono (false);
353       else if (tag == ly_symbol2scm ("unisilence"))
354         unisono (true);
355       else if (tag == ly_symbol2scm ("solo1"))
356         solo1 ();
357       else if (tag == ly_symbol2scm ("solo2"))
358         solo2 ();
359       else
360         {
361           String s =  "Unknown split directive: "
362             + (gh_symbol_p (tag) ? ly_symbol2string (tag) : String ("not a symbol")); 
363           programming_error (s);
364         }
365     }
366   
367   if (first_iter_->ok ())
368     first_iter_->process (m);
369   
370   if (second_iter_->ok ())
371     second_iter_->process (m);
372 }
373
374 Music_iterator*
375 New_pc_iterator::try_music_in_children (Music *m) const
376 {
377   Music_iterator * i =  first_iter_->try_music (m);
378   if (i)
379     return i;
380   else
381     return second_iter_->try_music (m);
382 }
383
384
385 SCM
386 New_pc_iterator::get_pending_events (Moment m)const
387 {
388   SCM s = SCM_EOL;
389   if (first_iter_)
390     s = gh_append2 (s,first_iter_->get_pending_events (m));
391   if (second_iter_)
392     s = gh_append2 (second_iter_->get_pending_events (m),s);
393   return s;
394 }
395
396 IMPLEMENT_CTOR_CALLBACK (New_pc_iterator);