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