2 sequential-iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "sequential-iterator.hh"
11 #include "translator-group.hh"
13 #include "grace-fixup.hh"
16 TODO: handling of grace notes is exquisite pain. This handling
17 should be formally specified and then the implementation verified.
21 Invariant for the data structure.
24 if (scm_is_pair (cursor_))
25 iter_->music_ == unsmob_music (scm_car (cursor_))
29 The length of musiclist from start to up to cursor_ (cursor_ not
32 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
34 Sequential_iterator::Sequential_iterator ()
36 here_mom_ = Moment (0);
43 Sequential_iterator::get_music_list () const
49 Sequential_iterator::do_quit ()
57 Sequential_iterator::derived_mark () const
60 scm_gc_mark (iter_->self_scm ());
61 scm_gc_mark (cursor_);
65 Sequential_iterator::derived_substitute (Context *f, Context *t)
68 iter_->substitute_outlet (f, t);
72 TODO: this should be made lazily.
75 create_grace_fixup_list (SCM cursor)
79 Grace_fixup *head = 0;
80 Grace_fixup **tail = &head;
82 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
84 Music *mus = unsmob_music (scm_car (cursor));
85 Moment s = mus->start_mom ();
86 Moment l = mus->get_length () - s;
90 if (last != Moment (-1))
92 Grace_fixup *p = new Grace_fixup;
94 p->length_ = here - last;
95 p->grace_start_ = s.grace_part_;
98 tail = &(*tail)->next_;
101 here.grace_part_ = s.grace_part_;
115 Sequential_iterator::construct_children ()
117 cursor_ = get_music_list ();
120 if (scm_is_pair (cursor_))
122 Music *m = unsmob_music (scm_car (cursor_));
123 iter_ = unsmob_iterator (get_iterator (m));
126 while (iter_ && !iter_->ok ())
131 last_mom_ = Moment (-1);
132 here_mom_ = get_music ()->start_mom ();
133 grace_fixups_ = create_grace_fixup_list (cursor_);
136 iter_->ok () is tautology, but what the heck.
138 if (iter_ && iter_->ok ())
139 descend_to_child (iter_->get_outlet ());
143 maintain invariants: change cursor, iter and here_mom_ in one fell
147 Sequential_iterator::next_element (bool)
149 Moment len = iter_->music_get_length () - iter_->music_start_mom ();
150 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
153 && get_grace_fixup ())
155 Grace_fixup *gf = get_grace_fixup ();
157 last_mom_ = here_mom_;
158 here_mom_ += gf->length_;
159 here_mom_.grace_part_ += gf->grace_start_;
163 else if (len.grace_part_ && !len.main_part_)
165 last_mom_ = here_mom_;
166 here_mom_.grace_part_ = 0;
171 !len.grace_part_ || len.main_part_
173 We skip over a big chunk (mainpart != 0). Any starting graces
174 in that chunk should be in len.grace_part_
177 last_mom_ = here_mom_;;
181 cursor_ = scm_cdr (cursor_);
184 if (scm_is_pair (cursor_))
185 iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
191 Sequential_iterator::process (Moment until)
195 Grace_fixup *gf = get_grace_fixup ();
197 && gf->start_ + gf->length_
198 + Moment (Rational (0), gf->grace_start_) == until)
201 do the stuff/note/rest preceding a grace.
203 iter_->process (iter_->music_get_length ());
207 Moment w = until - here_mom_ + iter_->music_start_mom ();
212 if the iter is still OK, there must be events left that have
220 descend_to_child (iter_->get_outlet ());
226 Sequential_iterator::pending_moment () const
228 Moment cp = iter_->pending_moment ();
231 Fix-up a grace note halfway in the music.
233 Grace_fixup *gf = get_grace_fixup ();
235 && gf->length_ + iter_->music_start_mom () == cp)
237 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
241 Fix-up a grace note at the start of the music.
243 return cp + here_mom_ - iter_->music_start_mom ();
247 Sequential_iterator::ok () const
253 Sequential_iterator::try_music_in_children (Music *m) const
255 return iter_ ? iter_->try_music (m) : 0;
258 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
261 Sequential_iterator::run_always () const
263 return iter_ ? iter_->run_always () : false;
267 Sequential_iterator::next_grace_fixup ()
269 Grace_fixup *n = grace_fixups_->next_;
270 delete grace_fixups_;
275 Sequential_iterator::get_grace_fixup () const
277 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
278 return grace_fixups_;