lilypond-1.3.147
[lilypond.git] / lily / repeat-engraver.cc
blob96b11d5e1186f2a58eecaba95fb5d2ba32c07aa9
1 /*
2 repeat-engraver.cc -- implement Repeat_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1998--2000 Jan Nieuwenhuizen <janneke@gnu.org>
7 */
9 #include "engraver.hh"
10 #include "cons.hh"
11 #include "bar.hh"
12 #include "bar-engraver.hh"
13 #include "musical-request.hh"
14 #include "multi-measure-rest.hh"
15 #include "command-request.hh"
16 #include "timing-translator.hh"
17 #include "engraver-group-engraver.hh"
18 #include "repeated-music.hh"
19 #include "timing-translator.hh"
20 #include "volta-spanner.hh"
21 #include "note-column.hh"
22 #include "paper-def.hh"
23 #include "music-list.hh"
24 #include "side-position-interface.hh"
25 #include "spanner.hh"
26 #include "note-column.hh"
28 struct Bar_create_event
30 Moment when_;
31 bool bar_b_;
32 bool last_b_;
33 String type_;
34 Bar_create_event();
35 Bar_create_event (Moment w, String s);
36 Bar_create_event (Moment w, int i, int j);
39 int compare (Bar_create_event const & c1, Bar_create_event const &c2)
41 return (c1.when_ - c2.when_).sign();
44 /**
45 Generate repeat-bars |: :| for repeated-music
47 class Repeat_engraver : public Engraver
49 public:
50 VIRTUAL_COPY_CONS(Translator);
51 Repeat_engraver ();
52 protected:
53 virtual void acknowledge_element (Score_element_info i);
54 virtual void do_removal_processing ();
55 virtual bool do_try_music (Music *req_l);
56 virtual void do_process_music();
57 virtual void do_pre_move_processing();
58 virtual void do_post_move_processing ();
59 void queue_events ();
61 private:
62 Repeated_music *repeated_music_l_;
63 bool done_this_one_b_;
66 Royal_brackla_create_queue is only two Whiskies away. :-)
68 Cons<Bar_create_event> *create_barmoments_queue_;
70 Spanner * volta_span_p_;
71 Spanner* end_volta_span_p_;
77 ADD_THIS_TRANSLATOR (Repeat_engraver);
79 bool
80 Repeat_engraver::do_try_music (Music* m)
82 if (Repeated_music* r = dynamic_cast<Repeated_music *> (m))
84 if (repeated_music_l_)
85 return false;
87 if (r->volta_fold_b_)
89 repeated_music_l_ = r;
93 We acknowledge other types of unfolded music as well, to
94 get auto context selection right.
96 if (r->type_ == "volta" || r->type_ == "unfolded")
97 return true;
100 return false;
104 Walk through repeat music, and generate events for appropriate times.
106 UGH. Should use Music_iteration for this.
108 Should also queue some event to get timing information reset during
109 2nd and following voltas.
111 void
112 Repeat_engraver::queue_events ()
114 Music_sequence* alt = repeated_music_l_->alternatives ();
115 Moment walk_mom = now_mom () + repeated_music_l_->body ()->length_mom ();
117 SCM novolta = get_property ("noVoltaBraces");
118 bool create_volta = !to_boolean (novolta);
120 Cons_list<Bar_create_event> becel;
121 becel.append (new Bar_create_event (now_mom (), "|:"));
123 if (!alt)
125 becel.append (new Bar_create_event (walk_mom, ":|"));
126 becel.append (new Bar_create_event (walk_mom, "stop"));
128 else
130 int last_number = 0;
131 int volta_number = repeated_music_l_->repeats_i_ - alt->length_i () + 1;
134 all repeat alternatives, and generate events with
135 appropriate timestamps. The volta spanner event (a number string)
136 happens at the begin of the alt. The :| bar event at the ending.
139 for (SCM s = repeated_music_l_->alternatives ()->music_list ();
140 gh_pair_p (s); s = gh_cdr (s))
142 Music *mus =unsmob_music (gh_car (s));
145 some idiot might typeset a repeat not starting on a
146 barline. Make sure there is one.
148 (todo: should try to avoid line breaks?)
150 if (last_number == 0)
152 becel.append (new Bar_create_event (walk_mom, ""));
156 if (create_volta)
158 Bar_create_event * c = new Bar_create_event (walk_mom, last_number+ 1,
159 volta_number);
161 if (!gh_pair_p (gh_cdr (s)))
162 c->last_b_ = true;
164 becel.append (c);
165 last_number = volta_number;
166 volta_number ++;
167 SCM l (get_property ("voltaSpannerDuration"));
168 if (unsmob_moment(l))
170 Moment vSD_mom = *unsmob_moment (l);
171 if ( vSD_mom < mus->length_mom() ) // terminate volta early ?
173 vSD_mom += walk_mom;
174 c->last_b_ = true;
175 becel.append (new Bar_create_event (vSD_mom, "stop"));
179 walk_mom += mus->length_mom();
181 if (gh_pair_p (gh_cdr (s)))
182 becel.append (new Bar_create_event (walk_mom, ":|"));
183 else
184 becel.append (new Bar_create_event (walk_mom, "stop"));
189 ugh, should merge :| and |: here.
191 Cons<Bar_create_event> * last = last_cons (create_barmoments_queue_);
192 Cons<Bar_create_event> **tail = last? & last->next_
193 : & create_barmoments_queue_;
195 *tail = becel.head_ ;
197 becel.head_ = 0;
200 void
201 Repeat_engraver::do_process_music ()
203 if (repeated_music_l_ && !done_this_one_b_)
205 queue_events ();
206 done_this_one_b_ = true;
210 Cons<Bar_create_event> * head = create_barmoments_queue_;
211 if (!head)
212 return;
215 Do all the events that need to be done now.
217 while (head && now_mom () == head->car_->when_)
219 create_barmoments_queue_ = create_barmoments_queue_->next_;
220 head->next_ =0;
221 String t = head->car_->type_;
222 if (head->car_->bar_b_)
224 if (t == "stop" || t == ":|")
226 end_volta_span_p_ = volta_span_p_;
227 volta_span_p_ =0;
230 SCM whsym = ly_symbol2scm ("whichBar");
231 Translator_group* where = daddy_trans_l_->where_defined (whsym);
232 SCM which = where->get_property (whsym);
235 Should use symbols for bar glyphs.
237 if (t == "stop" && which == SCM_UNDEFINED)
238 which = ly_str02scm ("");
239 else if (t != "stop")
241 SCM l = ly_str02scm (":|");
242 SCM r = ly_str02scm ("|:");
244 if ( (t == "|:" && scm_equal_p (which, l) == SCM_BOOL_T)
245 || (t == ":|" && scm_equal_p (which, r)== SCM_BOOL_T))
246 t = ":|:";
248 if (t != "" || !gh_string_p (which))
249 which = ly_str02scm (t.ch_C());
251 where->set_property (whsym, which);
253 else
255 assert (!volta_span_p_);
256 volta_span_p_ = new Spanner (get_property ("basicVoltaSpannerProperties"));
257 Volta_spanner::set_interface (volta_span_p_);
258 announce_element (volta_span_p_,0);
259 volta_span_p_->set_elt_property ("text",
260 ly_str02scm (t.ch_C()));
261 volta_span_p_->set_elt_property ("last-volta",
262 gh_bool2scm (head->car_->last_b_));
263 // voltaSpannerDuration stuff here.
264 // other property stuff here.
268 delete head->car_;
269 delete head;
271 head = create_barmoments_queue_;
274 assert (!head || head->car_->when_ > now_mom ());
278 void
279 Repeat_engraver::acknowledge_element (Score_element_info i)
281 if (Item* item = dynamic_cast<Item*> (i.elem_l_))
283 if (Note_column::has_interface (item))
285 if (volta_span_p_)
286 Volta_spanner::add_column (volta_span_p_,item);
287 if (end_volta_span_p_)
288 Volta_spanner::add_column (end_volta_span_p_,item);
290 if (Bar::has_interface (item))
292 if (volta_span_p_)
293 Volta_spanner::add_bar (volta_span_p_, item);
294 if (end_volta_span_p_)
295 Volta_spanner::add_bar(end_volta_span_p_ , item);
300 void
301 Repeat_engraver::do_removal_processing ()
303 if (volta_span_p_)
305 typeset_element(volta_span_p_);
307 if (end_volta_span_p_)
309 typeset_element (end_volta_span_p_);
311 // todo: the paranoid may also delete create_barmoments_queue_
314 void
315 Repeat_engraver::do_post_move_processing ()
317 for (Cons<Bar_create_event> *p = create_barmoments_queue_;
318 p && p->car_->when_ == now_mom (); p = p->next_)
319 if (p->car_->type_ == "stop")
321 repeated_music_l_ = 0;
322 done_this_one_b_ = false;
326 void
327 Repeat_engraver::do_pre_move_processing ()
329 if (end_volta_span_p_)
331 Side_position::add_staff_support (end_volta_span_p_);
333 typeset_element (end_volta_span_p_ );
334 end_volta_span_p_ =0;
340 Repeat_engraver::Repeat_engraver()
342 repeated_music_l_ =0;
343 end_volta_span_p_ =0;
344 volta_span_p_ =0;
345 done_this_one_b_ = false;
346 create_barmoments_queue_ =0;
349 /* ************** */
350 Bar_create_event::Bar_create_event()
352 last_b_ =false;
353 bar_b_ = true;
356 Bar_create_event::Bar_create_event (Moment w, String s)
358 last_b_ =false;
359 when_ = w;
360 type_ = s;
361 bar_b_ = true;
364 Bar_create_event::Bar_create_event (Moment w, int i, int j)
366 last_b_ =false;
367 when_ = w ;
368 bar_b_ = false;
370 if (i!=j)
371 type_ = to_str (i) + ".-" ;
373 type_ += to_str(j) + ".";