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>
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"
26 #include "note-column.hh"
28 struct 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();
45 Generate repeat-bars |: :| for repeated-music
47 class Repeat_engraver
: public Engraver
50 VIRTUAL_COPY_CONS(Translator
);
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 ();
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
);
80 Repeat_engraver::do_try_music (Music
* m
)
82 if (Repeated_music
* r
= dynamic_cast<Repeated_music
*> (m
))
84 if (repeated_music_l_
)
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")
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.
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 (), "|:"));
125 becel
.append (new Bar_create_event (walk_mom
, ":|"));
126 becel
.append (new Bar_create_event (walk_mom
, "stop"));
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
, ""));
158 Bar_create_event
* c
= new Bar_create_event (walk_mom
, last_number
+ 1,
161 if (!gh_pair_p (gh_cdr (s
)))
165 last_number
= 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 ?
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
, ":|"));
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_
;
201 Repeat_engraver::do_process_music ()
203 if (repeated_music_l_
&& !done_this_one_b_
)
206 done_this_one_b_
= true;
210 Cons
<Bar_create_event
> * head
= create_barmoments_queue_
;
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_
;
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_
;
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
))
248 if (t
!= "" || !gh_string_p (which
))
249 which
= ly_str02scm (t
.ch_C());
251 where
->set_property (whsym
, which
);
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.
271 head
= create_barmoments_queue_
;
274 assert (!head
|| head
->car_
->when_
> now_mom ());
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
))
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
))
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
);
301 Repeat_engraver::do_removal_processing ()
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_
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;
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;
345 done_this_one_b_
= false;
346 create_barmoments_queue_
=0;
350 Bar_create_event::Bar_create_event()
356 Bar_create_event::Bar_create_event (Moment w
, String s
)
364 Bar_create_event::Bar_create_event (Moment w
, int i
, int j
)
371 type_
= to_str (i
) + ".-" ;
373 type_
+= to_str(j
) + ".";