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