2 new-part-combine-music-iterator.cc -- implement Part_combine_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2004 Han-Wen Nienhuys
11 #include "music-sequence.hh"
12 #include "lily-guile.hh"
14 #include "music-iterator.hh"
15 #include "interpretation-context-handle.hh"
17 class Part_combine_iterator : public Music_iterator
20 Part_combine_iterator ();
22 DECLARE_SCHEME_CALLBACK (constructor, ());
24 virtual void derived_substitute (Context *f, Context *t) ;
25 virtual void derived_mark () const;
26 Part_combine_iterator (Part_combine_iterator const &);
28 virtual void construct_children ();
29 virtual Moment pending_moment () const;
30 virtual void do_quit ();
31 virtual void process (Moment);
33 virtual Music_iterator *try_music_in_children (Music *) const;
35 virtual bool ok () const;
38 Music_iterator * first_iter_;
39 Music_iterator * second_iter_;
50 Status playing_state_;
53 TODO: this is getting of hand...
55 Interpretation_context_handle one_;
56 Interpretation_context_handle two_;
57 Interpretation_context_handle null_;
58 Interpretation_context_handle shared_;
59 Interpretation_context_handle solo_;
61 void substitute_both (Context * to1,
64 void kill_mmrest (Context *);
65 void chords_together ();
68 void apart (bool silent);
69 void unisono (bool silent);
73 Part_combine_iterator::Part_combine_iterator ()
77 split_list_ = SCM_EOL;
79 playing_state_ = APART;
83 Part_combine_iterator::derived_mark () const
86 scm_gc_mark (first_iter_->self_scm ());
88 scm_gc_mark (second_iter_->self_scm ());
92 Part_combine_iterator::derived_substitute (Context *f,
96 first_iter_->substitute_outlet (f,t);
98 second_iter_->substitute_outlet (f,t);
102 Part_combine_iterator::do_quit ()
105 first_iter_->quit ();
107 second_iter_->quit ();
109 null_.set_translator (0);
110 one_ .set_translator (0);
111 two_.set_translator (0);
112 shared_.set_translator (0);
113 solo_.set_translator (0);
117 Part_combine_iterator::pending_moment () const
121 if (first_iter_->ok ())
122 p = p <? first_iter_->pending_moment ();
124 if (second_iter_->ok ())
125 p = p <? second_iter_->pending_moment ();
130 Part_combine_iterator::ok () const
132 return first_iter_->ok () || second_iter_->ok ();
136 Part_combine_iterator::chords_together ()
138 if (state_ == TOGETHER)
142 playing_state_ = TOGETHER;
145 substitute_both (shared_.get_outlet (), shared_.get_outlet ());
151 Part_combine_iterator::kill_mmrest (Context * tg)
153 static Music * mmrest;
156 mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
157 mmrest->set_property ("duration", SCM_EOL);
160 tg->try_music (mmrest);
164 Part_combine_iterator::solo1 ()
171 substitute_both (solo_.get_outlet (),
172 null_.get_outlet ());
174 kill_mmrest (two_.get_outlet ());
175 kill_mmrest (shared_.get_outlet ());
177 if (playing_state_ != SOLO1)
181 event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
183 first_iter_-> try_music_in_children (event);
185 playing_state_ = SOLO1;
190 Part_combine_iterator::substitute_both (Context * to1,
193 Context *tos[] = {to1,to2};
194 Music_iterator *mis[] = {first_iter_, second_iter_};
195 Interpretation_context_handle *hs[] = {
202 for (int i = 0; i < 2 ; i++)
204 for (int j = 0; hs[j]; j++)
205 if (hs[j]->get_outlet () != tos[i])
206 mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]);
209 for (int j = 0; hs[j]; j++)
211 Context * t = hs[j]->get_outlet ();
212 if (t != to1 && t != to2)
219 Part_combine_iterator::unisono (bool silent)
221 Status newstate = (silent) ? UNISILENCE : UNISONO;
223 if (newstate == state_)
228 If we're coming from SOLO2 state, we might have kill mmrests
229 in the 1st voice, so in that case, we use the second voice
230 as a basis for events.
232 Context *c1 = (state_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet();
233 Context *c2 = (state_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet();
235 substitute_both (c1, c2);
238 kill_mmrest ((state_ == SOLO2)
239 ? one_.get_outlet () : two_.get_outlet ());
240 kill_mmrest (shared_.get_outlet ());
242 if (playing_state_ != UNISONO
243 && newstate == UNISONO)
247 event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
249 (state_ == SOLO2 ? second_iter_ : first_iter_)
250 ->try_music_in_children (event);
251 playing_state_ = UNISONO;
258 Part_combine_iterator::solo2 ()
266 substitute_both (null_.get_outlet (), solo_.get_outlet ());
268 if (playing_state_ != SOLO2)
272 event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
274 second_iter_-> try_music_in_children (event);
275 playing_state_ = SOLO2;
281 Part_combine_iterator::apart (bool silent)
284 playing_state_ = APART;
291 substitute_both (one_.get_outlet (), two_.get_outlet ());
297 Part_combine_iterator::construct_children ()
299 start_moment_ = get_outlet ()->now_mom ();
300 split_list_ = get_music ()->get_property ("split-list");
301 SCM lst = get_music ()->get_property ("elements");
303 SCM props = scm_list_n (/*
304 used to have tweaks here.
310 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
313 shared_.set_translator (tr);
316 If we don't, we get a new staff for every Voice.
321 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
324 solo_ .set_translator (solo_tr);
327 = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
331 programming_error ("No Devnull found?");
333 null_.set_translator (null);
335 Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
338 one_.set_translator (one);
340 set_translator (one);
341 first_iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (lst))));
344 Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
346 two_.set_translator (two);
347 set_translator (two);
348 second_iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_cadr (lst))));
354 char const * syms[] = {
356 "DynamicLineSpanner",
366 for (char const**p = syms; *p; p++)
368 SCM sym = ly_symbol2scm (*p);
369 execute_pushpop_property (one, sym,
370 ly_symbol2scm ("direction"), scm_int2num (1));
372 execute_pushpop_property (two, sym,
373 ly_symbol2scm ("direction"), scm_int2num (-1));
379 Part_combine_iterator::process (Moment m)
381 Moment now = get_outlet ()->now_mom ();
384 for (; ly_c_pair_p (split_list_); split_list_ = ly_cdr (split_list_))
386 splitm = unsmob_moment (ly_caar (split_list_));
387 if (splitm && *splitm + start_moment_ > now)
390 SCM tag = ly_cdar (split_list_);
392 if (tag == ly_symbol2scm ("chords"))
394 else if (tag == ly_symbol2scm ("apart")
395 || tag == ly_symbol2scm ("apart-silence")
396 || tag == ly_symbol2scm ("apart-spanner"))
397 apart (tag == ly_symbol2scm ("apart-silence"));
398 else if (tag == ly_symbol2scm ("unisono"))
400 else if (tag == ly_symbol2scm ("unisilence"))
402 else if (tag == ly_symbol2scm ("solo1"))
404 else if (tag == ly_symbol2scm ("solo2"))
406 else if (scm_is_symbol (tag))
408 String s = "Unknown split directive: "
409 + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
410 programming_error (s);
414 if (first_iter_->ok ())
415 first_iter_->process (m);
417 if (second_iter_->ok ())
418 second_iter_->process (m);
422 Part_combine_iterator::try_music_in_children (Music *m) const
424 Music_iterator * i = first_iter_->try_music (m);
428 return second_iter_->try_music (m);
431 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);