2 Sequential_iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2003 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->get_length () - 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)
179 Moment len =iter_->music_get_length () - 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 ()
224 Translator_group * child_report = child_report = iter_->report_to ();
225 Translator_group * me_report = report_to ();
227 Translator_group * c = child_report;
228 while (c && c != me_report)
234 set_translator (child_report);
239 Retrieve all music (starting at HERE), until a music with length L >
240 0 is found. From the precondition, we know that UNTIL is later than
241 the earliest event. Hence we know
245 so something that comes after this thing with L > 0 happens after
247 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
249 Hence all events after the one with L>0 are uninteresting, so we
255 Sequential_iterator::get_pending_events (Moment until) const
258 if (until < pending_moment ())
261 Sequential_iterator * me =
262 dynamic_cast<Sequential_iterator*> (clone ());
265 SCM nm = me->iter_->get_pending_events (until - me->here_mom_);
266 s = gh_append2 (nm, s);
269 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
271 Music *mus=unsmob_music (ly_car (i));
272 m = m >? (mus->get_length () - mus->start_mom ());
277 me->next_element (false);
280 scm_gc_unprotect_object (me->self_scm());
286 Skip events till UNTIL. We don't do any other side effects such as
287 descending to child iterator contexts, because they might depend on
288 \context specs and \translator changes being executed
291 Sequential_iterator::skip (Moment until)
296 grace_fixups_->start_ == here_mom_
297 && (grace_fixups_->start_ + grace_fixups_->length_
298 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
301 do the stuff/note/rest preceding a grace.
303 iter_->skip (iter_->music_get_length ());
305 else if (iter_->music_get_length () >= until - here_mom_)
306 iter_->skip (until - here_mom_ + iter_->music_start_mom ());
311 next_element (false);
316 Sequential_iterator::process (Moment until)
321 grace_fixups_->start_ == here_mom_
322 && (grace_fixups_->start_ + grace_fixups_->length_
323 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
326 do the stuff/note/rest preceding a grace.
328 iter_->process (iter_->music_get_length ());
331 iter_->process (until - here_mom_ + iter_->music_start_mom ());
334 if the iter is still OK, there must be events left that have
348 Sequential_iterator::pending_moment () const
350 Moment cp = iter_->pending_moment ();
353 Fix-up a grace note halfway in the music.
355 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
356 && grace_fixups_->length_ + iter_->music_start_mom () == cp)
358 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
362 Fix-up a grace note at the start of the music.
364 return cp + here_mom_ - iter_->music_start_mom ();
369 Sequential_iterator::ok () const
375 Sequential_iterator::try_music_in_children (Music *m) const
377 return iter_ ? iter_->try_music (m) : 0;
380 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);