2 Sequential_iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "sequential-iterator.hh"
11 #include "translator-group.hh"
13 #include "music-list.hh"
14 #include "grace-fixup.hh"
18 TODO: handling of grace notes is exquisite pain. This handling
19 should be formally specified and then the implementation verified.
24 Invariant for the data structure.
27 if (scm_is_pair (cursor_))
28 iter_->music_ == unsmob_music (scm_car (cursor_))
32 The length of musiclist from start to up to cursor_ (cursor_ not
35 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
38 Sequential_iterator::Sequential_iterator ()
40 here_mom_ = Moment (0);
47 Sequential_iterator::get_music_list () const
53 Sequential_iterator::do_quit ()
63 Sequential_iterator::derived_mark () const
66 scm_gc_mark (iter_->self_scm ());
67 scm_gc_mark (cursor_);
72 Sequential_iterator::derived_substitute (Context *f, Context *t)
75 iter_->substitute_outlet (f, t);
79 TODO: this should be made lazily.
82 create_grace_fixup_list (SCM cursor)
86 Grace_fixup *head = 0;
87 Grace_fixup **tail = &head;
89 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
91 Music *mus = unsmob_music (scm_car (cursor));
92 Moment s = mus->start_mom ();
93 Moment l = mus->get_length () - s;
97 if (last != Moment (-1))
99 Grace_fixup *p = new Grace_fixup;
101 p->length_ = here - last;
102 p->grace_start_ = s.grace_part_;
105 tail = &(*tail)->next_;
108 here.grace_part_ = s.grace_part_;
122 Sequential_iterator::construct_children ()
124 cursor_ = get_music_list ();
127 if (scm_is_pair (cursor_))
129 Music *m = unsmob_music (scm_car (cursor_));
130 iter_ = unsmob_iterator (get_iterator (m));
133 while (iter_ && !iter_->ok ())
138 last_mom_ = Moment (-1);
139 here_mom_ = get_music ()->start_mom ();
140 grace_fixups_ = create_grace_fixup_list (cursor_);
143 iter_->ok () is tautology, but what the heck.
145 if (iter_ && iter_->ok ())
146 descend_to_child (iter_->get_outlet ());
151 maintain invariants: change cursor, iter and here_mom_ in one fell
155 Sequential_iterator::next_element (bool)
157 Moment len = iter_->music_get_length () - iter_->music_start_mom ();
158 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
161 && get_grace_fixup ())
163 Grace_fixup *gf = get_grace_fixup ();
165 last_mom_ = here_mom_;
166 here_mom_ += gf->length_;
167 here_mom_.grace_part_ += gf->grace_start_;
171 else if (len.grace_part_ && !len.main_part_)
173 last_mom_ = here_mom_;
174 here_mom_.grace_part_ = 0;
179 !len.grace_part_ || len.main_part_
181 We skip over a big chunk (mainpart != 0). Any starting graces
182 in that chunk should be in len.grace_part_
185 last_mom_ = here_mom_;;
189 cursor_ = scm_cdr (cursor_);
192 if (scm_is_pair (cursor_))
193 iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
201 Sequential_iterator::process (Moment until)
205 Grace_fixup * gf = get_grace_fixup ();
207 && gf->start_ + gf->length_
208 + Moment (Rational (0), gf->grace_start_) == until)
211 do the stuff/note/rest preceding a grace.
213 iter_->process (iter_->music_get_length ());
217 Moment w = until - here_mom_ + iter_->music_start_mom ();
222 if the iter is still OK, there must be events left that have
230 descend_to_child (iter_->get_outlet ());
236 Sequential_iterator::pending_moment () const
238 Moment cp = iter_->pending_moment ();
241 Fix-up a grace note halfway in the music.
243 Grace_fixup * gf = get_grace_fixup ();
245 && gf->length_ + iter_->music_start_mom () == cp)
247 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
251 Fix-up a grace note at the start of the music.
253 return cp + here_mom_ - iter_->music_start_mom ();
258 Sequential_iterator::ok () const
264 Sequential_iterator::try_music_in_children (Music *m) const
266 return iter_ ? iter_->try_music (m) : 0;
269 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
272 Sequential_iterator::run_always () const
274 return iter_ ? iter_->run_always () : false;
278 Sequential_iterator::next_grace_fixup ()
280 Grace_fixup * n = grace_fixups_->next_;
281 delete grace_fixups_;
286 Sequential_iterator::get_grace_fixup () const
288 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
289 return grace_fixups_;