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 DOUT << String ("ending autobeam at: ") + now_mom ().str () + "\n";
190 if (stem_l_arr_p_->size () < 2)
192 DOUT << "junking autombeam: less than two stems\n";
197 finished_beam_p_ = create_beam_p ();
198 finished_grouping_p_ = grouping_p_;
199 delete stem_l_arr_p_;
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 ())
239 DOUT << "Unfinished beam\n";
245 Auto_beam_engraver::acknowledge_element (Score_element_info info)
247 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
251 DOUT << "junking autobeam: beam encountered\n";
255 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
259 DOUT << "junking autobeam: bar encountered\n";
266 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
270 if (dynamic_cast<Rest *> (info.elem_l_))
272 DOUT << "junking autobeam: rest encountered\n";
277 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
283 DOUT << "junking autobeam: beamed stem encountered\n";
290 now that we have last_add_mom_, perhaps we can (should) do away
291 with these individual junk_beams
293 if (rhythmic_req->duration_.durlog_i_ <= 2)
295 DOUT << "ending autobeam: stem doesn't fit in beam\n";
300 Moment start = get_staff_info().time_C_->whole_in_measure_;
301 if (!grouping_p_->child_fit_b (start))
303 DOUT << "ending autobeam: stem doesn't fit in group\n";
309 if shortest duration would change
310 reconsider ending/starting beam first.
312 Moment mom = rhythmic_req->duration_.length_mom ();
313 if (mom < shortest_mom_)
316 consider_end_and_begin ();
318 grouping_p_->add_child (start, rhythmic_req->length_mom ());
320 //stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
322 stem_l_arr_p_->push (stem_l);
323 Moment now = now_mom ();
325 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
331 Auto_beam_engraver::junk_beam ()
333 assert (stem_l_arr_p_);
334 /* for (int i = 0; i < stem_l_arr_p_->size (); i++)
335 (*stem_l_arr_p_)[i]->flag_i_ = 0;*/
337 delete stem_l_arr_p_;
345 Auto_beam_engraver::process_acknowledged ()
349 Moment now = now_mom ();
350 if ((extend_mom_ < now)
351 || ((extend_mom_ == now) && (last_add_mom_ != now )))
353 DOUT << String ("junking autobeam: no stem added since: ")
354 + last_add_mom_.str () + "\n";
357 else if (!stem_l_arr_p_->size ())
359 DOUT << "junking started autobeam: no stems\n";