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