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