2 Sequential_music_iterator.cc -- implement Sequential_music_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
9 #include "translator-group.hh"
11 #include "sequential-music-iterator.hh"
12 #include "music-list.hh"
13 #include "request-chord-iterator.hh"
18 TODO: handling of grace notes is excuisite pain. This handling
19 should be formally specified and then the implementation verified.
25 TODO: the grace note handling hasn't been done for skip() and
26 get_music(), meaning that staff-switching and partcombining will be
27 broken with grace notes.
32 TODO: the grace note handling hasn't been done for skip() and
33 get_music(), meaning that staff-switching and partcombining will be
34 broken with grace notes.
38 Invariant for the data structure.
41 if (gh_pair_p (cursor_))
42 iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
46 The length of musiclist from start to up to cursor_ (cursor_ not
49 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
52 Sequential_music_iterator::Sequential_music_iterator ()
55 here_mom_ = Moment (0);
60 Sequential_music_iterator::Sequential_music_iterator (Sequential_music_iterator const &src)
61 : Music_iterator (src)
63 grace_fixups_ = src.grace_fixups_;
64 cursor_ = src.cursor_;
65 here_mom_ = src.here_mom_;
67 iter_p_ = src.iter_p_->clone ();
72 Sequential_music_iterator::~Sequential_music_iterator ()
81 if (start_music.grace)
82 here.grace -= start_music.grace
90 get_grace_fixups (SCM cursor)
94 Grace_fixup *head = 0;
95 Grace_fixup **tail = &head;
97 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
99 Music * mus = unsmob_music (ly_car (cursor));
100 Moment s = mus->start_mom ();
101 Moment l =mus->length_mom () - s;
105 if (last != Moment (-1))
107 Grace_fixup *p =new Grace_fixup;
109 p->length_ = here - last;
110 p->grace_start_ = s.grace_part_;
113 tail = &(*tail)->next_;
116 here.grace_part_ = s.grace_part_;
129 Sequential_music_iterator::construct_children ()
131 cursor_ = dynamic_cast<Music_sequence const*> (music_l ())->music_list ();
133 iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
134 while (iter_p_ && !iter_p_->ok ())
139 here_mom_ = music_l ()->start_mom ();
140 grace_fixups_ = get_grace_fixups (cursor_);
143 iter_p_->ok () is tautology, but what the heck.
145 if (iter_p_ && iter_p_->ok ())
151 maintain invariants: change cursor, iter and here_mom_ in one fell
155 Sequential_music_iterator::next_element ()
157 Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
158 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
160 if (len.main_part_ && grace_fixups_ &&
161 grace_fixups_->start_ == here_mom_)
163 here_mom_ += grace_fixups_->length_;
164 here_mom_.grace_part_ += grace_fixups_->grace_start_;
166 Grace_fixup * n =grace_fixups_->next_;
167 delete grace_fixups_;
170 else if (len.grace_part_ && !len.main_part_)
172 here_mom_.grace_part_ =0;
177 !len.grace_part_ || len.main_part_
179 We skip over a big chunk (mainpart != 0). Any starting graces
180 in that chunk should be in len.grace_part_
187 cursor_ = ly_cdr (cursor_);
189 if (gh_pair_p (cursor_))
190 iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
196 move to context of child iterator if it is deeper down in the
200 Sequential_music_iterator::descend_to_child ()
202 Translator_group * child_report = child_report = iter_p_->report_to_l ();
203 Translator_group * me_report = report_to_l ();
205 Translator_group * c = child_report;
206 while (c && c != me_report)
208 c= c->daddy_trans_l_;
212 set_translator (child_report);
217 Retrieve all music (starting at HERE), until a music with length L >
218 0 is found. From the precondition, we know that UNTIL is later than
219 the earliest event. Hence we know
223 so something that comes after this thing with L > 0 happens after
225 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
227 Hence all events after the one with L>0 are uninteresting, so we
233 Sequential_music_iterator::get_music (Moment until)const
236 if (until < pending_moment ())
239 Sequential_music_iterator * me =
240 dynamic_cast<Sequential_music_iterator*> (clone ());
243 SCM nm = me->iter_p_->get_music (until - me->here_mom_);
244 s = gh_append2 (nm, s);
247 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
249 Music *mus=unsmob_music (ly_car (i));
250 m = m >? (mus->length_mom () - mus->start_mom ());
264 Skip events till UNTIL. We don't do any other side effects such as
265 descending to child iterator contexts, because they might depend on
266 \context specs and \translator changes being executed
267 TODO: build support for grace notes here.
270 Sequential_music_iterator::skip (Moment until)
274 Moment l =iter_p_->music_length_mom ();
275 if (l >= until - here_mom_)
276 iter_p_->skip (until - here_mom_);
286 Sequential_music_iterator::process (Moment until)
291 grace_fixups_->start_ == here_mom_
292 && (grace_fixups_->start_ + grace_fixups_->length_
293 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
296 do the stuff/note/rest preceding a grace.
298 iter_p_->process (iter_p_->music_length_mom ());
301 iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
304 if the iter is still OK, there must be events left that have
318 Sequential_music_iterator::pending_moment () const
320 Moment cp = iter_p_->pending_moment ();
323 Fix-up a grace note halfway in the music.
325 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
326 && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
328 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
332 Fix-up a grace note at the start of the music.
334 return cp + here_mom_ - iter_p_->music_start_mom ();
339 Sequential_music_iterator::ok () const
345 Sequential_music_iterator::try_music_in_children (Music *m) const
347 return iter_p_ ? iter_p_->try_music (m) : 0;
349 IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);