2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "musical-request.hh"
15 #include "engraver-group-engraver.hh"
18 #include "engraver.hh"
23 TODO: figure what to do in grace?
25 class Auto_beam_engraver : public Engraver
28 Auto_beam_engraver ();
29 VIRTUAL_COPY_CONS (Translator);
32 virtual bool do_try_music (Music*);
33 virtual void do_pre_move_processing ();
34 virtual void do_post_move_processing ();
35 virtual void do_removal_processing ();
36 virtual void acknowledge_element (Score_element_info);
37 virtual void do_process_music ();
38 virtual void process_acknowledged ();
41 void consider_end_and_begin (Moment test_mom);
42 Spanner* create_beam_p ();
45 bool same_grace_state_b (Score_element* e);
49 Spanner *finished_beam_p_;
50 Link_array<Item>* stem_l_arr_p_;
54 Moment beam_start_moment_;
55 Moment beam_start_location_;
57 // We act as if beam were created, and start a grouping anyway.
58 Beaming_info_list*grouping_p_;
59 Beaming_info_list*finished_grouping_p_;
62 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
64 Auto_beam_engraver::Auto_beam_engraver ()
67 shortest_mom_ = Moment (1, 8);
69 finished_grouping_p_ = 0;
74 Auto_beam_engraver::do_try_music (Music*)
80 Auto_beam_engraver::do_process_music ()
82 consider_end_and_begin (shortest_mom_);
86 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
88 Moment one_beat = *unsmob_moment( get_property ("beatLength"));
90 int num = *unsmob_moment (get_property("measureLength")) / one_beat;
91 int den = one_beat.den_i ();
93 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
96 if (test_mom.num () != 1)
97 type_str = to_str (test_mom.num ());
98 if (test_mom.den () != 1)
99 type_str = type_str + "_" + to_str (test_mom.den ());
104 FIXME: SHOULD USE ALIST
109 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
110 In order of increasing priority:
113 ii. time<num>_<den>beamAutoEnd
114 iii. time<num>_<den>beamAutoEnd<type>
121 [to be defined in config file]
122 i. easy catch-all rule
123 ii. exceptions for time signature
124 iii. exceptions for time signature, for specific duration type
128 v. override for specific duration type
130 The user overrides should be required for common cases.
134 first guess: begin beam at any position
136 Moment begin_mom (0);
138 first guess: end beam at end of beat
140 SCM one (get_property ("beatLength"));
143 if (unsmob_moment (one))
144 end_mom = *unsmob_moment (one);
147 second guess: property generic time exception
149 SCM begin = get_property ((time_str + "beamAutoBegin").ch_C());
150 if (unsmob_moment (begin))
151 begin_mom = * unsmob_moment (begin);
153 SCM end = get_property ((time_str + "beamAutoEnd").ch_C());
154 if (unsmob_moment (end))
155 end_mom = * unsmob_moment (end);
158 third guess: property time exception, specific for duration type
160 if (type_str.length_i ())
162 SCM end_mult = get_property ((time_str + "beamAutoEnd" + type_str).ch_C());
163 if (unsmob_moment (end_mult))
164 end_mom = * unsmob_moment (end_mult);
166 SCM begin_mult = get_property ((time_str + "beamAutoBegin" + type_str).ch_C());
167 if (unsmob_moment (begin_mult))
168 begin_mom = * unsmob_moment (begin_mult);
172 fourth guess [user override]: property plain generic
174 begin = get_property ("beamAutoBegin");
175 if (unsmob_moment (begin))
176 begin_mom = * unsmob_moment (begin);
180 end = get_property ("beamAutoEnd");
181 if (unsmob_moment (end))
182 end_mom = * unsmob_moment (end);
185 fifth guess [user override]: property plain, specific for duration type
187 if (type_str.length_i ())
189 SCM end_mult = get_property ((String ("beamAutoEnd") + type_str).ch_C());
190 if (unsmob_moment (end_mult))
191 end_mom = * unsmob_moment (end_mult);
193 SCM begin_mult = get_property ((String ("beamAutoBegin") + type_str).ch_C());
194 if (unsmob_moment (begin_mult))
195 begin_mom = * unsmob_moment (begin_mult);
200 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (end_mom);
204 if (stem_l_arr_p_ && !r)
208 Allow already started autobeam to end
210 SCM on = get_property ("noAutoBeaming");
215 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (begin_mom);
216 if (!stem_l_arr_p_ && (!begin_mom || !r))
222 Auto_beam_engraver::begin_beam ()
224 assert (!stem_l_arr_p_);
225 stem_l_arr_p_ = new Link_array<Item>;
226 assert (!grouping_p_);
227 grouping_p_ = new Beaming_info_list;
228 beam_start_moment_ = now_mom ();
229 beam_start_location_ = *unsmob_moment (get_property ("measurePosition"));
233 Auto_beam_engraver::create_beam_p ()
235 Spanner* beam_p = new Spanner (get_property ("Beam"));
236 Beam::set_interface (beam_p);
238 for (int i = 0; i < stem_l_arr_p_->size (); i++)
241 watch out for stem tremolos and abbreviation beams
243 if (Stem::beam_l ((*stem_l_arr_p_)[i]))
247 Beam::add_stem (beam_p,(*stem_l_arr_p_)[i]);
250 announce_element (beam_p, 0);
256 Auto_beam_engraver::end_beam ()
258 if (stem_l_arr_p_->size () < 2)
264 finished_beam_p_ = create_beam_p ();
265 if (finished_beam_p_)
266 finished_grouping_p_ = grouping_p_;
267 delete stem_l_arr_p_;
270 shortest_mom_ = Moment (1, 8);
275 Auto_beam_engraver::typeset_beam ()
277 if (finished_beam_p_)
279 finished_grouping_p_->beamify ();
280 Beam::set_beaming (finished_beam_p_, finished_grouping_p_);
281 typeset_element (finished_beam_p_);
282 finished_beam_p_ = 0;
284 delete finished_grouping_p_;
285 finished_grouping_p_= 0;
290 Auto_beam_engraver::do_post_move_processing ()
293 don't beam over skips
297 Moment now = now_mom ();
298 if (extend_mom_ < now)
306 Auto_beam_engraver::do_pre_move_processing ()
312 Auto_beam_engraver::do_removal_processing ()
314 /* finished beams may be typeset */
316 /* but unfinished may need another announce/acknowledge pass */
322 Auto_beam_engraver::same_grace_state_b (Score_element* e)
324 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
325 SCM wg =get_property ("weAreGraceContext");
326 return (to_boolean (wg)) == gr;
330 Auto_beam_engraver::acknowledge_element (Score_element_info info)
332 if (!same_grace_state_b (info.elem_l_))
337 if (Beam::has_interface (info.elem_l_))
341 else if (Bar::has_interface (info.elem_l_))
345 else if (Rest::has_interface (info.elem_l_))
351 if (Stem::has_interface (info.elem_l_))
353 Item* stem_l = dynamic_cast<Item *> (info.elem_l_);
355 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
358 programming_error ("Stem must have rhythmic structure");
363 Don't (start) auto-beam over empty stems; skips or rests
365 if (!Stem::heads_i (stem_l))
372 if (Stem::beam_l (stem_l))
379 int durlog =rhythmic_req->duration_.durlog_i_;
388 if shortest duration would change
389 reconsider ending/starting beam first.
391 Moment mom = rhythmic_req->duration_.length_mom ();
392 consider_end_and_begin (mom);
395 if (mom < shortest_mom_)
397 if (stem_l_arr_p_->size ())
400 consider_end_and_begin (shortest_mom_);
406 Moment now = now_mom ();
408 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
410 stem_l_arr_p_->push (stem_l);
412 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
417 Auto_beam_engraver::junk_beam ()
419 assert (stem_l_arr_p_);
421 delete stem_l_arr_p_;
425 shortest_mom_ = Moment (1, 8);
429 Auto_beam_engraver::process_acknowledged ()
433 Moment now = now_mom ();
434 if ((extend_mom_ < now)
435 || ((extend_mom_ == now) && (last_add_mom_ != now )))
439 else if (!stem_l_arr_p_->size ())