2 sequential-iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2006 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
49 Sequential_iterator::do_quit ()
56 Sequential_iterator::derived_mark () const
59 scm_gc_mark (iter_
->self_scm ());
60 scm_gc_mark (cursor_
);
64 Sequential_iterator::derived_substitute (Context
*f
, Context
*t
)
67 iter_
->substitute_outlet (f
, t
);
71 TODO: this should be made lazily.
74 create_grace_fixup_list (SCM cursor
)
78 Grace_fixup
*head
= 0;
79 Grace_fixup
**tail
= &head
;
81 for (; scm_is_pair (cursor
); cursor
= scm_cdr (cursor
))
83 Music
*mus
= unsmob_music (scm_car (cursor
));
84 Moment s
= mus
->start_mom ();
85 Moment l
= mus
->get_length () - s
;
89 if (last
!= Moment (-1))
91 Grace_fixup
*p
= new Grace_fixup
;
93 p
->length_
= here
- last
;
94 p
->grace_start_
= s
.grace_part_
;
97 tail
= &(*tail
)->next_
;
100 here
.grace_part_
= s
.grace_part_
;
114 Sequential_iterator::construct_children ()
116 cursor_
= get_music_list ();
119 if (scm_is_pair (cursor_
))
121 Music
*m
= unsmob_music (scm_car (cursor_
));
122 iter_
= unsmob_iterator (get_iterator (m
));
125 while (iter_
&& !iter_
->ok ())
128 last_mom_
= Moment (-1);
129 here_mom_
= get_music ()->start_mom ();
130 grace_fixups_
= create_grace_fixup_list (cursor_
);
133 iter_->ok () is tautology, but what the heck.
135 if (iter_
&& iter_
->ok ())
136 descend_to_child (iter_
->get_outlet ());
140 maintain invariants: change cursor, iter and here_mom_ in one fell
144 Sequential_iterator::next_element (bool)
146 Moment len
= iter_
->music_get_length () - iter_
->music_start_mom ();
147 assert (!grace_fixups_
|| grace_fixups_
->start_
>= here_mom_
);
150 && get_grace_fixup ())
152 Grace_fixup
*gf
= get_grace_fixup ();
154 last_mom_
= here_mom_
;
155 here_mom_
+= gf
->length_
;
156 here_mom_
.grace_part_
+= gf
->grace_start_
;
160 else if (len
.grace_part_
&& !len
.main_part_
)
162 last_mom_
= here_mom_
;
163 here_mom_
.grace_part_
= 0;
168 !len.grace_part_ || len.main_part_
170 We skip over a big chunk (mainpart != 0). Any starting graces
171 in that chunk should be in len.grace_part_
174 last_mom_
= here_mom_
;;
178 cursor_
= scm_cdr (cursor_
);
181 if (scm_is_pair (cursor_
))
182 iter_
= unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_
))));
188 Sequential_iterator::process (Moment until
)
192 Grace_fixup
*gf
= get_grace_fixup ();
194 && gf
->start_
+ gf
->length_
195 + Moment (Rational (0), gf
->grace_start_
) == until
)
198 do the stuff/note/rest preceding a grace.
200 iter_
->process (iter_
->music_get_length ());
204 Moment w
= until
- here_mom_
+ iter_
->music_start_mom ();
209 if the iter is still OK, there must be events left that have
217 descend_to_child (iter_
->get_outlet ());
223 Sequential_iterator::pending_moment () const
225 Moment cp
= iter_
->pending_moment ();
228 Fix-up a grace note halfway in the music.
230 Grace_fixup
*gf
= get_grace_fixup ();
232 && gf
->length_
+ iter_
->music_start_mom () == cp
)
233 return here_mom_
+ gf
->length_
+ Moment (0, gf
->grace_start_
);
236 Fix-up a grace note at the start of the music.
238 return cp
+ here_mom_
- iter_
->music_start_mom ();
242 Sequential_iterator::ok () const
248 Sequential_iterator::try_music_in_children (Music
*m
) const
250 return iter_
? iter_
->try_music (m
) : 0;
253 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator
);
256 Sequential_iterator::run_always () const
258 return iter_
? iter_
->run_always () : false;
262 Sequential_iterator::next_grace_fixup ()
264 Grace_fixup
*n
= grace_fixups_
->next_
;
265 delete grace_fixups_
;
270 Sequential_iterator::get_grace_fixup () const
272 if (grace_fixups_
&& grace_fixups_
->start_
== here_mom_
)
273 return grace_fixups_
;