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