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"
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.
26 TODO: the grace note handling hasn't been done for skip() and
27 get_music(), meaning that staff-switching and partcombining will be
28 broken with grace notes.
33 TODO: the grace note handling hasn't been done for skip() and
34 get_music(), meaning that staff-switching and partcombining will be
35 broken with grace notes.
39 Invariant for the data structure.
42 if (gh_pair_p (cursor_))
43 iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
47 The length of musiclist from start to up to cursor_ (cursor_ not
50 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
53 Sequential_music_iterator::Sequential_music_iterator ()
56 here_mom_ = Moment (0);
61 Sequential_music_iterator::Sequential_music_iterator (Sequential_music_iterator const &src)
62 : Music_iterator (src)
64 grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
65 cursor_ = src.cursor_;
66 here_mom_ = src.here_mom_;
68 iter_p_ = src.iter_p_->clone ();
73 Sequential_music_iterator::~Sequential_music_iterator ()
80 get_grace_fixups (SCM cursor)
84 Grace_fixup *head = 0;
85 Grace_fixup **tail = &head;
87 for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
89 Music * mus = unsmob_music (ly_car (cursor));
90 Moment s = mus->start_mom ();
91 Moment l =mus->length_mom () - s;
95 if (last != Moment (-1))
97 Grace_fixup *p =new Grace_fixup;
99 p->length_ = here - last;
100 p->grace_start_ = s.grace_part_;
103 tail = &(*tail)->next_;
106 here.grace_part_ = s.grace_part_;
119 copy_grace_fixups (Grace_fixup* src)
122 Grace_fixup * head = 0;
123 Grace_fixup **dest = &head;
127 *dest = new Grace_fixup (*src);
128 dest = & (*dest)->next_;
136 Sequential_music_iterator::construct_children ()
138 cursor_ = dynamic_cast<Music_sequence const*> (music_l ())->music_list ();
140 iter_p_ = gh_pair_p (cursor_) ? get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
141 while (iter_p_ && !iter_p_->ok ())
146 here_mom_ = music_l ()->start_mom ();
147 grace_fixups_ = get_grace_fixups (cursor_);
150 iter_p_->ok () is tautology, but what the heck.
152 if (iter_p_ && iter_p_->ok ())
158 maintain invariants: change cursor, iter and here_mom_ in one fell
162 Sequential_music_iterator::next_element ()
164 Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
165 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
167 if (len.main_part_ && grace_fixups_ &&
168 grace_fixups_->start_ == here_mom_)
170 here_mom_ += grace_fixups_->length_;
171 here_mom_.grace_part_ += grace_fixups_->grace_start_;
173 Grace_fixup * n =grace_fixups_->next_;
174 delete grace_fixups_;
177 else if (len.grace_part_ && !len.main_part_)
179 here_mom_.grace_part_ =0;
184 !len.grace_part_ || len.main_part_
186 We skip over a big chunk (mainpart != 0). Any starting graces
187 in that chunk should be in len.grace_part_
194 cursor_ = ly_cdr (cursor_);
196 if (gh_pair_p (cursor_))
197 iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
203 move to context of child iterator if it is deeper down in the
207 Sequential_music_iterator::descend_to_child ()
209 Translator_group * child_report = child_report = iter_p_->report_to_l ();
210 Translator_group * me_report = report_to_l ();
212 Translator_group * c = child_report;
213 while (c && c != me_report)
215 c= c->daddy_trans_l_;
219 set_translator (child_report);
224 Retrieve all music (starting at HERE), until a music with length L >
225 0 is found. From the precondition, we know that UNTIL is later than
226 the earliest event. Hence we know
230 so something that comes after this thing with L > 0 happens after
232 HERE + L >= HERE + (UNTIL - HERE) = UNTIL
234 Hence all events after the one with L>0 are uninteresting, so we
240 Sequential_music_iterator::get_music (Moment until)const
243 if (until < pending_moment ())
246 Sequential_music_iterator * me =
247 dynamic_cast<Sequential_music_iterator*> (clone ());
250 SCM nm = me->iter_p_->get_music (until - me->here_mom_);
251 s = gh_append2 (nm, s);
254 for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
256 Music *mus=unsmob_music (ly_car (i));
257 m = m >? (mus->length_mom () - mus->start_mom ());
271 Skip events till UNTIL. We don't do any other side effects such as
272 descending to child iterator contexts, because they might depend on
273 \context specs and \translator changes being executed
275 TODO: check support for grace notes here.
278 Sequential_music_iterator::skip (Moment until)
283 grace_fixups_->start_ == here_mom_
284 && (grace_fixups_->start_ + grace_fixups_->length_
285 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
288 do the stuff/note/rest preceding a grace.
290 iter_p_->skip (iter_p_->music_length_mom ());
292 else if (iter_p_->music_length_mom () >= until - here_mom_)
293 iter_p_->skip (until - here_mom_ + iter_p_->music_start_mom ());
303 Sequential_music_iterator::process (Moment until)
308 grace_fixups_->start_ == here_mom_
309 && (grace_fixups_->start_ + grace_fixups_->length_
310 + Moment (Rational (0), grace_fixups_->grace_start_) == until))
313 do the stuff/note/rest preceding a grace.
315 iter_p_->process (iter_p_->music_length_mom ());
318 iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
321 if the iter is still OK, there must be events left that have
335 Sequential_music_iterator::pending_moment () const
337 Moment cp = iter_p_->pending_moment ();
340 Fix-up a grace note halfway in the music.
342 if (grace_fixups_ && here_mom_ == grace_fixups_->start_
343 && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
345 return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
349 Fix-up a grace note at the start of the music.
351 return cp + here_mom_ - iter_p_->music_start_mom ();
356 Sequential_music_iterator::ok () const
362 Sequential_music_iterator::try_music_in_children (Music *m) const
364 return iter_p_ ? iter_p_->try_music (m) : 0;
366 IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);