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 // must set minVerticalAlign = = maxVerticalAlign to get sane results
183 // see input/test/beam-interstaff.ly
184 prop = get_property ("minVerticalAlign", 0);
186 beam_p->vertical_align_drul_[MIN] = prop;
188 prop = get_property ("maxVerticalAlign", 0);
190 beam_p->vertical_align_drul_[MAX] = prop;
192 announce_element (Score_element_info (beam_p, 0));
197 Auto_beam_engraver::end_beam ()
199 DOUT << String ("ending autobeam at: ") + now_mom ().str () + "\n";
200 if (stem_l_arr_p_->size () < 2)
202 DOUT << "junking autombeam: less than two stems\n";
207 finished_beam_p_ = create_beam_p ();
208 finished_grouping_p_ = grouping_p_;
209 delete stem_l_arr_p_;
217 Auto_beam_engraver::typeset_beam ()
219 if (finished_beam_p_)
221 Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
222 rg_C->extend (finished_grouping_p_->interval());
223 finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
224 typeset_element (finished_beam_p_);
225 finished_beam_p_ = 0;
227 delete finished_grouping_p_;
228 finished_grouping_p_= 0;
233 Auto_beam_engraver::do_post_move_processing ()
238 Auto_beam_engraver::do_pre_move_processing ()
244 Auto_beam_engraver::do_removal_processing ()
247 if (stem_l_arr_p_ && stem_l_arr_p_->size ())
249 DOUT << "Unfinished beam\n";
255 Auto_beam_engraver::acknowledge_element (Score_element_info info)
257 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
261 DOUT << "junking autobeam: beam encountered\n";
265 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
269 DOUT << "junking autobeam: bar encountered\n";
276 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
280 if (dynamic_cast<Rest *> (info.elem_l_))
282 DOUT << "junking autobeam: rest encountered\n";
287 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
293 DOUT << "junking autobeam: beamed stem encountered\n";
300 now that we have last_add_mom_, perhaps we can (should) do away
301 with these individual junk_beams
303 if (rhythmic_req->duration_.durlog_i_ <= 2)
305 DOUT << "ending autobeam: stem doesn't fit in beam\n";
310 Moment start = get_staff_info().time_C_->whole_in_measure_;
311 if (!grouping_p_->child_fit_b (start))
313 DOUT << "ending autobeam: stem doesn't fit in group\n";
319 if shortest duration would change
320 reconsider ending/starting beam first.
322 Moment mom = rhythmic_req->duration_.length_mom ();
323 if (mom < shortest_mom_)
326 consider_end_and_begin ();
328 grouping_p_->add_child (start, rhythmic_req->length_mom ());
330 //stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
332 stem_l_arr_p_->push (stem_l);
333 Moment now = now_mom ();
335 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
341 Auto_beam_engraver::junk_beam ()
343 assert (stem_l_arr_p_);
344 /* for (int i = 0; i < stem_l_arr_p_->size (); i++)
345 (*stem_l_arr_p_)[i]->flag_i_ = 0;*/
347 delete stem_l_arr_p_;
355 Auto_beam_engraver::process_acknowledged ()
359 Moment now = now_mom ();
360 if ((extend_mom_ < now)
361 || ((extend_mom_ == now) && (last_add_mom_ != now )))
363 DOUT << String ("junking autobeam: no stem added since: ")
364 + last_add_mom_.str () + "\n";
367 else if (!stem_l_arr_p_->size ())
369 DOUT << "junking started autobeam: no stems\n";