Fixes Issue 1504, allowing feather beam line breaking.
[lilypond/patrick.git] / lily / sequential-iterator.cc
blob84d677df00e1ce07c9ebdf8d37a18deb0b0715d3
1 /*
2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2011 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"
21 #include "music.hh"
22 #include "translator-group.hh"
23 #include "context.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_ == unsmob_music (scm_car (cursor_))
37 else
38 iter_ == 0;
40 The length of musiclist from start to up to cursor_ (cursor_ not
41 including), is summed
43 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
45 Sequential_iterator::Sequential_iterator ()
47 here_mom_ = Moment (0);
48 cursor_ = SCM_EOL;
49 grace_fixups_ = 0;
50 iter_ = 0;
53 SCM
54 Sequential_iterator::get_music_list () const
56 Music *m = get_music ();
57 SCM proc = m->get_property ("elements-callback");
58 if (scm_procedure_p (proc))
59 return scm_call_1 (proc, m->self_scm ());
60 else
61 return SCM_EOL;
64 void
65 Sequential_iterator::do_quit ()
67 if (iter_)
68 iter_->quit ();
71 void
72 Sequential_iterator::derived_mark () const
74 if (iter_)
75 scm_gc_mark (iter_->self_scm ());
76 scm_gc_mark (cursor_);
79 void
80 Sequential_iterator::derived_substitute (Context *f, Context *t)
82 if (iter_)
83 iter_->substitute_outlet (f, t);
87 TODO: this should be made lazily.
89 Grace_fixup *
90 create_grace_fixup_list (SCM cursor)
92 Moment here;
93 Moment last (-1);
94 Grace_fixup *head = 0;
95 Grace_fixup **tail = &head;
97 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
99 Music *mus = unsmob_music (scm_car (cursor));
100 Moment s = mus->start_mom ();
101 Moment l = mus->get_length () - s;
103 if (s.grace_part_)
105 if (last != Moment (-1))
107 Grace_fixup *p = new Grace_fixup;
108 p->start_ = last;
109 p->length_ = here - last;
110 p->grace_start_ = s.grace_part_;
111 p->next_ = 0;
112 *tail = p;
113 tail = &(*tail)->next_;
116 here.grace_part_ = s.grace_part_;
119 if (l.to_bool ())
121 last = here;
122 here += l;
126 return head;
129 void
130 Sequential_iterator::construct_children ()
132 cursor_ = get_music_list ();
134 iter_ = 0;
135 if (scm_is_pair (cursor_))
137 Music *m = unsmob_music (scm_car (cursor_));
138 iter_ = unsmob_iterator (get_iterator (m));
141 while (iter_ && !iter_->ok ())
142 next_element (true);
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
157 swoop.
159 void
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_);
165 if (len.main_part_
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_;
174 next_grace_fixup ();
176 else if (len.grace_part_ && !len.main_part_)
178 last_mom_ = here_mom_;
179 here_mom_.grace_part_ = 0;
181 else
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_;
191 here_mom_ += len;
194 cursor_ = scm_cdr (cursor_);
196 iter_->quit ();
197 if (scm_is_pair (cursor_))
198 iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
199 else
200 iter_ = 0;
203 void
204 Sequential_iterator::process (Moment until)
206 while (iter_)
208 Grace_fixup *gf = get_grace_fixup ();
209 if (gf
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 ());
218 else
220 Moment w = until - here_mom_ + iter_->music_start_mom ();
221 iter_->process (w);
225 if the iter is still OK, there must be events left that have
227 TIME > LEFT
230 if (iter_->ok ())
231 return;
233 descend_to_child (iter_->get_outlet ());
234 next_element (true);
238 Moment
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 ();
247 if (gf
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 ();
257 bool
258 Sequential_iterator::ok () const
260 return iter_;
263 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
265 bool
266 Sequential_iterator::run_always () const
268 return iter_ ? iter_->run_always () : false;
271 void
272 Sequential_iterator::next_grace_fixup ()
274 Grace_fixup *n = grace_fixups_->next_;
275 delete grace_fixups_;
276 grace_fixups_ = n;
279 Grace_fixup *
280 Sequential_iterator::get_grace_fixup () const
282 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
283 return grace_fixups_;
284 else
285 return 0;