2 sequential-iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
9 #include "sequential-iterator.hh"
11 #include "translator-group.hh"
13 #include "grace-fixup.hh"
16 TODO: handling of grace notes is exquisite pain. This handling
17 should be formally specified and then the implementation verified.
21 Invariant for the data structure.
24 if (scm_is_pair (cursor_))
25 iter_->music_ == unsmob_music (scm_car (cursor_))
29 The length of musiclist from start to up to cursor_ (cursor_ not
32 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
34 Sequential_iterator::Sequential_iterator ()
36 here_mom_
= Moment (0);
43 Sequential_iterator::get_music_list () const
45 Music
*m
= get_music ();
46 SCM proc
= m
->get_property ("elements-callback");
47 if (scm_procedure_p (proc
))
48 return scm_call_1 (proc
, m
->self_scm ());
54 Sequential_iterator::do_quit ()
61 Sequential_iterator::derived_mark () const
64 scm_gc_mark (iter_
->self_scm ());
65 scm_gc_mark (cursor_
);
69 Sequential_iterator::derived_substitute (Context
*f
, Context
*t
)
72 iter_
->substitute_outlet (f
, t
);
76 TODO: this should be made lazily.
79 create_grace_fixup_list (SCM cursor
)
83 Grace_fixup
*head
= 0;
84 Grace_fixup
**tail
= &head
;
86 for (; scm_is_pair (cursor
); cursor
= scm_cdr (cursor
))
88 Music
*mus
= unsmob_music (scm_car (cursor
));
89 Moment s
= mus
->start_mom ();
90 Moment l
= mus
->get_length () - s
;
94 if (last
!= Moment (-1))
96 Grace_fixup
*p
= new Grace_fixup
;
98 p
->length_
= here
- last
;
99 p
->grace_start_
= s
.grace_part_
;
102 tail
= &(*tail
)->next_
;
105 here
.grace_part_
= s
.grace_part_
;
119 Sequential_iterator::construct_children ()
121 cursor_
= get_music_list ();
124 if (scm_is_pair (cursor_
))
126 Music
*m
= unsmob_music (scm_car (cursor_
));
127 iter_
= unsmob_iterator (get_iterator (m
));
130 while (iter_
&& !iter_
->ok ())
133 last_mom_
= Moment (-1);
134 here_mom_
= get_music ()->start_mom ();
135 grace_fixups_
= create_grace_fixup_list (cursor_
);
138 iter_->ok () is tautology, but what the heck.
140 if (iter_
&& iter_
->ok ())
141 descend_to_child (iter_
->get_outlet ());
145 maintain invariants: change cursor, iter and here_mom_ in one fell
149 Sequential_iterator::next_element (bool)
151 Moment len
= iter_
->music_get_length () - iter_
->music_start_mom ();
152 assert (!grace_fixups_
|| grace_fixups_
->start_
>= here_mom_
);
155 && get_grace_fixup ())
157 Grace_fixup
*gf
= get_grace_fixup ();
159 last_mom_
= here_mom_
;
160 here_mom_
+= gf
->length_
;
161 here_mom_
.grace_part_
+= gf
->grace_start_
;
165 else if (len
.grace_part_
&& !len
.main_part_
)
167 last_mom_
= here_mom_
;
168 here_mom_
.grace_part_
= 0;
173 !len.grace_part_ || len.main_part_
175 We skip over a big chunk (mainpart != 0). Any starting graces
176 in that chunk should be in len.grace_part_
179 last_mom_
= here_mom_
;
183 cursor_
= scm_cdr (cursor_
);
186 if (scm_is_pair (cursor_
))
187 iter_
= unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_
))));
193 Sequential_iterator::process (Moment until
)
197 Grace_fixup
*gf
= get_grace_fixup ();
199 && gf
->start_
+ gf
->length_
200 + Moment (Rational (0), gf
->grace_start_
) == until
)
203 do the stuff/note/rest preceding a grace.
205 iter_
->process (iter_
->music_get_length ());
209 Moment w
= until
- here_mom_
+ iter_
->music_start_mom ();
214 if the iter is still OK, there must be events left that have
222 descend_to_child (iter_
->get_outlet ());
228 Sequential_iterator::pending_moment () const
230 Moment cp
= iter_
->pending_moment ();
233 Fix-up a grace note halfway in the music.
235 Grace_fixup
*gf
= get_grace_fixup ();
237 && gf
->length_
+ iter_
->music_start_mom () == cp
)
238 return here_mom_
+ gf
->length_
+ Moment (0, gf
->grace_start_
);
241 Fix-up a grace note at the start of the music.
243 return cp
+ here_mom_
- iter_
->music_start_mom ();
247 Sequential_iterator::ok () const
252 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator
);
255 Sequential_iterator::run_always () const
257 return iter_
? iter_
->run_always () : false;
261 Sequential_iterator::next_grace_fixup ()
263 Grace_fixup
*n
= grace_fixups_
->next_
;
264 delete grace_fixups_
;
269 Sequential_iterator::get_grace_fixup () const
271 if (grace_fixups_
&& grace_fixups_
->start_
== here_mom_
)
272 return grace_fixups_
;