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);
49 Sequential_iterator::get_music_list () const
55 Sequential_iterator::do_quit ()
62 Sequential_iterator::Sequential_iterator (Sequential_iterator const &src)
63 : Music_iterator (src)
65 grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
66 cursor_ = src.cursor_;
68 here_mom_ = src.here_mom_;
73 iter_ = src.iter_->clone ();
74 scm_gc_unprotect_object (iter_->self_scm());
79 Sequential_iterator::derived_mark ()const
82 scm_gc_mark (iter_->self_scm());
84 scm_gc_mark (cursor_);
89 get_grace_fixups (SCM cursor)
93 Grace_fixup *head = 0;
94 Grace_fixup **tail = &head;
96 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
98 Music * mus = unsmob_music (ly_car (cursor));
99 Moment s = mus->start_mom ();
100 Moment l =mus->length_mom () - s;
104 if (last != Moment (-1))
106 Grace_fixup *p =new Grace_fixup;
108 p->length_ = here - last;
109 p->grace_start_ = s.grace_part_;
112 tail = &(*tail)->next_;
115 here.grace_part_ = s.grace_part_;
128 copy_grace_fixups (Grace_fixup* src)
130 Grace_fixup * head = 0;
131 Grace_fixup **dest = &head;
135 *dest = new Grace_fixup (*src);
136 dest = & (*dest)->next_;
144 Sequential_iterator::construct_children ()
146 list_ = get_music_list ();
150 if (gh_pair_p (cursor_))
152 Music *m =unsmob_music (ly_car (cursor_));
153 iter_ = unsmob_iterator (get_iterator (m));
156 while (iter_ && !iter_->ok ())
161 here_mom_ = get_music ()->start_mom ();
162 grace_fixups_ = get_grace_fixups (cursor_);
165 iter_->ok () is tautology, but what the heck.
167 if (iter_ && iter_->ok ())
173 maintain invariants: change cursor, iter and here_mom_ in one fell
177 Sequential_iterator::next_element (bool side_effect)
179 Moment len =iter_->music_length_mom () - iter_->music_start_mom ();
180 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
182 if (len.main_part_ && grace_fixups_ &&
183 grace_fixups_->start_ == here_mom_)
185 here_mom_ += grace_fixups_->length_;
186 here_mom_.grace_part_ += grace_fixups_->grace_start_;
188 Grace_fixup * n =grace_fixups_->next_;
189 delete grace_fixups_;
192 else if (len.grace_part_ && !len.main_part_)
194 here_mom_.grace_part_ =0;
199 !len.grace_part_ || len.main_part_
201 We skip over a big chunk (mainpart != 0). Any starting graces
202 in that chunk should be in len.grace_part_
208 cursor_ = ly_cdr (cursor_);
211 if (gh_pair_p (cursor_))
212 iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
218 move to context of child iterator if it is deeper down in the
222 Sequential_iterator::descend_to_child ()
228 Retrieve all music (starting at HERE), until a music with length L >
229 0 is found. From the precondition, we know that UNTIL is later than
230 the earliest event. Hence we know
234 so something that comes after this thing with L > 0 happens after
236 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
238 Hence all events after the one with L>0 are uninteresting, so we
244 Sequential_iterator::get_pending_events (Moment until)const
247 if (until < pending_moment ())
250 Sequential_iterator * me =
251 dynamic_cast<Sequential_iterator*> (clone ());
254 SCM nm = me->iter_->get_pending_events (until - me->here_mom_);
255 s = gh_append2 (nm, s);
258 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
260 Music *mus=unsmob_music (ly_car (i));
261 m = m >? (mus->length_mom () - mus->start_mom ());
266 me->next_element (false);
269 scm_gc_unprotect_object (me->self_scm());
275 Skip events till UNTIL. We don't do any other side effects such as
276 descending to child iterator contexts, because they might depend on
277 \context specs and \translator changes being executed
280 Sequential_iterator::skip (Moment until)
285 grace_fixups_->start_ == here_mom_
286 && (grace_fixups_->start_ + grace_fixups_->length_
287 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
290 do the stuff/note/rest preceding a grace.
292 iter_->skip (iter_->music_length_mom ());
294 else if (iter_->music_length_mom () >= until - here_mom_)
295 iter_->skip (until - here_mom_ + iter_->music_start_mom ());
300 next_element (false);
305 Sequential_iterator::process (Moment until)
310 grace_fixups_->start_ == here_mom_
311 && (grace_fixups_->start_ + grace_fixups_->length_
312 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
315 do the stuff/note/rest preceding a grace.
317 iter_->process (iter_->music_length_mom ());
320 iter_->process (until - here_mom_ + iter_->music_start_mom ());
323 if the iter is still OK, there must be events left that have
337 Sequential_iterator::pending_moment () const
339 Moment cp = iter_->pending_moment ();
342 Fix-up a grace note halfway in the music.
344 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
345 && grace_fixups_->length_ + iter_->music_start_mom () == cp)
347 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
351 Fix-up a grace note at the start of the music.
353 return cp + here_mom_ - iter_->music_start_mom ();
358 Sequential_iterator::ok () const
364 Sequential_iterator::try_music_in_children (Music *m) const
366 return iter_ ? iter_->try_music (m) : 0;
369 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);