]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-iterator.cc
Fix some bugs in the dynamic engraver and PostScript backend
[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--2006 Han-Wen Nienhuys <hanwen@xs4all.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 void
56 Sequential_iterator::derived_mark () const
57 {
58   if (iter_)
59     scm_gc_mark (iter_->self_scm ());
60   scm_gc_mark (cursor_);
61 }
62
63 void
64 Sequential_iterator::derived_substitute (Context *f, Context *t)
65 {
66   if (iter_)
67     iter_->substitute_outlet (f, t);
68 }
69
70 /*
71   TODO: this should be made lazily.
72 */
73 Grace_fixup *
74 create_grace_fixup_list (SCM cursor)
75 {
76   Moment here;
77   Moment last (-1);
78   Grace_fixup *head = 0;
79   Grace_fixup **tail = &head;
80
81   for (; scm_is_pair (cursor); cursor = scm_cdr (cursor))
82     {
83       Music *mus = unsmob_music (scm_car (cursor));
84       Moment s = mus->start_mom ();
85       Moment l = mus->get_length () - s;
86
87       if (s.grace_part_)
88         {
89           if (last != Moment (-1))
90             {
91               Grace_fixup *p = new Grace_fixup;
92               p->start_ = last;
93               p->length_ = here - last;
94               p->grace_start_ = s.grace_part_;
95               p->next_ = 0;
96               *tail = p;
97               tail = &(*tail)->next_;
98             }
99
100           here.grace_part_ = s.grace_part_;
101         }
102
103       if (l.to_bool ())
104         {
105           last = here;
106           here += l;
107         }
108     }
109
110   return head;
111 }
112
113 void
114 Sequential_iterator::construct_children ()
115 {
116   cursor_ = get_music_list ();
117
118   iter_ = 0;
119   if (scm_is_pair (cursor_))
120     {
121       Music *m = unsmob_music (scm_car (cursor_));
122       iter_ = unsmob_iterator (get_iterator (m));
123     }
124
125   while (iter_ && !iter_->ok ())
126     next_element (true);
127
128   last_mom_ = Moment (-1);
129   here_mom_ = get_music ()->start_mom ();
130   grace_fixups_ = create_grace_fixup_list (cursor_);
131
132   /*
133     iter_->ok () is tautology, but what the heck.
134   */
135   if (iter_ && iter_->ok ())
136     descend_to_child (iter_->get_outlet ());
137 }
138
139 /*
140   maintain invariants: change cursor, iter and here_mom_ in one fell
141   swoop.
142 */
143 void
144 Sequential_iterator::next_element (bool)
145 {
146   Moment len = iter_->music_get_length () - iter_->music_start_mom ();
147   assert (!grace_fixups_ || grace_fixups_->start_ >= here_mom_);
148
149   if (len.main_part_
150       && get_grace_fixup ())
151     {
152       Grace_fixup *gf = get_grace_fixup ();
153
154       last_mom_ = here_mom_;
155       here_mom_ += gf->length_;
156       here_mom_.grace_part_ += gf->grace_start_;
157
158       next_grace_fixup ();
159     }
160   else if (len.grace_part_ && !len.main_part_)
161     {
162       last_mom_ = here_mom_;
163       here_mom_.grace_part_ = 0;
164     }
165   else
166     {
167       /*
168         !len.grace_part_ || len.main_part_
169
170         We skip over a big chunk (mainpart != 0). Any starting graces
171         in that chunk should be in len.grace_part_
172
173       */
174       last_mom_ = here_mom_;;
175       here_mom_ += len;
176     }
177
178   cursor_ = scm_cdr (cursor_);
179
180   iter_->quit ();
181   if (scm_is_pair (cursor_))
182     iter_ = unsmob_iterator (get_iterator (unsmob_music (scm_car (cursor_))));
183   else
184     iter_ = 0;
185 }
186
187 void
188 Sequential_iterator::process (Moment until)
189 {
190   while (iter_)
191     {
192       Grace_fixup *gf = get_grace_fixup ();
193       if (gf
194           && gf->start_ + gf->length_
195           + Moment (Rational (0), gf->grace_start_) == until)
196         {
197           /*
198             do the stuff/note/rest preceding a grace.
199           */
200           iter_->process (iter_->music_get_length ());
201         }
202       else
203         {
204           Moment w = until - here_mom_ + iter_->music_start_mom ();
205           iter_->process (w);
206         }
207
208       /*
209         if the iter is still OK, there must be events left that have
210
211         TIME > LEFT
212
213       */
214       if (iter_->ok ())
215         return;
216
217       descend_to_child (iter_->get_outlet ());
218       next_element (true);
219     }
220 }
221
222 Moment
223 Sequential_iterator::pending_moment () const
224 {
225   Moment cp = iter_->pending_moment ();
226
227   /*
228     Fix-up a grace note halfway in the music.
229   */
230   Grace_fixup *gf = get_grace_fixup ();
231   if (gf
232       && gf->length_ + iter_->music_start_mom () == cp)
233     return here_mom_ + gf->length_ + Moment (0, gf->grace_start_);
234
235   /*
236     Fix-up a grace note at  the start of the music.
237   */
238   return cp + here_mom_ - iter_->music_start_mom ();
239 }
240
241 bool
242 Sequential_iterator::ok () const
243 {
244   return iter_;
245 }
246
247 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
248
249 bool
250 Sequential_iterator::run_always () const
251 {
252   return iter_ ? iter_->run_always () : false;
253 }
254
255 void
256 Sequential_iterator::next_grace_fixup ()
257 {
258   Grace_fixup *n = grace_fixups_->next_;
259   delete grace_fixups_;
260   grace_fixups_ = n;
261 }
262
263 Grace_fixup *
264 Sequential_iterator::get_grace_fixup () const
265 {
266   if (grace_fixups_ && grace_fixups_->start_ == here_mom_)
267     return grace_fixups_;
268   else
269     return 0;
270 }