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_;
71 here_mom_ = src.here_mom_;
73 iter_p_ = src.iter_p_->clone ();
78 Sequential_iterator::~Sequential_iterator ()
85 get_grace_fixups (SCM cursor)
89 Grace_fixup *head = 0;
90 Grace_fixup **tail = &head;
92 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
94 Music * mus = unsmob_music (ly_car (cursor));
95 Moment s = mus->start_mom ();
96 Moment l =mus->length_mom () - s;
100 if (last != Moment (-1))
102 Grace_fixup *p =new Grace_fixup;
104 p->length_ = here - last;
105 p->grace_start_ = s.grace_part_;
108 tail = &(*tail)->next_;
111 here.grace_part_ = s.grace_part_;
124 copy_grace_fixups (Grace_fixup* src)
126 Grace_fixup * head = 0;
127 Grace_fixup **dest = &head;
131 *dest = new Grace_fixup (*src);
132 dest = & (*dest)->next_;
140 Sequential_iterator::construct_children ()
142 cursor_ = get_music_list ();
144 iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
145 while (iter_p_ && !iter_p_->ok ())
150 here_mom_ = music_l ()->start_mom ();
151 grace_fixups_ = get_grace_fixups (cursor_);
154 iter_p_->ok () is tautology, but what the heck.
156 if (iter_p_ && iter_p_->ok ())
162 maintain invariants: change cursor, iter and here_mom_ in one fell
166 Sequential_iterator::next_element (bool side_effect)
168 Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
169 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
171 if (len.main_part_ && grace_fixups_ &&
172 grace_fixups_->start_ == here_mom_)
174 here_mom_ += grace_fixups_->length_;
175 here_mom_.grace_part_ += grace_fixups_->grace_start_;
177 Grace_fixup * n =grace_fixups_->next_;
178 delete grace_fixups_;
181 else if (len.grace_part_ && !len.main_part_)
183 here_mom_.grace_part_ =0;
188 !len.grace_part_ || len.main_part_
190 We skip over a big chunk (mainpart != 0). Any starting graces
191 in that chunk should be in len.grace_part_
198 cursor_ = ly_cdr (cursor_);
200 if (gh_pair_p (cursor_))
201 iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
207 move to context of child iterator if it is deeper down in the
211 Sequential_iterator::descend_to_child ()
217 Retrieve all music (starting at HERE), until a music with length L >
218 0 is found. From the precondition, we know that UNTIL is later than
219 the earliest event. Hence we know
223 so something that comes after this thing with L > 0 happens after
225 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
227 Hence all events after the one with L>0 are uninteresting, so we
233 Sequential_iterator::get_music (Moment until)const
236 if (until < pending_moment ())
239 Sequential_iterator * me =
240 dynamic_cast<Sequential_iterator*> (clone ());
243 SCM nm = me->iter_p_->get_music (until - me->here_mom_);
244 s = gh_append2 (nm, s);
247 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
249 Music *mus=unsmob_music (ly_car (i));
250 m = m >? (mus->length_mom () - mus->start_mom ());
255 me->next_element (false);
264 Skip events till UNTIL. We don't do any other side effects such as
265 descending to child iterator contexts, because they might depend on
266 \context specs and \translator changes being executed
268 TODO: check support for grace notes here.
271 Sequential_iterator::skip (Moment until)
276 grace_fixups_->start_ == here_mom_
277 && (grace_fixups_->start_ + grace_fixups_->length_
278 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
281 do the stuff/note/rest preceding a grace.
283 iter_p_->skip (iter_p_->music_length_mom ());
285 else if (iter_p_->music_length_mom () >= until - here_mom_)
286 iter_p_->skip (until - here_mom_ + iter_p_->music_start_mom ());
291 next_element (false);
296 Sequential_iterator::process (Moment until)
301 grace_fixups_->start_ == here_mom_
302 && (grace_fixups_->start_ + grace_fixups_->length_
303 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
306 do the stuff/note/rest preceding a grace.
308 iter_p_->process (iter_p_->music_length_mom ());
311 iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
314 if the iter is still OK, there must be events left that have
328 Sequential_iterator::pending_moment () const
330 Moment cp = iter_p_->pending_moment ();
333 Fix-up a grace note halfway in the music.
335 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
336 && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
338 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
342 Fix-up a grace note at the start of the music.
344 return cp + here_mom_ - iter_p_->music_start_mom ();
349 Sequential_iterator::ok () const
355 Sequential_iterator::try_music_in_children (Music *m) const
357 return iter_p_ ? iter_p_->try_music (m) : 0;
360 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);