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