2 new-part-combine-music-iterator.cc -- implement Part_combine_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2004--2005 Han-Wen Nienhuys
11 #include "music-sequence.hh"
12 #include "lily-guile.hh"
14 #include "music-iterator.hh"
16 class Part_combine_iterator : public Music_iterator
19 Part_combine_iterator ();
21 DECLARE_SCHEME_CALLBACK (constructor, ());
23 virtual void derived_substitute (Context *f, Context *t);
24 virtual void derived_mark () const;
25 Part_combine_iterator (Part_combine_iterator const &);
27 virtual void construct_children ();
28 virtual Moment pending_moment () const;
29 virtual void do_quit ();
30 virtual void process (Moment);
32 virtual Music_iterator *try_music_in_children (Music *) const;
34 virtual bool ok () const;
37 Music_iterator *first_iter_;
38 Music_iterator *second_iter_;
53 Status playing_state_;
56 Should be SOLO1 or SOLO2
61 TODO: this is getting of hand...
66 Context_handle shared_;
69 void substitute_both (Context *to1,
72 void kill_mmrest (Context *);
73 void chords_together ();
76 void apart (bool silent);
77 void unisono (bool silent);
80 static Music *busy_playing_event;
83 Part_combine_iterator::do_quit ()
88 second_iter_->quit ();
90 null_.set_context (0);
93 shared_.set_context (0);
94 solo_.set_context (0);
97 Part_combine_iterator::Part_combine_iterator ()
101 split_list_ = SCM_EOL;
103 playing_state_ = APART;
105 if (!busy_playing_event)
108 = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
113 Part_combine_iterator::derived_mark () const
116 scm_gc_mark (first_iter_->self_scm ());
118 scm_gc_mark (second_iter_->self_scm ());
122 Part_combine_iterator::derived_substitute (Context *f,
126 first_iter_->substitute_outlet (f, t);
130 Part_combine_iterator::pending_moment () const
134 if (first_iter_->ok ())
135 p = min (p, first_iter_->pending_moment ());
137 if (second_iter_->ok ())
138 p = min (p, second_iter_->pending_moment ());
143 Part_combine_iterator::ok () const
145 return first_iter_->ok () || second_iter_->ok ();
149 Part_combine_iterator::chords_together ()
151 if (state_ == TOGETHER)
155 playing_state_ = TOGETHER;
158 substitute_both (shared_.get_outlet (), shared_.get_outlet ());
163 Part_combine_iterator::kill_mmrest (Context *tg)
165 static Music *mmrest;
168 mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
169 mmrest->set_property ("duration", SCM_EOL);
172 tg->try_music (mmrest);
176 Part_combine_iterator::solo1 ()
183 substitute_both (solo_.get_outlet (),
184 null_.get_outlet ());
186 kill_mmrest (two_.get_outlet ());
187 kill_mmrest (shared_.get_outlet ());
189 if (playing_state_ != SOLO1)
193 event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
195 first_iter_->try_music_in_children (event);
197 playing_state_ = SOLO1;
202 Part_combine_iterator::substitute_both (Context *to1,
205 Context *tos[] = {to1, to2};
206 Music_iterator *mis[] = {first_iter_, second_iter_};
215 for (int i = 0; i < 2; i++)
217 for (int j = 0; hs[j]; j++)
218 if (hs[j]->get_outlet () != tos[i])
219 mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]);
222 for (int j = 0; hs[j]; j++)
224 Context *t = hs[j]->get_outlet ();
225 if (t != to1 && t != to2)
231 Part_combine_iterator::unisono (bool silent)
233 Status newstate = (silent) ? UNISILENCE : UNISONO;
235 if (newstate == state_)
240 If we're coming from SOLO2 state, we might have kill mmrests
241 in the 1st voice, so in that case, we use the second voice
242 as a basis for events.
244 Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet () : shared_.get_outlet ();
245 Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet () : null_.get_outlet ();
246 substitute_both (c1, c2);
247 kill_mmrest ((last_playing_ == SOLO2)
248 ? one_.get_outlet () : two_.get_outlet ());
249 kill_mmrest (shared_.get_outlet ());
251 if (playing_state_ != UNISONO
252 && newstate == UNISONO)
256 event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
258 (last_playing_ == SOLO2 ? second_iter_ : first_iter_)
259 ->try_music_in_children (event);
260 playing_state_ = UNISONO;
267 Part_combine_iterator::solo2 ()
275 substitute_both (null_.get_outlet (), solo_.get_outlet ());
277 if (playing_state_ != SOLO2)
281 event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
283 second_iter_->try_music_in_children (event);
284 playing_state_ = SOLO2;
290 Part_combine_iterator::apart (bool silent)
293 playing_state_ = APART;
300 substitute_both (one_.get_outlet (), two_.get_outlet ());
305 Part_combine_iterator::construct_children ()
307 start_moment_ = get_outlet ()->now_mom ();
308 split_list_ = get_music ()->get_property ("split-list");
309 SCM lst = get_music ()->get_property ("elements");
311 SCM props = scm_list_n (/*
312 used to have tweaks here.
318 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
321 shared_.set_context (tr);
324 If we don't, we get a new staff for every Voice.
329 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
332 solo_.set_context (solo_tr);
335 = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
339 programming_error ("no Devnull found");
341 null_.set_context (null);
343 Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
346 one_.set_context (one);
349 first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst))));
351 Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
353 two_.set_context (two);
355 second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst))));
362 "DynamicLineSpanner",
372 for (char const **p = syms; *p; p++)
374 SCM sym = ly_symbol2scm (*p);
375 execute_pushpop_property (one, sym,
376 ly_symbol2scm ("direction"), scm_int2num (1));
378 execute_pushpop_property (two, sym,
379 ly_symbol2scm ("direction"), scm_int2num (-1));
384 Part_combine_iterator::process (Moment m)
386 Moment now = get_outlet ()->now_mom ();
389 for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_))
391 splitm = unsmob_moment (scm_caar (split_list_));
392 if (splitm && *splitm + start_moment_ > now)
395 SCM tag = scm_cdar (split_list_);
397 if (tag == ly_symbol2scm ("chords"))
399 else if (tag == ly_symbol2scm ("apart")
400 || tag == ly_symbol2scm ("apart-silence")
401 || tag == ly_symbol2scm ("apart-spanner"))
402 apart (tag == ly_symbol2scm ("apart-silence"));
403 else if (tag == ly_symbol2scm ("unisono"))
405 else if (tag == ly_symbol2scm ("unisilence"))
407 else if (tag == ly_symbol2scm ("solo1"))
409 else if (tag == ly_symbol2scm ("solo2"))
411 else if (scm_is_symbol (tag))
413 String s = "Unknown split directive: "
414 + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
415 programming_error (s);
419 if (first_iter_->ok ())
421 first_iter_->process (m);
422 if (first_iter_->try_music_in_children (busy_playing_event))
423 last_playing_ = SOLO1;
426 if (second_iter_->ok ())
428 second_iter_->process (m);
429 if (first_iter_->try_music_in_children (busy_playing_event))
430 last_playing_ = SOLO2;
435 Part_combine_iterator::try_music_in_children (Music *m) const
437 Music_iterator *i = first_iter_->try_music (m);
441 return second_iter_->try_music (m);
444 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);