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 ()
27 finished_grouping_p_ = 0;
32 Auto_beam_engraver::do_process_requests ()
34 consider_end_and_begin ();
38 Auto_beam_engraver::consider_end_and_begin ()
40 Time_description const *time = get_staff_info().time_C_;
41 int num = time->whole_per_measure_ / time->one_beat_;
42 int den = time->one_beat_.den_i ();
43 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
45 if (shortest_mom_.num () != 1)
46 type_str = to_str (shortest_mom_.num ());
47 if (shortest_mom_.den () != 1)
48 type_str = type_str + "_" + to_str (shortest_mom_.den ());
51 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
52 In order of increasing priority:
55 ii. time<num>_<den>beamAutoEnd
56 iii. time<num>_<den>beamAutoEnd<type>
63 [to be defined in config file]
64 i. easy catch-all rule
65 ii. exceptions for time signature
66 iii. exceptions for time signature, for specific duration type
70 v. override for specific duration type
72 The user overrides should be required for common cases.
76 first guess: begin beam at any position
80 first guess: end beam at end of beat
82 Moment end_mom = time->one_beat_;
85 second guess: property generic time exception
87 Scalar begin = get_property (time_str + "beamAutoBegin", 0);
88 if (begin.length_i ())
89 begin_mom = begin.to_rat ();
91 Scalar end = get_property (time_str + "beamAutoEnd", 0);
93 end_mom = end.to_rat ();
96 third guess: property time exception, specific for duration type
98 if (type_str.length_i ())
100 Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
101 if (end_mult.length_i ())
102 end_mom = end_mult.to_rat ();
103 Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
104 if (begin_mult.length_i ())
105 begin_mom = begin_mult.to_rat ();
109 fourth guess [user override]: property plain generic
111 begin = get_property ("beamAutoBegin", 0);
112 if (begin.length_i ())
113 begin_mom = begin.to_rat ();
115 end = get_property ("beamAutoEnd", 0);
117 end_mom = end.to_rat ();
120 fifth guess [user override]: property plain, specific for duration type
122 if (type_str.length_i ())
124 Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
125 if (end_mult.length_i ())
126 end_mom = end_mult.to_rat ();
127 Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
128 if (begin_mult.length_i ())
129 begin_mom = begin_mult.to_rat ();
134 r = time->whole_in_measure_.mod_rat (end_mom);
138 if (stem_l_arr_p_ && !r)
142 Allow already started autobeam to end
144 Scalar on = get_property ("beamAuto", 0);
149 r = time->whole_in_measure_.mod_rat (begin_mom);
150 if (!stem_l_arr_p_ && (!begin_mom || !r))
156 Auto_beam_engraver::begin_beam ()
158 // DOUT << String ("starting autobeam at: ") + now_mom ().str () + "\n";
159 assert (!stem_l_arr_p_);
160 stem_l_arr_p_ = new Array<Stem*>;
161 assert (!grouping_p_);
162 grouping_p_ = new Rhythmic_grouping;
166 Auto_beam_engraver::create_beam_p ()
168 Beam* beam_p = new Beam;
170 for (int i = 0; i < stem_l_arr_p_->size (); i++)
171 beam_p->add_stem ((*stem_l_arr_p_)[i]);
173 /* urg, copied from Beam_engraver */
174 Scalar prop = get_property ("beamslopedamping", 0);
176 beam_p->set_elt_property (damping_scm_sym, gh_int2scm( prop));
178 prop = get_property ("beamquantisation", 0);
180 beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
182 announce_element (Score_element_info (beam_p, 0));
187 Auto_beam_engraver::end_beam ()
189 if (stem_l_arr_p_->size () < 2)
195 finished_beam_p_ = create_beam_p ();
196 finished_grouping_p_ = grouping_p_;
197 delete stem_l_arr_p_;
205 Auto_beam_engraver::typeset_beam ()
207 if (finished_beam_p_)
209 Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
210 rg_C->extend (finished_grouping_p_->interval());
211 finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
212 typeset_element (finished_beam_p_);
213 finished_beam_p_ = 0;
215 delete finished_grouping_p_;
216 finished_grouping_p_= 0;
221 Auto_beam_engraver::do_post_move_processing ()
226 Auto_beam_engraver::do_pre_move_processing ()
232 Auto_beam_engraver::do_removal_processing ()
235 if (stem_l_arr_p_ && stem_l_arr_p_->size ())
242 Auto_beam_engraver::acknowledge_element (Score_element_info info)
244 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
251 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
261 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
265 if (dynamic_cast<Rest *> (info.elem_l_))
271 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
283 now that we have last_add_mom_, perhaps we can (should) do away
284 with these individual junk_beams
286 if (rhythmic_req->duration_.durlog_i_ <= 2)
292 Moment start = get_staff_info().time_C_->whole_in_measure_;
293 if (!grouping_p_->child_fit_b (start))
300 if shortest duration would change
301 reconsider ending/starting beam first.
303 Moment mom = rhythmic_req->duration_.length_mom ();
304 if (mom < shortest_mom_)
307 consider_end_and_begin ();
309 grouping_p_->add_child (start, rhythmic_req->length_mom ());
311 //stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
313 stem_l_arr_p_->push (stem_l);
314 Moment now = now_mom ();
316 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
322 Auto_beam_engraver::junk_beam ()
324 assert (stem_l_arr_p_);
325 /* for (int i = 0; i < stem_l_arr_p_->size (); i++)
326 (*stem_l_arr_p_)[i]->flag_i_ = 0;*/
328 delete stem_l_arr_p_;
336 Auto_beam_engraver::process_acknowledged ()
340 Moment now = now_mom ();
341 if ((extend_mom_ < now)
342 || ((extend_mom_ == now) && (last_add_mom_ != now )))
346 else if (!stem_l_arr_p_->size ())