2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
14 #include "rhythmic-grouping.hh"
18 #include "time-description.hh"
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
22 Auto_beam_engraver::Auto_beam_engraver ()
26 shortest_mom_ = Moment (1, 8);
28 finished_grouping_p_ = 0;
33 Auto_beam_engraver::do_process_requests ()
35 consider_end_and_begin ();
39 Auto_beam_engraver::consider_end_and_begin ()
41 Time_description const *time = get_staff_info().time_C_;
42 int num = time->whole_per_measure_ / time->one_beat_;
43 int den = time->one_beat_.den_i ();
44 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
46 if (shortest_mom_.num () != 1)
47 type_str = to_str (shortest_mom_.num ());
48 if (shortest_mom_.den () != 1)
49 type_str = type_str + "_" + to_str (shortest_mom_.den ());
52 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
53 In order of increasing priority:
56 ii. time<num>_<den>beamAutoEnd
57 iii. time<num>_<den>beamAutoEnd<type>
64 [to be defined in config file]
65 i. easy catch-all rule
66 ii. exceptions for time signature
67 iii. exceptions for time signature, for specific duration type
71 v. override for specific duration type
73 The user overrides should be required for common cases.
77 first guess: begin beam at any position
81 first guess: end beam at end of beat
83 Moment end_mom = time->one_beat_;
86 second guess: property generic time exception
88 Scalar begin = get_property (time_str + "beamAutoBegin", 0);
89 if (begin.length_i ())
90 begin_mom = begin.to_rat ();
92 Scalar end = get_property (time_str + "beamAutoEnd", 0);
94 end_mom = end.to_rat ();
97 third guess: property time exception, specific for duration type
99 if (type_str.length_i ())
101 Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
102 if (end_mult.length_i ())
103 end_mom = end_mult.to_rat ();
104 Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
105 if (begin_mult.length_i ())
106 begin_mom = begin_mult.to_rat ();
110 fourth guess [user override]: property plain generic
112 begin = get_property ("beamAutoBegin", 0);
113 if (begin.length_i ())
114 begin_mom = begin.to_rat ();
116 end = get_property ("beamAutoEnd", 0);
118 end_mom = end.to_rat ();
121 fifth guess [user override]: property plain, specific for duration type
123 if (type_str.length_i ())
125 Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
126 if (end_mult.length_i ())
127 end_mom = end_mult.to_rat ();
128 Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
129 if (begin_mult.length_i ())
130 begin_mom = begin_mult.to_rat ();
135 r = time->whole_in_measure_.mod_rat (end_mom);
139 if (stem_l_arr_p_ && !r)
143 Allow already started autobeam to end
145 Scalar on = get_property ("beamAuto", 0);
150 r = time->whole_in_measure_.mod_rat (begin_mom);
151 if (!stem_l_arr_p_ && (!begin_mom || !r))
157 Auto_beam_engraver::begin_beam ()
159 // DOUT << String ("starting autobeam at: ") + now_mom ().str () + "\n";
160 assert (!stem_l_arr_p_);
161 stem_l_arr_p_ = new Array<Stem*>;
162 assert (!grouping_p_);
163 grouping_p_ = new Rhythmic_grouping;
167 Auto_beam_engraver::create_beam_p ()
169 Beam* beam_p = new Beam;
171 for (int i = 0; i < stem_l_arr_p_->size (); i++)
172 beam_p->add_stem ((*stem_l_arr_p_)[i]);
174 /* urg, copied from Beam_engraver */
175 Scalar prop = get_property ("beamslopedamping", 0);
177 beam_p->set_elt_property (damping_scm_sym, gh_int2scm( prop));
179 prop = get_property ("beamquantisation", 0);
181 beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
183 announce_element (Score_element_info (beam_p, 0));
188 Auto_beam_engraver::end_beam ()
190 if (stem_l_arr_p_->size () < 2)
196 finished_beam_p_ = create_beam_p ();
197 finished_grouping_p_ = grouping_p_;
198 delete stem_l_arr_p_;
202 shortest_mom_ = Moment (1, 8);
207 Auto_beam_engraver::typeset_beam ()
209 if (finished_beam_p_)
211 Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
212 rg_C->extend (finished_grouping_p_->interval());
213 finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
214 typeset_element (finished_beam_p_);
215 finished_beam_p_ = 0;
217 delete finished_grouping_p_;
218 finished_grouping_p_= 0;
223 Auto_beam_engraver::do_post_move_processing ()
228 Auto_beam_engraver::do_pre_move_processing ()
234 Auto_beam_engraver::do_removal_processing ()
237 if (stem_l_arr_p_ && stem_l_arr_p_->size ())
244 Auto_beam_engraver::acknowledge_element (Score_element_info info)
246 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
253 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
263 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
267 if (dynamic_cast<Rest *> (info.elem_l_))
273 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
285 now that we have last_add_mom_, perhaps we can (should) do away
286 with these individual junk_beams
288 if (rhythmic_req->duration_.durlog_i_ <= 2)
294 Moment start = get_staff_info().time_C_->whole_in_measure_;
295 if (!grouping_p_->child_fit_b (start))
302 if shortest duration would change
303 reconsider ending/starting beam first.
305 Moment mom = rhythmic_req->duration_.length_mom ();
306 if (mom < shortest_mom_)
309 consider_end_and_begin ();
311 grouping_p_->add_child (start, rhythmic_req->length_mom ());
313 //stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
315 stem_l_arr_p_->push (stem_l);
316 Moment now = now_mom ();
318 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
324 Auto_beam_engraver::junk_beam ()
326 assert (stem_l_arr_p_);
327 /* for (int i = 0; i < stem_l_arr_p_->size (); i++)
328 (*stem_l_arr_p_)[i]->flag_i_ = 0;*/
330 delete stem_l_arr_p_;
335 shortest_mom_ = Moment (1, 8);
339 Auto_beam_engraver::process_acknowledged ()
343 Moment now = now_mom ();
344 if ((extend_mom_ < now)
345 || ((extend_mom_ == now) && (last_add_mom_ != now )))
349 else if (!stem_l_arr_p_->size ())