]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-iterator.cc
* lily/include/grob-info.hh: origin_contexts() now does not
[lilypond.git] / lily / sequential-iterator.cc
1 /*
2   Sequential_iterator.cc -- implement Sequential_iterator
3
4   source file of the GNU LilyPond music typesetter
5
6   (c) 1997--2004 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7 */
8
9 #include "translator-group.hh"
10 #include "context.hh"
11 #include "sequential-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   Invariant for the data structure.
26
27
28   if (gh_pair_p (cursor_))
29     iter_->music_ == unsmob_music (ly_car (cursor_))
30   else
31     iter_ == 0;
32
33   The length of musiclist from start to up to cursor_ (cursor_ not
34   including), is summed
35
36   here_mom_  = sum (length (musiclist [start ... cursor>))  %)  
37   
38  */
39 Sequential_iterator::Sequential_iterator ()
40 {
41   here_mom_ = Moment (0);
42   list_ = SCM_EOL;
43   cursor_ = SCM_EOL; 
44   grace_fixups_ = 0;
45   iter_ =0;
46 }
47
48 SCM 
49 Sequential_iterator::get_music_list () const
50 {
51   return SCM_EOL;
52 }
53
54 void
55 Sequential_iterator::do_quit ()
56 {
57   if (iter_)
58     iter_->quit();
59 }
60
61
62
63
64 void
65 Sequential_iterator::derived_mark ()const
66 {
67   if (iter_)
68     scm_gc_mark (iter_->self_scm());
69   scm_gc_mark (list_);
70   scm_gc_mark (cursor_);
71 }
72
73
74 void
75 Sequential_iterator::derived_substitute (Context *f,Context *t)
76 {
77   if (iter_)
78     iter_->substitute_outlet (f,t);
79   
80 }
81
82 Grace_fixup *
83 get_grace_fixups (SCM cursor)
84 {
85   Moment here;
86   Moment last (-1);
87   Grace_fixup *head = 0;
88   Grace_fixup **tail = &head;
89
90   for (; gh_pair_p (cursor); cursor = ly_cdr (cursor))
91     {
92       Music * mus = unsmob_music (ly_car (cursor));
93       Moment s = mus->start_mom ();
94       Moment l =mus->get_length () - s;
95
96       if (s.grace_part_)
97         {
98           if (last != Moment (-1))
99             {
100               Grace_fixup *p =new Grace_fixup;
101               p->start_ = last;
102               p->length_ = here - last;
103               p->grace_start_ = s.grace_part_;
104               p->next_ = 0;
105               *tail = p;
106               tail = &(*tail)->next_; 
107             }
108
109           here.grace_part_ = s.grace_part_;
110         }
111       
112       if (l.to_bool())
113         {
114           last = here;
115           here += l;
116         }
117     }
118   return  head;
119 }
120
121 Grace_fixup *
122 copy_grace_fixups (Grace_fixup* src)
123 {
124   Grace_fixup * head = 0;
125   Grace_fixup **dest = &head;
126
127   while (src)
128     {
129       *dest = new Grace_fixup (*src);
130       dest = & (*dest)->next_;
131       src = src ->next_;
132     }
133
134   return head;
135 }
136
137 void
138 Sequential_iterator::construct_children ()
139 {
140   list_ = get_music_list ();
141   cursor_ = list_; 
142
143   iter_ = 0;
144   if (gh_pair_p (cursor_))
145     {
146       Music *m  =unsmob_music (ly_car (cursor_));
147       iter_ = unsmob_iterator (get_iterator (m));
148     }
149   
150   while (iter_ && !iter_->ok ())
151     {
152       next_element (true);
153     }
154
155   here_mom_ = get_music ()->start_mom ();
156   grace_fixups_ = get_grace_fixups (cursor_);
157
158   /*
159     iter_->ok () is tautology, but what the heck.
160    */
161   if (iter_ && iter_->ok ()) 
162     descend_to_child ();
163 }
164
165
166 /*
167   maintain invariants: change cursor, iter and here_mom_ in one fell
168   swoop.
169 */
170 void
171 Sequential_iterator::next_element (bool)
172 {
173   Moment len =iter_->music_get_length () - iter_->music_start_mom ();
174   assert (!grace_fixups_  || grace_fixups_->start_ >= here_mom_);
175   
176   if (len.main_part_ && grace_fixups_ &&
177       grace_fixups_->start_ == here_mom_)
178     {
179       here_mom_ += grace_fixups_->length_;
180       here_mom_.grace_part_ += grace_fixups_->grace_start_;
181
182       Grace_fixup * n =grace_fixups_->next_;
183       delete grace_fixups_;
184       grace_fixups_ = n;
185     }
186   else if (len.grace_part_ && !len.main_part_)
187     {
188       here_mom_.grace_part_ =0;
189     }
190   else
191     {
192       /*
193         !len.grace_part_ || len.main_part_
194
195         We skip over a big chunk (mainpart != 0). Any starting graces
196         in that chunk should be in len.grace_part_
197
198       */
199       here_mom_ += len;
200     }
201   
202   cursor_ = ly_cdr (cursor_);
203
204   iter_->quit();
205   if (gh_pair_p (cursor_))
206     iter_ = unsmob_iterator (get_iterator (unsmob_music (ly_car (cursor_))));
207   else
208     iter_ = 0;
209 }
210
211 /*
212   move to context of child iterator if it is deeper down in the
213   hierarchy.
214   */
215 void
216 Sequential_iterator::descend_to_child ()
217 {
218   Context * child_report = child_report = iter_->get_outlet ();
219   Context * me_report = get_outlet ();
220
221   Context * c = child_report;
222   while (c && c != me_report)
223     {
224       c= c->daddy_context_;
225     }
226   
227   if (c == me_report)
228     set_translator (child_report);
229 }
230
231
232
233 void
234 Sequential_iterator::process (Moment until)
235 {
236   while (iter_)
237     {
238       if (grace_fixups_ &&
239           grace_fixups_->start_ == here_mom_
240           && (grace_fixups_->start_ + grace_fixups_->length_
241               + Moment (Rational (0), grace_fixups_->grace_start_) == until))
242         {
243           /*
244             do the stuff/note/rest preceding a grace.
245            */
246           iter_->process (iter_->music_get_length ());
247         }
248       else
249         iter_->process (until - here_mom_ + iter_->music_start_mom ());
250
251       /*
252         if the iter is still OK, there must be events left that have
253         
254           TIME > LEFT
255           
256       */
257       if (iter_->ok ())
258         return ;
259
260       descend_to_child ();
261       next_element (true);
262     }
263 }
264
265 Moment
266 Sequential_iterator::pending_moment () const
267 {
268   Moment cp = iter_->pending_moment ();
269
270   /*
271     Fix-up a grace note halfway in the music.
272   */
273   if (grace_fixups_ && here_mom_ == grace_fixups_->start_
274       && grace_fixups_->length_ + iter_->music_start_mom () == cp)
275     {
276       return here_mom_ + grace_fixups_->length_ + Moment (0, grace_fixups_->grace_start_);
277     }
278
279   /*
280     Fix-up a grace note at  the start of the music.
281   */
282   return cp + here_mom_ - iter_->music_start_mom ();
283 }
284
285
286 bool
287 Sequential_iterator::ok () const
288 {
289   return iter_;
290 }
291
292 Music_iterator*
293 Sequential_iterator::try_music_in_children (Music *m) const
294
295   return iter_ ? iter_->try_music (m) : 0;
296 }
297
298 IMPLEMENT_CTOR_CALLBACK (Sequential_iterator);
299
300 bool
301 Sequential_iterator::run_always () const
302 {
303   return iter_ ? iter_->run_always () : false; 
304 }