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...
63 Interpretation_context_handle one_;
64 Interpretation_context_handle two_;
65 Interpretation_context_handle null_;
66 Interpretation_context_handle shared_;
67 Interpretation_context_handle solo_;
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);
91 one_ .set_context (0);
93 shared_.set_context (0);
94 solo_.set_context (0);
98 Part_combine_iterator::Part_combine_iterator ()
102 split_list_ = SCM_EOL;
104 playing_state_ = APART;
106 if (!busy_playing_event)
109 = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
114 Part_combine_iterator::derived_mark () const
117 scm_gc_mark (first_iter_->self_scm ());
119 scm_gc_mark (second_iter_->self_scm ());
123 Part_combine_iterator::derived_substitute (Context *f,
127 first_iter_->substitute_outlet (f, t);
132 Part_combine_iterator::pending_moment () const
136 if (first_iter_->ok ())
137 p = p <? first_iter_->pending_moment ();
139 if (second_iter_->ok ())
140 p = p <? second_iter_->pending_moment ();
145 Part_combine_iterator::ok () const
147 return first_iter_->ok () || second_iter_->ok ();
151 Part_combine_iterator::chords_together ()
153 if (state_ == TOGETHER)
157 playing_state_ = TOGETHER;
160 substitute_both (shared_.get_outlet (), shared_.get_outlet ());
165 Part_combine_iterator::kill_mmrest (Context *tg)
167 static Music *mmrest;
170 mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
171 mmrest->set_property ("duration", SCM_EOL);
174 tg->try_music (mmrest);
178 Part_combine_iterator::solo1 ()
185 substitute_both (solo_.get_outlet (),
186 null_.get_outlet ());
188 kill_mmrest (two_.get_outlet ());
189 kill_mmrest (shared_.get_outlet ());
191 if (playing_state_ != SOLO1)
195 event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
197 first_iter_-> try_music_in_children (event);
199 playing_state_ = SOLO1;
204 Part_combine_iterator::substitute_both (Context *to1,
207 Context *tos[] = {to1, to2};
208 Music_iterator *mis[] = {first_iter_, second_iter_};
209 Interpretation_context_handle *hs[]
217 for (int i = 0; i < 2; i++)
219 for (int j = 0; hs[j]; j++)
220 if (hs[j]->get_outlet () != tos[i])
221 mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]);
224 for (int j = 0; hs[j]; j++)
226 Context *t = hs[j]->get_outlet ();
227 if (t != to1 && t != to2)
233 Part_combine_iterator::unisono (bool silent)
235 Status newstate = (silent) ? UNISILENCE : UNISONO;
237 if (newstate == state_)
242 If we're coming from SOLO2 state, we might have kill mmrests
243 in the 1st voice, so in that case, we use the second voice
244 as a basis for events.
246 Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet () : shared_.get_outlet ();
247 Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet () : null_.get_outlet ();
248 substitute_both (c1, c2);
249 kill_mmrest ((last_playing_ == SOLO2)
250 ? one_.get_outlet () : two_.get_outlet ());
251 kill_mmrest (shared_.get_outlet ());
253 if (playing_state_ != UNISONO
254 && newstate == UNISONO)
258 event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
260 (last_playing_ == SOLO2 ? second_iter_ : first_iter_)
261 ->try_music_in_children (event);
262 playing_state_ = UNISONO;
269 Part_combine_iterator::solo2 ()
277 substitute_both (null_.get_outlet (), solo_.get_outlet ());
279 if (playing_state_ != SOLO2)
283 event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
285 second_iter_-> try_music_in_children (event);
286 playing_state_ = SOLO2;
292 Part_combine_iterator::apart (bool silent)
295 playing_state_ = APART;
302 substitute_both (one_.get_outlet (), two_.get_outlet ());
307 Part_combine_iterator::construct_children ()
309 start_moment_ = get_outlet ()->now_mom ();
310 split_list_ = get_music ()->get_property ("split-list");
311 SCM lst = get_music ()->get_property ("elements");
313 SCM props = scm_list_n (/*
314 used to have tweaks here.
320 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
323 shared_.set_context (tr);
326 If we don't, we get a new staff for every Voice.
331 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
334 solo_ .set_context (solo_tr);
337 = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
341 programming_error ("No Devnull found?");
343 null_.set_context (null);
345 Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
348 one_.set_context (one);
351 first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst))));
353 Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
355 two_.set_context (two);
357 second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst))));
364 "DynamicLineSpanner",
374 for (char const **p = syms; *p; p++)
376 SCM sym = ly_symbol2scm (*p);
377 execute_pushpop_property (one, sym,
378 ly_symbol2scm ("direction"), scm_int2num (1));
380 execute_pushpop_property (two, sym,
381 ly_symbol2scm ("direction"), scm_int2num (-1));
387 Part_combine_iterator::process (Moment m)
389 Moment now = get_outlet ()->now_mom ();
392 for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_))
394 splitm = unsmob_moment (scm_caar (split_list_));
395 if (splitm && *splitm + start_moment_ > now)
398 SCM tag = scm_cdar (split_list_);
400 if (tag == ly_symbol2scm ("chords"))
402 else if (tag == ly_symbol2scm ("apart")
403 || tag == ly_symbol2scm ("apart-silence")
404 || tag == ly_symbol2scm ("apart-spanner"))
405 apart (tag == ly_symbol2scm ("apart-silence"));
406 else if (tag == ly_symbol2scm ("unisono"))
408 else if (tag == ly_symbol2scm ("unisilence"))
410 else if (tag == ly_symbol2scm ("solo1"))
412 else if (tag == ly_symbol2scm ("solo2"))
414 else if (scm_is_symbol (tag))
416 String s = "Unknown split directive: "
417 + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
418 programming_error (s);
422 if (first_iter_->ok ())
424 first_iter_->process (m);
425 if (first_iter_->try_music_in_children (busy_playing_event))
426 last_playing_ = SOLO1;
429 if (second_iter_->ok ())
431 second_iter_->process (m);
432 if (first_iter_->try_music_in_children (busy_playing_event))
433 last_playing_ = SOLO2;
438 Part_combine_iterator::try_music_in_children (Music *m) const
440 Music_iterator *i = first_iter_->try_music (m);
444 return second_iter_->try_music (m);
447 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);