2 Sequential_iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "translator-group.hh"
11 #include "sequential-iterator.hh"
12 #include "music-list.hh"
13 #include "grace-fixup.hh"
17 TODO: handling of grace notes is exquisite pain. This handling
18 should be formally specified and then the implementation verified.
23 Invariant for the data structure.
26 if (gh_pair_p (cursor_))
27 iter_->music_ == unsmob_music (ly_car (cursor_))
31 The length of musiclist from start to up to cursor_ (cursor_ not
34 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
37 Sequential_iterator::Sequential_iterator ()
39 here_mom_
= Moment (0);
46 Sequential_iterator::get_music_list () const
52 Sequential_iterator::do_quit ()
62 Sequential_iterator::derived_mark () const
65 scm_gc_mark (iter_
->self_scm ());
66 scm_gc_mark (cursor_
);
71 Sequential_iterator::derived_substitute (Context
*f
, Context
*t
)
74 iter_
->substitute_outlet (f
, t
);
78 TODO: this should be made lazily.
81 create_grace_fixup_list (SCM cursor
)
85 Grace_fixup
*head
= 0;
86 Grace_fixup
**tail
= &head
;
88 for (; gh_pair_p (cursor
); cursor
= ly_cdr (cursor
))
90 Music
*mus
= unsmob_music (ly_car (cursor
));
91 Moment s
= mus
->start_mom ();
92 Moment l
= mus
->get_length () - s
;
96 if (last
!= Moment (-1))
98 Grace_fixup
*p
= new Grace_fixup
;
100 p
->length_
= here
- last
;
101 p
->grace_start_
= s
.grace_part_
;
104 tail
= &(*tail
)->next_
;
107 here
.grace_part_
= s
.grace_part_
;
121 Sequential_iterator::construct_children ()
123 cursor_
= get_music_list ();
126 if (gh_pair_p (cursor_
))
128 Music
*m
= unsmob_music (ly_car (cursor_
));
129 iter_
= unsmob_iterator (get_iterator (m
));
132 while (iter_
&& !iter_
->ok ())
137 last_mom_
= Moment (-1);
138 here_mom_
= get_music ()->start_mom ();
139 grace_fixups_
= create_grace_fixup_list (cursor_
);
142 iter_->ok () is tautology, but what the heck.
144 if (iter_
&& iter_
->ok ())
145 descend_to_child (iter_
->get_outlet ());
150 maintain invariants: change cursor, iter and here_mom_ in one fell
154 Sequential_iterator::next_element (bool)
156 Moment len
=iter_
->music_get_length () - iter_
->music_start_mom ();
157 assert (!grace_fixups_
|| grace_fixups_
->start_
>= here_mom_
);
160 && get_grace_fixup ())
162 Grace_fixup
*gf
= get_grace_fixup ();
164 last_mom_
= here_mom_
;
165 here_mom_
+= gf
->length_
;
166 here_mom_
.grace_part_
+= gf
->grace_start_
;
170 else if (len
.grace_part_
&& !len
.main_part_
)
172 last_mom_
= here_mom_
;
173 here_mom_
.grace_part_
=0;
178 !len.grace_part_ || len.main_part_
180 We skip over a big chunk (mainpart != 0). Any starting graces
181 in that chunk should be in len.grace_part_
184 last_mom_
= here_mom_
;;
188 cursor_
= ly_cdr (cursor_
);
191 if (gh_pair_p (cursor_
))
192 iter_
= unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_
))));
200 Sequential_iterator::process (Moment until
)
204 Grace_fixup
* gf
= get_grace_fixup ();
206 && gf
->start_
+ gf
->length_
207 + Moment (Rational (0), gf
->grace_start_
) == until
)
210 do the stuff/note/rest preceding a grace.
212 iter_
->process (iter_
->music_get_length ());
216 Moment w
= until
- here_mom_
+ iter_
->music_start_mom ();
221 if the iter is still OK, there must be events left that have
229 descend_to_child (iter_
->get_outlet ());
235 Sequential_iterator::pending_moment () const
237 Moment cp
= iter_
->pending_moment ();
240 Fix-up a grace note halfway in the music.
242 Grace_fixup
* gf
= get_grace_fixup ();
244 && gf
->length_
+ iter_
->music_start_mom () == cp
)
246 return here_mom_
+ gf
->length_
+ Moment (0, gf
->grace_start_
);
250 Fix-up a grace note at the start of the music.
252 return cp
+ here_mom_
- iter_
->music_start_mom ();
257 Sequential_iterator::ok () const
263 Sequential_iterator::try_music_in_children (Music
*m
) const
265 return iter_
? iter_
->try_music (m
) : 0;
268 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator
);
271 Sequential_iterator::run_always () const
273 return iter_
? iter_
->run_always () : false;
277 Sequential_iterator::next_grace_fixup ()
279 Grace_fixup
* n
= grace_fixups_
->next_
;
280 delete grace_fixups_
;
285 Sequential_iterator::get_grace_fixup () const
287 if (grace_fixups_
&& grace_fixups_
->start_
== here_mom_
)
288 return grace_fixups_
;