2 part-combine-music-iterator.cc -- implement Part_combine_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2003 Jan Nieuwenhuizen <janneke@gnu.org>
9 #include "part-combine-music-iterator.hh"
10 #include "translator-group.hh"
12 #include "music-sequence.hh"
13 #include "lily-guile.hh"
16 Part_combine_music_iterator::Part_combine_music_iterator ()
26 Part_combine_music_iterator::derived_mark () const
29 scm_gc_mark (first_iter_
->self_scm());
31 scm_gc_mark(second_iter_
->self_scm());
35 Part_combine_music_iterator::do_quit ()
43 Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator
const &src
)
44 : Music_iterator (src
)
50 first_iter_
= src
.first_iter_
->clone ();
52 second_iter_
= src
.second_iter_
->clone ();
54 first_until_
= src
.first_until_
;
55 second_until_
= src
.second_until_
;
57 suffix_
= src
.suffix_
;
60 scm_gc_unprotect_object (first_iter_
->self_scm());
62 scm_gc_unprotect_object (second_iter_
->self_scm());
66 Part_combine_music_iterator::pending_moment () const
70 if (first_iter_
->ok ())
71 p
= p
<? first_iter_
->pending_moment ();
73 if (second_iter_
->ok ())
74 p
= p
<? second_iter_
->pending_moment ();
79 Part_combine_music_iterator::ok () const
81 return first_iter_
->ok () || second_iter_
->ok ();
86 Part_combine_music_iterator::construct_children ()
88 SCM lst
= get_music ()->get_mus_property ("elements");
90 first_iter_
= unsmob_iterator (get_iterator (unsmob_music (gh_car (lst
))));
91 second_iter_
= unsmob_iterator (get_iterator (unsmob_music (gh_cadr (lst
))));
95 Part_combine_music_iterator::change_to (Music_iterator
*it
, SCM to_type
,
98 Translator_group
* current
= it
->report_to ();
99 Translator_group
* last
= 0;
102 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
104 TODO: abstract this function
107 /* find the type of translator that we're changing.
109 If \translator Staff = bass, then look for Staff = *
111 while (current
&& !current
->is_alias_b (to_type
))
114 current
= current
->daddy_trans_
;
117 if (current
&& current
->id_string_
== to_id
)
120 msg
+= _ ("Can't switch translators, I'm there already");
126 Translator_group
* dest
=
127 it
->report_to ()->find_create_translator (to_type
, to_id
);
128 current
->remove_translator (last
);
129 dest
->add_used_group_translator (last
);
134 We could change the current translator's id, but that would make
137 last->translator_id_string_ = get_change ()->change_to_id_string_;
139 error (_f ("I'm one myself: `%s'", ly_symbol2string (to_type
).to_str0 ()));
142 error (_f ("none of these in my family: `%s'", to_id
.to_str0 ()));
146 // SCM*, moet / kan dat niet met set_x ofzo?
148 get_music_info (Moment m
, Music_iterator
* iter
, SCM
*pitches
, SCM
*durations
)
152 for (SCM i
= iter
->get_pending_events (m
); gh_pair_p (i
); i
= ly_cdr (i
))
154 Music
*m
= unsmob_music (ly_car (i
));
155 SCM p
= m
->get_mus_property ("pitch");
156 SCM d
= m
->get_mus_property ("duration");
157 if (unsmob_pitch (p
))
158 *pitches
= gh_cons (p
, *pitches
);
159 if (unsmob_duration (d
))
160 *durations
= gh_cons (d
, *durations
);
166 Part_combine_music_iterator::get_state (Moment
)
170 Music
*p
= get_music ();
172 SCM w
= p
->get_mus_property ("what");
175 Translator_group
*first_translator
= first_iter_
->report_to ()->find_create_translator (w
, "one" + suffix_
);
177 SCM s
= first_translator
->get_property ("changeMoment");
181 Moment change_mom
= *unsmob_moment (ly_car (s
));
182 Moment diff_mom
= *unsmob_moment (ly_cdr (s
));
184 Moment now
= pending_moment ();
186 if (!now
.main_part_
.mod_rat (change_mom
.main_part_
))
188 SCM interval
= SCM_BOOL_F
;
189 if (first_until_
< now
)
191 if (second_until_
< now
)
194 Moment first_mom
= first_until_
;
195 Moment second_mom
= second_until_
;
196 Moment diff_until
= diff_mom
+ now
;
200 Music_iterator
*first_iter
= first_iter_
->clone ();
201 Music_iterator
*second_iter
= second_iter_
->clone ();
203 Moment
last_pending (-1);
204 Moment pending
= now
;
205 while (now
< diff_until
206 && (first_iter
->ok () || second_iter
->ok ())
208 // urg, this is a hack, haven't caught this case yet
209 && (pending
!= last_pending
))
211 if (!second_iter
->ok ())
212 pending
= first_iter
->pending_moment ();
213 else if (!first_iter
->ok ())
214 pending
= second_iter
->pending_moment ();
216 pending
= first_iter
->pending_moment () <? second_iter
->pending_moment ();
217 last_pending
= pending
;
219 SCM first_pitches
= SCM_EOL
;
220 SCM first_durations
= SCM_EOL
;
221 get_music_info (pending
, first_iter
,
222 &first_pitches
, &first_durations
);
224 SCM second_pitches
= SCM_EOL
;
225 SCM second_durations
= SCM_EOL
;
226 get_music_info (pending
, second_iter
,
227 &second_pitches
, &second_durations
);
229 if (first_pitches
!= SCM_EOL
&& second_pitches
!= SCM_EOL
)
231 scm_sort_list_x (first_pitches
, Pitch::less_p_proc
);
232 scm_sort_list_x (second_pitches
, Pitch::less_p_proc
);
234 interval
= gh_int2scm (unsmob_pitch (ly_car (first_pitches
))->steps ()
235 - unsmob_pitch (ly_car (scm_last_pair (second_pitches
)))->steps ());
238 if (first_durations
!= SCM_EOL
)
240 scm_sort_list_x (first_durations
,
241 Duration::less_p_proc
);
242 first_mom
+= unsmob_duration (ly_car (first_durations
))->get_length ();
245 if (second_durations
!= SCM_EOL
)
247 scm_sort_list_x (second_durations
,
248 Duration::less_p_proc
);
249 second_mom
+= unsmob_duration (ly_car (second_durations
))->get_length ();
252 if (first_pitches
!= SCM_EOL
&& second_pitches
== SCM_EOL
253 && ! (second_until_
> now
))
256 state
&= ~UNISILENCE
;
257 if (! (state
& ~ (UNRELATED
| SOLO1
| UNISILENCE
)))
263 if (first_pitches
== SCM_EOL
&& second_pitches
!= SCM_EOL
264 && ! (first_until_
> now
))
267 state
&= ~UNISILENCE
;
268 if (! (state
& ~ (UNRELATED
| SOLO2
| UNISILENCE
)))
274 if (gh_equal_p (first_durations
, second_durations
))
276 state
&= ~UNISILENCE
;
277 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
281 state
&= ~ (UNIRHYTHM
| UNISILENCE
);
283 if (first_pitches
!= SCM_EOL
284 && gh_equal_p (first_pitches
, second_pitches
))
286 state
&= ~UNISILENCE
;
287 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
293 if (first_pitches
== SCM_EOL
&& second_pitches
== SCM_EOL
)
295 if (! (state
& ~ (UNIRHYTHM
| UNISILENCE
)))
301 state
&= ~ (UNISILENCE
);
303 if (gh_number_p (interval
))
305 SCM s
= first_translator
->get_property ("splitInterval");
306 int i
= gh_scm2int (interval
);
308 && gh_number_p (ly_car (s
))
309 && gh_number_p (ly_cdr (s
))
310 && i
>= gh_scm2int (ly_car (s
))
311 && i
<= gh_scm2int (ly_cdr (s
)))
313 if (! (state
& ~ (SPLIT_INTERVAL
| UNIRHYTHM
| UNISON
)))
314 state
|= SPLIT_INTERVAL
;
317 state
&= ~ (SPLIT_INTERVAL
);
320 if (first
&& first_pitches
!= SCM_EOL
)
321 first_until_
= first_mom
;
322 if (first
&& second_pitches
!= SCM_EOL
)
323 second_until_
= second_mom
;
326 if (first_iter
->ok ())
327 first_iter
->skip (pending
);
328 if (second_iter
->ok ())
329 second_iter
->skip (pending
);
332 scm_gc_unprotect_object (first_iter
->self_scm ());
333 scm_gc_unprotect_object (second_iter
->self_scm ());
339 static Music
* abort_req
= NULL
;
342 Part_combine_music_iterator::process (Moment m
)
347 - Use three named contexts (be it Thread or Voice): one, two, solo.
348 Let user pre-set (pushproperty) stem direction, remove
349 dynamic-engraver, and such.
351 **** Tried this, but won't work:
353 s Consider thread switching: threads "one", "two" and "both".
354 User can't pre-set the (most important) stem direction at
358 if (suffix_
.empty_b ())
359 suffix_
= first_iter_
->report_to ()
360 ->daddy_trans_
->id_string_
.cut_string (3, INT_MAX
);
362 int state
= get_state (m
);
368 Music
*p
=get_music ();
371 bool previously_combined_b
= first_iter_
->report_to ()->daddy_trans_
372 == second_iter_
->report_to ()->daddy_trans_
;
374 bool combine_b
= previously_combined_b
;
376 if (! (state
& UNIRHYTHM
)
377 || (state
& SPLIT_INTERVAL
)
378 || (state
& (SOLO1
| SOLO2
)))
380 else if (state
& (UNIRHYTHM
| UNISILENCE
))
384 When combining, abort all running spanners
389 abort_req
= make_music_by_name (ly_symbol2scm ("AbortEvent"));
392 if (combine_b
&& combine_b
!= previously_combined_b
)
394 if (second_iter_
&& second_iter_
->ok ())
395 second_iter_
->try_music (abort_req
);
397 SCM w
= p
->get_mus_property ("what");
398 if (combine_b
!= previously_combined_b
)
399 change_to (second_iter_
, w
, (combine_b
? "one" : "two")
402 Translator_group
*first_translator
= first_iter_
->report_to ()->find_create_translator (w
, "one" + suffix_
);
403 Translator_group
*second_translator
= second_iter_
->report_to ()->find_create_translator (w
, "two" + suffix_
);
407 first_translator
->set_property ("combineParts", SCM_BOOL_T
);
408 second_translator
->set_property ("combineParts", SCM_BOOL_T
);
412 SCM b
= (state
& UNIRHYTHM
) ? SCM_BOOL_T
: SCM_BOOL_F
;
413 first_translator
->set_property ("unirhythm", b
);
414 second_translator
->set_property ("unirhythm", b
);
416 b
= (state
& SPLIT_INTERVAL
) ? SCM_BOOL_T
: SCM_BOOL_F
;
417 first_translator
->set_property ("split-interval", b
);
418 second_translator
->set_property ("split-interval", b
);
420 b
= (state
& UNISILENCE
) ? SCM_BOOL_T
: SCM_BOOL_F
;
421 first_translator
->set_property ("unisilence", b
);
422 second_translator
->set_property ("unisilence", b
);
424 // difference in definition...
425 //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
426 b
= ((state
& UNISON
) && (state
& UNIRHYTHM
)) ? SCM_BOOL_T
: SCM_BOOL_F
;
427 first_translator
->set_property ("unison", b
);
428 second_translator
->set_property ("unison", b
);
430 SCM b1
= (state
& SOLO1
) ? SCM_BOOL_T
: SCM_BOOL_F
;
431 SCM b2
= (state
& SOLO2
) ? SCM_BOOL_T
: SCM_BOOL_F
;
432 first_translator
->set_property ("solo", b1
);
433 second_translator
->set_property ("solo", b2
);
435 /* Can't these be computed? */
436 first_translator
->set_property ("othersolo", b2
);
437 second_translator
->set_property ("othersolo", b1
);
439 if (first_iter_
->ok ())
440 first_iter_
->process (m
);
442 if (second_iter_
->ok ())
443 second_iter_
->process (m
);
447 Part_combine_music_iterator::try_music_in_children (Music
*m
) const
449 Music_iterator
* i
= first_iter_
->try_music (m
);
453 return second_iter_
->try_music (m
);
458 Part_combine_music_iterator::get_pending_events (Moment m
)const
462 s
= gh_append2 (s
,first_iter_
->get_pending_events (m
));
464 s
= gh_append2 (second_iter_
->get_pending_events (m
),s
);
468 IMPLEMENT_CTOR_CALLBACK (Part_combine_music_iterator
);