]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
patch::: 1.3.86.jcn1
[lilypond.git] / lily / part-combine-music-iterator.cc
1 /*   
2   part-combine-music-iterator.cc -- implement  Part_combine_music_iterator
3
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 2000 Jan Nieuwenhuizen <janneke@gnu.org>
7  */
8
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"
14 #include "warn.hh"
15
16 Part_combine_music_iterator::Part_combine_music_iterator ()
17 {
18   first_iter_p_ = 0;
19   second_iter_p_ = 0;
20   first_until_ = 0;
21   second_until_ = 0;
22 }
23
24 Part_combine_music_iterator::~Part_combine_music_iterator ()
25 {
26   delete second_iter_p_;
27   delete first_iter_p_;
28 }
29
30 Moment
31 Part_combine_music_iterator::next_moment () const
32 {
33   Moment first_next = infinity_mom;
34   if (first_iter_p_->ok ())
35     first_next = first_iter_p_->next_moment ();
36   Moment second_next = infinity_mom;
37   if (second_iter_p_->ok ())
38     second_next = second_iter_p_->next_moment ();
39   if (first_next == infinity_mom && second_next == infinity_mom)
40     return 0;
41   return first_next <? second_next;
42 }
43
44 bool
45 Part_combine_music_iterator::ok () const
46 {
47   //hmm
48   return first_iter_p_->ok () || second_iter_p_->ok ();
49 }
50
51 void
52 Part_combine_music_iterator::do_print () const
53 {
54   first_iter_p_->print ();
55   second_iter_p_->print ();
56 }
57
58 void
59 Part_combine_music_iterator::construct_children ()
60 {
61   Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
62   
63   first_iter_p_ = get_iterator_p (m->first_l ());
64   second_iter_p_ = get_iterator_p (m->second_l ());
65 }
66
67 void
68 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
69                                         String to_id)
70 {
71   Translator_group * current = it->report_to_l ();
72   Translator_group * last = 0;
73
74   /*
75     Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
76
77     TODO: abstract this function 
78    */
79   
80   /* find the type  of translator that we're changing.
81      
82      If \translator Staff = bass, then look for Staff = *
83    */
84   while  (current && current->type_str_ != to_type)
85     {
86       last = current;
87       current = current->daddy_trans_l_;
88     }
89
90   if (current && current->id_str_ == to_id)
91     {
92       String msg;
93       msg += _ ("Can't switch translators, I'm there already");
94     }
95   
96   if (current) 
97     if (last)
98       {
99         Translator_group * dest = 
100           it->report_to_l ()->find_create_translator_l (to_type, to_id);
101         current->remove_translator_p (last);
102         dest->add_group_translator (last);
103       }
104     else
105       {
106         /*
107           We could change the current translator's id, but that would make 
108           errors hard to catch
109           
110            last->translator_id_str_  = change_l ()->change_to_id_str_;
111         */
112         error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
113       }
114   else
115     error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
116 }
117
118 void
119 Part_combine_music_iterator::do_process_and_next (Moment m)
120 {
121   Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
122
123   Moment now = next_moment ();
124
125   Array<Musical_pitch> first_pitches;
126   Array<Duration> first_durations;
127   if (first_iter_p_->ok ())
128     {
129       Music_iterator* i = first_iter_p_->clone ();
130       Moment until = i->next_moment ();
131
132       /* Urg, silly first_b_ stuff */
133       if (now && i->next ())
134         until = i->next_moment ();
135
136       /* How about a 'now_moment ()' for iterators? */
137       for (; i->ok () && i->next_moment () == until; i->next ())
138         {
139           if (Music_sequence* m = dynamic_cast<Music_sequence *> (i->get_music ()))
140             {
141               for (SCM s = m->music_list (); gh_pair_p (s);  s = gh_cdr (s))
142                 {
143                   Music *u = unsmob_music (gh_car (s));
144                   if (Melodic_req *r = dynamic_cast<Melodic_req *> (u))
145                     first_pitches.push (r->pitch_);
146                   if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (u))
147                     first_durations.push (r->duration_);
148                 }
149             }
150         }
151     }
152
153   Array<Musical_pitch> second_pitches;
154   Array<Duration> second_durations;
155   if (second_iter_p_->ok ())
156     {
157       Music_iterator* i = second_iter_p_->clone ();
158       Moment until = i->next_moment ();
159
160       /* Urg, silly second_b_ stuff */
161       if (now && i->next ())
162         until = i->next_moment ();
163
164       /* How about a 'now_moment ()' for iterators? */
165       for (; i->ok () && i->next_moment () == until; i->next ())
166         {
167           if (Music_sequence* m = dynamic_cast<Music_sequence *> (i->get_music ()))
168             {
169               for (SCM s = m->music_list (); gh_pair_p (s);  s = gh_cdr (s))
170                 {
171                   Music *u = unsmob_music (gh_car (s));
172                   if (Melodic_req *r = dynamic_cast<Melodic_req *> (u))
173                     second_pitches.push (r->pitch_);
174                   if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (u))
175                     second_durations.push (r->duration_);
176                 }
177             }
178         }
179     }
180   
181   SCM interval = SCM_BOOL_F;
182   if (first_pitches.size () && second_pitches.size ())
183     {
184       first_pitches.sort (Musical_pitch::compare);
185       second_pitches.sort (Musical_pitch::compare);
186       interval = gh_int2scm (first_pitches.top ().steps ()
187                              - second_pitches[0].steps ());
188     }
189   if (first_durations.size ())
190     {
191       first_durations.sort (Duration::compare);
192       Moment new_until = now + first_durations.top ().length_mom ();
193       if (new_until > first_until_)
194         first_until_ = new_until;
195     }
196
197     if (second_durations.size ())
198     {
199       second_durations.sort (Duration::compare);
200       Moment new_until = now + second_durations.top ().length_mom ();
201       if (new_until > second_until_)
202         second_until_ = new_until;
203     }
204
205 #if 0 /* DEBUG */
206   printf ("now: %s\n", now.str ().ch_C ());
207   printf ("first: ");
208   for (int i = 0; i < first_pitches.size (); i++)
209     {
210       printf ("%s, ", first_pitches[i].str ().ch_C ());
211     }
212   printf ("\nsecond: ");
213   for (int i = 0; i < second_pitches.size (); i++)
214     {
215       printf ("%s, ", second_pitches[i].str ().ch_C ());
216     }
217   printf ("\n");
218 #endif
219
220   Translator_group * fir = first_iter_p_->report_to_l ();
221   Translator_group * sir = second_iter_p_->report_to_l ();
222
223   bool solo_b = (first_pitches.empty () != second_pitches.empty ())
224     && !(first_until_ > now && second_until_ > now);
225
226   bool unirhythm_b = !solo_b && !compare (&first_durations, &second_durations);
227   bool unison_b = unirhythm_b && !first_pitches.empty ()
228     &&!compare (&first_pitches, &second_pitches);
229   bool unisilence_b = unirhythm_b && first_pitches.empty ();
230
231   Translator_group * fd = fir->find_create_translator_l (p->what_str_, "one");
232   Translator_group * sd = sir->find_create_translator_l (p->what_str_, "two");
233
234   bool split_interval_b = false;
235   if (gh_number_p (interval))
236     {
237       SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
238       int i = gh_scm2int (interval);
239       if (gh_pair_p (s)
240           && gh_number_p (gh_car (s))
241           && gh_number_p (gh_cdr (s))
242           && i >= gh_scm2int (gh_car (s))
243           && i <= gh_scm2int (gh_cdr (s)))
244         split_interval_b = true;
245     }
246
247   bool combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
248     == second_iter_p_->report_to_l ()->daddy_trans_l_;
249
250   String to_id =  combined_b ? "one" : "two";
251   if ((!unirhythm_b && combined_b)
252       || (split_interval_b && combined_b)
253       || (solo_b && combined_b)
254       /*|| (unisilence_b && combined_b) */
255       || ((unirhythm_b || unison_b || unisilence_b)
256           && !combined_b && !split_interval_b && !solo_b))
257     {
258       combined_b = !combined_b;
259       to_id =  combined_b ? "one" : "two";
260       change_to (second_iter_p_, p->what_str_, to_id);
261     }
262
263   if (!combined_b)
264     sir = second_iter_p_->report_to_l ();
265
266   SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
267   fd->set_property ("unirhythm", b);
268   sd->set_property ("unirhythm", b);
269
270   b = split_interval_b ? SCM_BOOL_T : SCM_BOOL_F;
271   fd->set_property ("split-interval", b);
272   sd->set_property ("split-interval",  b);
273
274   b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
275   fd->set_property ("unisilence", b);
276   sd->set_property ("unisilence", b);
277
278   b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
279   fd->set_property ("unison", b);
280   sd->set_property ("unison", b);
281
282   b = solo_b  ? SCM_BOOL_T : SCM_BOOL_F;
283   if (first_pitches.size ())
284     {
285       fd->set_property ("solo", b);
286       sd->set_property ("solo", SCM_BOOL_F);
287     }
288
289   if (second_pitches.size ())
290     {
291       fd->set_property ("solo", SCM_BOOL_F);
292       sd->set_property ("solo", b);
293     }
294
295   /*
296     Hmm, shouldn't we check per iterator if next_moment < m?
297   */
298   if (first_iter_p_->ok ())
299     first_iter_p_->process_and_next (m);
300   
301   if (second_iter_p_->ok ())
302     second_iter_p_->process_and_next (m);
303
304   Music_iterator::do_process_and_next (m);
305 }
306
307 Music_iterator*
308 Part_combine_music_iterator::try_music_in_children (Music *m) const
309 {
310   Music_iterator * i =  first_iter_p_->try_music (m);
311   if (i)
312     return i;
313   else
314     return second_iter_p_->try_music (m);
315 }
316