* The grand 2005-2006 replace.
[lilypond/patrick.git] / lily / sequential-iterator.cc
blob76b97efc39a3eb7e98fd87cadd70a06de229de36
1 /*
2 sequential-iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2006 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "sequential-iterator.hh"
10 #include "music.hh"
11 #include "translator-group.hh"
12 #include "context.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_))
26 else
27 iter_ == 0;
29 The length of musiclist from start to up to cursor_ (cursor_ not
30 including), is summed
32 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
34 Sequential_iterator::Sequential_iterator ()
36 here_mom_ = Moment (0);
37 cursor_ = SCM_EOL;
38 grace_fixups_ = 0;
39 iter_ = 0;
42 SCM
43 Sequential_iterator::get_music_list () const
45 return SCM_EOL;
48 void
49 Sequential_iterator::do_quit ()
51 if (iter_)
52 iter_->quit ();
55 void
56 Sequential_iterator::derived_mark () const
58 if (iter_)
59 scm_gc_mark (iter_->self_scm ());
60 scm_gc_mark (cursor_);
63 void
64 Sequential_iterator::derived_substitute (Context *f, Context *t)
66 if (iter_)
67 iter_->substitute_outlet (f, t);
71 TODO: this should be made lazily.
73 Grace_fixup *
74 create_grace_fixup_list (SCM cursor)
76 Moment here;
77 Moment last (-1);
78 Grace_fixup *head = 0;
79 Grace_fixup **tail = &head;
81 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
83 Music *mus = unsmob_music (scm_car (cursor));
84 Moment s = mus->start_mom ();
85 Moment l = mus->get_length () - s;
87 if (s.grace_part_)
89 if (last != Moment (-1))
91 Grace_fixup *p = new Grace_fixup;
92 p->start_ = last;
93 p->length_ = here - last;
94 p->grace_start_ = s.grace_part_;
95 p->next_ = 0;
96 *tail = p;
97 tail = &(*tail)->next_;
100 here.grace_part_ = s.grace_part_;
103 if (l.to_bool ())
105 last = here;
106 here += l;
110 return head;
113 void
114 Sequential_iterator::construct_children ()
116 cursor_ = get_music_list ();
118 iter_ = 0;
119 if (scm_is_pair (cursor_))
121 Music *m = unsmob_music (scm_car (cursor_));
122 iter_ = unsmob_iterator (get_iterator (m));
125 while (iter_ && !iter_->ok ())
126 next_element (true);
128 last_mom_ = Moment (-1);
129 here_mom_ = get_music ()->start_mom ();
130 grace_fixups_ = create_grace_fixup_list (cursor_);
133 iter_->ok () is tautology, but what the heck.
135 if (iter_ && iter_->ok ())
136 descend_to_child (iter_->get_outlet ());
140 maintain invariants: change cursor, iter and here_mom_ in one fell
141 swoop.
143 void
144 Sequential_iterator::next_element (bool)
146 Moment len = iter_->music_get_length () - iter_->music_start_mom ();
147 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
149 if (len.main_part_
150 && get_grace_fixup ())
152 Grace_fixup *gf = get_grace_fixup ();
154 last_mom_ = here_mom_;
155 here_mom_ += gf->length_;
156 here_mom_.grace_part_ += gf->grace_start_;
158 next_grace_fixup ();
160 else if (len.grace_part_ && !len.main_part_)
162 last_mom_ = here_mom_;
163 here_mom_.grace_part_ = 0;
165 else
168 !len.grace_part_ || len.main_part_
170 We skip over a big chunk (mainpart != 0). Any starting graces
171 in that chunk should be in len.grace_part_
174 last_mom_ = here_mom_;;
175 here_mom_ += len;
178 cursor_ = scm_cdr (cursor_);
180 iter_->quit ();
181 if (scm_is_pair (cursor_))
182 iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
183 else
184 iter_ = 0;
187 void
188 Sequential_iterator::process (Moment until)
190 while (iter_)
192 Grace_fixup *gf = get_grace_fixup ();
193 if (gf
194 && gf->start_ + gf->length_
195 + Moment (Rational (0), gf->grace_start_) == until)
198 do the stuff/note/rest preceding a grace.
200 iter_->process (iter_->music_get_length ());
202 else
204 Moment w = until - here_mom_ + iter_->music_start_mom ();
205 iter_->process (w);
209 if the iter is still OK, there must be events left that have
211 TIME > LEFT
214 if (iter_->ok ())
215 return;
217 descend_to_child (iter_->get_outlet ());
218 next_element (true);
222 Moment
223 Sequential_iterator::pending_moment () const
225 Moment cp = iter_->pending_moment ();
228 Fix-up a grace note halfway in the music.
230 Grace_fixup *gf = get_grace_fixup ();
231 if (gf
232 && gf->length_ + iter_->music_start_mom () == cp)
233 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
236 Fix-up a grace note at the start of the music.
238 return cp + here_mom_ - iter_->music_start_mom ();
241 bool
242 Sequential_iterator::ok () const
244 return iter_;
247 Music_iterator *
248 Sequential_iterator::try_music_in_children (Music *m) const
250 return iter_ ? iter_->try_music (m) : 0;
253 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
255 bool
256 Sequential_iterator::run_always () const
258 return iter_ ? iter_->run_always () : false;
261 void
262 Sequential_iterator::next_grace_fixup ()
264 Grace_fixup *n = grace_fixups_->next_;
265 delete grace_fixups_;
266 grace_fixups_ = n;
269 Grace_fixup *
270 Sequential_iterator::get_grace_fixup () const
272 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
273 return grace_fixups_;
274 else
275 return 0;