2 Sequential_iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "translator-group.hh"
11 #include "sequential-iterator.hh"
12 #include "music-list.hh"
14 Grace_fixup *copy_grace_fixups (Grace_fixup* src);
15 Grace_fixup *get_grace_fixups (SCM cursor);
19 TODO: handling of grace notes is exquisite pain. This handling
20 should be formally specified and then the implementation verified.
25 Invariant for the data structure.
28 if (gh_pair_p (cursor_))
29 iter_->music_ == unsmob_music (ly_car (cursor_))
33 The length of musiclist from start to up to cursor_ (cursor_ not
36 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
39 Sequential_iterator::Sequential_iterator ()
41 here_mom_ = Moment (0);
47 Sequential_iterator::get_music_list () const
52 Sequential_iterator::Sequential_iterator (Sequential_iterator const &src)
53 : Music_iterator (src)
55 grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
56 cursor_ = src.cursor_;
58 here_mom_ = src.here_mom_;
60 iter_ = src.iter_->clone ();
65 scm_gc_unprotect_object (iter_->self_scm());
69 Sequential_iterator::derived_mark ()const
72 scm_gc_mark (iter_->self_scm());
77 get_grace_fixups (SCM cursor)
81 Grace_fixup *head = 0;
82 Grace_fixup **tail = &head;
84 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
86 Music * mus = unsmob_music (ly_car (cursor));
87 Moment s = mus->start_mom ();
88 Moment l =mus->length_mom () - s;
92 if (last != Moment (-1))
94 Grace_fixup *p =new Grace_fixup;
96 p->length_ = here - last;
97 p->grace_start_ = s.grace_part_;
100 tail = &(*tail)->next_;
103 here.grace_part_ = s.grace_part_;
116 copy_grace_fixups (Grace_fixup* src)
118 Grace_fixup * head = 0;
119 Grace_fixup **dest = &head;
123 *dest = new Grace_fixup (*src);
124 dest = & (*dest)->next_;
132 Sequential_iterator::construct_children ()
134 list_ = get_music_list ();
138 if (gh_pair_p (cursor_))
140 Music *m =unsmob_music (ly_car (cursor_));
141 iter_ = unsmob_iterator ( get_iterator (m));
144 while (iter_ && !iter_->ok ())
149 here_mom_ = get_music ()->start_mom ();
150 grace_fixups_ = get_grace_fixups (cursor_);
153 iter_->ok () is tautology, but what the heck.
155 if (iter_ && iter_->ok ())
161 maintain invariants: change cursor, iter and here_mom_ in one fell
165 Sequential_iterator::next_element (bool side_effect)
167 Moment len =iter_->music_length_mom () - iter_->music_start_mom ();
168 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
170 if (len.main_part_ && grace_fixups_ &&
171 grace_fixups_->start_ == here_mom_)
173 here_mom_ += grace_fixups_->length_;
174 here_mom_.grace_part_ += grace_fixups_->grace_start_;
176 Grace_fixup * n =grace_fixups_->next_;
177 delete grace_fixups_;
180 else if (len.grace_part_ && !len.main_part_)
182 here_mom_.grace_part_ =0;
187 !len.grace_part_ || len.main_part_
189 We skip over a big chunk (mainpart != 0). Any starting graces
190 in that chunk should be in len.grace_part_
196 cursor_ = ly_cdr (cursor_);
198 if (gh_pair_p (cursor_))
199 iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
205 move to context of child iterator if it is deeper down in the
209 Sequential_iterator::descend_to_child ()
215 Retrieve all music (starting at HERE), until a music with length L >
216 0 is found. From the precondition, we know that UNTIL is later than
217 the earliest event. Hence we know
221 so something that comes after this thing with L > 0 happens after
223 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
225 Hence all events after the one with L>0 are uninteresting, so we
231 Sequential_iterator::get_pending_events (Moment until)const
234 if (until < pending_moment ())
237 Sequential_iterator * me =
238 dynamic_cast<Sequential_iterator*> (clone ());
241 SCM nm = me->iter_->get_pending_events (until - me->here_mom_);
242 s = gh_append2 (nm, s);
245 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
247 Music *mus=unsmob_music (ly_car (i));
248 m = m >? (mus->length_mom () - mus->start_mom ());
253 me->next_element (false);
256 scm_gc_unprotect_object (me->self_scm());
262 Skip events till UNTIL. We don't do any other side effects such as
263 descending to child iterator contexts, because they might depend on
264 \context specs and \translator changes being executed
267 Sequential_iterator::skip (Moment until)
272 grace_fixups_->start_ == here_mom_
273 && (grace_fixups_->start_ + grace_fixups_->length_
274 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
277 do the stuff/note/rest preceding a grace.
279 iter_->skip (iter_->music_length_mom ());
281 else if (iter_->music_length_mom () >= until - here_mom_)
282 iter_->skip (until - here_mom_ + iter_->music_start_mom ());
287 next_element (false);
292 Sequential_iterator::process (Moment until)
297 grace_fixups_->start_ == here_mom_
298 && (grace_fixups_->start_ + grace_fixups_->length_
299 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
302 do the stuff/note/rest preceding a grace.
304 iter_->process (iter_->music_length_mom ());
307 iter_->process (until - here_mom_ + iter_->music_start_mom ());
310 if the iter is still OK, there must be events left that have
324 Sequential_iterator::pending_moment () const
326 Moment cp = iter_->pending_moment ();
329 Fix-up a grace note halfway in the music.
331 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
332 && grace_fixups_->length_ + iter_->music_start_mom () == cp)
334 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
338 Fix-up a grace note at the start of the music.
340 return cp + here_mom_ - iter_->music_start_mom ();
345 Sequential_iterator::ok () const
351 Sequential_iterator::try_music_in_children (Music *m) const
353 return iter_ ? iter_->try_music (m) : 0;
356 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);