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