2 part-combine-music-iterator.cc -- implement Part_combine_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "part-combine-music.hh"
10 #include "part-combine-music-iterator.hh"
11 #include "translator-group.hh"
12 #include "musical-request.hh"
13 #include "music-sequence.hh"
16 Part_combine_music_iterator::Part_combine_music_iterator ()
24 Part_combine_music_iterator::~Part_combine_music_iterator ()
26 delete second_iter_p_;
31 Part_combine_music_iterator::pending_moment () const
35 if (first_iter_p_->ok ())
36 p = p <? first_iter_p_->pending_moment ();
38 if (second_iter_p_->ok ())
39 p = p <? second_iter_p_->pending_moment ();
44 Part_combine_music_iterator::ok () const
46 return first_iter_p_->ok () || second_iter_p_->ok ();
50 Part_combine_music_iterator::construct_children ()
52 Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
54 first_iter_p_ = get_iterator_p (m->first_l ());
55 second_iter_p_ = get_iterator_p (m->second_l ());
59 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
62 Translator_group * current = it->report_to_l ();
63 Translator_group * last = 0;
66 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
68 TODO: abstract this function
71 /* find the type of translator that we're changing.
73 If \translator Staff = bass, then look for Staff = *
75 while (current && current->type_str_ != to_type)
78 current = current->daddy_trans_l_;
81 if (current && current->id_str_ == to_id)
84 msg += _ ("Can't switch translators, I'm there already");
90 Translator_group * dest =
91 it->report_to_l ()->find_create_translator_l (to_type, to_id);
92 current->remove_translator_p (last);
93 dest->add_group_translator (last);
98 We could change the current translator's id, but that would make
101 last->translator_id_str_ = change_l ()->change_to_id_str_;
103 error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
106 error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
111 get_music_info (Moment m, Music_iterator* iter, Array<Musical_pitch> *pitches, Array<Duration> *durations)
115 for (SCM i = iter->get_music (m); gh_pair_p (i); i = gh_cdr (i))
117 Music *m = unsmob_music (gh_car (i));
118 if (Melodic_req *r = dynamic_cast<Melodic_req *> (m))
119 pitches->push (r->pitch_);
120 if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (m))
121 durations->push (r->duration_);
127 Part_combine_music_iterator::get_state (Moment)
130 Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l_);
132 String w = ly_scm2string (p->get_mus_property ("what"));
135 Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (w, "one" + suffix_);
137 SCM s = first_translator->get_property (ly_symbol2scm ("changeMoment"));
141 Moment change_mom = *unsmob_moment (gh_car (s));
142 Moment diff_mom = *unsmob_moment (gh_cdr (s));
144 Moment now = pending_moment ();
146 if (!now.mod_rat (change_mom))
148 SCM interval = SCM_BOOL_F;
149 if (first_until_ < now)
151 if (second_until_ < now)
154 Moment first_mom = first_until_;
155 Moment second_mom = second_until_;
156 Moment diff_until = diff_mom + now;
159 Music_iterator *first_iter = first_iter_p_->clone ();
160 Music_iterator *second_iter = second_iter_p_->clone ();
162 Moment last_pending (-1);
163 Moment pending = now;
164 while (now < diff_until
165 && (first_iter->ok () || second_iter->ok ())
167 // urg, this is a hack, haven't caught this case yet
168 && (pending != last_pending))
170 if (!second_iter->ok ())
171 pending = first_iter->pending_moment ();
172 else if (!first_iter->ok ())
173 pending = second_iter->pending_moment ();
175 pending = first_iter->pending_moment () <? second_iter->pending_moment ();
176 last_pending = pending;
178 Array<Musical_pitch> first_pitches;
179 Array<Duration> first_durations;
180 get_music_info (pending, first_iter, &first_pitches, &first_durations);
182 Array<Musical_pitch> second_pitches;
183 Array<Duration> second_durations;
184 get_music_info (pending, second_iter, &second_pitches, &second_durations);
186 if (first_pitches.size () && second_pitches.size ())
188 first_pitches.sort (Musical_pitch::compare);
189 second_pitches.sort (Musical_pitch::compare);
190 interval = gh_int2scm (first_pitches.top ().steps ()
191 - second_pitches[0].steps ());
193 if (first_durations.size ())
195 first_durations.sort (Duration::compare);
196 first_mom += first_durations.top ().length_mom ();
199 if (second_durations.size ())
201 second_durations.sort (Duration::compare);
202 second_mom += second_durations.top ().length_mom ();
205 if (!first_pitches.empty () && second_pitches.empty ()
206 && !(second_until_ > now))
209 state &= ~UNISILENCE;
210 if (!(state & ~(UNRELATED | SOLO1 | UNISILENCE)))
216 if (first_pitches.empty () && !second_pitches.empty ()
217 && !(first_until_ > now))
220 state &= ~UNISILENCE;
221 if (!(state & ~(UNRELATED | SOLO2 | UNISILENCE)))
227 if (!compare (&first_durations, &second_durations))
229 state &= ~UNISILENCE;
230 if (!(state & ~(UNIRHYTHM | UNISON)))
234 state &= ~(UNIRHYTHM | UNISILENCE);
236 if (!first_pitches.empty ()
237 &&!compare (&first_pitches, &second_pitches))
239 state &= ~UNISILENCE;
240 if (!(state & ~(UNIRHYTHM | UNISON)))
246 if (first_pitches.empty () && second_pitches.empty ())
248 if (!(state & ~(UNIRHYTHM | UNISILENCE)))
254 state &= ~(UNISILENCE);
256 if (gh_number_p (interval))
258 SCM s = first_translator->get_property (ly_symbol2scm ("splitInterval"));
259 int i = gh_scm2int (interval);
261 && gh_number_p (gh_car (s))
262 && gh_number_p (gh_cdr (s))
263 && i >= gh_scm2int (gh_car (s))
264 && i <= gh_scm2int (gh_cdr (s)))
266 if (!(state & ~(SPLIT_INTERVAL | UNIRHYTHM | UNISON)))
267 state |= SPLIT_INTERVAL;
270 state &= ~(SPLIT_INTERVAL);
273 if (first && !first_pitches.empty ())
274 first_until_ = first_mom;
275 if (first && !second_pitches.empty ())
276 second_until_ = second_mom;
279 if (first_iter->ok ())
280 first_iter->skip (pending);
281 if (second_iter->ok ())
282 second_iter->skip (pending);
291 static Span_req* abort_req = NULL;
294 Part_combine_music_iterator::process (Moment m)
299 - Use three named contexts (be it Thread or Voice): one, two, solo.
300 Let user pre-set (pushproperty) stem direction, remove
301 dynamic-engraver, and such.
303 **** Tried this, but won't work:
305 Consider thread switching: threads "one", "two" and "both".
306 User can't pre-set the (most important) stem direction at
310 if (suffix_.empty_b ())
311 suffix_ = first_iter_p_->report_to_l ()->daddy_trans_l_->id_str_.cut_str (3, INT_MAX);
313 int state = get_state (m);
319 Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l_);
322 bool previously_combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
323 == second_iter_p_->report_to_l ()->daddy_trans_l_;
325 bool combine_b = previously_combined_b;
327 if (!(state & UNIRHYTHM)
328 || (state & SPLIT_INTERVAL)
329 || (state & (SOLO1 | SOLO2)))
331 else if (state & (UNIRHYTHM | UNISILENCE))
335 When combining, abort all running spanners
340 abort_req = new Span_req;
341 abort_req->set_mus_property ("span-type", ly_str02scm ("abort"));
344 if (combine_b && combine_b != previously_combined_b)
346 if (second_iter_p_ && second_iter_p_->ok ())
347 second_iter_p_->try_music (abort_req);
349 String w = ly_scm2string (p->get_mus_property ("what"));
350 if (combine_b != previously_combined_b)
351 change_to (second_iter_p_, w, (combine_b ? "one" : "two")
354 Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (w, "one" + suffix_);
355 Translator_group *second_translator = second_iter_p_->report_to_l ()->find_create_translator_l (w, "two" + suffix_);
360 SCM b = (state & UNIRHYTHM) ? SCM_BOOL_T : SCM_BOOL_F;
361 first_translator->set_property ("unirhythm", b);
362 second_translator->set_property ("unirhythm", b);
364 b = (state & SPLIT_INTERVAL) ? SCM_BOOL_T : SCM_BOOL_F;
365 first_translator->set_property ("split-interval", b);
366 second_translator->set_property ("split-interval", b);
368 b = (state & UNISILENCE) ? SCM_BOOL_T : SCM_BOOL_F;
369 first_translator->set_property ("unisilence", b);
370 second_translator->set_property ("unisilence", b);
372 // difference in definition...
373 //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
374 b = ((state & UNISON) && (state & UNIRHYTHM)) ? SCM_BOOL_T : SCM_BOOL_F;
375 first_translator->set_property ("unison", b);
376 second_translator->set_property ("unison", b);
378 SCM b1 = (state & SOLO1) ? SCM_BOOL_T : SCM_BOOL_F;
379 SCM b2 = (state & SOLO2) ? SCM_BOOL_T : SCM_BOOL_F;
380 first_translator->set_property ("solo", b1);
381 second_translator->set_property ("solo", b2);
383 if (first_iter_p_->ok ())
384 first_iter_p_->process (m);
386 if (second_iter_p_->ok ())
387 second_iter_p_->process (m);
391 Part_combine_music_iterator::try_music_in_children (Music *m) const
393 Music_iterator * i = first_iter_p_->try_music (m);
397 return second_iter_p_->try_music (m);
402 Part_combine_music_iterator::get_music (Moment m)const
406 s = gh_append2 (s,first_iter_p_->get_music (m));
408 s = gh_append2 (second_iter_p_->get_music (m),s);