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 ();
131 f = fmod (time->whole_in_measure_, end_mom);
136 Real epsilon_f = Moment (1, 512);
137 if (beam_p_ && (abs (f) < epsilon_f))
141 Allow already started autobeam to end
143 Scalar on = get_property ("beamAuto", 0);
148 f = fmod (time->whole_in_measure_, begin_mom);
149 if (!beam_p_ && (!begin_mom || (abs (f) < epsilon_f)))
155 Auto_beam_engraver::begin_beam ()
157 DOUT << String ("starting autobeam at: ") + now_mom ().str () + "\n";
159 grouping_p_ = new Rhythmic_grouping;
161 /* urg, copied from Beam_engraver */
162 Scalar prop = get_property ("beamslopedamping", 0);
164 beam_p_->damping_i_ = prop;
166 prop = get_property ("beamquantisation", 0);
168 beam_p_->quantisation_ = (Beam::Quantisation)(int)prop;
170 // must set minVerticalAlign = = maxVerticalAlign to get sane results
171 // see input/test/beam-interstaff.ly
172 prop = get_property ("minVerticalAlign", 0);
174 beam_p_->vertical_align_drul_[MIN] = prop;
176 prop = get_property ("maxVerticalAlign", 0);
178 beam_p_->vertical_align_drul_[MAX] = prop;
180 announce_element (Score_element_info (beam_p_, 0));
184 Auto_beam_engraver::end_beam ()
186 DOUT << String ("ending autobeam at: ") + now_mom ().str () + "\n";
187 if (beam_p_->stems_.size () < 2)
189 DOUT << "junking autombeam: less than two stems\n";
194 finished_beam_p_ = beam_p_;
195 finished_grouping_p_ = grouping_p_;
203 Auto_beam_engraver::typeset_beam ()
205 if (finished_beam_p_)
207 Rhythmic_grouping const * rg_C = get_staff_info().rhythmic_C_;
208 rg_C->extend (finished_grouping_p_->interval());
209 finished_beam_p_->set_grouping (*rg_C, *finished_grouping_p_);
210 typeset_element (finished_beam_p_);
211 finished_beam_p_ = 0;
213 delete finished_grouping_p_;
214 finished_grouping_p_= 0;
219 Auto_beam_engraver::do_post_move_processing ()
224 Auto_beam_engraver::do_pre_move_processing ()
230 Auto_beam_engraver::do_removal_processing ()
235 DOUT << "Unfinished beam\n";
241 Auto_beam_engraver::acknowledge_element (Score_element_info info)
243 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
247 DOUT << "junking autobeam: beam encountered\n";
251 if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
255 DOUT << "junking autobeam: bar encountered\n";
262 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
266 if (dynamic_cast<Rest *> (info.elem_l_))
268 DOUT << "junking autobeam: rest encountered\n";
273 Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_);
277 if (stem_l->beam_l_ && (stem_l->beam_l_ != beam_p_))
279 DOUT << "junking autobeam: beamed stem encountered\n";
286 now that we have last_add_mom_, perhaps we can (should) do away
287 with these individual junk_beams
289 if (rhythmic_req->duration_.durlog_i_<= 2)
291 DOUT << "ending autobeam: stem doesn't fit in beam\n";
296 Moment start = get_staff_info().time_C_->whole_in_measure_;
297 if (!grouping_p_->child_fit_b (start))
299 DOUT << "ending autobeam: stem doesn't fit in group\n";
304 int m = (rhythmic_req->duration_.durlog_i_ - 2);
306 if multiplicity would become greater,
307 reconsider ending/starting beam first.
312 consider_end_and_begin ();
315 grouping_p_->add_child (start, rhythmic_req->length_mom ());
316 stem_l->flag_i_ = rhythmic_req->duration_.durlog_i_;
317 beam_p_->add_stem (stem_l);
318 Moment now = now_mom ();
320 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
326 Auto_beam_engraver::junk_beam ()
329 for (int i=0; i < beam_p_->stems_.size (); i++)
331 Stem* s = beam_p_->stems_[i];
332 s->beams_i_drul_[LEFT] = 0;
333 s->beams_i_drul_[RIGHT] = 0;
346 Auto_beam_engraver::process_acknowledged ()
350 Moment now = now_mom ();
351 if ((extend_mom_ < now)
352 || ((extend_mom_ == now) && (last_add_mom_ != now )))
354 DOUT << String ("junking autobeam: no stem added since: ")
355 + last_add_mom_.str () + "\n";
358 else if (!beam_p_->stems_.size ())
360 DOUT << "junking started autobeam: no stems\n";