2 This file is part of LilyPond, the GNU music typesetter.
4 Copyright (C) 1997--2010 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_ == unsmob_music (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 (scm_procedure_p (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
= unsmob_music (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
= unsmob_music (scm_car (cursor_
));
138 iter_
= unsmob_iterator (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_
= unsmob_iterator (get_iterator (unsmob_music (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_
;