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.
26 TODO: the grace note handling hasn't been done for skip() and
27 get_music(), meaning that staff-switching and partcombining will be
28 broken with grace notes.
33 TODO: the grace note handling hasn't been done for skip() and
34 get_music(), meaning that staff-switching and partcombining will be
35 broken with grace notes.
39 Invariant for the data structure.
42 if (gh_pair_p (cursor_))
43 iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
47 The length of musiclist from start to up to cursor_ (cursor_ not
50 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
53 Sequential_iterator::Sequential_iterator ()
55 here_mom_ = Moment (0);
61 Sequential_iterator::get_music_list () const
66 Sequential_iterator::Sequential_iterator (Sequential_iterator const &src)
67 : Music_iterator (src)
69 grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
70 cursor_ = src.cursor_;
72 here_mom_ = src.here_mom_;
74 iter_p_ = src.iter_p_->clone ();
79 Sequential_iterator::~Sequential_iterator ()
86 get_grace_fixups (SCM cursor)
90 Grace_fixup *head = 0;
91 Grace_fixup **tail = &head;
93 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
95 Music * mus = unsmob_music (ly_car (cursor));
96 Moment s = mus->start_mom ();
97 Moment l =mus->length_mom () - s;
101 if (last != Moment (-1))
103 Grace_fixup *p =new Grace_fixup;
105 p->length_ = here - last;
106 p->grace_start_ = s.grace_part_;
109 tail = &(*tail)->next_;
112 here.grace_part_ = s.grace_part_;
125 copy_grace_fixups (Grace_fixup* src)
127 Grace_fixup * head = 0;
128 Grace_fixup **dest = &head;
132 *dest = new Grace_fixup (*src);
133 dest = & (*dest)->next_;
141 Sequential_iterator::construct_children ()
143 list_ = get_music_list ();
146 iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
147 while (iter_p_ && !iter_p_->ok ())
152 here_mom_ = music_l ()->start_mom ();
153 grace_fixups_ = get_grace_fixups (cursor_);
156 iter_p_->ok () is tautology, but what the heck.
158 if (iter_p_ && iter_p_->ok ())
164 maintain invariants: change cursor, iter and here_mom_ in one fell
168 Sequential_iterator::next_element (bool side_effect)
170 Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
171 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
173 if (len.main_part_ && grace_fixups_ &&
174 grace_fixups_->start_ == here_mom_)
176 here_mom_ += grace_fixups_->length_;
177 here_mom_.grace_part_ += grace_fixups_->grace_start_;
179 Grace_fixup * n =grace_fixups_->next_;
180 delete grace_fixups_;
183 else if (len.grace_part_ && !len.main_part_)
185 here_mom_.grace_part_ =0;
190 !len.grace_part_ || len.main_part_
192 We skip over a big chunk (mainpart != 0). Any starting graces
193 in that chunk should be in len.grace_part_
200 cursor_ = ly_cdr (cursor_);
202 if (gh_pair_p (cursor_))
203 iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
209 move to context of child iterator if it is deeper down in the
213 Sequential_iterator::descend_to_child ()
219 Retrieve all music (starting at HERE), until a music with length L >
220 0 is found. From the precondition, we know that UNTIL is later than
221 the earliest event. Hence we know
225 so something that comes after this thing with L > 0 happens after
227 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
229 Hence all events after the one with L>0 are uninteresting, so we
235 Sequential_iterator::get_music (Moment until)const
238 if (until < pending_moment ())
241 Sequential_iterator * me =
242 dynamic_cast<Sequential_iterator*> (clone ());
245 SCM nm = me->iter_p_->get_music (until - me->here_mom_);
246 s = gh_append2 (nm, s);
249 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
251 Music *mus=unsmob_music (ly_car (i));
252 m = m >? (mus->length_mom () - mus->start_mom ());
257 me->next_element (false);
266 Skip events till UNTIL. We don't do any other side effects such as
267 descending to child iterator contexts, because they might depend on
268 \context specs and \translator changes being executed
270 TODO: check support for grace notes here.
273 Sequential_iterator::skip (Moment until)
278 grace_fixups_->start_ == here_mom_
279 && (grace_fixups_->start_ + grace_fixups_->length_
280 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
283 do the stuff/note/rest preceding a grace.
285 iter_p_->skip (iter_p_->music_length_mom ());
287 else if (iter_p_->music_length_mom () >= until - here_mom_)
288 iter_p_->skip (until - here_mom_ + iter_p_->music_start_mom ());
293 next_element (false);
298 Sequential_iterator::process (Moment until)
303 grace_fixups_->start_ == here_mom_
304 && (grace_fixups_->start_ + grace_fixups_->length_
305 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
308 do the stuff/note/rest preceding a grace.
310 iter_p_->process (iter_p_->music_length_mom ());
313 iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
316 if the iter is still OK, there must be events left that have
330 Sequential_iterator::pending_moment () const
332 Moment cp = iter_p_->pending_moment ();
335 Fix-up a grace note halfway in the music.
337 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
338 && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
340 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
344 Fix-up a grace note at the start of the music.
346 return cp + here_mom_ - iter_p_->music_start_mom ();
351 Sequential_iterator::ok () const
357 Sequential_iterator::try_music_in_children (Music *m) const
359 return iter_p_ ? iter_p_->try_music (m) : 0;
362 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);