]> git.donarmstrong.com Git - lilypond.git/blob - lily/unfolded-repeat-iterator.cc
* lily/include/debug.hh: deprecate.
[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 "warn.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   here_mom_ = src.here_mom_;
97   alternative_count_i_ = src.alternative_count_i_;
98   alternative_cons_ = src.alternative_cons_;
99 }
100
101 Unfolded_repeat_iterator::Unfolded_repeat_iterator ()
102 {
103   done_count_ =0;
104   current_iter_p_ =0;
105   volta_b_ = false;
106   do_main_b_ = false;
107   here_mom_ = Moment (0);
108   alternative_count_i_ =0;
109   alternative_cons_ = SCM_EOL;
110 }
111
112 /**
113
114 If we are in the body of the repeat always go to the current alternative.
115
116 If we are not in the body, then we are in an alternative.  If we are
117 fully unfolding, advance the current alternative and go back to main.
118 If we are semi-unfolding, advance the current alternative, and go to
119 the  alternative just set.
120    
121  */
122 void
123 Unfolded_repeat_iterator::next_element (bool side_effect) 
124 {
125   Repeated_music * repmus =dynamic_cast<Repeated_music *> (music_l ());
126   delete current_iter_p_;
127   current_iter_p_ =0;
128
129   bool do_repcommands = side_effect && volta_b_;
130   
131   if (do_main_b_)
132     {
133       /*
134         we were busy doing the main body, so
135
136         - go to alternative if we're a volta
137
138         - make a :| if there are no alternatives   
139         
140         - do something intelligent when we're fully unfolding (fixcomment)
141        */
142       
143       here_mom_ += repmus->body ()->length_mom ();
144
145       if (!volta_b_)
146         done_count_ ++;
147      
148       if (gh_pair_p (alternative_cons_))
149         {
150           current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
151           do_main_b_ = false;
152
153           if (volta_b_)
154             {
155               String repstr = to_str (done_count_ + 1) + ".";
156
157               /*
158                 we're coming in from main, so we're always on the first repeat.
159                */
160               assert (done_count_ == 0);
161
162               if (done_count_ == 0
163                   && alternative_count_i_ < repmus->repeat_count ())
164                 {
165                   done_count_ += repmus->repeat_count () - alternative_count_i_;                  
166                   repstr = "1.--" + to_str (done_count_ + 1) + ".";               
167                 }                 
168               
169               if (do_repcommands)
170                 add_repeat_command (scm_list_n (ly_symbol2scm ("volta"),
171                                              ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
172             }     
173         }
174       else if (volta_b_)
175         {
176           add_repeat_command (ly_symbol2scm ("end-repeat"));
177         }
178       else if (done_count_ <  repmus->repeat_count ())
179         {
180           current_iter_p_ = get_iterator_p (repmus->body ());
181           do_main_b_ = true;
182         }
183     }
184   else
185     {
186       /*
187         we're not in the main part. So we're either in an alternative, or
188         we just finished.
189       */
190
191       /*
192         we're in the alternatives.  We move the pointer to the
193         next alternative.
194        */
195       if (alternative_cons_)
196         {
197           here_mom_ += unsmob_music (ly_car (alternative_cons_))->length_mom ();
198
199           if (volta_b_ || 
200               repmus->repeat_count () - done_count_  < alternative_count_i_)
201             alternative_cons_ = ly_cdr (alternative_cons_);
202           
203           if (do_repcommands)
204             add_repeat_command (scm_list_n (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED));
205
206           
207           
208           /*
209             we've done the main body as well, but didn't go over the other
210             increment.  */
211           if (volta_b_)
212             done_count_ ++;
213         }
214
215       /*
216         We still have alternatives left, so
217
218         if we're volta: traverse them
219
220         if we're full unfold: go back to main body.
221        */
222       
223       if (done_count_ < repmus->repeat_count () && gh_pair_p (alternative_cons_))
224         {
225           if (do_repcommands)
226             {
227               String repstr = to_str (done_count_ + 1) + ".";
228               add_repeat_command (scm_list_n (ly_symbol2scm ("volta"),
229                                            ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
230               add_repeat_command (ly_symbol2scm ("end-repeat"));
231             }
232
233           
234           if (volta_b_)
235             current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
236           else
237             {
238               current_iter_p_ = get_iterator_p (repmus->body ());
239               do_main_b_ = true;
240             }
241         }
242     }
243 }
244
245
246 bool
247 Unfolded_repeat_iterator::ok () const
248 {
249   return current_iter_p_;
250 }
251
252 Moment
253 Unfolded_repeat_iterator::pending_moment () const
254 {
255   return here_mom_ + current_iter_p_->pending_moment ();
256 }
257
258 void
259 Unfolded_repeat_iterator::construct_children ()
260 {
261   Repeated_music * mus =dynamic_cast<Repeated_music *> (music_l ());
262   
263   alternative_cons_ = (mus->alternatives ())
264     ? mus->alternatives ()
265     : SCM_EOL;
266
267   for (SCM p = alternative_cons_; gh_pair_p (p); p = ly_cdr (p))
268     alternative_count_i_ ++;
269
270   if (mus->body ())
271     {
272       current_iter_p_  = get_iterator_p (mus->body ());
273       do_main_b_ = true;
274     }
275   else if (gh_pair_p (alternative_cons_))
276     {
277       current_iter_p_ = get_iterator_p (unsmob_music (ly_car (alternative_cons_)));
278       do_main_b_ = false;
279     }
280
281   while (current_iter_p_ && !current_iter_p_-> ok ())
282     {
283       next_element (true);
284     }
285 }
286
287 /*
288   TODO: add source information for debugging
289  */
290 void
291 Unfolded_repeat_iterator::add_repeat_command (SCM what)
292 {
293   SCM reps = ly_symbol2scm ("repeatCommands");
294   SCM current_reps = report_to_l ()->internal_get_property (reps);
295
296   Translator_group * where = report_to_l ()->where_defined (reps);
297   if (where
298       && current_reps == SCM_EOL || gh_pair_p (current_reps))
299     {
300       current_reps = gh_cons (what, current_reps);
301       where->internal_set_property (reps, current_reps);
302     }
303 }
304
305 void
306 Unfolded_repeat_iterator::process (Moment m) 
307 {
308   if (!m.to_bool ())
309     {
310       if (volta_b_)
311         add_repeat_command (ly_symbol2scm ("start-repeat"));
312     }
313   while (1)
314     {
315       while (!current_iter_p_->ok ())
316         {
317           next_element (true);
318
319           if (!current_iter_p_)
320             return;
321         }
322       
323       if (m - here_mom_ >= current_iter_p_->pending_moment ())
324         current_iter_p_->process (m - here_mom_);
325       else
326         return;
327     }
328 }
329
330 void
331 Unfolded_repeat_iterator::skip (Moment until)
332 {
333   while (current_iter_p_)
334     {
335       Moment l =current_iter_p_->music_length_mom ();
336       if (l >= until - here_mom_)
337         current_iter_p_->skip (until - here_mom_);
338
339       if (current_iter_p_->ok ())
340         return ; 
341
342       next_element (false);
343     }
344 }
345
346 SCM
347 Unfolded_repeat_iterator::get_music (Moment until)const
348 {
349   SCM s = SCM_EOL;
350   if (until <  pending_moment ())
351     return s;
352
353
354   Unfolded_repeat_iterator * me
355     = dynamic_cast<Unfolded_repeat_iterator*> (this->clone ());
356   
357   while (me->ok ())
358     {
359       SCM nm = me->current_iter_p_->get_music (until -
360                                                me->here_mom_);
361       
362       s = gh_append2 (nm, s);
363       
364       Moment m = 0;
365       for (SCM i = nm; gh_pair_p (i); i = ly_cdr (i))
366         m = m >? unsmob_music (ly_car (i))->length_mom ();
367
368       if (m > Moment (0))
369         break ;
370       else
371         me->next_element (false);
372     }
373
374   delete me;
375   
376   return s;
377 }
378
379
380 Music_iterator* 
381 Unfolded_repeat_iterator::try_music_in_children (Music  * m) const
382 {
383   return  current_iter_p_->try_music (m);
384 }
385
386 IMPLEMENT_CTOR_CALLBACK (Unfolded_repeat_iterator);
387 IMPLEMENT_CTOR_CALLBACK (Volta_repeat_iterator);
388
389 Volta_repeat_iterator::Volta_repeat_iterator ()
390 {
391   volta_b_ = true;
392 }