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