]> git.donarmstrong.com Git - lilypond.git/blob - lily/sequential-music-iterator.cc
patch::: 1.3.136.jcn3
[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 #include "grace-iterator.hh"
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   Invariant for the data structure.
17
18
19   if (gh_pair_p (cursor_))
20     iter_p_->music_l_ == unsmob_music (gh_car (cursor_))
21   else
22     iter_p_ == 0;
23
24   The length of musiclist from start to up to cursor_ (cursor_ not
25   including), is summed
26
27   here_mom_  = sum (length (musiclist [start ... cursor>))  %)  
28   
29  */
30
31
32 Sequential_music_iterator::Sequential_music_iterator ()
33 {
34   cursor_ = SCM_EOL;
35   here_mom_ = Moment (0);
36
37   iter_p_ =0;
38 }
39
40 Sequential_music_iterator::Sequential_music_iterator (Sequential_music_iterator const &src)
41   : Music_iterator (src)
42 {
43   cursor_ = src.cursor_;
44   here_mom_ = src.here_mom_;
45   if (src.iter_p_)
46     iter_p_ = src.iter_p_->clone ();
47   else
48     iter_p_ = 0;
49 }
50
51 Sequential_music_iterator::~Sequential_music_iterator ()
52 {
53   delete iter_p_;
54 }
55
56 void
57 Sequential_music_iterator::construct_children ()
58 {
59   cursor_ = dynamic_cast<Music_sequence const*> (music_l_)->music_list ();
60
61   iter_p_ = gh_pair_p (cursor_) ?  get_iterator_p (unsmob_music (gh_car (cursor_))) : 0;
62   while (iter_p_ && !iter_p_->ok ())
63     {
64       next_element ();
65     }
66
67   /*
68     iter_p_->ok () is tautology, but what the heck.
69    */
70   if (iter_p_ && iter_p_->ok ()) 
71     descend_to_child ();
72
73 }
74
75
76 /*
77   maintain invariants: change cursor, iter and here_mom_ in one fell
78   swoop.
79 */
80 void
81 Sequential_music_iterator::next_element ()
82 {
83   here_mom_ += iter_p_->music_length_mom ();
84   delete iter_p_;
85   cursor_ = gh_cdr (cursor_);
86
87   if (gh_pair_p (cursor_))
88     iter_p_ = get_iterator_p (unsmob_music (gh_car (cursor_)));
89   else
90     iter_p_ = 0;
91 }
92
93 /*
94   move to context of child iterator if it is deeper down in the
95   hierarchy.
96   */
97
98 void
99 Sequential_music_iterator::descend_to_child ()
100 {
101   Translator_group  * child_report = child_report = iter_p_->report_to_l ();
102   Translator_group * me_report = report_to_l ();
103
104   if (dynamic_cast<Grace_iterator*> (iter_p_))
105     child_report = child_report->daddy_trans_l_;
106
107   Translator_group * c = child_report;
108   while (c && c != me_report)
109     {
110       c= c->daddy_trans_l_;
111     }
112   
113   if (c == me_report)
114     set_translator (child_report);
115 }
116
117
118 /*
119   Retrieve all music (starting at HERE), until a music with length L >
120   0 is found.  From the precondition, we know that UNTIL is later than
121   the earliest event. Hence we know
122   
123   L >= (UNTIL - HERE)
124
125   so something that comes after this thing with L > 0 happens after
126
127   HERE + L >= HERE + (UNTIL - HERE) = UNTIL
128
129   Hence all events after the one with L>0 are uninteresting, so we
130   ignore them.
131   
132 */
133
134 SCM
135 Sequential_music_iterator::get_music (Moment until)const
136 {
137   SCM s = SCM_EOL;
138   if (until <  pending_moment ())
139     return s;
140
141   Sequential_music_iterator * me =
142     dynamic_cast<Sequential_music_iterator*> (clone ());
143   while (me->ok ())
144     {
145       SCM nm = me->iter_p_->get_music (until - me->here_mom_);
146       s = gh_append2 (nm, s);
147       
148       Moment m = 0;
149       for (SCM i = nm; gh_pair_p (i); i = gh_cdr (i))
150         m = m >? unsmob_music (gh_car (i))->length_mom ();
151
152       if (m > Moment (0))
153         break ;
154       else
155         me->next_element ();
156     }
157   delete me;
158   
159   return s;
160 }
161 /*
162   Skip events till UNTIL. We don't do any other side effects (such as
163   moving descending to child iterator contexts, because they might
164   depend on \context specs and \translator changes being executed
165     
166  */
167 void
168 Sequential_music_iterator::skip (Moment until)
169 {
170   while (ok ())
171     {
172       Moment l =iter_p_->music_length_mom ();
173       if (l >= until - here_mom_)
174         iter_p_->skip (until - here_mom_);
175
176       if (iter_p_->ok ())
177         return ; 
178
179       next_element ();
180     }
181 }
182
183 void
184 Sequential_music_iterator::process (Moment until)
185 {
186   while (iter_p_)
187     {
188       iter_p_->process (until - here_mom_);
189
190       /*
191         if the iter is still OK, there must be events left that have
192         
193           TIME > LEFT
194           
195       */
196       if (iter_p_->ok ())
197         return ;
198
199       descend_to_child ();
200       next_element ();
201     }
202 }
203
204 Moment
205 Sequential_music_iterator::pending_moment () const
206 {
207   return iter_p_->pending_moment () + here_mom_;
208 }
209
210
211 bool
212 Sequential_music_iterator::ok () const
213 {
214   return iter_p_;
215 }
216
217 Music_iterator*
218 Sequential_music_iterator::try_music_in_children (Music *m) const
219
220   return iter_p_ ? iter_p_->try_music (m) : 0;
221 }
222 IMPLEMENT_CTOR_CALLBACK (Sequential_music_iterator);