]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
release: 1.3.82
[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 "warn.hh"
14
15 Part_combine_music_iterator::Part_combine_music_iterator ()
16 {
17   combined_b_ = true;
18
19   now_ = 0;
20   first_iter_p_ = 0;
21   second_iter_p_ = 0;
22   first_until_ = 0;
23   second_until_ = 0;
24 }
25
26 Part_combine_music_iterator::~Part_combine_music_iterator ()
27 {
28   delete second_iter_p_;
29   delete first_iter_p_;
30 }
31
32 Moment
33 Part_combine_music_iterator::next_moment () const
34 {
35   Moment first_next = infinity_mom;
36   if (first_iter_p_->ok ())
37     first_next = first_iter_p_->next_moment ();
38   Moment second_next = infinity_mom;
39   if (second_iter_p_->ok ())
40     second_next = second_iter_p_->next_moment ();
41   if (first_next == infinity_mom && second_next == infinity_mom)
42     return 0;
43   return first_next <? second_next;
44 }
45
46 bool
47 Part_combine_music_iterator::ok () const
48 {
49   //hmm
50   return first_iter_p_->ok () || second_iter_p_->ok ();
51 }
52
53 void
54 Part_combine_music_iterator::do_print () const
55 {
56   first_iter_p_->print ();
57   second_iter_p_->print ();
58 }
59
60 void
61 Part_combine_music_iterator::construct_children ()
62 {
63   Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
64   
65   first_iter_p_ = get_iterator_p (m->first_l ());
66   second_iter_p_ = get_iterator_p (m->second_l ());
67 }
68
69 void
70 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
71                                         String to_id)
72 {
73   Translator_group * current = it->report_to_l ();
74   Translator_group * last = 0;
75
76   /*
77     Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
78
79     TODO: abstract this function 
80    */
81   
82   /* find the type  of translator that we're changing.
83      
84      If \translator Staff = bass, then look for Staff = *
85    */
86   while  (current && current->type_str_ != to_type)
87     {
88       last = current;
89       current = current->daddy_trans_l_;
90     }
91
92   if (current && current->id_str_ == to_id)
93     {
94       String msg;
95       msg += _ ("Can't switch translators, I'm there already");
96     }
97   
98   if (current) 
99     if (last)
100       {
101         Translator_group * dest = 
102           it->report_to_l ()->find_create_translator_l (to_type, to_id);
103         current->remove_translator_p (last);
104         dest->add_group_translator (last);
105       }
106     else
107       {
108         /*
109           We could change the current translator's id, but that would make 
110           errors hard to catch
111           
112            last->translator_id_str_  = change_l ()->change_to_id_str_;
113         */
114         error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
115       }
116   else
117     error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
118 }
119
120 Pitch_interrogate_req* first_spanish_inquisition; // nobody expects it
121 Pitch_interrogate_req* second_spanish_inquisition; // won't strike twice
122
123 Rhythm_interrogate_req* first_rhythmic_inquisition;
124 Rhythm_interrogate_req* second_rhythmic_inquisition;
125
126 void
127 Part_combine_music_iterator::do_process_and_next (Moment m)
128 {
129   Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
130
131   now_ = next_moment ();
132
133   /*
134     Hmm, shouldn't we check per iterator if next_moment < m?
135    */
136   if (first_iter_p_->ok ())
137     first_iter_p_->process_and_next (m);
138   
139   if (second_iter_p_->ok ())
140     second_iter_p_->process_and_next (m);
141
142   Music_iterator::do_process_and_next (m);
143
144   /*
145     TODO:
146
147     * Maybe we need a Skip_engraver?
148
149     (check): can this all be handled now?
150     
151     Maybe different modes exist?
152
153     * Wind instruments (Flute I/II)
154     * Hymnals:  
155
156
157       Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
158
159       1. if S and A differ by less than a third, the stems should be up/down.
160       2. else if S and A have different values, the stems should be up/down.
161       3. else if A sings "la" or higher, both S and A stems should be down.
162       4. else both stems should be up
163
164     * This may get really tricky: combining voices/staffs: string instruments
165
166    */
167   
168   if (!first_spanish_inquisition)
169     first_spanish_inquisition = new Pitch_interrogate_req;
170   first_iter_p_->try_music (first_spanish_inquisition);
171   
172   if (!second_spanish_inquisition)
173     second_spanish_inquisition = new Pitch_interrogate_req;
174   second_iter_p_->try_music (second_spanish_inquisition);
175
176   Array<Musical_pitch>* first_pitches = &first_spanish_inquisition->pitch_arr_;
177   Array<Musical_pitch>* second_pitches = &second_spanish_inquisition->pitch_arr_;
178
179   if (!first_rhythmic_inquisition)
180     first_rhythmic_inquisition = new Rhythm_interrogate_req;
181   first_iter_p_->try_music (first_rhythmic_inquisition);
182
183   if (!second_rhythmic_inquisition)
184     second_rhythmic_inquisition = new Rhythm_interrogate_req;
185   second_iter_p_->try_music (second_rhythmic_inquisition);
186
187   Array<Duration>* first_durations = &first_rhythmic_inquisition->duration_arr_;
188   Array<Duration>* second_durations = &second_rhythmic_inquisition->duration_arr_;
189
190   SCM interval = SCM_BOOL_F;
191   if (first_pitches->size () && second_pitches->size ())
192     {
193       first_pitches->sort (Musical_pitch::compare);
194       second_pitches->sort (Musical_pitch::compare);
195       interval = gh_int2scm (first_pitches->top ().steps ()
196                              - (*second_pitches)[0].steps ());
197     }
198   if (first_durations->size ())
199     {
200       first_durations->sort (Duration::compare);
201       Moment new_until = now_ + first_durations->top ().length_mom ();
202       if (new_until > first_until_)
203         first_until_ = new_until;
204     }
205
206     if (second_durations->size ())
207     {
208       second_durations->sort (Duration::compare);
209       Moment new_until = now_ + second_durations->top ().length_mom ();
210       if (new_until > second_until_)
211         second_until_ = new_until;
212     }
213
214   Translator_group * fir = first_iter_p_->report_to_l ();
215   Translator_group * sir = second_iter_p_->report_to_l ();
216
217   bool solo_b = (first_pitches->empty () != second_pitches->empty ())
218     && !(first_until_ > now_ && second_until_ > now_);
219
220   bool unirhythm_b = !solo_b && !compare (first_durations, second_durations);
221   bool unison_b = unirhythm_b && !first_pitches->empty ()
222     &&!compare (first_pitches, second_pitches);
223   bool unisilence_b = unirhythm_b && first_pitches->empty ();
224
225   Translator_group * fd = fir->find_create_translator_l (p->what_str_, "one");
226   Translator_group * sd = sir->find_create_translator_l (p->what_str_, "two");
227
228   bool split_interval_b = false;
229   if (gh_number_p (interval))
230     {
231       SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
232       int i = gh_scm2int (interval);
233       if (gh_pair_p (s)
234           && gh_number_p (gh_car (s))
235           && gh_number_p (gh_cdr (s))
236           && i >= gh_scm2int (gh_car (s))
237           && i <= gh_scm2int (gh_cdr (s)))
238         split_interval_b = true;
239     }
240
241   /*
242     Hmm, maybe we should set/check combined_b_ against
243
244        first_iter_p_->report_to_l () == second_iter_p_->report_to_l ()
245
246    ? 
247    */
248
249   String to_id =  combined_b_ ? "one" : "two";
250   if ((!unirhythm_b && combined_b_)
251       || (split_interval_b && combined_b_)
252       || (solo_b && combined_b_)
253       /*|| (unisilence_b && combined_b_) */
254       || ((unirhythm_b || unison_b || unisilence_b)
255           && !combined_b_ && !split_interval_b && !solo_b))
256     {
257       combined_b_ = !combined_b_;
258       to_id =  combined_b_ ? "one" : "two";
259       change_to (second_iter_p_, p->what_str_, to_id);
260     }
261
262   if (!combined_b_)
263     sir = second_iter_p_->report_to_l ();
264
265   SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
266   fd->set_property ("unirhythm", b);
267   sd->set_property ("unirhythm", b);
268
269   b = split_interval_b ? SCM_BOOL_T : SCM_BOOL_F;
270   fd->set_property ("split-interval", b);
271   sd->set_property ("split-interval",  b);
272
273   b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
274   fd->set_property ("unisilence", b);
275   sd->set_property ("unisilence", b);
276
277   b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
278   fd->set_property ("unison", b);
279   sd->set_property ("unison", b);
280
281   b = solo_b  ? SCM_BOOL_T : SCM_BOOL_F;
282   if (first_pitches->size ())
283     {
284       fd->set_property ("solo", b);
285       sd->set_property ("solo", SCM_BOOL_F);
286     }
287
288   if (second_pitches->size ())
289     {
290       fd->set_property ("solo", SCM_BOOL_F);
291       sd->set_property ("solo", b);
292     }
293
294   first_pitches->clear ();
295   second_pitches->clear ();
296   first_durations->clear ();
297   second_durations->clear ();
298 }
299
300 Music_iterator*
301 Part_combine_music_iterator::try_music_in_children (Music *m) const
302 {
303   Music_iterator * i =  first_iter_p_->try_music (m);
304   if (i)
305     return i;
306   else
307     return second_iter_p_->try_music (m);
308 }
309