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