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);
44 int type = 1 << (mult_i_ + 2);
45 String type_str = to_str (type);
48 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
49 In order of increasing priority:
52 ii. time<num>_<den>beamAutoEnd
53 iii. time<num>_<den>beamAutoEnd<type>
60 [to be defined in config file]
61 i. easy catch-all rule
62 ii. exceptions for time signature
63 iii. exceptions for time signature, for specific duration type
67 v. override for specific duration type
69 The user overrides should be required for common cases.
73 first guess: begin beam at any position
77 first guess: end beam at end of beat
79 Moment end_mom = time->one_beat_;
82 second guess: property generic time exception
84 Scalar begin = get_property (time_str + "beamAutoBegin", 0);
85 if (begin.length_i ())
86 begin_mom = begin.to_rat ();
88 Scalar end = get_property (time_str + "beamAutoEnd", 0);
90 end_mom = end.to_rat ();
93 third guess: property time exception, specific for duration type
97 Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
98 if (end_mult.length_i ())
99 end_mom = end_mult.to_rat ();
100 Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
101 if (begin_mult.length_i ())
102 begin_mom = begin_mult.to_rat ();
106 fourth guess [user override]: property plain generic
108 begin = get_property ("beamAutoBegin", 0);
109 if (begin.length_i ())
110 begin_mom = begin.to_rat ();
112 end = get_property ("beamAutoEnd", 0);
114 end_mom = end.to_rat ();
117 fifth guess [user override]: property plain, specific for duration type
121 Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
122 if (end_mult.length_i ())
123 end_mom = end_mult.to_rat ();
124 Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
125 if (begin_mult.length_i ())
126 begin_mom = begin_mult.to_rat ();
134 f = fmod (time->whole_in_measure_, end_mom);
139 Real epsilon_f = Moment (1, 512);
140 if (beam_p_ && (abs (f) < epsilon_f))
144 Allow already started autobeam to end
146 Scalar on = get_property ("beamAuto", 0);
151 f = fmod (time->whole_in_measure_, begin_mom);
152 if (!beam_p_ && (!begin_mom || (abs (f) < epsilon_f)))
158 Auto_beam_engraver::begin_beam ()
160 DOUT << String ("starting autobeam at: ") + now_mom ().str () + "\n";
162 grouping_p_ = new Rhythmic_grouping;
164 /* urg, copied from Beam_engraver */
165 Scalar prop = get_property ("beamslopedamping", 0);
167 beam_p_->damping_i_ = prop;
169 prop = get_property ("beamquantisation", 0);
171 beam_p_->quantisation_ = (Beam::Quantisation)(int)prop;
173 // must set minVerticalAlign = = maxVerticalAlign to get sane results
174 // see input/test/beam-interstaff.ly
175 prop = get_property ("minVerticalAlign", 0);
177 beam_p_->vertical_align_drul_[MIN] = prop;
179 prop = get_property ("maxVerticalAlign", 0);
181 beam_p_->vertical_align_drul_[MAX] = prop;
183 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 (beam_p_->stems_.size () < 2)
192 DOUT << "junking autombeam: less than two stems\n";
197 finished_beam_p_ = beam_p_;
198 finished_grouping_p_ = grouping_p_;
206 Auto_beam_engraver::typeset_beam ()
208 if (finished_beam_p_)
210 Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
211 rg_C->extend (finished_grouping_p_->interval());
212 finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
213 typeset_element (finished_beam_p_);
214 finished_beam_p_ = 0;
216 delete finished_grouping_p_;
217 finished_grouping_p_= 0;
222 Auto_beam_engraver::do_post_move_processing ()
227 Auto_beam_engraver::do_pre_move_processing ()
233 Auto_beam_engraver::do_removal_processing ()
238 DOUT << "Unfinished beam\n";
244 Auto_beam_engraver::acknowledge_element (Score_element_info info)
246 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
250 DOUT << "junking autobeam: beam encountered\n";
254 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
258 DOUT << "junking autobeam: bar encountered\n";
265 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
269 if (dynamic_cast<Rest *> (info.elem_l_))
271 DOUT << "junking autobeam: rest encountered\n";
276 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
280 if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_))
282 DOUT << "junking autobeam: beamed stem encountered\n";
289 now that we have last_add_mom_, perhaps we can (should) do away
290 with these individual junk_beams
292 if (rhythmic_req->duration_.durlog_i_<= 2)
294 DOUT << "ending autobeam: stem doesn't fit in beam\n";
299 Moment start = get_staff_info().time_C_->whole_in_measure_;
300 if (!grouping_p_->child_fit_b (start))
302 DOUT << "ending autobeam: stem doesn't fit in group\n";
307 int m = (rhythmic_req->duration_.durlog_i_ - 2);
309 if multiplicity would become greater,
310 reconsider ending/starting beam first.
315 consider_end_and_begin ();
318 grouping_p_->add_child (start, rhythmic_req->length_mom ());
319 stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
320 beam_p_->add_stem (stem_l);
321 Moment now = now_mom ();
323 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
329 Auto_beam_engraver::junk_beam ()
332 for (int i=0; i < beam_p_->stems_.size (); i++)
334 Stem* s = beam_p_->stems_[i];
335 s->beams_i_drul_[LEFT] = 0;
336 s->beams_i_drul_[RIGHT] = 0;
349 Auto_beam_engraver::process_acknowledged ()
353 Moment now = now_mom ();
354 if ((extend_mom_ < now)
355 || ((extend_mom_ == now) && (last_add_mom_ != now )))
357 DOUT << String ("junking autobeam: no stem added since: ")
358 + last_add_mom_.str () + "\n";
361 else if (!beam_p_->stems_.size ())
363 DOUT << "junking started autobeam: no stems\n";