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