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_;
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);
81 static Music *busy_playing_event;
84 Part_combine_iterator::do_quit ()
89 second_iter_->quit ();
91 null_.set_translator (0);
92 one_ .set_translator (0);
93 two_.set_translator (0);
94 shared_.set_translator (0);
95 solo_.set_translator (0);
99 Part_combine_iterator::Part_combine_iterator ()
103 split_list_ = SCM_EOL;
105 playing_state_ = APART;
107 if (!busy_playing_event)
110 = make_music_by_name (ly_symbol2scm ("BusyPlayingEvent"));
115 Part_combine_iterator::derived_mark () const
118 scm_gc_mark (first_iter_->self_scm ());
120 scm_gc_mark (second_iter_->self_scm ());
124 Part_combine_iterator::derived_substitute (Context *f,
128 first_iter_->substitute_outlet (f,t);
133 Part_combine_iterator::pending_moment () const
137 if (first_iter_->ok ())
138 p = p <? first_iter_->pending_moment ();
140 if (second_iter_->ok ())
141 p = p <? second_iter_->pending_moment ();
146 Part_combine_iterator::ok () const
148 return first_iter_->ok () || second_iter_->ok ();
152 Part_combine_iterator::chords_together ()
154 if (state_ == TOGETHER)
158 playing_state_ = TOGETHER;
161 substitute_both (shared_.get_outlet (), shared_.get_outlet ());
167 Part_combine_iterator::kill_mmrest (Context * tg)
169 static Music * mmrest;
172 mmrest = make_music_by_name (ly_symbol2scm ("MultiMeasureRestEvent"));
173 mmrest->set_property ("duration", SCM_EOL);
176 tg->try_music (mmrest);
180 Part_combine_iterator::solo1 ()
187 substitute_both (solo_.get_outlet (),
188 null_.get_outlet ());
190 kill_mmrest (two_.get_outlet ());
191 kill_mmrest (shared_.get_outlet ());
193 if (playing_state_ != SOLO1)
197 event = make_music_by_name (ly_symbol2scm ("SoloOneEvent"));
199 first_iter_-> try_music_in_children (event);
201 playing_state_ = SOLO1;
206 Part_combine_iterator::substitute_both (Context * to1,
209 Context *tos[] = {to1,to2};
210 Music_iterator *mis[] = {first_iter_, second_iter_};
211 Interpretation_context_handle *hs[] = {
218 for (int i = 0; i < 2 ; i++)
220 for (int j = 0; hs[j]; j++)
221 if (hs[j]->get_outlet () != tos[i])
222 mis[i]->substitute_outlet (hs[j]->get_outlet (), tos[i]);
225 for (int j = 0; hs[j]; j++)
227 Context * t = hs[j]->get_outlet ();
228 if (t != to1 && t != to2)
235 Part_combine_iterator::unisono (bool silent)
237 Status newstate = (silent) ? UNISILENCE : UNISONO;
239 if (newstate == state_)
244 If we're coming from SOLO2 state, we might have kill mmrests
245 in the 1st voice, so in that case, we use the second voice
246 as a basis for events.
248 Context *c1 = (last_playing_ == SOLO2) ? null_.get_outlet() : shared_.get_outlet();
249 Context *c2 = (last_playing_ == SOLO2) ? shared_.get_outlet() : null_.get_outlet();
250 substitute_both (c1, c2);
251 kill_mmrest ((last_playing_ == SOLO2)
252 ? one_.get_outlet () : two_.get_outlet ());
253 kill_mmrest (shared_.get_outlet ());
255 if (playing_state_ != UNISONO
256 && newstate == UNISONO)
260 event = make_music_by_name (ly_symbol2scm ("UnisonoEvent"));
262 (last_playing_ == SOLO2 ? second_iter_ : first_iter_)
263 ->try_music_in_children (event);
264 playing_state_ = UNISONO;
271 Part_combine_iterator::solo2 ()
279 substitute_both (null_.get_outlet (), solo_.get_outlet ());
281 if (playing_state_ != SOLO2)
285 event = make_music_by_name (ly_symbol2scm ("SoloTwoEvent"));
287 second_iter_-> try_music_in_children (event);
288 playing_state_ = SOLO2;
294 Part_combine_iterator::apart (bool silent)
297 playing_state_ = APART;
304 substitute_both (one_.get_outlet (), two_.get_outlet ());
310 Part_combine_iterator::construct_children ()
312 start_moment_ = get_outlet ()->now_mom ();
313 split_list_ = get_music ()->get_property ("split-list");
314 SCM lst = get_music ()->get_property ("elements");
316 SCM props = scm_list_n (/*
317 used to have tweaks here.
323 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
326 shared_.set_translator (tr);
329 If we don't, we get a new staff for every Voice.
334 = get_outlet ()->find_create_context (ly_symbol2scm ("Voice"),
337 solo_ .set_translator (solo_tr);
340 = get_outlet ()->find_create_context (ly_symbol2scm ("Devnull"),
344 programming_error ("No Devnull found?");
346 null_.set_translator (null);
348 Context *one = tr->find_create_context (ly_symbol2scm ("Voice"),
351 one_.set_translator (one);
353 set_translator (one);
354 first_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (lst))));
357 Context *two = tr->find_create_context (ly_symbol2scm ("Voice"),
359 two_.set_translator (two);
360 set_translator (two);
361 second_iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_cadr (lst))));
367 char const * syms[] = {
369 "DynamicLineSpanner",
379 for (char const**p = syms; *p; p++)
381 SCM sym = ly_symbol2scm (*p);
382 execute_pushpop_property (one, sym,
383 ly_symbol2scm ("direction"), scm_int2num (1));
385 execute_pushpop_property (two, sym,
386 ly_symbol2scm ("direction"), scm_int2num (-1));
392 Part_combine_iterator::process (Moment m)
394 Moment now = get_outlet ()->now_mom ();
397 for (; scm_is_pair (split_list_); split_list_ = scm_cdr (split_list_))
399 splitm = unsmob_moment (scm_caar (split_list_));
400 if (splitm && *splitm + start_moment_ > now)
403 SCM tag = scm_cdar (split_list_);
405 if (tag == ly_symbol2scm ("chords"))
407 else if (tag == ly_symbol2scm ("apart")
408 || tag == ly_symbol2scm ("apart-silence")
409 || tag == ly_symbol2scm ("apart-spanner"))
410 apart (tag == ly_symbol2scm ("apart-silence"));
411 else if (tag == ly_symbol2scm ("unisono"))
413 else if (tag == ly_symbol2scm ("unisilence"))
415 else if (tag == ly_symbol2scm ("solo1"))
417 else if (tag == ly_symbol2scm ("solo2"))
419 else if (scm_is_symbol (tag))
421 String s = "Unknown split directive: "
422 + (scm_is_symbol (tag) ? ly_symbol2string (tag) : String ("not a symbol"));
423 programming_error (s);
427 if (first_iter_->ok ())
429 first_iter_->process (m);
430 if (first_iter_->try_music_in_children (busy_playing_event))
431 last_playing_ = SOLO1;
434 if (second_iter_->ok ())
436 second_iter_->process (m);
437 if (first_iter_->try_music_in_children (busy_playing_event))
438 last_playing_ = SOLO2;
443 Part_combine_iterator::try_music_in_children (Music *m) const
445 Music_iterator * i = first_iter_->try_music (m);
449 return second_iter_->try_music (m);
452 IMPLEMENT_CTOR_CALLBACK (Part_combine_iterator);