2002->2003
[lilypond.git] / lily / sequential-iterator.cc
blob0658853a122a0d14c86879bed50a3d89db8cffff
1 /*
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>
7 */
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_))
30 else
31 iter_ == 0;
33 The length of musiclist from start to up to cursor_ (cursor_ not
34 including), is summed
36 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
39 Sequential_iterator::Sequential_iterator ()
41 here_mom_ = Moment (0);
42 list_ = SCM_EOL;
43 cursor_ = SCM_EOL;
44 grace_fixups_ = 0;
45 iter_ =0;
48 SCM
49 Sequential_iterator::get_music_list () const
51 return SCM_EOL;
54 void
55 Sequential_iterator::do_quit ()
57 if (iter_)
58 iter_->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_;
67 list_ = src.cursor_;
68 here_mom_ = src.here_mom_;
69 iter_ = 0;
71 if (src.iter_)
73 iter_ = src.iter_->clone ();
74 scm_gc_unprotect_object (iter_->self_scm());
78 void
79 Sequential_iterator::derived_mark ()const
81 if (iter_)
82 scm_gc_mark (iter_->self_scm());
83 scm_gc_mark (list_);
84 scm_gc_mark (cursor_);
88 Grace_fixup *
89 get_grace_fixups (SCM cursor)
91 Moment here;
92 Moment last (-1);
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;
102 if (s.grace_part_)
104 if (last != Moment (-1))
106 Grace_fixup *p =new Grace_fixup;
107 p->start_ = last;
108 p->length_ = here - last;
109 p->grace_start_ = s.grace_part_;
110 p->next_ = 0;
111 *tail = p;
112 tail = &(*tail)->next_;
115 here.grace_part_ = s.grace_part_;
118 if (l.to_bool())
120 last = here;
121 here += l;
124 return head;
127 Grace_fixup *
128 copy_grace_fixups (Grace_fixup* src)
130 Grace_fixup * head = 0;
131 Grace_fixup **dest = &head;
133 while (src)
135 *dest = new Grace_fixup (*src);
136 dest = & (*dest)->next_;
137 src = src ->next_;
140 return head;
143 void
144 Sequential_iterator::construct_children ()
146 list_ = get_music_list ();
147 cursor_ = list_;
149 iter_ = 0;
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 ())
158 next_element (true);
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 ())
168 descend_to_child ();
173 maintain invariants: change cursor, iter and here_mom_ in one fell
174 swoop.
176 void
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_;
190 grace_fixups_ = n;
192 else if (len.grace_part_ && !len.main_part_)
194 here_mom_.grace_part_ =0;
196 else
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_
205 here_mom_ += len;
208 cursor_ = ly_cdr (cursor_);
210 iter_->quit();
211 if (gh_pair_p (cursor_))
212 iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
213 else
214 iter_ = 0;
218 move to context of child iterator if it is deeper down in the
219 hierarchy.
221 void
222 Sequential_iterator::descend_to_child ()
228 Retrieve all music (starting at HERE), until a music with length L >
229 0 is found. From the precondition, we know that UNTIL is later than
230 the earliest event. Hence we know
232 L >= (UNTIL - HERE)
234 so something that comes after this thing with L > 0 happens after
236 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
238 Hence all events after the one with L>0 are uninteresting, so we
239 ignore them.
244 Sequential_iterator::get_pending_events (Moment until)const
246 SCM s = SCM_EOL;
247 if (until < pending_moment ())
248 return s;
250 Sequential_iterator * me =
251 dynamic_cast<Sequential_iterator*> (clone ());
252 while (me->ok ())
254 SCM nm = me->iter_->get_pending_events (until - me->here_mom_);
255 s = gh_append2 (nm, s);
257 Moment m = 0;
258 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
260 Music *mus=unsmob_music (ly_car (i));
261 m = m >? (mus->get_length () - mus->start_mom ());
263 if (m > Moment (0))
264 break ;
265 else
266 me->next_element (false);
269 scm_gc_unprotect_object (me->self_scm());
270 return s;
275 Skip events till UNTIL. We don't do any other side effects such as
276 descending to child iterator contexts, because they might depend on
277 \context specs and \translator changes being executed
279 void
280 Sequential_iterator::skip (Moment until)
282 while (ok ())
284 if (grace_fixups_ &&
285 grace_fixups_->start_ == here_mom_
286 && (grace_fixups_->start_ + grace_fixups_->length_
287 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
290 do the stuff/note/rest preceding a grace.
292 iter_->skip (iter_->music_get_length ());
294 else if (iter_->music_get_length () >= until - here_mom_)
295 iter_->skip (until - here_mom_ + iter_->music_start_mom ());
297 if (iter_->ok ())
298 return ;
300 next_element (false);
304 void
305 Sequential_iterator::process (Moment until)
307 while (iter_)
309 if (grace_fixups_ &&
310 grace_fixups_->start_ == here_mom_
311 && (grace_fixups_->start_ + grace_fixups_->length_
312 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
315 do the stuff/note/rest preceding a grace.
317 iter_->process (iter_->music_get_length ());
319 else
320 iter_->process (until - here_mom_ + iter_->music_start_mom ());
323 if the iter is still OK, there must be events left that have
325 TIME > LEFT
328 if (iter_->ok ())
329 return ;
331 descend_to_child ();
332 next_element (true);
336 Moment
337 Sequential_iterator::pending_moment () const
339 Moment cp = iter_->pending_moment ();
342 Fix-up a grace note halfway in the music.
344 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
345 && grace_fixups_->length_ + iter_->music_start_mom () == cp)
347 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
351 Fix-up a grace note at the start of the music.
353 return cp + here_mom_ - iter_->music_start_mom ();
357 bool
358 Sequential_iterator::ok () const
360 return iter_;
363 Music_iterator*
364 Sequential_iterator::try_music_in_children (Music *m) const
366 return iter_ ? iter_->try_music (m) : 0;
369 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);