]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-iterator.cc
* lily/include/sequential-iterator.hh (class Sequential_iterator):
[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
26   TODO: the grace note handling hasn't been done for skip() and
27   get_music(), meaning that staff-switching and partcombining will be
28   broken with grace notes.
29   
30  */
31 /*
32
33   TODO: the grace note handling hasn't been done for skip() and
34   get_music(), meaning that staff-switching and partcombining will be
35   broken with grace notes.
36   
37  */
38 /*
39   Invariant for the data structure.
40
41
42   if (gh_pair_p (cursor_))
43     iter_p_->music_l_ == unsmob_music (ly_car (cursor_))
44   else
45     iter_p_ == 0;
46
47   The length of musiclist from start to up to cursor_ (cursor_ not
48   including), is summed
49
50   here_mom_  = sum (length (musiclist [start ... cursor>))  %)  
51   
52  */
53 Sequential_iterator::Sequential_iterator ()
54 {
55   here_mom_ = Moment (0);
56   grace_fixups_ = 0;
57   iter_p_ =0;
58 }
59
60 SCM 
61 Sequential_iterator::get_music_list () const
62 {
63   return SCM_EOL;
64 }
65
66 Sequential_iterator::Sequential_iterator (Sequential_iterator const &src)
67   : Music_iterator (src)
68 {
69   grace_fixups_ = copy_grace_fixups (src.grace_fixups_);
70   cursor_ = src.cursor_;
71   list_ = src.cursor_;
72   here_mom_ = src.here_mom_;
73   if (src.iter_p_)
74     iter_p_ = src.iter_p_->clone ();
75   else
76     iter_p_ = 0;
77 }
78
79 Sequential_iterator::~Sequential_iterator ()
80 {
81   delete iter_p_;
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_p_ = gh_pair_p (cursor_) ?  get_iterator_p (unsmob_music (ly_car (cursor_))) : 0;
147   while (iter_p_ && !iter_p_->ok ())
148     {
149       next_element (true);
150     }
151
152   here_mom_ = music_l ()->start_mom ();
153   grace_fixups_ = get_grace_fixups (cursor_);
154
155   /*
156     iter_p_->ok () is tautology, but what the heck.
157    */
158   if (iter_p_ && iter_p_->ok ()) 
159     descend_to_child ();
160 }
161
162
163 /*
164   maintain invariants: change cursor, iter and here_mom_ in one fell
165   swoop.
166 */
167 void
168 Sequential_iterator::next_element (bool side_effect)
169 {
170   Moment len =iter_p_->music_length_mom () - iter_p_->music_start_mom ();
171   assert (!grace_fixups_  || grace_fixups_->start_ >= here_mom_);
172   
173   if (len.main_part_ && grace_fixups_ &&
174       grace_fixups_->start_ == here_mom_)
175     {
176       here_mom_ += grace_fixups_->length_;
177       here_mom_.grace_part_ += grace_fixups_->grace_start_;
178
179       Grace_fixup * n =grace_fixups_->next_;
180       delete grace_fixups_;
181       grace_fixups_ = n;
182     }
183   else if (len.grace_part_ && !len.main_part_)
184     {
185       here_mom_.grace_part_ =0;
186     }
187   else
188     {
189       /*
190         !len.grace_part_ || len.main_part_
191
192         We skip over a big chunk (mainpart != 0). Any starting graces
193         in that chunk should be in len.grace_part_
194
195       */
196       here_mom_ += len;
197     }
198   
199   delete iter_p_;
200   cursor_ = ly_cdr (cursor_);
201
202   if (gh_pair_p (cursor_))
203     iter_p_ = get_iterator_p (unsmob_music (ly_car (cursor_)));
204   else
205     iter_p_ = 0;
206 }
207
208 /*
209   move to context of child iterator if it is deeper down in the
210   hierarchy.
211   */
212 void
213 Sequential_iterator::descend_to_child ()
214 {
215 }
216
217
218 /*
219   Retrieve all music (starting at HERE), until a music with length L >
220   0 is found.  From the precondition, we know that UNTIL is later than
221   the earliest event. Hence we know
222   
223   L >= (UNTIL - HERE)
224
225   so something that comes after this thing with L > 0 happens after
226
227   HERE + L >= HERE + (UNTIL - HERE) = UNTIL
228
229   Hence all events after the one with L>0 are uninteresting, so we
230   ignore them.
231   
232 */
233
234 SCM
235 Sequential_iterator::get_music (Moment until)const
236 {
237   SCM s = SCM_EOL;
238   if (until <  pending_moment ())
239     return s;
240
241   Sequential_iterator * me =
242     dynamic_cast<Sequential_iterator*> (clone ());
243   while (me->ok ())
244     {
245       SCM nm = me->iter_p_->get_music (until - me->here_mom_);
246       s = gh_append2 (nm, s);
247       
248       Moment m = 0;
249       for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
250         {
251           Music *mus=unsmob_music (ly_car (i));
252           m = m >? (mus->length_mom () - mus->start_mom ());
253         }
254       if (m > Moment (0))
255         break ;
256       else
257         me->next_element (false);
258     }
259   delete me;
260   
261   return s;
262 }
263
264
265 /*
266   Skip events till UNTIL. We don't do any other side effects such as
267   descending to child iterator contexts, because they might depend on
268   \context specs and \translator changes being executed
269
270   TODO: check support for grace notes here.
271  */
272 void
273 Sequential_iterator::skip (Moment until)
274 {
275   while (ok ())
276     {
277       if (grace_fixups_ &&
278           grace_fixups_->start_ == here_mom_
279           && (grace_fixups_->start_ + grace_fixups_->length_
280               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
281         {
282           /*
283             do the stuff/note/rest preceding a grace.
284            */
285           iter_p_->skip (iter_p_->music_length_mom ());
286         }
287       else if (iter_p_->music_length_mom () >= until - here_mom_)
288         iter_p_->skip (until - here_mom_ + iter_p_->music_start_mom ());
289
290       if (iter_p_->ok ())
291         return ; 
292
293       next_element (false);
294     }
295 }
296
297 void
298 Sequential_iterator::process (Moment until)
299 {
300   while (iter_p_)
301     {
302       if (grace_fixups_ &&
303           grace_fixups_->start_ == here_mom_
304           && (grace_fixups_->start_ + grace_fixups_->length_
305               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
306         {
307           /*
308             do the stuff/note/rest preceding a grace.
309            */
310           iter_p_->process (iter_p_->music_length_mom ());
311         }
312       else
313         iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
314
315       /*
316         if the iter is still OK, there must be events left that have
317         
318           TIME > LEFT
319           
320       */
321       if (iter_p_->ok ())
322         return ;
323
324       descend_to_child ();
325       next_element (true);
326     }
327 }
328
329 Moment
330 Sequential_iterator::pending_moment () const
331 {
332   Moment cp = iter_p_->pending_moment ();
333
334   /*
335     Fix-up a grace note halfway in the music.
336   */
337   if (grace_fixups_ && here_mom_ == grace_fixups_->start_
338       && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
339     {
340       return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
341     }
342
343   /*
344     Fix-up a grace note at  the start of the music.
345   */
346   return cp + here_mom_ - iter_p_->music_start_mom ();
347 }
348
349
350 bool
351 Sequential_iterator::ok () const
352 {
353   return iter_p_;
354 }
355
356 Music_iterator*
357 Sequential_iterator::try_music_in_children (Music *m) const
358
359   return iter_p_ ? iter_p_->try_music (m) : 0;
360 }
361
362 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);