Workaround for broken MusicXML files (percussion clef in MuseScore)
[lilypond.git] / lily / sequential-iterator.cc
blob3fd7da3839de88a3084219081ed478f39b1b3a20
1 /*
2 sequential-iterator.cc -- implement Sequential_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1997--2009 Han-Wen Nienhuys <hanwen@xs4all.nl>
7 */
9 #include "sequential-iterator.hh"
10 #include "music.hh"
11 #include "translator-group.hh"
12 #include "context.hh"
13 #include "grace-fixup.hh"
16 TODO: handling of grace notes is exquisite pain. This handling
17 should be formally specified and then the implementation verified.
21 Invariant for the data structure.
24 if (scm_is_pair (cursor_))
25 iter_->music_ == unsmob_music (scm_car (cursor_))
26 else
27 iter_ == 0;
29 The length of musiclist from start to up to cursor_ (cursor_ not
30 including), is summed
32 here_mom_ = sum (length (musiclist [start ... cursor>)) %)
34 Sequential_iterator::Sequential_iterator ()
36 here_mom_ = Moment (0);
37 cursor_ = SCM_EOL;
38 grace_fixups_ = 0;
39 iter_ = 0;
42 SCM
43 Sequential_iterator::get_music_list () const
45 Music *m = get_music ();
46 SCM proc = m->get_property ("elements-callback");
47 if (scm_procedure_p (proc))
48 return scm_call_1 (proc, m->self_scm ());
49 else
50 return SCM_EOL;
53 void
54 Sequential_iterator::do_quit ()
56 if (iter_)
57 iter_->quit ();
60 void
61 Sequential_iterator::derived_mark () const
63 if (iter_)
64 scm_gc_mark (iter_->self_scm ());
65 scm_gc_mark (cursor_);
68 void
69 Sequential_iterator::derived_substitute (Context *f, Context *t)
71 if (iter_)
72 iter_->substitute_outlet (f, t);
76 TODO: this should be made lazily.
78 Grace_fixup *
79 create_grace_fixup_list (SCM cursor)
81 Moment here;
82 Moment last (-1);
83 Grace_fixup *head = 0;
84 Grace_fixup **tail = &head;
86 for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
88 Music *mus = unsmob_music (scm_car (cursor));
89 Moment s = mus->start_mom ();
90 Moment l = mus->get_length () - s;
92 if (s.grace_part_)
94 if (last != Moment (-1))
96 Grace_fixup *p = new Grace_fixup;
97 p->start_ = last;
98 p->length_ = here - last;
99 p->grace_start_ = s.grace_part_;
100 p->next_ = 0;
101 *tail = p;
102 tail = &(*tail)->next_;
105 here.grace_part_ = s.grace_part_;
108 if (l.to_bool ())
110 last = here;
111 here += l;
115 return head;
118 void
119 Sequential_iterator::construct_children ()
121 cursor_ = get_music_list ();
123 iter_ = 0;
124 if (scm_is_pair (cursor_))
126 Music *m = unsmob_music (scm_car (cursor_));
127 iter_ = unsmob_iterator (get_iterator (m));
130 while (iter_ && !iter_->ok ())
131 next_element (true);
133 last_mom_ = Moment (-1);
134 here_mom_ = get_music ()->start_mom ();
135 grace_fixups_ = create_grace_fixup_list (cursor_);
138 iter_->ok () is tautology, but what the heck.
140 if (iter_ && iter_->ok ())
141 descend_to_child (iter_->get_outlet ());
145 maintain invariants: change cursor, iter and here_mom_ in one fell
146 swoop.
148 void
149 Sequential_iterator::next_element (bool)
151 Moment len = iter_->music_get_length () - iter_->music_start_mom ();
152 assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
154 if (len.main_part_
155 && get_grace_fixup ())
157 Grace_fixup *gf = get_grace_fixup ();
159 last_mom_ = here_mom_;
160 here_mom_ += gf->length_;
161 here_mom_.grace_part_ += gf->grace_start_;
163 next_grace_fixup ();
165 else if (len.grace_part_ && !len.main_part_)
167 last_mom_ = here_mom_;
168 here_mom_.grace_part_ = 0;
170 else
173 !len.grace_part_ || len.main_part_
175 We skip over a big chunk (mainpart != 0). Any starting graces
176 in that chunk should be in len.grace_part_
179 last_mom_ = here_mom_;
180 here_mom_ += len;
183 cursor_ = scm_cdr (cursor_);
185 iter_->quit ();
186 if (scm_is_pair (cursor_))
187 iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
188 else
189 iter_ = 0;
192 void
193 Sequential_iterator::process (Moment until)
195 while (iter_)
197 Grace_fixup *gf = get_grace_fixup ();
198 if (gf
199 && gf->start_ + gf->length_
200 + Moment (Rational (0), gf->grace_start_) == until)
203 do the stuff/note/rest preceding a grace.
205 iter_->process (iter_->music_get_length ());
207 else
209 Moment w = until - here_mom_ + iter_->music_start_mom ();
210 iter_->process (w);
214 if the iter is still OK, there must be events left that have
216 TIME > LEFT
219 if (iter_->ok ())
220 return;
222 descend_to_child (iter_->get_outlet ());
223 next_element (true);
227 Moment
228 Sequential_iterator::pending_moment () const
230 Moment cp = iter_->pending_moment ();
233 Fix-up a grace note halfway in the music.
235 Grace_fixup *gf = get_grace_fixup ();
236 if (gf
237 && gf->length_ + iter_->music_start_mom () == cp)
238 return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
241 Fix-up a grace note at the start of the music.
243 return cp + here_mom_ - iter_->music_start_mom ();
246 bool
247 Sequential_iterator::ok () const
249 return iter_;
252 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
254 bool
255 Sequential_iterator::run_always () const
257 return iter_ ? iter_->run_always () : false;
260 void
261 Sequential_iterator::next_grace_fixup ()
263 Grace_fixup *n = grace_fixups_->next_;
264 delete grace_fixups_;
265 grace_fixups_ = n;
268 Grace_fixup *
269 Sequential_iterator::get_grace_fixup () const
271 if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
272 return grace_fixups_;
273 else
274 return 0;