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