2 part-combine-music-iterator.cc -- implement Part_combine_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 2000--2001 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 ()
25 Part_combine_music_iterator::~Part_combine_music_iterator ()
27 delete second_iter_p_
;
31 Part_combine_music_iterator::Part_combine_music_iterator (Part_combine_music_iterator
const &src
)
32 : Music_iterator (src
)
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;
37 first_until_
= src
.first_until_
;
38 second_until_
= src
.second_until_
;
40 suffix_
= src
.suffix_
;
44 Part_combine_music_iterator::pending_moment () const
48 if (first_iter_p_
->ok ())
49 p
= p
<? first_iter_p_
->pending_moment ();
51 if (second_iter_p_
->ok ())
52 p
= p
<? second_iter_p_
->pending_moment ();
57 Part_combine_music_iterator::ok () const
59 return first_iter_p_
->ok () || second_iter_p_
->ok ();
63 Part_combine_music_iterator::construct_children ()
65 Part_combine_music
const * m
= dynamic_cast<Part_combine_music
const*> (music_l ());
67 first_iter_p_
= get_iterator_p (m
->first_l ());
68 second_iter_p_
= get_iterator_p (m
->second_l ());
72 Part_combine_music_iterator::change_to (Music_iterator
*it
, String to_type
,
75 Translator_group
* current
= it
->report_to_l ();
76 Translator_group
* last
= 0;
79 Cut & Paste from from Auto_change_iterator from Change_iterator (ugh).
81 TODO: abstract this function
84 /* find the type of translator that we're changing.
86 If \translator Staff = bass, then look for Staff = *
88 while (current
&& current
->type_str_
!= to_type
)
91 current
= current
->daddy_trans_l_
;
94 if (current
&& current
->id_str_
== to_id
)
97 msg
+= _ ("Can't switch translators, I'm there already");
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_group_translator (last
);
111 We could change the current translator's id, but that would make
114 last->translator_id_str_ = change_l ()->change_to_id_str_;
116 error (_f ("I'm one myself: `%s'", to_type
.ch_C ()));
119 error (_f ("none of these in my family: `%s'", to_id
.ch_C ()));
123 // SCM*, moet / kan dat niet met set_x ofzo?
125 get_music_info (Moment m
, Music_iterator
* iter
, SCM
*pitches
, SCM
*durations
)
129 for (SCM i
= iter
->get_music (m
); gh_pair_p (i
); i
= gh_cdr (i
))
131 Music
*m
= unsmob_music (gh_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 *durations
= gh_cons (r
->get_mus_property ("duration"), *durations
);
141 Part_combine_music_iterator::get_state (Moment
)
144 Part_combine_music
const *p
= dynamic_cast<Part_combine_music
const* > (music_l ());
146 String w
= ly_scm2string (p
->get_mus_property ("what"));
149 Translator_group
*first_translator
= first_iter_p_
->report_to_l ()->find_create_translator_l (w
, "one" + suffix_
);
151 SCM s
= first_translator
->get_property (ly_symbol2scm ("changeMoment"));
155 Moment change_mom
= *unsmob_moment (gh_car (s
));
156 Moment diff_mom
= *unsmob_moment (gh_cdr (s
));
158 Moment now
= pending_moment ();
160 if (!now
.main_part_
.mod_rat (change_mom
.main_part_
))
162 SCM interval
= SCM_BOOL_F
;
163 if (first_until_
< now
)
165 if (second_until_
< now
)
168 Moment first_mom
= first_until_
;
169 Moment second_mom
= second_until_
;
170 Moment diff_until
= diff_mom
+ now
;
173 Music_iterator
*first_iter
= first_iter_p_
->clone ();
174 Music_iterator
*second_iter
= second_iter_p_
->clone ();
176 Moment
last_pending (-1);
177 Moment pending
= now
;
178 while (now
< diff_until
179 && (first_iter
->ok () || second_iter
->ok ())
181 // urg, this is a hack, haven't caught this case yet
182 && (pending
!= last_pending
))
184 if (!second_iter
->ok ())
185 pending
= first_iter
->pending_moment ();
186 else if (!first_iter
->ok ())
187 pending
= second_iter
->pending_moment ();
189 pending
= first_iter
->pending_moment () <? second_iter
->pending_moment ();
190 last_pending
= pending
;
192 SCM first_pitches
= SCM_EOL
;
193 SCM first_durations
= SCM_EOL
;
194 get_music_info (pending
, first_iter
,
195 &first_pitches
, &first_durations
);
197 SCM second_pitches
= SCM_EOL
;
198 SCM second_durations
= SCM_EOL
;
199 get_music_info (pending
, second_iter
,
200 &second_pitches
, &second_durations
);
202 if (first_pitches
!= SCM_EOL
&& second_pitches
!= SCM_EOL
)
204 scm_sort_list_x (first_pitches
,
205 scm_eval2 (ly_str02scm ("Pitch::less_p"),
207 scm_sort_list_x (second_pitches
,
208 scm_eval2 (ly_str02scm ("Pitch::less_p"),
210 interval
= gh_int2scm (unsmob_pitch (gh_car (first_pitches
))->steps ()
211 - unsmob_pitch (gh_car (scm_last_pair (second_pitches
)))->steps ());
214 if (first_durations
!= SCM_EOL
)
216 scm_sort_list_x (first_durations
,
217 scm_eval2 (ly_str02scm ("Duration::less_p"),
219 first_mom
+= unsmob_duration (gh_car (first_durations
))->length_mom ();
222 if (second_durations
!= SCM_EOL
)
224 scm_sort_list_x (second_durations
,
225 scm_eval2 (ly_str02scm ("Duration::less_p"),
227 second_mom
+= unsmob_duration (gh_car (second_durations
))->length_mom ();
230 if (first_pitches
!= SCM_EOL
&& second_pitches
== SCM_EOL
231 && ! (second_until_
> now
))
234 state
&= ~UNISILENCE
;
235 if (! (state
& ~ (UNRELATED
| SOLO1
| UNISILENCE
)))
241 if (first_pitches
== SCM_EOL
&& second_pitches
!= SCM_EOL
242 && ! (first_until_
> now
))
245 state
&= ~UNISILENCE
;
246 if (! (state
& ~ (UNRELATED
| SOLO2
| UNISILENCE
)))
252 if (gh_equal_p (first_durations
, second_durations
))
254 state
&= ~UNISILENCE
;
255 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
259 state
&= ~ (UNIRHYTHM
| UNISILENCE
);
261 if (first_pitches
!= SCM_EOL
262 && gh_equal_p (first_pitches
, second_pitches
))
264 state
&= ~UNISILENCE
;
265 if (! (state
& ~ (UNIRHYTHM
| UNISON
)))
271 if (first_pitches
== SCM_EOL
&& second_pitches
== SCM_EOL
)
273 if (! (state
& ~ (UNIRHYTHM
| UNISILENCE
)))
279 state
&= ~ (UNISILENCE
);
281 if (gh_number_p (interval
))
283 SCM s
= first_translator
->get_property (ly_symbol2scm ("splitInterval"));
284 int i
= gh_scm2int (interval
);
286 && gh_number_p (gh_car (s
))
287 && gh_number_p (gh_cdr (s
))
288 && i
>= gh_scm2int (gh_car (s
))
289 && i
<= gh_scm2int (gh_cdr (s
)))
291 if (! (state
& ~ (SPLIT_INTERVAL
| UNIRHYTHM
| UNISON
)))
292 state
|= SPLIT_INTERVAL
;
295 state
&= ~ (SPLIT_INTERVAL
);
298 if (first
&& first_pitches
!= SCM_EOL
)
299 first_until_
= first_mom
;
300 if (first
&& second_pitches
!= SCM_EOL
)
301 second_until_
= second_mom
;
304 if (first_iter
->ok ())
305 first_iter
->skip (pending
);
306 if (second_iter
->ok ())
307 second_iter
->skip (pending
);
316 static Span_req
* abort_req
= NULL
;
319 Part_combine_music_iterator::process (Moment m
)
324 - Use three named contexts (be it Thread or Voice): one, two, solo.
325 Let user pre-set (pushproperty) stem direction, remove
326 dynamic-engraver, and such.
328 **** Tried this, but won't work:
330 Consider thread switching: threads "one", "two" and "both".
331 User can't pre-set the (most important) stem direction at
335 if (suffix_
.empty_b ())
336 suffix_
= first_iter_p_
->report_to_l ()->daddy_trans_l_
->id_str_
.cut_str (3, INT_MAX
);
338 int state
= get_state (m
);
344 Part_combine_music
const *p
= dynamic_cast<Part_combine_music
const* > (music_l ());
347 bool previously_combined_b
= first_iter_p_
->report_to_l ()->daddy_trans_l_
348 == second_iter_p_
->report_to_l ()->daddy_trans_l_
;
350 bool combine_b
= previously_combined_b
;
352 if (! (state
& UNIRHYTHM
)
353 || (state
& SPLIT_INTERVAL
)
354 || (state
& (SOLO1
| SOLO2
)))
356 else if (state
& (UNIRHYTHM
| UNISILENCE
))
360 When combining, abort all running spanners
365 abort_req
= new Span_req
;
366 abort_req
->set_mus_property ("span-type", ly_str02scm ("abort"));
369 if (combine_b
&& combine_b
!= previously_combined_b
)
371 if (second_iter_p_
&& second_iter_p_
->ok ())
372 second_iter_p_
->try_music (abort_req
);
374 String w
= ly_scm2string (p
->get_mus_property ("what"));
375 if (combine_b
!= previously_combined_b
)
376 change_to (second_iter_p_
, w
, (combine_b
? "one" : "two")
379 Translator_group
*first_translator
= first_iter_p_
->report_to_l ()->find_create_translator_l (w
, "one" + suffix_
);
380 Translator_group
*second_translator
= second_iter_p_
->report_to_l ()->find_create_translator_l (w
, "two" + suffix_
);
384 first_translator
->set_property ("combineParts", SCM_BOOL_T
);
385 second_translator
->set_property ("combineParts", SCM_BOOL_T
);
389 SCM b
= (state
& UNIRHYTHM
) ? SCM_BOOL_T
: SCM_BOOL_F
;
390 first_translator
->set_property ("unirhythm", b
);
391 second_translator
->set_property ("unirhythm", b
);
393 b
= (state
& SPLIT_INTERVAL
) ? SCM_BOOL_T
: SCM_BOOL_F
;
394 first_translator
->set_property ("split-interval", b
);
395 second_translator
->set_property ("split-interval", b
);
397 b
= (state
& UNISILENCE
) ? SCM_BOOL_T
: SCM_BOOL_F
;
398 first_translator
->set_property ("unisilence", b
);
399 second_translator
->set_property ("unisilence", b
);
401 // difference in definition...
402 //b = ((state & UNISON) ? SCM_BOOL_T : SCM_BOOL_F;
403 b
= ((state
& UNISON
) && (state
& UNIRHYTHM
)) ? SCM_BOOL_T
: SCM_BOOL_F
;
404 first_translator
->set_property ("unison", b
);
405 second_translator
->set_property ("unison", b
);
407 SCM b1
= (state
& SOLO1
) ? SCM_BOOL_T
: SCM_BOOL_F
;
408 SCM b2
= (state
& SOLO2
) ? SCM_BOOL_T
: SCM_BOOL_F
;
409 first_translator
->set_property ("solo", b1
);
410 second_translator
->set_property ("solo", b2
);
412 if (first_iter_p_
->ok ())
413 first_iter_p_
->process (m
);
415 if (second_iter_p_
->ok ())
416 second_iter_p_
->process (m
);
420 Part_combine_music_iterator::try_music_in_children (Music
*m
) const
422 Music_iterator
* i
= first_iter_p_
->try_music (m
);
426 return second_iter_p_
->try_music (m
);
431 Part_combine_music_iterator::get_music (Moment m
)const
435 s
= gh_append2 (s
,first_iter_p_
->get_music (m
));
437 s
= gh_append2 (second_iter_p_
->get_music (m
),s
);
441 IMPLEMENT_CTOR_CALLBACK (Part_combine_music_iterator
);