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
47 return first_iter_p_->ok () || second_iter_p_->ok ();
51 Part_combine_music_iterator::construct_children ()
53 Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
55 first_iter_p_ = get_iterator_p (m->first_l ());
56 second_iter_p_ = get_iterator_p (m->second_l ());
60 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
63 Translator_group * current = it->report_to_l ();
64 Translator_group * last = 0;
67 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
69 TODO: abstract this function
72 /* find the type of translator that we're changing.
74 If \translator Staff = bass, then look for Staff = *
76 while (current && current->type_str_ != to_type)
79 current = current->daddy_trans_l_;
82 if (current && current->id_str_ == to_id)
85 msg += _ ("Can't switch translators, I'm there already");
91 Translator_group * dest =
92 it->report_to_l ()->find_create_translator_l (to_type, to_id);
93 current->remove_translator_p (last);
94 dest->add_group_translator (last);
99 We could change the current translator's id, but that would make
102 last->translator_id_str_ = change_l ()->change_to_id_str_;
104 error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
107 error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
111 Part_combine_music_iterator::process (Moment m)
116 - Use three named contexts (be it Thread or Voice): one, two, solo.
117 Let user pre-set (pushproperty) stem direction, remove
118 dynamic-engraver, and such.
119 - staff-combiner must switch only on per-measure basis (maybe even on
120 per-line-basis, but that's not feasible). Maybe set minimum lengths
121 of matching rhythm for combine/split?
124 Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
126 Moment now = pending_moment ();
128 Array<Musical_pitch> first_pitches;
129 Array<Duration> first_durations;
130 if (first_iter_p_->ok ())
132 /* get_music () also performs next, modifying iterator */
133 Music_iterator *mi = first_iter_p_->clone ();
134 for (SCM i = mi->get_music (now); gh_pair_p (i); i = gh_cdr (i))
136 Music *m = unsmob_music (gh_car (i));
137 if (Melodic_req *r = dynamic_cast<Melodic_req *> (m))
138 first_pitches.push (r->pitch_);
139 if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (m))
140 first_durations.push (r->duration_);
145 Array<Musical_pitch> second_pitches;
146 Array<Duration> second_durations;
147 if (second_iter_p_->ok ())
149 Music_iterator *mi = second_iter_p_->clone ();
150 for (SCM i = mi->get_music (now); gh_pair_p (i); i = gh_cdr (i))
152 Music *m = unsmob_music (gh_car (i));
153 if (Melodic_req *r = dynamic_cast<Melodic_req *> (m))
154 second_pitches.push (r->pitch_);
155 if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (m))
156 second_durations.push (r->duration_);
161 SCM interval = SCM_BOOL_F;
162 if (first_pitches.size () && second_pitches.size ())
164 first_pitches.sort (Musical_pitch::compare);
165 second_pitches.sort (Musical_pitch::compare);
166 interval = gh_int2scm (first_pitches.top ().steps ()
167 - second_pitches[0].steps ());
169 if (first_durations.size ())
171 first_durations.sort (Duration::compare);
172 Moment new_until = now + first_durations.top ().length_mom ();
173 if (new_until > first_until_)
174 first_until_ = new_until;
177 if (second_durations.size ())
179 second_durations.sort (Duration::compare);
180 Moment new_until = now + second_durations.top ().length_mom ();
181 if (new_until > second_until_)
182 second_until_ = new_until;
186 printf ("now: %s\n", now.str ().ch_C ());
188 for (int i = 0; i < first_pitches.size (); i++)
190 printf ("%s, ", first_pitches[i].str ().ch_C ());
192 printf ("\nsecond: ");
193 for (int i = 0; i < second_pitches.size (); i++)
195 printf ("%s, ", second_pitches[i].str ().ch_C ());
200 Translator_group * fir = first_iter_p_->report_to_l ();
201 Translator_group * sir = second_iter_p_->report_to_l ();
203 bool solo_b = (first_pitches.empty () != second_pitches.empty ())
204 && !(first_until_ > now && second_until_ > now);
206 bool unirhythm_b = !solo_b && !compare (&first_durations, &second_durations);
207 bool unison_b = unirhythm_b && !first_pitches.empty ()
208 &&!compare (&first_pitches, &second_pitches);
209 bool unisilence_b = unirhythm_b && first_pitches.empty ();
211 Translator_group * fd = fir->find_create_translator_l (p->what_str_, "one");
212 Translator_group * sd = sir->find_create_translator_l (p->what_str_, "two");
214 bool split_interval_b = false;
215 if (gh_number_p (interval))
217 SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
218 int i = gh_scm2int (interval);
220 && gh_number_p (gh_car (s))
221 && gh_number_p (gh_cdr (s))
222 && i >= gh_scm2int (gh_car (s))
223 && i <= gh_scm2int (gh_cdr (s)))
224 split_interval_b = true;
227 bool combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
228 == second_iter_p_->report_to_l ()->daddy_trans_l_;
230 String to_id = combined_b ? "one" : "two";
231 if ((!unirhythm_b && combined_b)
232 || (split_interval_b && combined_b)
233 || (solo_b && combined_b)
234 /*|| (unisilence_b && combined_b) */
235 || ((unirhythm_b || unison_b || unisilence_b)
236 && !combined_b && !split_interval_b && !solo_b))
238 combined_b = !combined_b;
239 to_id = combined_b ? "one" : "two";
240 change_to (second_iter_p_, p->what_str_, to_id);
244 sir = second_iter_p_->report_to_l ();
246 SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
247 fd->set_property ("unirhythm", b);
248 sd->set_property ("unirhythm", b);
250 b = split_interval_b ? SCM_BOOL_T : SCM_BOOL_F;
251 fd->set_property ("split-interval", b);
252 sd->set_property ("split-interval", b);
254 b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
255 fd->set_property ("unisilence", b);
256 sd->set_property ("unisilence", b);
258 b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
259 fd->set_property ("unison", b);
260 sd->set_property ("unison", b);
262 b = solo_b ? SCM_BOOL_T : SCM_BOOL_F;
263 if (first_pitches.size ())
265 fd->set_property ("solo", b);
266 sd->set_property ("solo", SCM_BOOL_F);
269 if (second_pitches.size ())
271 fd->set_property ("solo", SCM_BOOL_F);
272 sd->set_property ("solo", b);
275 if (first_iter_p_->ok ())
276 first_iter_p_->process (m);
278 if (second_iter_p_->ok ())
279 second_iter_p_->process (m);
283 Part_combine_music_iterator::try_music_in_children (Music *m) const
285 Music_iterator * i = first_iter_p_->try_music (m);
289 return second_iter_p_->try_music (m);
294 Part_combine_music_iterator::get_music (Moment m)const
298 s = gh_append2 (s,first_iter_p_->get_music (m));
300 s = gh_append2 (second_iter_p_->get_music (m),s);