]> git.donarmstrong.com Git - lilypond.git/blob - lily/unfolded-repeat-iterator.cc
release: 1.3.98
[lilypond.git] / lily / unfolded-repeat-iterator.cc
1 /*   
2   unfolded-repeat-iterator.cc --  implement Unfolded_repeat_iterator
3   
4   source file of the GNU LilyPond music typesetter
5   
6   (c) 1999--2000 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10
11 #include "repeated-music.hh"
12 #include "music-list.hh"
13 #include "unfolded-repeat-iterator.hh"
14 #include "debug.hh"
15 #include "translator-group.hh"
16
17 Unfolded_repeat_iterator::~Unfolded_repeat_iterator ()
18 {
19   delete current_iter_p_;
20 }
21
22 Unfolded_repeat_iterator::Unfolded_repeat_iterator ()
23 {
24   done_count_ =0;
25   current_iter_p_ =0;
26   do_main_b_ = false;
27   alternative_count_i_ =0;
28 }
29
30 /**
31
32 If we are in the body of the repeat always go to the current alternative.
33
34 If we are not in the body, then we are in an alternative.  If we are
35 fully unfolding, advance the current alternative and go back to main.
36 If we are semi-unfolding, advance the current alternative, and go to
37 the  alternative just set.
38    
39  */
40 void
41 Unfolded_repeat_iterator::next_element (bool side_effect) 
42 {
43   Repeated_music * repmus =dynamic_cast<Repeated_music *> (music_l_);
44   delete current_iter_p_;
45   current_iter_p_ =0;
46
47   bool do_repcommands = side_effect && repmus->volta_fold_b_;
48   
49   if (do_main_b_)
50     {
51       /*
52         we were busy doing the main body, so
53
54         - go to alternative if we're a volta
55
56         - make a :| if there are no alternatives   
57         
58         - do something intelligent when we're fully unfolding (fixcomment)
59        */
60       
61       here_mom_ += repmus->body ()->length_mom ();
62
63       if (!repmus->volta_fold_b_)
64         done_count_ ++;
65      
66       if (gh_pair_p (alternative_cons_))
67         {
68           current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
69           do_main_b_ = false;
70
71           if (repmus->volta_fold_b_)
72             {
73               String repstr = to_str (done_count_ + 1);
74               if (do_repcommands)
75                 add_repeat_command (gh_list (ly_symbol2scm ("volta"),
76                                              ly_str02scm (repstr.ch_C()), SCM_UNDEFINED));
77             }     
78         }
79       else if (repmus->volta_fold_b_)
80         {
81           add_repeat_command (ly_symbol2scm ("end-repeat"));
82         }
83       else if (done_count_ <  repmus->repeats_i_)
84         {
85           current_iter_p_ = get_iterator_p (repmus->body ());
86           do_main_b_ = true;
87         }
88     }
89   else
90     {
91       /*
92         we're not in the main part. So we're either in an alternative, or
93         we just finished.
94       */
95
96       /*
97         we're in the alternatives.  We move the pointer to the
98         next alternative.
99        */
100       if (alternative_cons_)
101         {
102           here_mom_ += unsmob_music (gh_car (alternative_cons_))->length_mom ();
103
104           if (repmus->volta_fold_b_ || 
105               repmus->repeats_i_ - done_count_  < alternative_count_i_)
106             alternative_cons_ = gh_cdr (alternative_cons_);
107           
108           if (do_repcommands)
109             add_repeat_command (gh_list (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED));
110
111           
112           
113           /*
114             we've done the main body as well, but didn't go over the other
115             increment.  */
116           if (repmus->volta_fold_b_)
117             done_count_ ++;
118         }
119
120       /*
121         We still have alternatives left, so
122
123         if we're volta: traverse them
124
125         if we're full unfold: go back to main body.
126        */
127       
128       if (done_count_ < repmus->repeats_i_ && gh_pair_p (alternative_cons_))
129         {
130           if (do_repcommands)
131             {
132               String repstr = to_str (done_count_ + 1);
133               add_repeat_command (gh_list (ly_symbol2scm ("volta"),
134                                            ly_str02scm (repstr.ch_C()), SCM_UNDEFINED));
135               add_repeat_command (ly_symbol2scm ("end-repeat"));
136             }
137
138           
139           if (repmus->volta_fold_b_)
140             current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
141           else
142             {
143               current_iter_p_ = get_iterator_p (repmus->body ());
144               do_main_b_ = true;
145             }
146         }
147     }
148 }
149
150
151 bool
152 Unfolded_repeat_iterator::ok () const
153 {
154   return current_iter_p_ ;
155 }
156
157 Moment
158 Unfolded_repeat_iterator::pending_moment () const
159 {
160   return here_mom_ + current_iter_p_->pending_moment ();
161 }
162
163 void
164 Unfolded_repeat_iterator::construct_children ()
165 {
166   Repeated_music * mus =dynamic_cast<Repeated_music *> (music_l_);
167   
168   alternative_cons_ = (mus->alternatives ())
169     ? mus->alternatives ()->music_list ()
170     : SCM_EOL;
171
172   for (SCM p = alternative_cons_; gh_pair_p (p); p = gh_cdr (p))
173     alternative_count_i_ ++;
174
175   if (mus->body ())
176     {
177       current_iter_p_  = get_iterator_p (mus->body ());
178       do_main_b_ = true;
179     }
180   else if (gh_pair_p (alternative_cons_))
181     {
182       current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
183       do_main_b_ = false;
184     }
185 }
186
187 /*
188   TODO: add source information for debugging
189  */
190 void
191 Unfolded_repeat_iterator::add_repeat_command (SCM what)
192 {
193   SCM reps = ly_symbol2scm ("repeatCommands");
194   SCM current_reps = report_to_l ()->get_property(reps);
195
196   Translator_group * where = report_to_l ()->where_defined (reps);
197   if (where
198       && current_reps == SCM_EOL || gh_pair_p (current_reps))
199     {
200       current_reps = gh_cons (what, current_reps);
201       where->set_property (reps, current_reps);
202     }
203 }
204
205 void
206 Unfolded_repeat_iterator::process (Moment m) 
207 {
208   if (!m)
209     {
210       if (dynamic_cast<Repeated_music*> (music_l_)->volta_fold_b_)
211         add_repeat_command (ly_symbol2scm ("start-repeat"));
212     }
213   while (1)
214     {
215       while (!current_iter_p_->ok ())
216         {
217           next_element(true);
218
219           if (!current_iter_p_)
220             return;
221         }
222       
223       if (m - here_mom_ >= current_iter_p_->pending_moment ())
224         current_iter_p_->process (m - here_mom_);
225       else
226         return;
227     }
228 }
229
230 void
231 Unfolded_repeat_iterator::skip (Moment until)
232 {
233   while (current_iter_p_)
234     {
235       Moment l =current_iter_p_->music_length_mom ();
236       if (l >= until - here_mom_)
237         current_iter_p_->skip (until - here_mom_);
238
239       if (current_iter_p_->ok ())
240         return ; 
241
242       next_element (false);
243     }
244 }
245
246 SCM
247 Unfolded_repeat_iterator::get_music (Moment until)const
248 {
249   SCM s = SCM_EOL;
250   if (until <  pending_moment ())
251     return s;
252
253
254   Unfolded_repeat_iterator * me
255     = dynamic_cast<Unfolded_repeat_iterator*> (this->clone ());
256   
257   while (me->ok ())
258     {
259       SCM nm = me->current_iter_p_->get_music (until -
260                                                me->here_mom_);
261       
262       s = gh_append2 (nm, s);
263       
264       Moment m = 0;
265       for (SCM i = nm; gh_pair_p(i); i = gh_cdr (i))
266         m = m >? unsmob_music (gh_car (i))->length_mom ();
267
268       if (m > Moment (0))
269         break ;
270       else
271         me->next_element (false);
272     }
273
274   delete me;
275   
276   return s;
277 }
278
279
280 Music_iterator* 
281 Unfolded_repeat_iterator::try_music_in_children (Music  * m) const
282 {
283   return  current_iter_p_->try_music (m);
284 }