]> git.donarmstrong.com Git - lilypond.git/blob - lily/part-combine-music-iterator.cc
* Documentation/windows/zlily-profile.sh:
[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--2002 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 "lily-guile.hh"
15 #include "warn.hh"
16
17 Part_combine_music_iterator::Part_combine_music_iterator ()
18 {
19   first_iter_p_ = 0;
20   second_iter_p_ = 0;
21   first_until_ = 0;
22   second_until_ = 0;
23 }
24
25 Part_combine_music_iterator::~Part_combine_music_iterator ()
26 {
27   delete second_iter_p_;
28   delete first_iter_p_;
29 }
30
31 Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator const &src)
32   : Music_iterator (src)
33 {
34   second_iter_p_ = src.second_iter_p_ ? src.second_iter_p_->clone () : 0;
35   first_iter_p_ = src.first_iter_p_ ? src.first_iter_p_->clone () : 0;
36
37   first_until_ = src.first_until_;
38   second_until_ = src.second_until_;
39   state_ = src.state_;
40   suffix_ = src.suffix_;
41 }
42
43 Moment
44 Part_combine_music_iterator::pending_moment () const
45 {
46   Moment p;
47   p.set_infinite (1);
48   if (first_iter_p_->ok ())
49     p = p <? first_iter_p_->pending_moment ();
50
51   if (second_iter_p_->ok ())
52     p = p <? second_iter_p_->pending_moment ();
53   return p;
54 }
55
56 bool
57 Part_combine_music_iterator::ok () const
58 {
59   return first_iter_p_->ok () || second_iter_p_->ok ();
60 }
61
62 void
63 Part_combine_music_iterator::construct_children ()
64 {
65   Part_combine_music const * m = dynamic_cast<Part_combine_music const*> (music_l ());
66   
67   first_iter_p_ = get_iterator_p (m->first_l ());
68   second_iter_p_ = get_iterator_p (m->second_l ());
69 }
70
71 void
72 Part_combine_music_iterator::change_to (Music_iterator *it, String to_type,
73                                         String to_id)
74 {
75   Translator_group * current = it->report_to_l ();
76   Translator_group * last = 0;
77
78   /*
79     Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
80
81     TODO: abstract this function 
82    */
83   
84   /* find the type  of translator that we're changing.
85      
86      If \translator Staff = bass, then look for Staff = *
87    */
88   while (current && current->type_str_ != to_type)
89     {
90       last = current;
91       current = current->daddy_trans_l_;
92     }
93
94   if (current && current->id_str_ == to_id)
95     {
96       String msg;
97       msg += _ ("Can't switch translators, I'm there already");
98     }
99   
100   if (current) 
101     if (last)
102       {
103         Translator_group * dest = 
104           it->report_to_l ()->find_create_translator_l (to_type, to_id);
105         current->remove_translator_p (last);
106         dest->add_used_group_translator (last);
107       }
108     else
109       {
110         /*
111           We could change the current translator's id, but that would make 
112           errors hard to catch
113           
114            last->translator_id_str_  = change_l ()->change_to_id_str_;
115         */
116         error (_f ("I'm one myself: `%s'", to_type.ch_C ()));
117       }
118   else
119     error (_f ("none of these in my family: `%s'", to_id.ch_C ()));
120 }
121
122
123 // SCM*, moet / kan dat niet met set_x ofzo?
124 static void
125 get_music_info (Moment m, Music_iterator* iter, SCM *pitches, SCM *durations)
126 {
127   if (iter->ok ())
128     {
129       for (SCM i = iter->get_music (m); gh_pair_p (i); i = ly_cdr (i))
130         {
131           Music *m = unsmob_music (ly_car (i));
132           if (Melodic_req *r = dynamic_cast<Melodic_req *> (m))
133             *pitches = gh_cons (r->get_mus_property ("pitch"), *pitches);
134           if (Rhythmic_req *r = dynamic_cast<Rhythmic_req *> (m))
135             {
136               SCM d = r->get_mus_property ("duration");
137               if (d == SCM_EOL)
138                 r->origin ()->warning ("Rhythmic_req has no duration\n");
139                 else
140                   // *durations = gh_cons (r->get_mus_property ("duration"), *durations);
141                   *durations = gh_cons (d, *durations);
142             }
143         }
144     }
145 }
146   
147 int
148 Part_combine_music_iterator::get_state (Moment)
149 {
150   int state = UNKNOWN;
151   Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l ());
152
153   String w = ly_scm2string (p->get_mus_property ("what"));
154     
155   
156   Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (w, "one" + suffix_);
157
158   SCM s = first_translator->get_property ("changeMoment");
159   if (!gh_pair_p (s))
160     return state;
161
162   Moment change_mom = *unsmob_moment (ly_car (s));
163   Moment diff_mom = *unsmob_moment (ly_cdr (s));
164   
165   Moment now = pending_moment ();
166
167   if (!now.main_part_.mod_rat (change_mom.main_part_))
168     {
169       SCM interval = SCM_BOOL_F;
170       if (first_until_ < now)
171         first_until_ = now;
172       if (second_until_ < now)
173         second_until_ = now;
174
175       Moment first_mom = first_until_;
176       Moment second_mom = second_until_;
177       Moment diff_until = diff_mom + now;
178
179       bool first = true;
180       Music_iterator *first_iter = first_iter_p_->clone ();
181       Music_iterator *second_iter = second_iter_p_->clone ();
182
183       Moment last_pending (-1);
184       Moment pending = now;
185       while (now < diff_until
186               && (first_iter->ok () || second_iter->ok ())
187
188              // urg, this is a hack, haven't caught this case yet
189              && (pending != last_pending))
190         {
191           if (!second_iter->ok ())
192             pending = first_iter->pending_moment ();
193           else if (!first_iter->ok ())
194             pending = second_iter->pending_moment ();
195           else
196             pending = first_iter->pending_moment () <? second_iter->pending_moment ();
197           last_pending = pending;
198
199           SCM first_pitches = SCM_EOL;
200           SCM first_durations = SCM_EOL;
201           get_music_info (pending, first_iter,
202                           &first_pitches, &first_durations);
203       
204           SCM second_pitches = SCM_EOL;
205           SCM second_durations = SCM_EOL;
206           get_music_info (pending, second_iter,
207                           &second_pitches, &second_durations);
208
209           if (first_pitches != SCM_EOL && second_pitches != SCM_EOL)
210             {
211               scm_sort_list_x (first_pitches,
212                                scm_primitive_eval (ly_symbol2scm ("Pitch::less_p")));
213               scm_sort_list_x (second_pitches,
214                                scm_primitive_eval (ly_symbol2scm ("Pitch::less_p")));
215
216               interval = gh_int2scm (unsmob_pitch (ly_car (first_pitches))->steps ()
217                                      - unsmob_pitch (ly_car (scm_last_pair (second_pitches)))->steps ());
218             }
219
220           if (first_durations != SCM_EOL)
221             {
222               scm_sort_list_x (first_durations,
223                                scm_primitive_eval (ly_symbol2scm ("Duration::less_p")));
224               first_mom += unsmob_duration (ly_car (first_durations))->length_mom ();
225             }
226           
227           if (second_durations != SCM_EOL)
228             {
229               scm_sort_list_x (second_durations,
230                                scm_primitive_eval (ly_symbol2scm ("Duration::less_p")));
231               second_mom += unsmob_duration (ly_car (second_durations))->length_mom ();
232             }
233           
234           if (first_pitches != SCM_EOL && second_pitches == SCM_EOL
235                   && ! (second_until_ > now))
236             {
237               state |= UNRELATED;
238               state &= ~UNISILENCE;
239               if (! (state & ~ (UNRELATED | SOLO1 | UNISILENCE)))
240                 state |= SOLO1;
241             }
242           else
243             state &= ~SOLO1;
244
245           if (first_pitches == SCM_EOL && second_pitches != SCM_EOL
246               && ! (first_until_ > now))
247             {
248               state |= UNRELATED;
249               state &= ~UNISILENCE;
250               if (! (state & ~ (UNRELATED | SOLO2 | UNISILENCE)))
251                 state |= SOLO2;
252             }
253           else
254             state &= ~SOLO2;
255
256           if (gh_equal_p (first_durations, second_durations))
257             {
258               state &= ~UNISILENCE;
259               if (! (state & ~ (UNIRHYTHM | UNISON)))
260                 state |= UNIRHYTHM;
261             }
262           else
263             state &= ~ (UNIRHYTHM | UNISILENCE);
264           
265           if (first_pitches != SCM_EOL
266               && gh_equal_p (first_pitches, second_pitches))
267             {
268               state &= ~UNISILENCE;
269               if (! (state & ~ (UNIRHYTHM | UNISON)))
270                 state |= UNISON;
271             }
272           else
273             state &= ~ (UNISON);
274             
275           if (first_pitches == SCM_EOL && second_pitches == SCM_EOL)
276             {
277               if (! (state & ~ (UNIRHYTHM | UNISILENCE)))
278                 state |= UNISILENCE;
279             }
280           else if (!state)
281             state |= UNRELATED;
282           else
283             state &= ~ (UNISILENCE);
284
285           if (gh_number_p (interval))
286             {
287               SCM s = first_translator->get_property ("splitInterval");
288               int i = gh_scm2int (interval);
289               if (gh_pair_p (s)
290                   && gh_number_p (ly_car (s))
291                   && gh_number_p (ly_cdr (s))
292                   && i >= gh_scm2int (ly_car (s))
293                   && i <= gh_scm2int (ly_cdr (s)))
294                 {
295                   if (! (state & ~ (SPLIT_INTERVAL | UNIRHYTHM | UNISON)))
296                     state |= SPLIT_INTERVAL;
297                 }
298               else
299                 state &= ~ (SPLIT_INTERVAL);
300             }
301
302           if (first && first_pitches != SCM_EOL)
303             first_until_ = first_mom;
304           if (first && second_pitches != SCM_EOL)
305             second_until_ = second_mom;
306           first = false;
307
308           if (first_iter->ok ())
309             first_iter->skip (pending);
310           if (second_iter->ok ())
311             second_iter->skip (pending);
312           now = pending;
313         }
314       delete first_iter;
315       delete second_iter;
316     }
317   return state;
318 }
319
320 static Span_req* abort_req = NULL;
321
322 void
323 Part_combine_music_iterator::process (Moment m)
324 {
325
326   /*
327     TODO:
328     - Use three named contexts (be it Thread or Voice): one, two, solo.
329       Let user pre-set (pushproperty) stem direction, remove
330       dynamic-engraver, and such.
331
332       **** Tried this, but won't work:
333
334       Consider thread switching: threads "one", "two" and "both".
335       User can't pre-set the (most important) stem direction at
336       thread level!
337    */
338  
339   if (suffix_.empty_b ())
340     suffix_ = first_iter_p_->report_to_l ()->daddy_trans_l_->id_str_.cut_str (3, INT_MAX);
341
342   int state = get_state (m);
343   if (state)
344     state_ = state;
345   else
346     state = state_;
347   
348   Part_combine_music const *p = dynamic_cast<Part_combine_music const* > (music_l ());
349
350
351   bool previously_combined_b = first_iter_p_->report_to_l ()->daddy_trans_l_
352     == second_iter_p_->report_to_l ()->daddy_trans_l_;
353
354   bool combine_b = previously_combined_b;
355
356   if (! (state & UNIRHYTHM)
357       || (state & SPLIT_INTERVAL)
358       || (state & (SOLO1 | SOLO2)))
359     combine_b = false;
360   else if (state & (UNIRHYTHM | UNISILENCE))
361     combine_b = true;
362
363   /*
364     When combining, abort all running spanners
365    */
366
367   if (!abort_req)
368     {
369       abort_req = new Span_req;
370       abort_req->set_mus_property ("span-type", ly_str02scm ("abort"));
371     }
372   
373   if (combine_b && combine_b != previously_combined_b)
374     {
375       if (second_iter_p_ && second_iter_p_->ok ())
376         second_iter_p_->try_music (abort_req);
377      }
378   String w = ly_scm2string (p->get_mus_property ("what"));
379   if (combine_b != previously_combined_b)
380     change_to (second_iter_p_, w, (combine_b ? "one" : "two")
381                + suffix_);
382   
383   Translator_group *first_translator = first_iter_p_->report_to_l ()->find_create_translator_l (w, "one" + suffix_);
384   Translator_group *second_translator = second_iter_p_->report_to_l ()->find_create_translator_l (w, "two" + suffix_);
385   
386
387   /* Hmm */
388   first_translator->set_property ("combineParts", SCM_BOOL_T);
389   second_translator ->set_property ("combineParts", SCM_BOOL_T);
390  
391  
392   /* hmm */
393   SCM b = (state & UNIRHYTHM) ? SCM_BOOL_T : SCM_BOOL_F;
394   first_translator->set_property ("unirhythm", b);
395   second_translator->set_property ("unirhythm", b);
396
397   b = (state & SPLIT_INTERVAL) ? SCM_BOOL_T : SCM_BOOL_F;
398   first_translator->set_property ("split-interval", b);
399   second_translator->set_property ("split-interval",  b);
400
401   b = (state & UNISILENCE) ? SCM_BOOL_T : SCM_BOOL_F;
402   first_translator->set_property ("unisilence", b);
403   second_translator->set_property ("unisilence", b);
404
405   // difference in definition...
406   //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
407   b = ((state & UNISON) && (state & UNIRHYTHM)) ? SCM_BOOL_T : SCM_BOOL_F;
408   first_translator->set_property ("unison", b);
409   second_translator->set_property ("unison", b);
410
411   SCM b1 = (state & SOLO1) ? SCM_BOOL_T : SCM_BOOL_F;
412   SCM b2 = (state & SOLO2) ? SCM_BOOL_T : SCM_BOOL_F;
413   first_translator->set_property ("solo", b1);
414   second_translator->set_property ("solo", b2);
415
416   if (first_iter_p_->ok ())
417     first_iter_p_->process (m);
418   
419   if (second_iter_p_->ok ())
420     second_iter_p_->process (m);
421 }
422
423 Music_iterator*
424 Part_combine_music_iterator::try_music_in_children (Music *m) const
425 {
426   Music_iterator * i =  first_iter_p_->try_music (m);
427   if (i)
428     return i;
429   else
430     return second_iter_p_->try_music (m);
431 }
432
433
434 SCM
435 Part_combine_music_iterator::get_music (Moment m)const
436 {
437   SCM s = SCM_EOL;
438   if (first_iter_p_)
439     s = gh_append2 (s,first_iter_p_->get_music (m));
440   if (second_iter_p_)
441     s = gh_append2 (second_iter_p_->get_music (m),s);
442   return s;
443 }
444
445 IMPLEMENT_CTOR_CALLBACK (Part_combine_music_iterator);