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 ()
27 Part_combine_music_iterator::~Part_combine_music_iterator ()
29 delete second_iter_p_;
34 Part_combine_music_iterator::next_moment () const
36 Moment first_next = infinity_mom;
37 if (first_iter_p_->ok ())
38 first_next = first_iter_p_->next_moment ();
39 Moment second_next = infinity_mom;
40 if (second_iter_p_->ok ())
41 second_next = second_iter_p_->next_moment ();
42 if (first_next == infinity_mom && second_next == infinity_mom)
44 return first_next <? second_next;
48 Part_combine_music_iterator::ok () const
51 return first_iter_p_->ok () || second_iter_p_->ok ();
55 Part_combine_music_iterator::do_print () const
57 first_iter_p_->print ();
58 second_iter_p_->print ();
62 Part_combine_music_iterator::construct_children ()
64 Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
66 first_iter_p_ = get_iterator_p (m->first_l ());
67 second_iter_p_ = get_iterator_p (m->second_l ());
71 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
74 Translator_group * current = it->report_to_l ();
75 Translator_group * last = 0;
78 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
80 TODO: abstract this function
83 /* find the type of translator that we're changing.
85 If \translator Staff = bass, then look for Staff = *
87 while (current && current->type_str_ != to_type)
90 current = current->daddy_trans_l_;
93 if (current && current->id_str_ == to_id)
96 msg += _ ("Can't switch translators, I'm there already");
102 Translator_group * dest =
103 it->report_to_l ()->find_create_translator_l (to_type, to_id);
104 current->remove_translator_p (last);
105 dest->add_group_translator (last);
110 We could change the current translator's id, but that would make
113 last->translator_id_str_ = change_l ()->change_to_id_str_;
115 error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
118 error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
122 Pitch_interrogate_req* first_spanish_inquisition; // nobody expects it
123 Pitch_interrogate_req* second_spanish_inquisition; // won't strike twice
125 Rhythm_interrogate_req* first_rhythmic_inquisition;
126 Rhythm_interrogate_req* second_rhythmic_inquisition;
129 Part_combine_music_iterator::do_process_and_next (Moment m)
131 Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
133 now_ = next_moment ();
136 Hmm, shouldn't we check per iterator if next_moment < m?
138 if (first_iter_p_->ok ())
139 first_iter_p_->process_and_next (m);
141 if (second_iter_p_->ok ())
142 second_iter_p_->process_and_next (m);
144 Music_iterator::do_process_and_next (m);
149 * Maybe we need a Skip_engraver?
151 (check): can this all be handled now?
153 Maybe different modes exist?
155 * Wind instruments (Flute I/II)
159 Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
161 1. if S and A differ by less than a third, the stems should be up/down.
162 2. else if S and A have different values, the stems should be up/down.
163 3. else if A sings "la" or higher, both S and A stems should be down.
164 4. else both stems should be up
166 * This may get really tricky: combining voices/staffs: string instruments
170 if (!first_spanish_inquisition)
171 first_spanish_inquisition = new Pitch_interrogate_req;
172 first_iter_p_->try_music (first_spanish_inquisition);
174 if (!second_spanish_inquisition)
175 second_spanish_inquisition = new Pitch_interrogate_req;
176 second_iter_p_->try_music (second_spanish_inquisition);
178 Array<Musical_pitch>* first_pitches = &first_spanish_inquisition->pitch_arr_;
179 Array<Musical_pitch>* second_pitches = &second_spanish_inquisition->pitch_arr_;
181 if (!first_rhythmic_inquisition)
182 first_rhythmic_inquisition = new Rhythm_interrogate_req;
183 first_iter_p_->try_music (first_rhythmic_inquisition);
185 if (!second_rhythmic_inquisition)
186 second_rhythmic_inquisition = new Rhythm_interrogate_req;
187 second_iter_p_->try_music (second_rhythmic_inquisition);
189 Array<Duration>* first_durations = &first_rhythmic_inquisition->duration_arr_;
190 Array<Duration>* second_durations = &second_rhythmic_inquisition->duration_arr_;
192 SCM interval = SCM_BOOL_F;
193 if (first_pitches->size () && second_pitches->size ())
195 first_pitches->sort (Musical_pitch::compare);
196 second_pitches->sort (Musical_pitch::compare);
197 interval = gh_int2scm (first_pitches->top ().steps ()
198 - (*second_pitches)[0].steps ());
200 if (first_durations->size ())
202 first_durations->sort (Duration::compare);
203 Moment new_until = now_ + first_durations->top ().length_mom ();
204 if (new_until > first_until_)
205 first_until_ = new_until;
208 if (second_durations->size ())
210 second_durations->sort (Duration::compare);
211 Moment new_until = now_ + second_durations->top ().length_mom ();
212 if (new_until > second_until_)
213 second_until_ = new_until;
216 Translator_group * fir = first_iter_p_->report_to_l ();
217 Translator_group * sir = second_iter_p_->report_to_l ();
219 bool solo_b = (first_pitches->empty () != second_pitches->empty ())
220 && !(first_until_ > now_ && second_until_ > now_);
222 bool unirhythm_b = !solo_b && !compare (first_durations, second_durations);
223 bool unison_b = unirhythm_b && !first_pitches->empty ()
224 &&!compare (first_pitches, second_pitches);
225 bool unisilence_b = unirhythm_b && first_pitches->empty ();
227 Translator_group * fd = fir->find_create_translator_l (p->what_str_, "one");
228 Translator_group * sd = sir->find_create_translator_l (p->what_str_, "two");
230 bool split_interval_b = false;
231 if (gh_number_p (interval))
233 SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
234 int i = gh_scm2int (interval);
236 && gh_number_p (gh_car (s))
237 && gh_number_p (gh_cdr (s))
238 && i >= gh_scm2int (gh_car (s))
239 && i <= gh_scm2int (gh_cdr (s)))
240 split_interval_b = true;
244 Hmm, maybe we should set/check combined_b_ against
246 first_iter_p_->report_to_l () == second_iter_p_->report_to_l ()
251 String to_id = combined_b_ ? "one" : "two";
252 if ((!unirhythm_b && combined_b_)
253 || (split_interval_b && combined_b_)
254 || (solo_b && combined_b_)
255 /*|| (unisilence_b && combined_b_) */
256 || ((unirhythm_b || unison_b || unisilence_b)
257 && !combined_b_ && !split_interval_b && !solo_b))
259 combined_b_ = !combined_b_;
260 to_id = combined_b_ ? "one" : "two";
261 change_to (second_iter_p_, p->what_str_, to_id);
265 sir = second_iter_p_->report_to_l ();
267 SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
268 fd->set_property ("unirhythm", b);
269 sd->set_property ("unirhythm", b);
271 b = split_interval_b ? SCM_BOOL_T : SCM_BOOL_F;
272 fd->set_property ("split-interval", b);
273 sd->set_property ("split-interval", b);
275 b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
276 fd->set_property ("unisilence", b);
277 sd->set_property ("unisilence", b);
279 b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
280 fd->set_property ("unison", b);
281 sd->set_property ("unison", b);
283 b = solo_b ? SCM_BOOL_T : SCM_BOOL_F;
284 if (first_pitches->size ())
286 fd->set_property ("solo", b);
287 sd->set_property ("solo", SCM_BOOL_F);
290 if (second_pitches->size ())
292 fd->set_property ("solo", SCM_BOOL_F);
293 sd->set_property ("solo", b);
296 first_pitches->clear ();
297 second_pitches->clear ();
298 first_durations->clear ();
299 second_durations->clear ();
303 Part_combine_music_iterator::do_process_and_next (Moment m)
305 Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
310 // now_ = next_moment ();
315 * Maybe we need a Skip_engraver?
317 (check): can this all be handled now?
319 Maybe different modes exist?
321 * Wind instruments (Flute I/II)
325 Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
327 1. if S and A differ by less than a third, the stems should be up/down.
328 2. else if S and A have different values, the stems should be up/down.
329 3. else if A sings "la" or higher, both S and A stems should be down.
330 4. else both stems should be up
332 * This may get really tricky: combining voices/staffs: string instruments
339 if (first_iter_p_->ok ())
340 first_music = first_iter_p_->get_music ();
342 if (second_iter_p_->ok ())
343 second_music = second_iter_p_->get_music ();
346 Array<Musical_pitch> first_pitches;
347 Array<Duration> first_durations;
348 if (Music_sequence* m = dynamic_cast<Music_sequence *> (first_music))
350 for (SCM s = m->music_list (); gh_pair_p (s); s = gh_cdr (s))
352 Music *u = unsmob_music (gh_car (s));
353 if (Melodic_req *r = dynamic_cast<Melodic_req *> (u))
354 first_pitches.push (r->pitch_);
355 if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (u))
356 first_durations.push (r->duration_);
360 Array<Musical_pitch> second_pitches;
361 Array<Duration> second_durations;
362 if (Music_sequence* m = dynamic_cast<Music_sequence *> (second_music))
364 for (SCM s = m->music_list (); gh_pair_p (s); s = gh_cdr (s))
366 Music *u = unsmob_music (gh_car (s));
367 if (Melodic_req *r = dynamic_cast<Melodic_req *> (u))
368 second_pitches.push (r->pitch_);
369 if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (u))
370 second_durations.push (r->duration_);
374 SCM interval = SCM_BOOL_F;
375 if (first_pitches.size () && second_pitches.size ())
377 first_pitches.sort (Musical_pitch::compare);
378 second_pitches.sort (Musical_pitch::compare);
379 interval = gh_int2scm (first_pitches.top ().steps ()
380 - second_pitches[0].steps ());
382 if (first_durations.size ())
384 first_durations.sort (Duration::compare);
385 Moment new_until = now_ + first_durations.top ().length_mom ();
386 if (new_until > first_until_)
387 first_until_ = new_until;
390 if (second_durations.size ())
392 second_durations.sort (Duration::compare);
393 Moment new_until = now_ + second_durations.top ().length_mom ();
394 if (new_until > second_until_)
395 second_until_ = new_until;
398 Translator_group * fir = first_iter_p_->report_to_l ();
399 Translator_group * sir = second_iter_p_->report_to_l ();
401 bool solo_b = (first_pitches.empty () != second_pitches.empty ())
402 && !(first_until_ > now_ && second_until_ > now_);
404 bool unirhythm_b = !solo_b && !compare (&first_durations, &second_durations);
405 bool unison_b = unirhythm_b && !first_pitches.empty ()
406 &&!compare (&first_pitches, &second_pitches);
407 bool unisilence_b = unirhythm_b && first_pitches.empty ();
409 Translator_group * fd = fir->find_create_translator_l (p->what_str_, "one");
410 Translator_group * sd = sir->find_create_translator_l (p->what_str_, "two");
412 bool split_interval_b = false;
413 if (gh_number_p (interval))
415 SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
416 int i = gh_scm2int (interval);
418 && gh_number_p (gh_car (s))
419 && gh_number_p (gh_cdr (s))
420 && i >= gh_scm2int (gh_car (s))
421 && i <= gh_scm2int (gh_cdr (s)))
422 split_interval_b = true;
428 combined_b_ = first_iter_p_->report_to_l ()->daddy_trans_l_
429 == second_iter_p_->report_to_l ()->daddy_trans_l_;
431 String to_id = combined_b_ ? "one" : "two";
432 if ((!unirhythm_b && combined_b_)
433 || (split_interval_b && combined_b_)
434 || (solo_b && combined_b_)
435 /*|| (unisilence_b && combined_b_) */
436 || ((unirhythm_b || unison_b || unisilence_b)
437 && !combined_b_ && !split_interval_b && !solo_b))
439 combined_b_ = !combined_b_;
440 to_id = combined_b_ ? "one" : "two";
441 change_to (second_iter_p_, p->what_str_, to_id);
445 sir = second_iter_p_->report_to_l ();
447 SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
448 fd->set_property ("unirhythm", b);
449 sd->set_property ("unirhythm", b);
451 b = split_interval_b ? SCM_BOOL_T : SCM_BOOL_F;
452 fd->set_property ("split-interval", b);
453 sd->set_property ("split-interval", b);
455 b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
456 fd->set_property ("unisilence", b);
457 sd->set_property ("unisilence", b);
459 b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
460 fd->set_property ("unison", b);
461 sd->set_property ("unison", b);
463 b = solo_b ? SCM_BOOL_T : SCM_BOOL_F;
464 if (first_pitches.size ())
466 fd->set_property ("solo", b);
467 sd->set_property ("solo", SCM_BOOL_F);
470 if (second_pitches.size ())
472 fd->set_property ("solo", SCM_BOOL_F);
473 sd->set_property ("solo", b);
477 Hmm, shouldn't we check per iterator if next_moment < m?
479 if (first_iter_p_->ok ())
480 first_iter_p_->process_and_next (m);
482 if (second_iter_p_->ok ())
483 second_iter_p_->process_and_next (m);
485 Music_iterator::do_process_and_next (m);
486 now_ = next_moment ();
491 Part_combine_music_iterator::try_music_in_children (Music *m) const
493 Music_iterator * i = first_iter_p_->try_music (m);
497 return second_iter_p_->try_music (m);