2 Sequential_music_iterator.cc -- implement Sequential_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "translator-group.hh"
11 #include "sequential-music-iterator.hh"
12 #include "music-list.hh"
17 TODO: handling of grace notes is excuisite pain. This handling
18 should be formally specified and then the implementation verified.
24 TODO: the grace note handling hasn't been done for skip() and
25 get_music(), meaning that staff-switching and partcombining will be
26 broken with grace notes.
31 TODO: the grace note handling hasn't been done for skip() and
32 get_music(), meaning that staff-switching and partcombining will be
33 broken with grace notes.
37 Invariant for the data structure.
40 if (gh_pair_p (cursor_))
41 iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
45 The length of musiclist from start to up to cursor_ (cursor_ not
48 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
51 Sequential_music_iterator::Sequential_music_iterator ()
54 here_mom_ = Moment (0);
59 Sequential_music_iterator::Sequential_music_iterator (Sequential_music_iterator const &src)
60 : Music_iterator (src)
62 grace_fixups_ = src.grace_fixups_;
63 cursor_ = src.cursor_;
64 here_mom_ = src.here_mom_;
66 iter_p_ = src.iter_p_->clone ();
71 Sequential_music_iterator::~Sequential_music_iterator ()
80 if (start_music.grace)
81 here.grace -= start_music.grace
89 get_grace_fixups (SCM cursor)
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->length_mom () - s;
104 if (last != Moment (-1))
106 Grace_fixup *p =new Grace_fixup;
108 p->length_ = here - last;
109 p->grace_start_ = s.grace_part_;
112 tail = &(*tail)->next_;
115 here.grace_part_ = s.grace_part_;
128 Sequential_music_iterator::construct_children ()
130 cursor_ = dynamic_cast<Music_sequence const*> (music_l ())->music_list ();
132 iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
133 while (iter_p_ && !iter_p_->ok ())
138 here_mom_ = music_l ()->start_mom ();
139 grace_fixups_ = get_grace_fixups (cursor_);
142 iter_p_->ok () is tautology, but what the heck.
144 if (iter_p_ && iter_p_->ok ())
150 maintain invariants: change cursor, iter and here_mom_ in one fell
154 Sequential_music_iterator::next_element ()
156 Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
157 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
159 if (len.main_part_ && grace_fixups_ &&
160 grace_fixups_->start_ == here_mom_)
162 here_mom_ += grace_fixups_->length_;
163 here_mom_.grace_part_ += grace_fixups_->grace_start_;
165 Grace_fixup * n =grace_fixups_->next_;
166 delete grace_fixups_;
169 else if (len.grace_part_ && !len.main_part_)
171 here_mom_.grace_part_ =0;
176 !len.grace_part_ || len.main_part_
178 We skip over a big chunk (mainpart != 0). Any starting graces
179 in that chunk should be in len.grace_part_
186 cursor_ = ly_cdr (cursor_);
188 if (gh_pair_p (cursor_))
189 iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
195 move to context of child iterator if it is deeper down in the
199 Sequential_music_iterator::descend_to_child ()
201 Translator_group * child_report = child_report = iter_p_->report_to_l ();
202 Translator_group * me_report = report_to_l ();
204 Translator_group * c = child_report;
205 while (c && c != me_report)
207 c= c->daddy_trans_l_;
211 set_translator (child_report);
216 Retrieve all music (starting at HERE), until a music with length L >
217 0 is found. From the precondition, we know that UNTIL is later than
218 the earliest event. Hence we know
222 so something that comes after this thing with L > 0 happens after
224 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
226 Hence all events after the one with L>0 are uninteresting, so we
232 Sequential_music_iterator::get_music (Moment until)const
235 if (until < pending_moment ())
238 Sequential_music_iterator * me =
239 dynamic_cast<Sequential_music_iterator*> (clone ());
242 SCM nm = me->iter_p_->get_music (until - me->here_mom_);
243 s = gh_append2 (nm, s);
246 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
248 Music *mus=unsmob_music (ly_car (i));
249 m = m >? (mus->length_mom () - mus->start_mom ());
263 Skip events till UNTIL. We don't do any other side effects such as
264 descending to child iterator contexts, because they might depend on
265 \context specs and \translator changes being executed
266 TODO: build support for grace notes here.
269 Sequential_music_iterator::skip (Moment until)
273 Moment l =iter_p_->music_length_mom ();
274 if (l >= until - here_mom_)
275 iter_p_->skip (until - here_mom_);
285 Sequential_music_iterator::process (Moment until)
290 grace_fixups_->start_ == here_mom_
291 && (grace_fixups_->start_ + grace_fixups_->length_
292 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
295 do the stuff/note/rest preceding a grace.
297 iter_p_->process (iter_p_->music_length_mom ());
300 iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
303 if the iter is still OK, there must be events left that have
317 Sequential_music_iterator::pending_moment () const
319 Moment cp = iter_p_->pending_moment ();
322 Fix-up a grace note halfway in the music.
324 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
325 && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
327 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
331 Fix-up a grace note at the start of the music.
333 return cp + here_mom_ - iter_p_->music_start_mom ();
338 Sequential_music_iterator::ok () const
344 Sequential_music_iterator::try_music_in_children (Music *m) const
346 return iter_p_ ? iter_p_->try_music (m) : 0;
348 IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);