(all-grob-descriptions): remove gap from
[lilypond.git] / lily / sequential-iterator.cc
blob9c88c4e88aa49e175da2763599e0aae5b4c2db27
1 /*
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>
7 */
9 #include "translator-group.hh"
10 #include "context.hh"
11 #include "sequential-iterator.hh"
12 #include "music-list.hh"
13 #include "grace-fixup.hh"
17 TODO: handling of grace notes is exquisite pain. This handling
18 should be formally specified and then the implementation verified.
23 Invariant for the data structure.
26 if (gh_pair_p (cursor_))
27 iter_->music_ == unsmob_music (ly_car (cursor_))
28 else
29 iter_ == 0;
31 The length of musiclist from start to up to cursor_ (cursor_ not
32 including), is summed
34 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
37 Sequential_iterator::Sequential_iterator ()
39 here_mom_ = Moment (0);
40 cursor_ = SCM_EOL;
41 grace_fixups_ = 0;
42 iter_ = 0;
45 SCM
46 Sequential_iterator::get_music_list () const
48 return SCM_EOL;
51 void
52 Sequential_iterator::do_quit ()
54 if (iter_)
55 iter_->quit ();
61 void
62 Sequential_iterator::derived_mark () const
64 if (iter_)
65 scm_gc_mark (iter_->self_scm ());
66 scm_gc_mark (cursor_);
70 void
71 Sequential_iterator::derived_substitute (Context *f, Context *t)
73 if (iter_)
74 iter_->substitute_outlet (f, t);
78 TODO: this should be made lazily.
80 Grace_fixup *
81 create_grace_fixup_list (SCM cursor)
83 Moment here;
84 Moment last (-1);
85 Grace_fixup *head = 0;
86 Grace_fixup **tail = &head;
88 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
90 Music *mus = unsmob_music (ly_car (cursor));
91 Moment s = mus->start_mom ();
92 Moment l = mus->get_length () - s;
94 if (s.grace_part_)
96 if (last != Moment (-1))
98 Grace_fixup *p = new Grace_fixup;
99 p->start_ = last;
100 p->length_ = here - last;
101 p->grace_start_ = s.grace_part_;
102 p->next_ = 0;
103 *tail = p;
104 tail = &(*tail)->next_;
107 here.grace_part_ = s.grace_part_;
110 if (l.to_bool ())
112 last = here;
113 here += l;
117 return head;
120 void
121 Sequential_iterator::construct_children ()
123 cursor_ = get_music_list ();
125 iter_ = 0;
126 if (gh_pair_p (cursor_))
128 Music *m = unsmob_music (ly_car (cursor_));
129 iter_ = unsmob_iterator (get_iterator (m));
132 while (iter_ && !iter_->ok ())
134 next_element (true);
137 last_mom_ = Moment (-1);
138 here_mom_ = get_music ()->start_mom ();
139 grace_fixups_ = create_grace_fixup_list (cursor_);
142 iter_->ok () is tautology, but what the heck.
144 if (iter_ && iter_->ok ())
145 descend_to_child (iter_->get_outlet ());
150 maintain invariants: change cursor, iter and here_mom_ in one fell
151 swoop.
153 void
154 Sequential_iterator::next_element (bool)
156 Moment len =iter_->music_get_length () - iter_->music_start_mom ();
157 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
159 if (len.main_part_
160 && get_grace_fixup ())
162 Grace_fixup *gf = get_grace_fixup ();
164 last_mom_ = here_mom_;
165 here_mom_ += gf->length_;
166 here_mom_.grace_part_ += gf->grace_start_;
168 next_grace_fixup ();
170 else if (len.grace_part_ && !len.main_part_)
172 last_mom_ = here_mom_;
173 here_mom_.grace_part_ =0;
175 else
178 !len.grace_part_ || len.main_part_
180 We skip over a big chunk (mainpart != 0). Any starting graces
181 in that chunk should be in len.grace_part_
184 last_mom_ = here_mom_;;
185 here_mom_ += len;
188 cursor_ = ly_cdr (cursor_);
190 iter_->quit ();
191 if (gh_pair_p (cursor_))
192 iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
193 else
194 iter_ = 0;
199 void
200 Sequential_iterator::process (Moment until)
202 while (iter_)
204 Grace_fixup * gf = get_grace_fixup ();
205 if (gf
206 && gf->start_ + gf->length_
207 + Moment (Rational (0), gf->grace_start_) == until)
210 do the stuff/note/rest preceding a grace.
212 iter_->process (iter_->music_get_length ());
214 else
216 Moment w = until - here_mom_ + iter_->music_start_mom ();
217 iter_->process (w);
221 if the iter is still OK, there must be events left that have
223 TIME > LEFT
226 if (iter_->ok ())
227 return ;
229 descend_to_child (iter_->get_outlet ());
230 next_element (true);
234 Moment
235 Sequential_iterator::pending_moment () const
237 Moment cp = iter_->pending_moment ();
240 Fix-up a grace note halfway in the music.
242 Grace_fixup * gf = get_grace_fixup ();
243 if (gf
244 && gf->length_ + iter_->music_start_mom () == cp)
246 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
250 Fix-up a grace note at the start of the music.
252 return cp + here_mom_ - iter_->music_start_mom ();
256 bool
257 Sequential_iterator::ok () const
259 return iter_;
262 Music_iterator*
263 Sequential_iterator::try_music_in_children (Music *m) const
265 return iter_ ? iter_->try_music (m) : 0;
268 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
270 bool
271 Sequential_iterator::run_always () const
273 return iter_ ? iter_->run_always () : false;
276 void
277 Sequential_iterator::next_grace_fixup ()
279 Grace_fixup * n = grace_fixups_->next_;
280 delete grace_fixups_;
281 grace_fixups_ = n;
284 Grace_fixup*
285 Sequential_iterator::get_grace_fixup () const
287 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
288 return grace_fixups_;
289 else
290 return 0;