]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
patch::: 1.3.85.jcn3
[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   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_group_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 #if 0
122 Pitch_interrogate_req* first_spanish_inquisition; // nobody expects it
123 Pitch_interrogate_req* second_spanish_inquisition; // won't strike twice
124
125 Rhythm_interrogate_req* first_rhythmic_inquisition;
126 Rhythm_interrogate_req* second_rhythmic_inquisition;
127
128 void
129 Part_combine_music_iterator::do_process_and_next (Moment m)
130 {
131   Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
132
133   now_ = next_moment ();
134
135   /*
136     Hmm, shouldn't we check per iterator if next_moment < m?
137   */
138   if (first_iter_p_->ok ())
139     first_iter_p_->process_and_next (m);
140   
141   if (second_iter_p_->ok ())
142     second_iter_p_->process_and_next (m);
143
144   Music_iterator::do_process_and_next (m);
145
146   /*
147     TODO:
148
149     * Maybe we need a Skip_engraver?
150
151     (check): can this all be handled now?
152     
153     Maybe different modes exist?
154
155     * Wind instruments (Flute I/II)
156     * Hymnals:  
157
158
159     Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
160
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
165
166     * This may get really tricky: combining voices/staffs: string instruments
167
168     */
169   
170   if (!first_spanish_inquisition)
171     first_spanish_inquisition = new Pitch_interrogate_req;
172   first_iter_p_->try_music (first_spanish_inquisition);
173   
174   if (!second_spanish_inquisition)
175     second_spanish_inquisition = new Pitch_interrogate_req;
176   second_iter_p_->try_music (second_spanish_inquisition);
177
178   Array<Musical_pitch>* first_pitches = &first_spanish_inquisition->pitch_arr_;
179   Array<Musical_pitch>* second_pitches = &second_spanish_inquisition->pitch_arr_;
180
181   if (!first_rhythmic_inquisition)
182     first_rhythmic_inquisition = new Rhythm_interrogate_req;
183   first_iter_p_->try_music (first_rhythmic_inquisition);
184
185   if (!second_rhythmic_inquisition)
186     second_rhythmic_inquisition = new Rhythm_interrogate_req;
187   second_iter_p_->try_music (second_rhythmic_inquisition);
188
189   Array<Duration>* first_durations = &first_rhythmic_inquisition->duration_arr_;
190   Array<Duration>* second_durations = &second_rhythmic_inquisition->duration_arr_;
191
192   SCM interval = SCM_BOOL_F;
193   if (first_pitches->size () && second_pitches->size ())
194     {
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 ());
199     }
200   if (first_durations->size ())
201     {
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;
206     }
207
208     if (second_durations->size ())
209     {
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;
214     }
215
216   Translator_group * fir = first_iter_p_->report_to_l ();
217   Translator_group * sir = second_iter_p_->report_to_l ();
218
219   bool solo_b = (first_pitches->empty () != second_pitches->empty ())
220     && !(first_until_ > now_ && second_until_ > now_);
221
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 ();
226
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");
229
230   bool split_interval_b = false;
231   if (gh_number_p (interval))
232     {
233       SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
234       int i = gh_scm2int (interval);
235       if (gh_pair_p (s)
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;
241     }
242
243   /*
244     Hmm, maybe we should set/check combined_b_ against
245
246        first_iter_p_->report_to_l () == second_iter_p_->report_to_l ()
247
248    ? 
249    */
250
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))
258     {
259       combined_b_ = !combined_b_;
260       to_id =  combined_b_ ? "one" : "two";
261       change_to (second_iter_p_, p->what_str_, to_id);
262     }
263
264   if (!combined_b_)
265     sir = second_iter_p_->report_to_l ();
266
267   SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
268   fd->set_property ("unirhythm", b);
269   sd->set_property ("unirhythm", b);
270
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);
274
275   b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
276   fd->set_property ("unisilence", b);
277   sd->set_property ("unisilence", b);
278
279   b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
280   fd->set_property ("unison", b);
281   sd->set_property ("unison", b);
282
283   b = solo_b  ? SCM_BOOL_T : SCM_BOOL_F;
284   if (first_pitches->size ())
285     {
286       fd->set_property ("solo", b);
287       sd->set_property ("solo", SCM_BOOL_F);
288     }
289
290   if (second_pitches->size ())
291     {
292       fd->set_property ("solo", SCM_BOOL_F);
293       sd->set_property ("solo", b);
294     }
295
296   first_pitches->clear ();
297   second_pitches->clear ();
298   first_durations->clear ();
299   second_durations->clear ();
300 }
301 #else
302 void
303 Part_combine_music_iterator::do_process_and_next (Moment m)
304 {
305   Part_combine_music const * p = dynamic_cast<Part_combine_music const* > (music_l_);
306
307   /*
308     Huh?
309    */
310   //  now_ = next_moment ();
311
312   /*
313     TODO:
314
315     * Maybe we need a Skip_engraver?
316
317     (check): can this all be handled now?
318     
319     Maybe different modes exist?
320
321     * Wind instruments (Flute I/II)
322     * Hymnals:  
323
324
325       Rules for Hymnals/SATB (John Henckel <henckel@iname.com>):
326
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
331
332     * This may get really tricky: combining voices/staffs: string instruments
333
334    */
335   
336 #if 1
337   Music *first_music;
338   Music *second_music;
339   if (first_iter_p_->ok ())
340     first_music = first_iter_p_->get_music ();
341   
342   if (second_iter_p_->ok ())
343     second_music = second_iter_p_->get_music ();
344 #endif
345
346   Array<Musical_pitch> first_pitches;
347   Array<Duration> first_durations;
348   if (Music_sequence* m = dynamic_cast<Music_sequence *> (first_music))
349     {
350       for (SCM s = m->music_list (); gh_pair_p (s);  s = gh_cdr (s))
351         {
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_);
357         }
358     }
359
360   Array<Musical_pitch> second_pitches;
361   Array<Duration> second_durations;
362   if (Music_sequence* m = dynamic_cast<Music_sequence *> (second_music))
363     {
364       for (SCM s = m->music_list (); gh_pair_p (s);  s = gh_cdr (s))
365         {
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_);
371         }
372     }
373
374   SCM interval = SCM_BOOL_F;
375   if (first_pitches.size () && second_pitches.size ())
376     {
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 ());
381     }
382   if (first_durations.size ())
383     {
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;
388     }
389
390     if (second_durations.size ())
391     {
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;
396     }
397
398   Translator_group * fir = first_iter_p_->report_to_l ();
399   Translator_group * sir = second_iter_p_->report_to_l ();
400
401   bool solo_b = (first_pitches.empty () != second_pitches.empty ())
402     && !(first_until_ > now_ && second_until_ > now_);
403
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 ();
408
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");
411
412   bool split_interval_b = false;
413   if (gh_number_p (interval))
414     {
415       SCM s = fd->get_property (ly_symbol2scm ("splitInterval"));
416       int i = gh_scm2int (interval);
417       if (gh_pair_p (s)
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;
423     }
424
425   /*
426     URG, dememberme
427    */
428   combined_b_ = first_iter_p_->report_to_l ()->daddy_trans_l_
429     == second_iter_p_->report_to_l ()->daddy_trans_l_;
430
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))
438     {
439       combined_b_ = !combined_b_;
440       to_id =  combined_b_ ? "one" : "two";
441       change_to (second_iter_p_, p->what_str_, to_id);
442     }
443
444   if (!combined_b_)
445     sir = second_iter_p_->report_to_l ();
446
447   SCM b = unirhythm_b ? SCM_BOOL_T : SCM_BOOL_F;
448   fd->set_property ("unirhythm", b);
449   sd->set_property ("unirhythm", b);
450
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);
454
455   b = unisilence_b ? SCM_BOOL_T : SCM_BOOL_F;
456   fd->set_property ("unisilence", b);
457   sd->set_property ("unisilence", b);
458
459   b = unison_b ? SCM_BOOL_T : SCM_BOOL_F;
460   fd->set_property ("unison", b);
461   sd->set_property ("unison", b);
462
463   b = solo_b  ? SCM_BOOL_T : SCM_BOOL_F;
464   if (first_pitches.size ())
465     {
466       fd->set_property ("solo", b);
467       sd->set_property ("solo", SCM_BOOL_F);
468     }
469
470   if (second_pitches.size ())
471     {
472       fd->set_property ("solo", SCM_BOOL_F);
473       sd->set_property ("solo", b);
474     }
475
476   /*
477     Hmm, shouldn't we check per iterator if next_moment < m?
478   */
479   if (first_iter_p_->ok ())
480     first_iter_p_->process_and_next (m);
481   
482   if (second_iter_p_->ok ())
483     second_iter_p_->process_and_next (m);
484
485   Music_iterator::do_process_and_next (m);
486   now_ = next_moment ();
487 }
488 #endif
489
490 Music_iterator*
491 Part_combine_music_iterator::try_music_in_children (Music *m) const
492 {
493   Music_iterator * i =  first_iter_p_->try_music (m);
494   if (i)
495     return i;
496   else
497     return second_iter_p_->try_music (m);
498 }
499