3 auto-beam-engraver.cc -- implement Auto_beam_engraver
5 source file of the GNU LilyPond music typesetter
7 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "musical-request.hh"
15 #include "engraver-group-engraver.hh"
18 #include "engraver.hh"
22 class Auto_beam_engraver : public Engraver
25 Auto_beam_engraver ();
26 VIRTUAL_COPY_CONS (Translator);
29 virtual bool do_try_music (Music*);
30 virtual void do_pre_move_processing ();
31 virtual void do_post_move_processing ();
32 virtual void do_removal_processing ();
33 virtual void acknowledge_element (Score_element_info);
34 virtual void do_process_music ();
35 virtual void process_acknowledged ();
38 void consider_end_and_begin (Moment test_mom);
39 Spanner* create_beam_p ();
42 bool same_grace_state_b (Score_element* e);
46 Spanner *finished_beam_p_;
47 Link_array<Item>* stem_l_arr_p_;
51 Moment beam_start_moment_;
52 Moment beam_start_location_;
54 // We act as if beam were created, and start a grouping anyway.
55 Beaming_info_list*grouping_p_;
56 Beaming_info_list*finished_grouping_p_;
62 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
66 TODO: remove all references to Timing_engraver; should read properties.
69 Auto_beam_engraver::Auto_beam_engraver ()
72 shortest_mom_ = Moment (1, 8);
74 finished_grouping_p_ = 0;
80 Auto_beam_engraver::do_try_music (Music*)
86 Auto_beam_engraver::do_process_music ()
88 consider_end_and_begin (shortest_mom_);
92 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
94 Moment one_beat = *unsmob_moment( get_property ("beatLength"));
96 int num = *unsmob_moment (get_property("measureLength")) / one_beat;
97 int den = one_beat.den_i ();
100 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
103 if (test_mom.num () != 1)
104 type_str = to_str (test_mom.num ());
105 if (test_mom.den () != 1)
106 type_str = type_str + "_" + to_str (test_mom.den ());
111 FIXME: SHOULD USE ALIST
116 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
117 In order of increasing priority:
120 ii. time<num>_<den>beamAutoEnd
121 iii. time<num>_<den>beamAutoEnd<type>
128 [to be defined in config file]
129 i. easy catch-all rule
130 ii. exceptions for time signature
131 iii. exceptions for time signature, for specific duration type
135 v. override for specific duration type
137 The user overrides should be required for common cases.
141 first guess: begin beam at any position
143 Moment begin_mom (0);
145 first guess: end beam at end of beat
147 SCM one (get_property ("beatLength"));
150 if (unsmob_moment (one))
151 end_mom = *unsmob_moment (one);
154 second guess: property generic time exception
156 SCM begin = get_property ((time_str + "beamAutoBegin").ch_C());
157 if (unsmob_moment (begin))
158 begin_mom = * unsmob_moment (begin);
160 SCM end = get_property ((time_str + "beamAutoEnd").ch_C());
161 if (unsmob_moment (end))
162 end_mom = * unsmob_moment (end);
165 third guess: property time exception, specific for duration type
167 if (type_str.length_i ())
169 SCM end_mult = get_property ((time_str + "beamAutoEnd" + type_str).ch_C());
170 if (unsmob_moment (end_mult))
171 end_mom = * unsmob_moment (end_mult);
173 SCM begin_mult = get_property ((time_str + "beamAutoBegin" + type_str).ch_C());
174 if (unsmob_moment (begin_mult))
175 begin_mom = * unsmob_moment (begin_mult);
179 fourth guess [user override]: property plain generic
181 begin = get_property ("beamAutoBegin");
182 if (unsmob_moment (begin))
183 begin_mom = * unsmob_moment (begin);
187 end = get_property ("beamAutoEnd");
188 if (unsmob_moment (end))
189 end_mom = * unsmob_moment (end);
192 fifth guess [user override]: property plain, specific for duration type
194 if (type_str.length_i ())
196 SCM end_mult = get_property ((String ("beamAutoEnd") + type_str).ch_C());
197 if (unsmob_moment (end_mult))
198 end_mom = * unsmob_moment (end_mult);
200 SCM begin_mult = get_property ((String ("beamAutoBegin") + type_str).ch_C());
201 if (unsmob_moment (begin_mult))
202 begin_mom = * unsmob_moment (begin_mult);
207 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (end_mom);
211 if (stem_l_arr_p_ && !r)
215 Allow already started autobeam to end
217 SCM on = get_property ("noAutoBeaming");
222 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (begin_mom);
223 if (!stem_l_arr_p_ && (!begin_mom || !r))
229 Auto_beam_engraver::begin_beam ()
231 assert (!stem_l_arr_p_);
232 stem_l_arr_p_ = new Link_array<Item>;
233 assert (!grouping_p_);
234 grouping_p_ = new Beaming_info_list;
235 beam_start_moment_ = now_mom ();
236 beam_start_location_ = *unsmob_moment (get_property ("measurePosition"));
240 Auto_beam_engraver::create_beam_p ()
242 Spanner* beam_p = new Spanner (get_property ("basicBeamProperties"));
243 Beam::set_interface (beam_p);
245 for (int i = 0; i < stem_l_arr_p_->size (); i++)
248 watch out for stem tremolos and abbreviation beams
250 if (Stem::beam_l ((*stem_l_arr_p_)[i]))
254 Beam::add_stem (beam_p,(*stem_l_arr_p_)[i]);
257 announce_element (beam_p, 0);
263 Auto_beam_engraver::end_beam ()
265 if (stem_l_arr_p_->size () < 2)
271 finished_beam_p_ = create_beam_p ();
272 if (finished_beam_p_)
273 finished_grouping_p_ = grouping_p_;
274 delete stem_l_arr_p_;
277 shortest_mom_ = Moment (1, 8);
282 Auto_beam_engraver::typeset_beam ()
284 if (finished_beam_p_)
286 finished_grouping_p_->beamify ();
287 Beam::set_beaming (finished_beam_p_, finished_grouping_p_);
288 typeset_element (finished_beam_p_);
289 finished_beam_p_ = 0;
291 delete finished_grouping_p_;
292 finished_grouping_p_= 0;
297 Auto_beam_engraver::do_post_move_processing ()
300 don't beam over skips
304 Moment now = now_mom ();
305 if (extend_mom_ < now)
313 Auto_beam_engraver::do_pre_move_processing ()
319 Auto_beam_engraver::do_removal_processing ()
321 /* finished beams may be typeset */
323 /* but unfinished may need another announce/acknowledge pass */
329 Auto_beam_engraver::same_grace_state_b (Score_element* e)
331 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
332 SCM wg =get_property ("weAreGraceContext");
333 return (to_boolean (wg)) == gr;
337 Auto_beam_engraver::acknowledge_element (Score_element_info info)
339 if (!same_grace_state_b (info.elem_l_))
344 if (Beam::has_interface (info.elem_l_))
348 else if (Bar::has_interface (info.elem_l_))
352 else if (Rest::has_interface (info.elem_l_))
358 if (Stem::has_interface (info.elem_l_))
360 Item* stem_l = dynamic_cast<Item *> (info.elem_l_);
362 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
365 programming_error ("Stem must have rhythmic structure");
370 Don't (start) auto-beam over empty stems; skips or rests
372 if (!Stem::heads_i (stem_l))
379 if (Stem::beam_l (stem_l))
386 int durlog =rhythmic_req->duration_.durlog_i_;
395 if shortest duration would change
396 reconsider ending/starting beam first.
398 Moment mom = rhythmic_req->duration_.length_mom ();
399 consider_end_and_begin (mom);
402 if (mom < shortest_mom_)
404 if (stem_l_arr_p_->size ())
407 consider_end_and_begin (shortest_mom_);
413 Moment now = now_mom ();
415 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
417 stem_l_arr_p_->push (stem_l);
419 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
424 Auto_beam_engraver::junk_beam ()
426 assert (stem_l_arr_p_);
428 delete stem_l_arr_p_;
432 shortest_mom_ = Moment (1, 8);
436 Auto_beam_engraver::process_acknowledged ()
440 Moment now = now_mom ();
441 if ((extend_mom_ < now)
442 || ((extend_mom_ == now) && (last_add_mom_ != now )))
446 else if (!stem_l_arr_p_->size ())