]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
release: 1.3.89
[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" + suffix_);
132
133   SCM s = first_translator->get_property (ly_symbol2scm ("changeMoment"));
134   if (!gh_pair_p (s))
135     return state;
136
137   Moment change_mom = *unsmob_moment (gh_car (s));
138   Moment diff_mom = *unsmob_moment (gh_cdr (s));
139   
140   Moment now = pending_moment ();
141
142   if (!now.mod_rat (change_mom))
143     {
144       SCM interval = SCM_BOOL_F;
145       if (first_until_ < now)
146         first_until_ = now;
147       if (second_until_ < now)
148         second_until_ = now;
149
150       Moment first_mom = first_until_;
151       Moment second_mom = second_until_;
152       Moment diff_until = diff_mom + now;
153
154       bool first = true;
155       Music_iterator *first_iter = first_iter_p_->clone ();
156       Music_iterator *second_iter = second_iter_p_->clone ();
157
158       Moment last_pending (-1);
159       Moment pending = now;
160       while (now < diff_until
161               && (first_iter->ok () || second_iter->ok ())
162
163              // urg, this is a hack, haven't caught this case yet
164              && (pending != last_pending))
165         {
166           if (!second_iter->ok ())
167             pending = first_iter->pending_moment ();
168           else if (!first_iter->ok ())
169             pending = second_iter->pending_moment ();
170           else
171             pending = first_iter->pending_moment () <? second_iter->pending_moment ();
172           last_pending = pending;
173
174           Array<Musical_pitch> first_pitches;
175           Array<Duration> first_durations;
176           get_music_info (pending, first_iter, &first_pitches, &first_durations);
177       
178           Array<Musical_pitch> second_pitches;
179           Array<Duration> second_durations;
180           get_music_info (pending, second_iter, &second_pitches, &second_durations);
181
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               first_mom += first_durations.top ().length_mom ();
193             }
194
195           if (second_durations.size ())
196             {
197               second_durations.sort (Duration::compare);
198               second_mom += second_durations.top ().length_mom ();
199             }
200
201           if (!first_pitches.empty () && second_pitches.empty ()
202                && !(second_until_ > now))
203             {
204               state |= UNRELATED;
205               state &= ~UNISILENCE;
206               if (!(state & ~(UNRELATED | SOLO1 | UNISILENCE)))
207                 state |= SOLO1;
208             }
209           else
210             state &= ~SOLO1;
211
212           if (first_pitches.empty () && !second_pitches.empty ()
213               && !(first_until_ > now))
214             {
215               state |= UNRELATED;
216               state &= ~UNISILENCE;
217               if (!(state & ~(UNRELATED | SOLO2 | UNISILENCE)))
218                 state |= SOLO2;
219             }
220           else
221             state &= ~SOLO2;
222
223           if (!compare (&first_durations, &second_durations))
224             {
225               state &= ~UNISILENCE;
226               if (!(state & ~(UNIRHYTHM | UNISON)))
227                 state |= UNIRHYTHM;
228             }
229           else
230             state &= ~(UNIRHYTHM | UNISILENCE);
231           
232           if (!first_pitches.empty ()
233               &&!compare (&first_pitches, &second_pitches))
234             {
235               state &= ~UNISILENCE;
236               if (!(state & ~(UNIRHYTHM | UNISON)))
237                 state |= UNISON;
238             }
239           else
240             state &= ~(UNISON);
241             
242           if (first_pitches.empty () && second_pitches.empty ())
243             {
244               if (!(state & ~(UNIRHYTHM | UNISILENCE)))
245                 state |= UNISILENCE;
246             }
247           else if (!state)
248             state |= UNRELATED;
249           else
250             state &= ~(UNISILENCE);
251
252           if (gh_number_p (interval))
253             {
254               SCM s = first_translator->get_property (ly_symbol2scm ("splitInterval"));
255               int i = gh_scm2int (interval);
256               if (gh_pair_p (s)
257                   && gh_number_p (gh_car (s))
258                   && gh_number_p (gh_cdr (s))
259                   && i >= gh_scm2int (gh_car (s))
260                   && i <= gh_scm2int (gh_cdr (s)))
261                 {
262                   if (!(state & ~(SPLIT_INTERVAL | UNIRHYTHM | UNISON)))
263                     state |= SPLIT_INTERVAL;
264                 }
265               else
266                 state &= ~(SPLIT_INTERVAL);
267             }
268
269           if (first && !first_pitches.empty ())
270             first_until_ = first_mom;
271           if (first && !second_pitches.empty ())
272             second_until_ = second_mom;
273           first = false;
274
275           if (first_iter->ok ())
276             first_iter->skip (pending);
277           if (second_iter->ok ())
278             second_iter->skip (pending);
279           now = pending;
280         }
281       delete first_iter;
282       delete second_iter;
283     }
284   return state;
285 }
286
287 void
288 Part_combine_music_iterator::process (Moment m)
289 {
290
291   /*
292     TODO:
293     - Use three named contexts (be it Thread or Voice): one, two, solo.
294       Let user pre-set (pushproperty) stem direction, remove
295       dynamic-engraver, and such.
296
297       **** Tried this, but won't work:
298
299       Consider thread switching: threads "one", "two" and "both".
300       User can't pre-set the (most important) stem direction at
301       thread level!
302    */
303  
304   if (suffix_.empty_b ())
305     suffix_ = first_iter_p_->report_to_l ()->daddy_trans_l_->id_str_.cut_str (3, INT_MAX);
306
307   int state = get_state (m);
308   if (state)
309     state_ = state;
310   else
311     state = state_;
312   
313   Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l_);
314
315
316   bool previously_combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
317     == second_iter_p_->report_to_l ()->daddy_trans_l_;
318
319   bool combine_b = previously_combined_b;
320
321   if (!(state & UNIRHYTHM)
322       || (state & SPLIT_INTERVAL)
323       || (state & (SOLO1 | SOLO2)))
324     combine_b = false;
325   else if (state & (UNIRHYTHM | UNISILENCE))
326     combine_b = true;
327
328   if (combine_b != previously_combined_b)
329     change_to (second_iter_p_, p->what_str_, (combine_b ? "one" : "two")
330                + suffix_);
331
332   Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_, "one" + suffix_);
333   Translator_group *second_translator = second_iter_p_->report_to_l ()->find_create_translator_l (p->what_str_, "two" + suffix_);
334
335   /*
336     hmm
337    */
338   SCM b = (state & UNIRHYTHM) ? SCM_BOOL_T : SCM_BOOL_F;
339   first_translator->set_property ("unirhythm", b);
340   second_translator->set_property ("unirhythm", b);
341
342   b = (state & SPLIT_INTERVAL) ? SCM_BOOL_T : SCM_BOOL_F;
343   first_translator->set_property ("split-interval", b);
344   second_translator->set_property ("split-interval",  b);
345
346   b = (state & UNISILENCE) ? SCM_BOOL_T : SCM_BOOL_F;
347   first_translator->set_property ("unisilence", b);
348   second_translator->set_property ("unisilence", b);
349
350   // difference in definition...
351   //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
352   b = ((state & UNISON) && (state & UNIRHYTHM)) ? SCM_BOOL_T : SCM_BOOL_F;
353   first_translator->set_property ("unison", b);
354   second_translator->set_property ("unison", b);
355
356   SCM b1 = (state & SOLO1) ? SCM_BOOL_T : SCM_BOOL_F;
357   SCM b2 = (state & SOLO2) ? SCM_BOOL_T : SCM_BOOL_F;
358   first_translator->set_property ("solo", b1);
359   second_translator->set_property ("solo", b2);
360
361   if (first_iter_p_->ok ())
362     first_iter_p_->process (m);
363   
364   if (second_iter_p_->ok ())
365     second_iter_p_->process (m);
366 }
367
368 Music_iterator*
369 Part_combine_music_iterator::try_music_in_children (Music *m) const
370 {
371   Music_iterator * i =  first_iter_p_->try_music (m);
372   if (i)
373     return i;
374   else
375     return second_iter_p_->try_music (m);
376 }
377
378
379 SCM
380 Part_combine_music_iterator::get_music (Moment m)const
381 {
382   SCM s = SCM_EOL;
383   if (first_iter_p_)
384     s = gh_append2 (s,first_iter_p_->get_music (m));
385   if (second_iter_p_)
386     s = gh_append2 (second_iter_p_->get_music (m),s);
387   return s;
388 }