]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-iterator.cc
* VERSION (MY_PATCH_LEVEL): make 1.7.0
[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--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "translator-group.hh"
10
11 #include "sequential-iterator.hh"
12 #include "music-list.hh"
13
14 Grace_fixup *copy_grace_fixups (Grace_fixup* src);
15 Grace_fixup *get_grace_fixups (SCM cursor);
16
17 /*
18   
19   TODO: handling of grace notes is exquisite pain.  This handling
20   should be formally specified and then the implementation verified.
21
22 */
23
24 /*
25   Invariant for the data structure.
26
27
28   if (gh_pair_p (cursor_))
29     iter_->music_ == unsmob_music (ly_car (cursor_))
30   else
31     iter_ == 0;
32
33   The length of musiclist from start to up to cursor_ (cursor_ not
34   including), is summed
35
36   here_mom_  = sum (length (musiclist [start ... cursor>))  %)  
37   
38  */
39 Sequential_iterator::Sequential_iterator ()
40 {
41   here_mom_ = Moment (0);
42   list_ = SCM_EOL;
43   cursor_ = SCM_EOL; 
44   grace_fixups_ = 0;
45   iter_ =0;
46 }
47
48 SCM 
49 Sequential_iterator::get_music_list () const
50 {
51   return SCM_EOL;
52 }
53
54 void
55 Sequential_iterator::do_quit ()
56 {
57   if (iter_)
58     iter_->quit();
59 }
60
61
62 Sequential_iterator::Sequential_iterator (Sequential_iterator const &src)
63   : Music_iterator (src)
64 {
65   grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
66   cursor_ = src.cursor_;
67   list_ = src.cursor_;
68   here_mom_ = src.here_mom_;
69   iter_ = (src.iter_) ? src.iter_->clone () : 0;
70
71   if (iter_)
72     scm_gc_unprotect_object (iter_->self_scm());
73 }
74
75 void
76 Sequential_iterator::derived_mark ()const
77 {
78   if (iter_)
79     scm_gc_mark (iter_->self_scm());
80   scm_gc_mark (list_);
81   scm_gc_mark (cursor_);
82 }
83
84
85 Grace_fixup *
86 get_grace_fixups (SCM cursor)
87 {
88   Moment here;
89   Moment last (-1);
90   Grace_fixup *head = 0;
91   Grace_fixup **tail = &head;
92
93   for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
94     {
95       Music * mus = unsmob_music (ly_car (cursor));
96       Moment s = mus->start_mom ();
97       Moment l =mus->length_mom () - s;
98
99       if (s.grace_part_)
100         {
101           if (last != Moment (-1))
102             {
103               Grace_fixup *p =new Grace_fixup;
104               p->start_ = last;
105               p->length_ = here - last;
106               p->grace_start_ = s.grace_part_;
107               p->next_ = 0;
108               *tail = p;
109               tail = &(*tail)->next_; 
110             }
111
112           here.grace_part_ = s.grace_part_;
113         }
114       
115       if (l.to_bool())
116         {
117           last = here;
118           here += l;
119         }
120     }
121   return  head;
122 }
123
124 Grace_fixup *
125 copy_grace_fixups (Grace_fixup* src)
126 {
127   Grace_fixup * head = 0;
128   Grace_fixup **dest = &head;
129
130   while (src)
131     {
132       *dest = new Grace_fixup (*src);
133       dest = & (*dest)->next_;
134       src = src ->next_;
135     }
136
137   return head;
138 }
139
140 void
141 Sequential_iterator::construct_children ()
142 {
143   list_ = get_music_list ();
144   cursor_ = list_; 
145
146   iter_ = 0;
147   if (gh_pair_p (cursor_))
148     {
149       Music *m  =unsmob_music (ly_car (cursor_));
150       iter_ = unsmob_iterator (get_iterator (m));
151     }
152   
153   while (iter_ && !iter_->ok ())
154     {
155       next_element (true);
156     }
157
158   here_mom_ = get_music ()->start_mom ();
159   grace_fixups_ = get_grace_fixups (cursor_);
160
161   /*
162     iter_->ok () is tautology, but what the heck.
163    */
164   if (iter_ && iter_->ok ()) 
165     descend_to_child ();
166 }
167
168
169 /*
170   maintain invariants: change cursor, iter and here_mom_ in one fell
171   swoop.
172 */
173 void
174 Sequential_iterator::next_element (bool side_effect)
175 {
176   Moment len =iter_->music_length_mom () - iter_->music_start_mom ();
177   assert (!grace_fixups_  || grace_fixups_->start_ >= here_mom_);
178   
179   if (len.main_part_ && grace_fixups_ &&
180       grace_fixups_->start_ == here_mom_)
181     {
182       here_mom_ += grace_fixups_->length_;
183       here_mom_.grace_part_ += grace_fixups_->grace_start_;
184
185       Grace_fixup * n =grace_fixups_->next_;
186       delete grace_fixups_;
187       grace_fixups_ = n;
188     }
189   else if (len.grace_part_ && !len.main_part_)
190     {
191       here_mom_.grace_part_ =0;
192     }
193   else
194     {
195       /*
196         !len.grace_part_ || len.main_part_
197
198         We skip over a big chunk (mainpart != 0). Any starting graces
199         in that chunk should be in len.grace_part_
200
201       */
202       here_mom_ += len;
203     }
204   
205   cursor_ = ly_cdr (cursor_);
206
207   iter_->quit();
208   if (gh_pair_p (cursor_))
209     iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
210   else
211     iter_ = 0;
212 }
213
214 /*
215   move to context of child iterator if it is deeper down in the
216   hierarchy.
217   */
218 void
219 Sequential_iterator::descend_to_child ()
220 {
221 }
222
223
224 /*
225   Retrieve all music (starting at HERE), until a music with length L >
226   0 is found.  From the precondition, we know that UNTIL is later than
227   the earliest event. Hence we know
228   
229   L >= (UNTIL - HERE)
230
231   so something that comes after this thing with L > 0 happens after
232
233   HERE + L >= HERE + (UNTIL - HERE) = UNTIL
234
235   Hence all events after the one with L>0 are uninteresting, so we
236   ignore them.
237   
238 */
239
240 SCM
241 Sequential_iterator::get_pending_events (Moment until)const
242 {
243   SCM s = SCM_EOL;
244   if (until <  pending_moment ())
245     return s;
246
247   Sequential_iterator * me =
248     dynamic_cast<Sequential_iterator*> (clone ());
249   while (me->ok ())
250     {
251       SCM nm = me->iter_->get_pending_events (until - me->here_mom_);
252       s = gh_append2 (nm, s);
253       
254       Moment m = 0;
255       for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
256         {
257           Music *mus=unsmob_music (ly_car (i));
258           m = m >? (mus->length_mom () - mus->start_mom ());
259         }
260       if (m > Moment (0))
261         break ;
262       else
263         me->next_element (false);
264     }
265
266   scm_gc_unprotect_object (me->self_scm());
267   return s;
268 }
269
270
271 /*
272   Skip events till UNTIL. We don't do any other side effects such as
273   descending to child iterator contexts, because they might depend on
274   \context specs and \translator changes being executed
275  */
276 void
277 Sequential_iterator::skip (Moment until)
278 {
279   while (ok ())
280     {
281       if (grace_fixups_ &&
282           grace_fixups_->start_ == here_mom_
283           && (grace_fixups_->start_ + grace_fixups_->length_
284               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
285         {
286           /*
287             do the stuff/note/rest preceding a grace.
288            */
289           iter_->skip (iter_->music_length_mom ());
290         }
291       else if (iter_->music_length_mom () >= until - here_mom_)
292         iter_->skip (until - here_mom_ + iter_->music_start_mom ());
293
294       if (iter_->ok ())
295         return ; 
296
297       next_element (false);
298     }
299 }
300
301 void
302 Sequential_iterator::process (Moment until)
303 {
304   while (iter_)
305     {
306       if (grace_fixups_ &&
307           grace_fixups_->start_ == here_mom_
308           && (grace_fixups_->start_ + grace_fixups_->length_
309               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
310         {
311           /*
312             do the stuff/note/rest preceding a grace.
313            */
314           iter_->process (iter_->music_length_mom ());
315         }
316       else
317         iter_->process (until - here_mom_ + iter_->music_start_mom ());
318
319       /*
320         if the iter is still OK, there must be events left that have
321         
322           TIME > LEFT
323           
324       */
325       if (iter_->ok ())
326         return ;
327
328       descend_to_child ();
329       next_element (true);
330     }
331 }
332
333 Moment
334 Sequential_iterator::pending_moment () const
335 {
336   Moment cp = iter_->pending_moment ();
337
338   /*
339     Fix-up a grace note halfway in the music.
340   */
341   if (grace_fixups_ && here_mom_ == grace_fixups_->start_
342       && grace_fixups_->length_ + iter_->music_start_mom () == cp)
343     {
344       return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
345     }
346
347   /*
348     Fix-up a grace note at  the start of the music.
349   */
350   return cp + here_mom_ - iter_->music_start_mom ();
351 }
352
353
354 bool
355 Sequential_iterator::ok () const
356 {
357   return iter_;
358 }
359
360 Music_iterator*
361 Sequential_iterator::try_music_in_children (Music *m) const
362
363   return iter_ ? iter_->try_music (m) : 0;
364 }
365
366 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);