]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-music-iterator.cc
release: 1.5.29
[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 excuisite 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   TODO: build support for grace notes here.
267  */
268 void
269 Sequential_music_iterator::skip (Moment until)
270 {
271   while (ok ())
272     {
273       Moment l =iter_p_->music_length_mom ();
274       if (l >= until - here_mom_)
275         iter_p_->skip (until - here_mom_);
276
277       if (iter_p_->ok ())
278         return ; 
279
280       next_element ();
281     }
282 }
283
284 void
285 Sequential_music_iterator::process (Moment until)
286 {
287   while (iter_p_)
288     {
289       if (grace_fixups_ &&
290           grace_fixups_->start_ == here_mom_
291           && (grace_fixups_->start_ + grace_fixups_->length_
292               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
293         {
294           /*
295             do the stuff/note/rest preceding a grace.
296            */
297           iter_p_->process (iter_p_->music_length_mom ());
298         }
299       else
300         iter_p_->process (until - here_mom_ + iter_p_->music_start_mom ());
301
302       /*
303         if the iter is still OK, there must be events left that have
304         
305           TIME > LEFT
306           
307       */
308       if (iter_p_->ok ())
309         return ;
310
311       descend_to_child ();
312       next_element ();
313     }
314 }
315
316 Moment
317 Sequential_music_iterator::pending_moment () const
318 {
319   Moment cp = iter_p_->pending_moment ();
320
321   /*
322     Fix-up a grace note halfway in the music.
323   */
324   if (grace_fixups_ && here_mom_ == grace_fixups_->start_
325       && grace_fixups_->length_ + iter_p_->music_start_mom () == cp)
326     {
327       return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
328     }
329
330   /*
331     Fix-up a grace note at  the start of the music.
332   */
333   return cp + here_mom_ - iter_p_->music_start_mom ();
334 }
335
336
337 bool
338 Sequential_music_iterator::ok () const
339 {
340   return iter_p_;
341 }
342
343 Music_iterator*
344 Sequential_music_iterator::try_music_in_children (Music *m) const
345
346   return iter_p_ ? iter_p_->try_music (m) : 0;
347 }
348 IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);