]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
patch::: 1.3.88.hwn1.jcn2: 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 "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::pending_moment () const
32 {
33   Moment p;
34   p.set_infinite (1);
35   if (first_iter_p_->ok ())
36     p = p <? first_iter_p_->pending_moment ();
37
38   if (second_iter_p_->ok ())
39     p = p <? second_iter_p_->pending_moment ();
40   return p;
41 }
42
43 bool
44 Part_combine_music_iterator::ok () const
45 {
46   return first_iter_p_->ok () || second_iter_p_->ok ();
47 }
48
49 void
50 Part_combine_music_iterator::construct_children ()
51 {
52   Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l_);
53   
54   first_iter_p_ = get_iterator_p (m->first_l ());
55   second_iter_p_ = get_iterator_p (m->second_l ());
56 }
57
58 void
59 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
60                                         String to_id)
61 {
62   Translator_group * current = it->report_to_l ();
63   Translator_group * last = 0;
64
65   /*
66     Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
67
68     TODO: abstract this function 
69    */
70   
71   /* find the type  of translator that we're changing.
72      
73      If \translator Staff = bass, then look for Staff = *
74    */
75   while  (current && current->type_str_ != to_type)
76     {
77       last = current;
78       current = current->daddy_trans_l_;
79     }
80
81   if (current && current->id_str_ == to_id)
82     {
83       String msg;
84       msg += _ ("Can't switch translators, I'm there already");
85     }
86   
87   if (current) 
88     if (last)
89       {
90         Translator_group * dest = 
91           it->report_to_l ()->find_create_translator_l (to_type, to_id);
92         current->remove_translator_p (last);
93         dest->add_group_translator (last);
94       }
95     else
96       {
97         /*
98           We could change the current translator's id, but that would make 
99           errors hard to catch
100           
101            last->translator_id_str_  = change_l ()->change_to_id_str_;
102         */
103         error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
104       }
105   else
106     error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
107 }
108
109
110 static void
111 get_music_info (Moment m, Music_iterator* iter, Array<Musical_pitch> *pitches, Array<Duration> *durations)
112 {
113   if (iter->ok ())
114     {
115       for (SCM i = iter->get_music (m); gh_pair_p (i); i = gh_cdr (i))
116         {
117           Music *m = unsmob_music (gh_car (i));
118           if (Melodic_req *r = dynamic_cast<Melodic_req *> (m))
119             pitches->push (r->pitch_);
120           if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (m))
121             durations->push (r->duration_);
122         }
123     }
124 }
125   
126 int
127 Part_combine_music_iterator::get_state (Moment)
128 {
129   int state = UNKNOWN;
130   Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l_);
131   Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_, "one");
132
133   SCM s = first_translator->get_property (ly_symbol2scm ("changeMoment"));
134   Moment change_mom = *unsmob_moment (gh_car (s));
135   Moment diff_mom = *unsmob_moment (gh_cdr (s));
136   
137   Moment now = pending_moment ();
138
139   if (!now.mod_rat (change_mom))
140     {
141       SCM interval = SCM_BOOL_F;
142       Moment first_mom = first_until_ - now;
143       Moment second_mom = second_until_ - now;
144
145       bool first = true;
146       Music_iterator *first_iter = first_iter_p_->clone ();
147       Music_iterator *second_iter = second_iter_p_->clone ();
148       while ((first_mom <? second_mom) < diff_mom
149              && (first_iter->ok () || second_iter->ok ()))
150         {
151           Moment m;
152           if (!second_iter->ok ())
153             m = first_iter->pending_moment ();
154           else if (!first_iter->ok ())
155             m = second_iter->pending_moment ();
156           else
157             m = first_iter->pending_moment () <? second_iter->pending_moment ();
158
159           Array<Musical_pitch> first_pitches;
160           Array<Duration> first_durations;
161           get_music_info (m, first_iter, &first_pitches, &first_durations);
162       
163           Array<Musical_pitch> second_pitches;
164           Array<Duration> second_durations;
165           get_music_info (m, second_iter, &second_pitches, &second_durations);
166
167           if (first_pitches.size () && second_pitches.size ())
168             {
169               first_pitches.sort (Musical_pitch::compare);
170               second_pitches.sort (Musical_pitch::compare);
171               interval = gh_int2scm (first_pitches.top ().steps ()
172                                      - second_pitches[0].steps ());
173             }
174           if (first_durations.size ())
175             {
176               first_durations.sort (Duration::compare);
177               first_mom += first_durations.top ().length_mom ();
178               if (first && !first_pitches.empty ())
179                 first_until_ = first_mom + now;
180             }
181
182           if (second_durations.size ())
183             {
184               second_durations.sort (Duration::compare);
185               second_mom += second_durations.top ().length_mom ();
186               if (first && !second_pitches.empty ())
187                 second_until_ = second_mom + now;
188             }
189           first = false;
190
191 #if 0 /* DEBUG */
192           printf ("now: %s\n", now.str ().ch_C ());
193           printf ("first: ");
194           for (int i = 0; i < first_pitches.size (); i++)
195             {
196               printf ("%s, ", first_pitches[i].str ().ch_C ());
197             }
198           printf ("\nsecond: ");
199           for (int i = 0; i < second_pitches.size (); i++)
200             {
201               printf ("%s, ", second_pitches[i].str ().ch_C ());
202             }
203           printf ("\n");
204 #endif
205
206           if (!first_pitches.empty () && second_pitches.empty ()
207               && !(second_until_ > now))
208             {
209               state |= UNRELATED;
210               state &= ~UNISILENCE;
211               if (!(state & ~(UNRELATED | SOLO1 | UNISILENCE)))
212                 state |= SOLO1;
213             }
214           else
215             state &= ~SOLO1;
216
217           if (first_pitches.empty () && !second_pitches.empty ()
218               && !(first_until_ > now))
219             {
220               state |= UNRELATED;
221               state &= ~UNISILENCE;
222               if (!(state & ~(UNRELATED | SOLO2 | UNISILENCE)))
223                 state |= SOLO2;
224             }
225           else
226             state &= ~SOLO2;
227
228           if (!compare (&first_durations, &second_durations))
229             {
230               state &= ~UNISILENCE;
231               if (!(state & ~(UNIRHYTHM | UNISON)))
232                 state |= UNIRHYTHM;
233             }
234           else
235             state &= ~(UNIRHYTHM | UNISILENCE);
236           
237           if (!first_pitches.empty ()
238               &&!compare (&first_pitches, &second_pitches))
239             {
240               state &= ~UNISILENCE;
241               if (!(state & ~(UNIRHYTHM | UNISON)))
242                 state |= UNISON;
243             }
244           else
245             state &= ~(UNISON);
246             
247           if (first_pitches.empty () && second_pitches.empty ())
248             {
249               if (!(state & ~(UNIRHYTHM | UNISILENCE)))
250                 state |= UNISILENCE;
251             }
252           else
253             state &= ~(UNISILENCE);
254
255           if (gh_number_p (interval))
256             {
257               SCM s = first_translator->get_property (ly_symbol2scm ("splitInterval"));
258               int i = gh_scm2int (interval);
259               if (gh_pair_p (s)
260                   && gh_number_p (gh_car (s))
261                   && gh_number_p (gh_cdr (s))
262                   && i >= gh_scm2int (gh_car (s))
263                   && i <= gh_scm2int (gh_cdr (s)))
264                 {
265                   if (!(state & ~(SPLIT_INTERVAL | UNIRHYTHM | UNISON)))
266                     state |= SPLIT_INTERVAL;
267                 }
268               else
269                 state &= ~(SPLIT_INTERVAL);
270             }
271
272 #if 0
273           Moment next = (first_mom <? second_mom) + now;
274           if (first_iter->ok ())
275             first_iter->skip (next);
276           if (second_iter->ok ())
277             second_iter->skip (next);
278 #else
279           if (first_iter->ok ())
280             first_iter->skip (first_mom + now);
281           if (second_iter->ok ())
282             second_iter->skip (second_mom + now);
283 #endif
284         }
285       delete first_iter;
286       delete second_iter;
287     }
288   return state;
289 }
290
291 void
292 Part_combine_music_iterator::process (Moment m)
293 {
294
295   /*
296     TODO:
297     - Use three named contexts (be it Thread or Voice): one, two, solo.
298       Let user pre-set (pushproperty) stem direction, remove
299       dynamic-engraver, and such.
300    */
301  
302   int state = get_state (m);
303   if (state)
304     state_ = state;
305   else
306     state = state_;
307   
308   Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l_);
309
310   bool combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
311     == second_iter_p_->report_to_l ()->daddy_trans_l_;
312
313   String to_id =  combined_b ? "one" : "two";
314   if ((!(state & UNIRHYTHM) && combined_b)
315       || ((state & SPLIT_INTERVAL) && combined_b)
316       || ((state & (SOLO1 | SOLO2)) && combined_b)
317       || (((state & (UNIRHYTHM | UNISILENCE))
318            && !combined_b && !(state & SPLIT_INTERVAL)
319            && !(state & (SOLO1 | SOLO2)))))
320     {
321       combined_b = !combined_b;
322       to_id =  combined_b ? "one" : "two";
323       change_to (second_iter_p_, p->what_str_, to_id);
324     }
325
326
327   Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_, "one");
328   Translator_group *second_translator = second_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_, "two");
329
330   /*
331     hmm
332    */
333   SCM b = (state & UNIRHYTHM) ? SCM_BOOL_T : SCM_BOOL_F;
334   first_translator->set_property ("unirhythm", b);
335   second_translator->set_property ("unirhythm", b);
336
337   b = (state & SPLIT_INTERVAL) ? SCM_BOOL_T : SCM_BOOL_F;
338   first_translator->set_property ("split-interval", b);
339   second_translator->set_property ("split-interval",  b);
340
341   b = (state & UNISILENCE) ? SCM_BOOL_T : SCM_BOOL_F;
342   first_translator->set_property ("unisilence", b);
343   second_translator->set_property ("unisilence", b);
344
345   // difference in definition...
346   //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
347   b = ((state & UNISON) && (state & UNIRHYTHM)) ? SCM_BOOL_T : SCM_BOOL_F;
348   first_translator->set_property ("unison", b);
349   second_translator->set_property ("unison", b);
350
351   SCM b1 = (state & SOLO1) ? SCM_BOOL_T : SCM_BOOL_F;
352   SCM b2 = (state & SOLO2) ? SCM_BOOL_T : SCM_BOOL_F;
353   first_translator->set_property ("solo", b1);
354   second_translator->set_property ("solo", b2);
355
356   if (first_iter_p_->ok ())
357     first_iter_p_->process (m);
358   
359   if (second_iter_p_->ok ())
360     second_iter_p_->process (m);
361 }
362
363 Music_iterator*
364 Part_combine_music_iterator::try_music_in_children (Music *m) const
365 {
366   Music_iterator * i =  first_iter_p_->try_music (m);
367   if (i)
368     return i;
369   else
370     return second_iter_p_->try_music (m);
371 }
372
373
374 SCM
375 Part_combine_music_iterator::get_music (Moment m)const
376 {
377   SCM s = SCM_EOL;
378   if (first_iter_p_)
379     s = gh_append2 (s,first_iter_p_->get_music (m));
380   if (second_iter_p_)
381     s = gh_append2 (second_iter_p_->get_music (m),s);
382   return s;
383 }