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