]> git.donarmstrong.com Git - lilypond.git/blob - lily/unfolded-repeat-iterator.cc
47eabef881a6341b14734d9fbb6ca5465461ecb9
[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         - do something intelligent when we're fully unfolding (fixcomment)
57        */
58       
59       here_mom_ += repmus->body ()->length_mom ();
60
61       if (!repmus->volta_fold_b_)
62         done_count_ ++;
63      
64       if (gh_pair_p (alternative_cons_))
65         {
66           current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
67           do_main_b_ = false;
68
69           if (repmus->volta_fold_b_)
70             {
71               String repstr = to_str (done_count_ + 1);
72               if (do_repcommands)
73                 add_repeat_command (gh_list (ly_symbol2scm ("volta"),
74                                              ly_str02scm (repstr.ch_C()), SCM_UNDEFINED));
75             }     
76         }
77       else if (done_count_ <  repmus->repeats_i_ && !repmus->volta_fold_b_) 
78         {
79           current_iter_p_ = get_iterator_p (repmus->body ());
80           do_main_b_ = true;
81         }
82     }
83   else
84     {
85       /*
86         we're not in the main part. So we're either in an alternative, or
87         we just finished.
88       */
89
90       /*
91         we're in the alternatives.  We move the pointer to the
92         next alternative.
93        */
94       if (alternative_cons_)
95         {
96           here_mom_ += unsmob_music (gh_car (alternative_cons_))->length_mom ();
97
98           if (repmus->volta_fold_b_ || 
99               repmus->repeats_i_ - done_count_  < alternative_count_i_)
100             alternative_cons_ = gh_cdr (alternative_cons_);
101           
102           if (do_repcommands)
103             add_repeat_command (gh_list (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED));
104
105           
106           
107           /*
108             we've done the main body as well, but didn't go over the other
109             increment.  */
110           if (repmus->volta_fold_b_)
111             done_count_ ++;
112         }
113
114       /*
115         We still have alternatives left, so
116
117         if we're volta: traverse them
118
119         if we're full unfold: go back to main body.
120        */
121       
122       if (done_count_ < repmus->repeats_i_ && gh_pair_p (alternative_cons_))
123         {
124           if (do_repcommands)
125             {
126               String repstr = to_str (done_count_ + 1);
127               add_repeat_command (gh_list (ly_symbol2scm ("volta"),
128                                            ly_str02scm (repstr.ch_C()), SCM_UNDEFINED));
129               add_repeat_command (ly_symbol2scm ("end-repeat"));
130             }
131
132           
133           if (repmus->volta_fold_b_)
134             current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
135           else
136             {
137               current_iter_p_ = get_iterator_p (repmus->body ());
138               do_main_b_ = true;
139             }
140         }
141     }
142 }
143
144
145 bool
146 Unfolded_repeat_iterator::ok () const
147 {
148   return current_iter_p_ ;
149 }
150
151 Moment
152 Unfolded_repeat_iterator::pending_moment () const
153 {
154   return here_mom_ + current_iter_p_->pending_moment ();
155 }
156
157 void
158 Unfolded_repeat_iterator::construct_children ()
159 {
160   Repeated_music * mus =dynamic_cast<Repeated_music *> (music_l_);
161   
162   alternative_cons_ = (mus->alternatives ())
163     ? mus->alternatives ()->music_list ()
164     : SCM_EOL;
165
166   for (SCM p = alternative_cons_; gh_pair_p (p); p = gh_cdr (p))
167     alternative_count_i_ ++;
168
169   if (mus->body ())
170     {
171       current_iter_p_  = get_iterator_p (mus->body ());
172       do_main_b_ = true;
173     }
174   else if (gh_pair_p (alternative_cons_))
175     {
176       current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
177       do_main_b_ = false;
178     }
179 }
180
181 /*
182   TODO: add source information for debugging
183  */
184 void
185 Unfolded_repeat_iterator::add_repeat_command (SCM what)
186 {
187   SCM reps = ly_symbol2scm ("repeatCommands");
188   SCM current_reps = report_to_l ()->get_property(reps);
189
190   Translator_group * where = report_to_l ()->where_defined (reps);
191   if (where
192       && current_reps == SCM_EOL || gh_pair_p (current_reps))
193     {
194       current_reps = gh_cons (what, current_reps);
195       where->set_property (reps, current_reps);
196     }
197 }
198
199 void
200 Unfolded_repeat_iterator::process (Moment m) 
201 {
202   if (!m)
203     {
204       if (dynamic_cast<Repeated_music*> (music_l_)->volta_fold_b_)
205         add_repeat_command (ly_symbol2scm ("start-repeat"));
206     }
207   while (1)
208     {
209       while (!current_iter_p_->ok ())
210         {
211           next_element(true);
212
213           if (!current_iter_p_)
214             return;
215         }
216       
217       if (m - here_mom_ >= current_iter_p_->pending_moment ())
218         current_iter_p_->process (m - here_mom_);
219       else
220         return;
221     }
222 }
223
224 void
225 Unfolded_repeat_iterator::skip (Moment until)
226 {
227   while (current_iter_p_)
228     {
229       Moment l =current_iter_p_->music_length_mom ();
230       if (l >= until - here_mom_)
231         current_iter_p_->skip (until - here_mom_);
232
233       if (current_iter_p_->ok ())
234         return ; 
235
236       next_element (false);
237     }
238 }
239
240 SCM
241 Unfolded_repeat_iterator::get_music (Moment until)const
242 {
243   SCM s = SCM_EOL;
244   if (until <  pending_moment ())
245     return s;
246
247
248   Unfolded_repeat_iterator * me
249     = dynamic_cast<Unfolded_repeat_iterator*> (this->clone ());
250   
251   while (me->ok ())
252     {
253       SCM nm = me->current_iter_p_->get_music (until -
254                                                me->here_mom_);
255       
256       s = gh_append2 (nm, s);
257       
258       Moment m = 0;
259       for (SCM i = nm; gh_pair_p(i); i = gh_cdr (i))
260         m = m >? unsmob_music (gh_car (i))->length_mom ();
261
262       if (m > Moment (0))
263         break ;
264       else
265         me->next_element (false);
266     }
267
268   delete me;
269   
270   return s;
271 }
272
273
274 Music_iterator* 
275 Unfolded_repeat_iterator::try_music_in_children (Music  * m) const
276 {
277   return  current_iter_p_->try_music (m);
278 }