2 part-combine-music-iterator.cc -- implement Part_combine_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2002 Jan Nieuwenhuizen <janneke@gnu.org>
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"
17 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 ()
37 if (first_iter_
) first_iter_
->quit();
38 if (second_iter_
) second_iter_
->quit();
41 Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator
const &src
)
42 : Music_iterator (src
)
44 first_iter_
= src
.first_iter_
? src
.first_iter_
->clone () : 0;
45 second_iter_
= src
.second_iter_
? src
.second_iter_
->clone () : 0;
47 first_until_
= src
.first_until_
;
48 second_until_
= src
.second_until_
;
50 suffix_
= src
.suffix_
;
53 scm_gc_unprotect_object (first_iter_
->self_scm());
55 scm_gc_unprotect_object (second_iter_
->self_scm());
59 Part_combine_music_iterator::pending_moment () const
63 if (first_iter_
->ok ())
64 p
= p
<? first_iter_
->pending_moment ();
66 if (second_iter_
->ok ())
67 p
= p
<? second_iter_
->pending_moment ();
72 Part_combine_music_iterator::ok () const
74 return first_iter_
->ok () || second_iter_
->ok ();
78 Part_combine_music_iterator::construct_children ()
80 Part_combine_music
const * m
= dynamic_cast<Part_combine_music
const*> (get_music ());
82 first_iter_
= unsmob_iterator (get_iterator (m
->get_first ()));
83 second_iter_
= unsmob_iterator (get_iterator (m
->get_second ()));
87 Part_combine_music_iterator::change_to (Music_iterator
*it
, String to_type
,
90 Translator_group
* current
= it
->report_to ();
91 Translator_group
* last
= 0;
94 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
96 TODO: abstract this function
99 /* find the type of translator that we're changing.
101 If \translator Staff = bass, then look for Staff = *
103 while (current
&& current
->type_string_
!= to_type
)
106 current
= current
->daddy_trans_
;
109 if (current
&& current
->id_string_
== to_id
)
112 msg
+= _ ("Can't switch translators, I'm there already");
118 Translator_group
* dest
=
119 it
->report_to ()->find_create_translator (to_type
, to_id
);
120 current
->remove_translator (last
);
121 dest
->add_used_group_translator (last
);
126 We could change the current translator's id, but that would make
129 last->translator_id_string_ = get_change ()->change_to_id_string_;
131 error (_f ("I'm one myself: `%s'", to_type
.to_str0 ()));
134 error (_f ("none of these in my family: `%s'", to_id
.to_str0 ()));
138 // SCM*, moet / kan dat niet met set_x ofzo?
140 get_music_info (Moment m
, Music_iterator
* iter
, SCM
*pitches
, SCM
*durations
)
144 for (SCM i
= iter
->get_pending_events (m
); gh_pair_p (i
); i
= ly_cdr (i
))
146 Music
*m
= unsmob_music (ly_car (i
));
147 if (Melodic_req
*r
= dynamic_cast<Melodic_req
*> (m
))
148 *pitches
= gh_cons (r
->get_mus_property ("pitch"), *pitches
);
149 if (Rhythmic_req
*r
= dynamic_cast<Rhythmic_req
*> (m
))
151 SCM d
= r
->get_mus_property ("duration");
153 r
->origin ()->warning ("Rhythmic_req has no duration\n");
155 // *durations = gh_cons (r->get_mus_property ("duration"), *durations);
156 *durations
= gh_cons (d
, *durations
);
163 Part_combine_music_iterator::get_state (Moment
)
166 Part_combine_music
const *p
= dynamic_cast<Part_combine_music
const* > (get_music ());
168 String w
= ly_scm2string (p
->get_mus_property ("what"));
171 Translator_group
*first_translator
= first_iter_
->report_to ()->find_create_translator (w
, "one" + suffix_
);
173 SCM s
= first_translator
->get_property ("changeMoment");
177 Moment change_mom
= *unsmob_moment (ly_car (s
));
178 Moment diff_mom
= *unsmob_moment (ly_cdr (s
));
180 Moment now
= pending_moment ();
182 if (!now
.main_part_
.mod_rat (change_mom
.main_part_
))
184 SCM interval
= SCM_BOOL_F
;
185 if (first_until_
< now
)
187 if (second_until_
< now
)
190 Moment first_mom
= first_until_
;
191 Moment second_mom
= second_until_
;
192 Moment diff_until
= diff_mom
+ now
;
196 Music_iterator
*first_iter
= first_iter_
->clone ();
197 Music_iterator
*second_iter
= second_iter_
->clone ();
199 Moment
last_pending (-1);
200 Moment pending
= now
;
201 while (now
< diff_until
202 && (first_iter
->ok () || second_iter
->ok ())
204 // urg, this is a hack, haven't caught this case yet
205 && (pending
!= last_pending
))
207 if (!second_iter
->ok ())
208 pending
= first_iter
->pending_moment ();
209 else if (!first_iter
->ok ())
210 pending
= second_iter
->pending_moment ();
212 pending
= first_iter
->pending_moment () <? second_iter
->pending_moment ();
213 last_pending
= pending
;
215 SCM first_pitches
= SCM_EOL
;
216 SCM first_durations
= SCM_EOL
;
217 get_music_info (pending
, first_iter
,
218 &first_pitches
, &first_durations
);
220 SCM second_pitches
= SCM_EOL
;
221 SCM second_durations
= SCM_EOL
;
222 get_music_info (pending
, second_iter
,
223 &second_pitches
, &second_durations
);
225 if (first_pitches
!= SCM_EOL
&& second_pitches
!= SCM_EOL
)
227 scm_sort_list_x (first_pitches
,
228 scm_primitive_eval (ly_symbol2scm ("Pitch::less_p")));
229 scm_sort_list_x (second_pitches
,
230 scm_primitive_eval (ly_symbol2scm ("Pitch::less_p")));
232 interval
= gh_int2scm (unsmob_pitch (ly_car (first_pitches
))->steps ()
233 - unsmob_pitch (ly_car (scm_last_pair (second_pitches
)))->steps ());
236 if (first_durations
!= SCM_EOL
)
238 scm_sort_list_x (first_durations
,
239 scm_primitive_eval (ly_symbol2scm ("Duration::less_p")));
240 first_mom
+= unsmob_duration (ly_car (first_durations
))->length_mom ();
243 if (second_durations
!= SCM_EOL
)
245 scm_sort_list_x (second_durations
,
246 scm_primitive_eval (ly_symbol2scm ("Duration::less_p")));
247 second_mom
+= unsmob_duration (ly_car (second_durations
))->length_mom ();
250 if (first_pitches
!= SCM_EOL
&& second_pitches
== SCM_EOL
251 && ! (second_until_
> now
))
254 state
&= ~UNISILENCE
;
255 if (! (state
& ~ (UNRELATED
| SOLO1
| UNISILENCE
)))
261 if (first_pitches
== SCM_EOL
&& second_pitches
!= SCM_EOL
262 && ! (first_until_
> now
))
265 state
&= ~UNISILENCE
;
266 if (! (state
& ~ (UNRELATED
| SOLO2
| UNISILENCE
)))
272 if (gh_equal_p (first_durations
, second_durations
))
274 state
&= ~UNISILENCE
;
275 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
279 state
&= ~ (UNIRHYTHM
| UNISILENCE
);
281 if (first_pitches
!= SCM_EOL
282 && gh_equal_p (first_pitches
, second_pitches
))
284 state
&= ~UNISILENCE
;
285 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
291 if (first_pitches
== SCM_EOL
&& second_pitches
== SCM_EOL
)
293 if (! (state
& ~ (UNIRHYTHM
| UNISILENCE
)))
299 state
&= ~ (UNISILENCE
);
301 if (gh_number_p (interval
))
303 SCM s
= first_translator
->get_property ("splitInterval");
304 int i
= gh_scm2int (interval
);
306 && gh_number_p (ly_car (s
))
307 && gh_number_p (ly_cdr (s
))
308 && i
>= gh_scm2int (ly_car (s
))
309 && i
<= gh_scm2int (ly_cdr (s
)))
311 if (! (state
& ~ (SPLIT_INTERVAL
| UNIRHYTHM
| UNISON
)))
312 state
|= SPLIT_INTERVAL
;
315 state
&= ~ (SPLIT_INTERVAL
);
318 if (first
&& first_pitches
!= SCM_EOL
)
319 first_until_
= first_mom
;
320 if (first
&& second_pitches
!= SCM_EOL
)
321 second_until_
= second_mom
;
324 if (first_iter
->ok ())
325 first_iter
->skip (pending
);
326 if (second_iter
->ok ())
327 second_iter
->skip (pending
);
330 scm_gc_unprotect_object (first_iter
->self_scm ());
331 scm_gc_unprotect_object (second_iter
->self_scm ());
337 static Span_req
* abort_req
= NULL
;
340 Part_combine_music_iterator::process (Moment m
)
345 - Use three named contexts (be it Thread or Voice): one, two, solo.
346 Let user pre-set (pushproperty) stem direction, remove
347 dynamic-engraver, and such.
349 **** Tried this, but won't work:
351 s Consider thread switching: threads "one", "two" and "both".
352 User can't pre-set the (most important) stem direction at
356 if (suffix_
.empty_b ())
357 suffix_
= first_iter_
->report_to ()
358 ->daddy_trans_
->id_string_
.cut_string (3, INT_MAX
);
360 int state
= get_state (m
);
366 Part_combine_music
const *p
=
367 dynamic_cast<Part_combine_music
const* > (get_music ());
370 bool previously_combined_b
= first_iter_
->report_to ()->daddy_trans_
371 == second_iter_
->report_to ()->daddy_trans_
;
373 bool combine_b
= previously_combined_b
;
375 if (! (state
& UNIRHYTHM
)
376 || (state
& SPLIT_INTERVAL
)
377 || (state
& (SOLO1
| SOLO2
)))
379 else if (state
& (UNIRHYTHM
| UNISILENCE
))
383 When combining, abort all running spanners
388 abort_req
= new Span_req
;
389 abort_req
->set_mus_property ("span-type", scm_makfrom0str ("abort"));
392 if (combine_b
&& combine_b
!= previously_combined_b
)
394 if (second_iter_
&& second_iter_
->ok ())
395 second_iter_
->try_music (abort_req
);
397 String w
= ly_scm2string (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
);