]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-iterator.cc
* flower
[lilypond.git] / lily / sequential-iterator.cc
1 /*
2   sequential-iterator.cc -- implement Sequential_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2005 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "sequential-iterator.hh"
10 #include "music.hh"
11 #include "translator-group.hh"
12 #include "context.hh"
13 #include "grace-fixup.hh"
14
15 /*
16   TODO: handling of grace notes is exquisite pain.  This handling
17   should be formally specified and then the implementation verified.
18 */
19
20 /*
21   Invariant for the data structure.
22
23
24   if (scm_is_pair (cursor_))
25   iter_->music_ == unsmob_music (scm_car (cursor_))
26   else
27   iter_ == 0;
28
29   The length of musiclist from start to up to cursor_ (cursor_ not
30   including), is summed
31
32   here_mom_  = sum (length (musiclist [start ... cursor>))  %)
33 */
34 Sequential_iterator::Sequential_iterator ()
35 {
36   here_mom_ = Moment (0);
37   cursor_ = SCM_EOL;
38   grace_fixups_ = 0;
39   iter_ = 0;
40 }
41
42 SCM
43 Sequential_iterator::get_music_list () const
44 {
45   return SCM_EOL;
46 }
47
48 void
49 Sequential_iterator::do_quit ()
50 {
51   if (iter_)
52     iter_->quit ();
53 }
54
55
56 void
57 Sequential_iterator::derived_mark () const
58 {
59   if (iter_)
60     scm_gc_mark (iter_->self_scm ());
61   scm_gc_mark (cursor_);
62 }
63
64 void
65 Sequential_iterator::derived_substitute (Context *f, Context *t)
66 {
67   if (iter_)
68     iter_->substitute_outlet (f, t);
69 }
70
71 /*
72   TODO: this should be made lazily.
73 */
74 Grace_fixup *
75 create_grace_fixup_list (SCM cursor)
76 {
77   Moment here;
78   Moment last (-1);
79   Grace_fixup *head = 0;
80   Grace_fixup **tail = &head;
81
82   for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
83     {
84       Music *mus = unsmob_music (scm_car (cursor));
85       Moment s = mus->start_mom ();
86       Moment l = mus->get_length () - s;
87
88       if (s.grace_part_)
89         {
90           if (last != Moment (-1))
91             {
92               Grace_fixup *p = new Grace_fixup;
93               p->start_ = last;
94               p->length_ = here - last;
95               p->grace_start_ = s.grace_part_;
96               p->next_ = 0;
97               *tail = p;
98               tail = &(*tail)->next_;
99             }
100
101           here.grace_part_ = s.grace_part_;
102         }
103
104       if (l.to_bool ())
105         {
106           last = here;
107           here += l;
108         }
109     }
110
111   return head;
112 }
113
114 void
115 Sequential_iterator::construct_children ()
116 {
117   cursor_ = get_music_list ();
118
119   iter_ = 0;
120   if (scm_is_pair (cursor_))
121     {
122       Music *m = unsmob_music (scm_car (cursor_));
123       iter_ = unsmob_iterator (get_iterator (m));
124     }
125
126   while (iter_ && !iter_->ok ())
127     {
128       next_element (true);
129     }
130
131   last_mom_ = Moment (-1);
132   here_mom_ = get_music ()->start_mom ();
133   grace_fixups_ = create_grace_fixup_list (cursor_);
134
135   /*
136     iter_->ok () is tautology, but what the heck.
137   */
138   if (iter_ && iter_->ok ())
139     descend_to_child (iter_->get_outlet ());
140 }
141
142 /*
143   maintain invariants: change cursor, iter and here_mom_ in one fell
144   swoop.
145 */
146 void
147 Sequential_iterator::next_element (bool)
148 {
149   Moment len = iter_->music_get_length () - iter_->music_start_mom ();
150   assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
151
152   if (len.main_part_
153       && get_grace_fixup ())
154     {
155       Grace_fixup *gf = get_grace_fixup ();
156
157       last_mom_ = here_mom_;
158       here_mom_ += gf->length_;
159       here_mom_.grace_part_ += gf->grace_start_;
160
161       next_grace_fixup ();
162     }
163   else if (len.grace_part_ && !len.main_part_)
164     {
165       last_mom_ = here_mom_;
166       here_mom_.grace_part_ = 0;
167     }
168   else
169     {
170       /*
171         !len.grace_part_ || len.main_part_
172
173         We skip over a big chunk (mainpart != 0). Any starting graces
174         in that chunk should be in len.grace_part_
175
176       */
177       last_mom_ = here_mom_;;
178       here_mom_ += len;
179     }
180
181   cursor_ = scm_cdr (cursor_);
182
183   iter_->quit ();
184   if (scm_is_pair (cursor_))
185     iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
186   else
187     iter_ = 0;
188 }
189
190 void
191 Sequential_iterator::process (Moment until)
192 {
193   while (iter_)
194     {
195       Grace_fixup *gf = get_grace_fixup ();
196       if (gf
197           && gf->start_ + gf->length_
198           + Moment (Rational (0), gf->grace_start_) == until)
199         {
200           /*
201             do the stuff/note/rest preceding a grace.
202           */
203           iter_->process (iter_->music_get_length ());
204         }
205       else
206         {
207           Moment w = until - here_mom_ + iter_->music_start_mom ();
208           iter_->process (w);
209         }
210
211       /*
212         if the iter is still OK, there must be events left that have
213
214         TIME > LEFT
215
216       */
217       if (iter_->ok ())
218         return;
219
220       descend_to_child (iter_->get_outlet ());
221       next_element (true);
222     }
223 }
224
225 Moment
226 Sequential_iterator::pending_moment () const
227 {
228   Moment cp = iter_->pending_moment ();
229
230   /*
231     Fix-up a grace note halfway in the music.
232   */
233   Grace_fixup *gf = get_grace_fixup ();
234   if (gf
235       && gf->length_ + iter_->music_start_mom () == cp)
236     {
237       return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
238     }
239
240   /*
241     Fix-up a grace note at  the start of the music.
242   */
243   return cp + here_mom_ - iter_->music_start_mom ();
244 }
245
246 bool
247 Sequential_iterator::ok () const
248 {
249   return iter_;
250 }
251
252 Music_iterator *
253 Sequential_iterator::try_music_in_children (Music *m) const
254 {
255   return iter_ ? iter_->try_music (m) : 0;
256 }
257
258 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
259
260 bool
261 Sequential_iterator::run_always () const
262 {
263   return iter_ ? iter_->run_always () : false;
264 }
265
266 void
267 Sequential_iterator::next_grace_fixup ()
268 {
269   Grace_fixup *n = grace_fixups_->next_;
270   delete grace_fixups_;
271   grace_fixups_ = n;
272 }
273
274 Grace_fixup *
275 Sequential_iterator::get_grace_fixup () const
276 {
277   if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
278     return grace_fixups_;
279   else
280     return 0;
281 }