]> git.donarmstrong.com Git - lilypond.git/blob - lily/unfolded-repeat-iterator.cc
release: 1.5.29
[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--2002 Han-Wen Nienhuys <hanwen@cs.uu.nl>
7   
8  */
9
10 /*
11   This is too hairy.  Maybe split into subclasses for volta and full
12   unfold?
13   
14  */
15 #include "music-iterator.hh"
16 #include "repeated-music.hh"
17 #include "music-list.hh"
18 #include "debug.hh"
19 #include "translator-group.hh"
20
21 /**
22    Iterate repeats.  First do body, then alternatives one by one,
23    optionally interspersed by the body.
24  */
25 class Unfolded_repeat_iterator : public Music_iterator
26 {
27   void add_repeat_command (SCM);
28
29 public:
30   VIRTUAL_COPY_CONS (Music_iterator);
31   /**
32      How often have we done the body (assuming bodies are interspersed.)?
33
34      In volta: the number to print in the bracket.
35    */
36   int done_count_;
37   static SCM constructor_cxx_function; 
38
39   /*
40     are we now busy doing the body?
41
42    */
43   bool do_main_b_;
44
45   /*
46     are we doing volta's?
47    */
48   bool volta_b_;
49
50   /** How far have we progressed into the repeat.
51       This excludes the elt currently being iterated.
52   */
53   Moment here_mom_;
54   int alternative_count_i_;
55   Music_iterator * current_iter_p_;
56   
57   /// pointer to the alternative that will be processed next.
58   SCM alternative_cons_;
59   ~Unfolded_repeat_iterator ();
60   Unfolded_repeat_iterator ();
61   Unfolded_repeat_iterator (Unfolded_repeat_iterator const &);
62 protected:  
63   virtual void construct_children ();
64   virtual Moment pending_moment () const;
65   virtual void process (Moment);
66   virtual Music_iterator *try_music_in_children (Music *) const;
67   virtual void skip (Moment);
68   virtual SCM get_music (Moment) const;
69   
70   virtual bool ok () const;
71   virtual void next_element (bool side_effect);
72 };
73
74 class Volta_repeat_iterator : public Unfolded_repeat_iterator
75 {
76 public:
77   Volta_repeat_iterator ();
78   static  SCM constructor_cxx_function;
79   VIRTUAL_COPY_CONS (Music_iterator);
80 };
81
82
83
84 Unfolded_repeat_iterator::~Unfolded_repeat_iterator ()
85 {
86   delete current_iter_p_;
87 }
88
89 Unfolded_repeat_iterator::Unfolded_repeat_iterator (Unfolded_repeat_iterator const &src)
90   : Music_iterator (src)
91 {
92   done_count_ = src.done_count_;
93   current_iter_p_ = (src.current_iter_p_)? src.current_iter_p_->clone () : 0;
94   do_main_b_ = src.do_main_b_;
95   volta_b_ = src.volta_b_;
96   alternative_count_i_ = src.alternative_count_i_;
97   alternative_cons_ = src.alternative_cons_;
98 }
99
100 Unfolded_repeat_iterator::Unfolded_repeat_iterator ()
101 {
102   done_count_ =0;
103   current_iter_p_ =0;
104   volta_b_ = false;
105   do_main_b_ = false;
106   alternative_count_i_ =0;
107   alternative_cons_ = SCM_EOL;
108 }
109
110 /**
111
112 If we are in the body of the repeat always go to the current alternative.
113
114 If we are not in the body, then we are in an alternative.  If we are
115 fully unfolding, advance the current alternative and go back to main.
116 If we are semi-unfolding, advance the current alternative, and go to
117 the  alternative just set.
118    
119  */
120 void
121 Unfolded_repeat_iterator::next_element (bool side_effect) 
122 {
123   Repeated_music * repmus =dynamic_cast<Repeated_music *> (music_l ());
124   delete current_iter_p_;
125   current_iter_p_ =0;
126
127   bool do_repcommands = side_effect && volta_b_;
128   
129   if (do_main_b_)
130     {
131       /*
132         we were busy doing the main body, so
133
134         - go to alternative if we're a volta
135
136         - make a :| if there are no alternatives   
137         
138         - do something intelligent when we're fully unfolding (fixcomment)
139        */
140       
141       here_mom_ += repmus->body ()->length_mom ();
142
143       if (!volta_b_)
144         done_count_ ++;
145      
146       if (gh_pair_p (alternative_cons_))
147         {
148           current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
149           do_main_b_ = false;
150
151           if (volta_b_)
152             {
153               String repstr = to_str (done_count_ + 1) + ".";
154
155               /*
156                 we're coming in from main, so we're always on the first repeat.
157                */
158               assert (done_count_ == 0);
159
160               if (done_count_ == 0
161                   && alternative_count_i_ < repmus->repeat_count ())
162                 {
163                   done_count_ += repmus->repeat_count () - alternative_count_i_;                  
164                   repstr = "1.--" + to_str (done_count_ + 1) + ".";               
165                 }                 
166               
167               if (do_repcommands)
168                 add_repeat_command (scm_list_n (ly_symbol2scm ("volta"),
169                                              ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
170             }     
171         }
172       else if (volta_b_)
173         {
174           add_repeat_command (ly_symbol2scm ("end-repeat"));
175         }
176       else if (done_count_ <  repmus->repeat_count ())
177         {
178           current_iter_p_ = get_iterator_p (repmus->body ());
179           do_main_b_ = true;
180         }
181     }
182   else
183     {
184       /*
185         we're not in the main part. So we're either in an alternative, or
186         we just finished.
187       */
188
189       /*
190         we're in the alternatives.  We move the pointer to the
191         next alternative.
192        */
193       if (alternative_cons_)
194         {
195           here_mom_ += unsmob_music (ly_car (alternative_cons_))->length_mom ();
196
197           if (volta_b_ || 
198               repmus->repeat_count () - done_count_  < alternative_count_i_)
199             alternative_cons_ = ly_cdr (alternative_cons_);
200           
201           if (do_repcommands)
202             add_repeat_command (scm_list_n (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED));
203
204           
205           
206           /*
207             we've done the main body as well, but didn't go over the other
208             increment.  */
209           if (volta_b_)
210             done_count_ ++;
211         }
212
213       /*
214         We still have alternatives left, so
215
216         if we're volta: traverse them
217
218         if we're full unfold: go back to main body.
219        */
220       
221       if (done_count_ < repmus->repeat_count () && gh_pair_p (alternative_cons_))
222         {
223           if (do_repcommands)
224             {
225               String repstr = to_str (done_count_ + 1) + ".";
226               add_repeat_command (scm_list_n (ly_symbol2scm ("volta"),
227                                            ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
228               add_repeat_command (ly_symbol2scm ("end-repeat"));
229             }
230
231           
232           if (volta_b_)
233             current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
234           else
235             {
236               current_iter_p_ = get_iterator_p (repmus->body ());
237               do_main_b_ = true;
238             }
239         }
240     }
241 }
242
243
244 bool
245 Unfolded_repeat_iterator::ok () const
246 {
247   return current_iter_p_;
248 }
249
250 Moment
251 Unfolded_repeat_iterator::pending_moment () const
252 {
253   return here_mom_ + current_iter_p_->pending_moment ();
254 }
255
256 void
257 Unfolded_repeat_iterator::construct_children ()
258 {
259   Repeated_music * mus =dynamic_cast<Repeated_music *> (music_l ());
260   
261   alternative_cons_ = (mus->alternatives ())
262     ? mus->alternatives ()
263     : SCM_EOL;
264
265   for (SCM p = alternative_cons_; gh_pair_p (p); p = ly_cdr (p))
266     alternative_count_i_ ++;
267
268   if (mus->body ())
269     {
270       current_iter_p_  = get_iterator_p (mus->body ());
271       do_main_b_ = true;
272     }
273   else if (gh_pair_p (alternative_cons_))
274     {
275       current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
276       do_main_b_ = false;
277     }
278
279   while (current_iter_p_ && !current_iter_p_-> ok ())
280     {
281       next_element (true);
282     }
283 }
284
285 /*
286   TODO: add source information for debugging
287  */
288 void
289 Unfolded_repeat_iterator::add_repeat_command (SCM what)
290 {
291   SCM reps = ly_symbol2scm ("repeatCommands");
292   SCM current_reps = report_to_l ()->internal_get_property (reps);
293
294   Translator_group * where = report_to_l ()->where_defined (reps);
295   if (where
296       && current_reps == SCM_EOL || gh_pair_p (current_reps))
297     {
298       current_reps = gh_cons (what, current_reps);
299       where->internal_set_property (reps, current_reps);
300     }
301 }
302
303 void
304 Unfolded_repeat_iterator::process (Moment m) 
305 {
306   if (!m.to_bool ())
307     {
308       if (volta_b_)
309         add_repeat_command (ly_symbol2scm ("start-repeat"));
310     }
311   while (1)
312     {
313       while (!current_iter_p_->ok ())
314         {
315           next_element (true);
316
317           if (!current_iter_p_)
318             return;
319         }
320       
321       if (m - here_mom_ >= current_iter_p_->pending_moment ())
322         current_iter_p_->process (m - here_mom_);
323       else
324         return;
325     }
326 }
327
328 void
329 Unfolded_repeat_iterator::skip (Moment until)
330 {
331   while (current_iter_p_)
332     {
333       Moment l =current_iter_p_->music_length_mom ();
334       if (l >= until - here_mom_)
335         current_iter_p_->skip (until - here_mom_);
336
337       if (current_iter_p_->ok ())
338         return ; 
339
340       next_element (false);
341     }
342 }
343
344 SCM
345 Unfolded_repeat_iterator::get_music (Moment until)const
346 {
347   SCM s = SCM_EOL;
348   if (until <  pending_moment ())
349     return s;
350
351
352   Unfolded_repeat_iterator * me
353     = dynamic_cast<Unfolded_repeat_iterator*> (this->clone ());
354   
355   while (me->ok ())
356     {
357       SCM nm = me->current_iter_p_->get_music (until -
358                                                me->here_mom_);
359       
360       s = gh_append2 (nm, s);
361       
362       Moment m = 0;
363       for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
364         m = m >? unsmob_music (ly_car (i))->length_mom ();
365
366       if (m > Moment (0))
367         break ;
368       else
369         me->next_element (false);
370     }
371
372   delete me;
373   
374   return s;
375 }
376
377
378 Music_iterator* 
379 Unfolded_repeat_iterator::try_music_in_children (Music  * m) const
380 {
381   return  current_iter_p_->try_music (m);
382 }
383
384 IMPLEMENT_CTOR_CALLBACK (Unfolded_repeat_iterator);
385 IMPLEMENT_CTOR_CALLBACK (Volta_repeat_iterator);
386
387 Volta_repeat_iterator::Volta_repeat_iterator ()
388 {
389   volta_b_ = true;
390 }