lilypond-1.5.9
[lilypond.git] / lily / unfolded-repeat-iterator.cc
blob73343eee83af721a4af3e01c9866b6a22f9d3017
1 /*
2 unfolded-repeat-iterator.cc -- implement Unfolded_repeat_iterator
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2001 Han-Wen Nienhuys <hanwen@cs.uu.nl>
8 */
11 This is too hairy. Maybe split into subclasses for volta and full
12 unfold?
15 #include "music-iterator.hh"
16 #include "repeated-music.hh"
17 #include "music-list.hh"
18 #include "debug.hh"
19 #include "translator-group.hh"
21 /**
22 Iterate repeats. First do body, then alternatives one by one,
23 optionally interspersed by the body.
25 class Unfolded_repeat_iterator : public Music_iterator
27 void add_repeat_command (SCM);
29 public:
30 VIRTUAL_COPY_CONS (Music_iterator);
31 /**
32 How often have we done the body (assuming bodies are interspersed.)?
34 In volta: the number to print in the bracket.
36 int done_count_;
37 static SCM constructor_cxx_function;
40 are we now busy doing the body?
43 bool do_main_b_;
46 are we doing volta's?
48 bool volta_b_;
50 /** How far have we progressed into the repeat.
51 This excludes the elt currently being iterated.
53 Moment here_mom_;
54 int alternative_count_i_;
55 Music_iterator * current_iter_p_;
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;
70 virtual bool ok () const;
71 virtual void next_element (bool side_effect);
74 class Volta_repeat_iterator : public Unfolded_repeat_iterator
76 public:
77 Volta_repeat_iterator ();
78 static SCM constructor_cxx_function;
79 VIRTUAL_COPY_CONS (Music_iterator);
84 Unfolded_repeat_iterator::~Unfolded_repeat_iterator ()
86 delete current_iter_p_;
89 Unfolded_repeat_iterator::Unfolded_repeat_iterator (Unfolded_repeat_iterator const &src)
90 : Music_iterator (src)
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_;
100 Unfolded_repeat_iterator::Unfolded_repeat_iterator ()
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;
112 If we are in the body of the repeat always go to the current alternative.
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.
120 void
121 Unfolded_repeat_iterator::next_element (bool side_effect)
123 Repeated_music * repmus =dynamic_cast<Repeated_music *> (music_l ());
124 delete current_iter_p_;
125 current_iter_p_ =0;
127 bool do_repcommands = side_effect && volta_b_;
129 if (do_main_b_)
132 we were busy doing the main body, so
134 - go to alternative if we're a volta
136 - make a :| if there are no alternatives
138 - do something intelligent when we're fully unfolding (fixcomment)
141 here_mom_ += repmus->body ()->length_mom ();
143 if (!volta_b_)
144 done_count_ ++;
146 if (gh_pair_p (alternative_cons_))
148 current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
149 do_main_b_ = false;
151 if (volta_b_)
153 String repstr = to_str (done_count_ + 1) + ".";
156 we're coming in from main, so we're always on the first repeat.
158 assert (done_count_ == 0);
160 if (done_count_ == 0
161 && alternative_count_i_ < repmus->repeat_count ())
163 done_count_ += repmus->repeat_count () - alternative_count_i_;
164 repstr = "1.--" + to_str (done_count_ + 1) + ".";
167 if (do_repcommands)
168 add_repeat_command (gh_list (ly_symbol2scm ("volta"),
169 ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
172 else if (volta_b_)
174 add_repeat_command (ly_symbol2scm ("end-repeat"));
176 else if (done_count_ < repmus->repeat_count ())
178 current_iter_p_ = get_iterator_p (repmus->body ());
179 do_main_b_ = true;
182 else
185 we're not in the main part. So we're either in an alternative, or
186 we just finished.
190 we're in the alternatives. We move the pointer to the
191 next alternative.
193 if (alternative_cons_)
195 here_mom_ += unsmob_music (gh_car (alternative_cons_))->length_mom ();
197 if (volta_b_ ||
198 repmus->repeat_count () - done_count_ < alternative_count_i_)
199 alternative_cons_ = gh_cdr (alternative_cons_);
201 if (do_repcommands)
202 add_repeat_command (gh_list (ly_symbol2scm ("volta"), SCM_BOOL_F, SCM_UNDEFINED));
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_ ++;
214 We still have alternatives left, so
216 if we're volta: traverse them
218 if we're full unfold: go back to main body.
221 if (done_count_ < repmus->repeat_count () && gh_pair_p (alternative_cons_))
223 if (do_repcommands)
225 String repstr = to_str (done_count_ + 1) + ".";
226 add_repeat_command (gh_list (ly_symbol2scm ("volta"),
227 ly_str02scm (repstr.ch_C ()), SCM_UNDEFINED));
228 add_repeat_command (ly_symbol2scm ("end-repeat"));
232 if (volta_b_)
233 current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
234 else
236 current_iter_p_ = get_iterator_p (repmus->body ());
237 do_main_b_ = true;
244 bool
245 Unfolded_repeat_iterator::ok () const
247 return current_iter_p_;
250 Moment
251 Unfolded_repeat_iterator::pending_moment () const
253 return here_mom_ + current_iter_p_->pending_moment ();
256 void
257 Unfolded_repeat_iterator::construct_children ()
259 Repeated_music * mus =dynamic_cast<Repeated_music *> (music_l ());
261 alternative_cons_ = (mus->alternatives ())
262 ? mus->alternatives ()->music_list ()
263 : SCM_EOL;
265 for (SCM p = alternative_cons_; gh_pair_p (p); p = gh_cdr (p))
266 alternative_count_i_ ++;
268 if (mus->body ())
270 current_iter_p_ = get_iterator_p (mus->body ());
271 do_main_b_ = true;
273 else if (gh_pair_p (alternative_cons_))
275 current_iter_p_ = get_iterator_p (unsmob_music (gh_car (alternative_cons_)));
276 do_main_b_ = false;
279 while (current_iter_p_ && !current_iter_p_-> ok ())
281 next_element (true);
286 TODO: add source information for debugging
288 void
289 Unfolded_repeat_iterator::add_repeat_command (SCM what)
291 SCM reps = ly_symbol2scm ("repeatCommands");
292 SCM current_reps = report_to_l ()->get_property (reps);
294 Translator_group * where = report_to_l ()->where_defined (reps);
295 if (where
296 && current_reps == SCM_EOL || gh_pair_p (current_reps))
298 current_reps = gh_cons (what, current_reps);
299 where->set_property (reps, current_reps);
303 void
304 Unfolded_repeat_iterator::process (Moment m)
306 if (!m.to_bool ())
308 if (volta_b_)
309 add_repeat_command (ly_symbol2scm ("start-repeat"));
311 while (1)
313 while (!current_iter_p_->ok ())
315 next_element (true);
317 if (!current_iter_p_)
318 return;
321 if (m - here_mom_ >= current_iter_p_->pending_moment ())
322 current_iter_p_->process (m - here_mom_);
323 else
324 return;
328 void
329 Unfolded_repeat_iterator::skip (Moment until)
331 while (current_iter_p_)
333 Moment l =current_iter_p_->music_length_mom ();
334 if (l >= until - here_mom_)
335 current_iter_p_->skip (until - here_mom_);
337 if (current_iter_p_->ok ())
338 return ;
340 next_element (false);
345 Unfolded_repeat_iterator::get_music (Moment until)const
347 SCM s = SCM_EOL;
348 if (until < pending_moment ())
349 return s;
352 Unfolded_repeat_iterator * me
353 = dynamic_cast<Unfolded_repeat_iterator*> (this->clone ());
355 while (me->ok ())
357 SCM nm = me->current_iter_p_->get_music (until -
358 me->here_mom_);
360 s = gh_append2 (nm, s);
362 Moment m = 0;
363 for (SCM i = nm; gh_pair_p (i); i = gh_cdr (i))
364 m = m >? unsmob_music (gh_car (i))->length_mom ();
366 if (m > Moment (0))
367 break ;
368 else
369 me->next_element (false);
372 delete me;
374 return s;
378 Music_iterator*
379 Unfolded_repeat_iterator::try_music_in_children (Music * m) const
381 return current_iter_p_->try_music (m);
384 IMPLEMENT_CTOR_CALLBACK (Unfolded_repeat_iterator);
385 IMPLEMENT_CTOR_CALLBACK (Volta_repeat_iterator);
387 Volta_repeat_iterator::Volta_repeat_iterator ()
389 volta_b_ = true;