2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2014 Han-Wen Nienhuys <hanwen@xs4all.nl>
6 LilyPond is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 LilyPond is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with LilyPond. If not, see <http://www.gnu.org/licenses/>.
20 #include "sequential-iterator.hh"
22 #include "translator-group.hh"
24 #include "grace-fixup.hh"
27 TODO: handling of grace notes is exquisite pain. This handling
28 should be formally specified and then the implementation verified.
32 Invariant for the data structure.
35 if (scm_is_pair (cursor_))
36 iter_->music_ == Music::unsmob (scm_car (cursor_))
40 The length of musiclist from start to up to cursor_ (cursor_ not
43 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
45 Sequential_iterator::Sequential_iterator ()
47 here_mom_ = Moment (0);
54 Sequential_iterator::get_music_list () const
56 Music *m = get_music ();
57 SCM proc = m->get_property ("elements-callback");
58 if (ly_is_procedure (proc))
59 return scm_call_1 (proc, m->self_scm ());
65 Sequential_iterator::do_quit ()
72 Sequential_iterator::derived_mark () const
75 scm_gc_mark (iter_->self_scm ());
76 scm_gc_mark (cursor_);
80 Sequential_iterator::derived_substitute (Context *f, Context *t)
83 iter_->substitute_outlet (f, t);
87 TODO: this should be made lazily.
90 create_grace_fixup_list (SCM cursor)
94 Grace_fixup *head = 0;
95 Grace_fixup **tail = &head;
97 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
99 Music *mus = Music::unsmob (scm_car (cursor));
100 Moment s = mus->start_mom ();
101 Moment l = mus->get_length () - 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_;
130 Sequential_iterator::construct_children ()
132 cursor_ = get_music_list ();
135 if (scm_is_pair (cursor_))
137 Music *m = Music::unsmob (scm_car (cursor_));
138 iter_ = Music_iterator::unsmob (get_iterator (m));
141 while (iter_ && !iter_->ok ())
144 last_mom_ = Moment (-1);
145 here_mom_ = get_music ()->start_mom ();
146 grace_fixups_ = create_grace_fixup_list (cursor_);
149 iter_->ok () is tautology, but what the heck.
151 if (iter_ && iter_->ok ())
152 descend_to_child (iter_->get_outlet ());
156 maintain invariants: change cursor, iter and here_mom_ in one fell
160 Sequential_iterator::next_element (bool)
162 Moment len = iter_->music_get_length () - iter_->music_start_mom ();
163 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
166 && get_grace_fixup ())
168 Grace_fixup *gf = get_grace_fixup ();
170 last_mom_ = here_mom_;
171 here_mom_ += gf->length_;
172 here_mom_.grace_part_ += gf->grace_start_;
176 else if (len.grace_part_ && !len.main_part_)
178 last_mom_ = here_mom_;
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_
190 last_mom_ = here_mom_;
194 cursor_ = scm_cdr (cursor_);
197 if (scm_is_pair (cursor_))
198 iter_ = Music_iterator::unsmob (get_iterator (Music::unsmob (scm_car (cursor_))));
204 Sequential_iterator::process (Moment until)
208 Grace_fixup *gf = get_grace_fixup ();
210 && gf->start_ + gf->length_
211 + Moment (Rational (0), gf->grace_start_) == until)
214 do the stuff/note/rest preceding a grace.
216 iter_->process (iter_->music_get_length ());
220 Moment w = until - here_mom_ + iter_->music_start_mom ();
225 if the iter is still OK, there must be events left that have
233 descend_to_child (iter_->get_outlet ());
239 Sequential_iterator::pending_moment () const
241 Moment cp = iter_->pending_moment ();
244 Fix-up a grace note halfway in the music.
246 Grace_fixup *gf = get_grace_fixup ();
248 && gf->length_ + iter_->music_start_mom () == cp)
249 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
252 Fix-up a grace note at the start of the music.
254 return cp + here_mom_ - iter_->music_start_mom ();
258 Sequential_iterator::ok () const
263 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
266 Sequential_iterator::run_always () const
268 return iter_ ? iter_->run_always () : false;
272 Sequential_iterator::next_grace_fixup ()
274 Grace_fixup *n = grace_fixups_->next_;
275 delete grace_fixups_;
280 Sequential_iterator::get_grace_fixup () const
282 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
283 return grace_fixups_;