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"
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_;
52 Status playing_state_;
55 Should be SOLO1 or SOLO2
60 TODO: this is getting of hand...
62 Interpretation_context_handle one_;
63 Interpretation_context_handle two_;
64 Interpretation_context_handle null_;
65 Interpretation_context_handle shared_;
66 Interpretation_context_handle solo_;
68 void substitute_both (Context * to1,
71 void kill_mmrest (Context *);
72 void chords_together ();
75 void apart (bool silent);
76 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 ());
166 Part_combine_iterator::kill_mmrest (Context * tg)
168 static Music * mmrest;
171 mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
172 mmrest->set_property ("duration", SCM_EOL);
175 tg->try_music (mmrest);
179 Part_combine_iterator::solo1 ()
186 substitute_both (solo_.get_outlet (),
187 null_.get_outlet ());
189 kill_mmrest (two_.get_outlet ());
190 kill_mmrest (shared_.get_outlet ());
192 if (playing_state_ != SOLO1)
196 event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
198 first_iter_-> try_music_in_children (event);
200 playing_state_ = SOLO1;
205 Part_combine_iterator::substitute_both (Context * to1,
208 Context *tos[] = {to1,to2};
209 Music_iterator *mis[] = {first_iter_, second_iter_};
210 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)
234 Part_combine_iterator::unisono (bool silent)
236 Status newstate = (silent) ? UNISILENCE : UNISONO;
238 if (newstate == state_)
243 If we're coming from SOLO2 state, we might have kill mmrests
244 in the 1st voice, so in that case, we use the second voice
245 as a basis for events.
247 Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet();
248 Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet();
249 substitute_both (c1, c2);
250 kill_mmrest ((last_playing_ == SOLO2)
251 ? one_.get_outlet () : two_.get_outlet ());
252 kill_mmrest (shared_.get_outlet ());
254 if (playing_state_ != UNISONO
255 && newstate == UNISONO)
259 event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
261 (last_playing_ == SOLO2 ? second_iter_ : first_iter_)
262 ->try_music_in_children (event);
263 playing_state_ = UNISONO;
270 Part_combine_iterator::solo2 ()
278 substitute_both (null_.get_outlet (), solo_.get_outlet ());
280 if (playing_state_ != SOLO2)
284 event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
286 second_iter_-> try_music_in_children (event);
287 playing_state_ = SOLO2;
293 Part_combine_iterator::apart (bool silent)
296 playing_state_ = APART;
303 substitute_both (one_.get_outlet (), two_.get_outlet ());
309 Part_combine_iterator::construct_children ()
311 start_moment_ = get_outlet ()->now_mom ();
312 split_list_ = get_music ()->get_property ("split-list");
313 SCM lst = get_music ()->get_property ("elements");
315 SCM props = scm_list_n (/*
316 used to have tweaks here.
322 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
325 shared_.set_context (tr);
328 If we don't, we get a new staff for every Voice.
333 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
336 solo_ .set_context (solo_tr);
339 = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
343 programming_error ("No Devnull found?");
345 null_.set_context (null);
347 Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
350 one_.set_context (one);
353 first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst))));
356 Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
358 two_.set_context (two);
360 second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst))));
366 char const * syms[] = {
368 "DynamicLineSpanner",
378 for (char const**p = syms; *p; p++)
380 SCM sym = ly_symbol2scm (*p);
381 execute_pushpop_property (one, sym,
382 ly_symbol2scm ("direction"), scm_int2num (1));
384 execute_pushpop_property (two, sym,
385 ly_symbol2scm ("direction"), scm_int2num (-1));
391 Part_combine_iterator::process (Moment m)
393 Moment now = get_outlet ()->now_mom ();
396 for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_))
398 splitm = unsmob_moment (scm_caar (split_list_));
399 if (splitm && *splitm + start_moment_ > now)
402 SCM tag = scm_cdar (split_list_);
404 if (tag == ly_symbol2scm ("chords"))
406 else if (tag == ly_symbol2scm ("apart")
407 || tag == ly_symbol2scm ("apart-silence")
408 || tag == ly_symbol2scm ("apart-spanner"))
409 apart (tag == ly_symbol2scm ("apart-silence"));
410 else if (tag == ly_symbol2scm ("unisono"))
412 else if (tag == ly_symbol2scm ("unisilence"))
414 else if (tag == ly_symbol2scm ("solo1"))
416 else if (tag == ly_symbol2scm ("solo2"))
418 else if (scm_is_symbol (tag))
420 String s = "Unknown split directive: "
421 + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
422 programming_error (s);
426 if (first_iter_->ok ())
428 first_iter_->process (m);
429 if (first_iter_->try_music_in_children (busy_playing_event))
430 last_playing_ = SOLO1;
433 if (second_iter_->ok ())
435 second_iter_->process (m);
436 if (first_iter_->try_music_in_children (busy_playing_event))
437 last_playing_ = SOLO2;
442 Part_combine_iterator::try_music_in_children (Music *m) const
444 Music_iterator * i = first_iter_->try_music (m);
448 return second_iter_->try_music (m);
451 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);