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 "chord-tremolo.hh"
18 #include "timing-engraver.hh"
19 #include "engraver-group-engraver.hh"
21 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
23 Auto_beam_engraver::Auto_beam_engraver ()
26 shortest_mom_ = Moment (1, 8);
28 finished_grouping_p_ = 0;
34 Auto_beam_engraver::do_creation_processing ()
36 Translator * t = daddy_grav_l ()->get_simple_translator ("Timing_engraver");
37 timer_l_ = dynamic_cast<Timing_engraver*> (t);
41 Auto_beam_engraver::do_try_music (Music*)
47 Auto_beam_engraver::do_process_requests ()
49 consider_end_and_begin (shortest_mom_);
53 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
58 Time_description const *time = &timer_l_->time_;
59 int num = time->whole_per_measure_ / time->one_beat_;
60 int den = time->one_beat_.den_i ();
61 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
64 if (test_mom.num () != 1)
65 type_str = to_str (test_mom.num ());
66 if (test_mom.den () != 1)
67 type_str = type_str + "_" + to_str (test_mom.den ());
70 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
71 In order of increasing priority:
74 ii. time<num>_<den>beamAutoEnd
75 iii. time<num>_<den>beamAutoEnd<type>
82 [to be defined in config file]
83 i. easy catch-all rule
84 ii. exceptions for time signature
85 iii. exceptions for time signature, for specific duration type
89 v. override for specific duration type
91 The user overrides should be required for common cases.
95 first guess: begin beam at any position
99 first guess: end beam at end of beat
101 Moment end_mom = time->one_beat_;
104 second guess: property generic time exception
106 SCM begin = get_property (time_str + "beamAutoBegin", 0);
107 if (SMOB_IS_TYPE_B(Moment, begin))
108 begin_mom = * SMOB_TO_TYPE(Moment, begin);
110 SCM end = get_property (time_str + "beamAutoEnd", 0);
111 if (SMOB_IS_TYPE_B (Moment, end))
112 end_mom = * SMOB_TO_TYPE(Moment,end);
115 third guess: property time exception, specific for duration type
117 if (type_str.length_i ())
119 SCM end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
120 if (SMOB_IS_TYPE_B (Moment, end_mult))
121 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
123 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
124 if (SMOB_IS_TYPE_B (Moment, begin_mult))
125 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
129 fourth guess [user override]: property plain generic
131 begin = get_property ("beamAutoBegin", 0);
132 if (SMOB_IS_TYPE_B(Moment, begin))
133 begin_mom = * SMOB_TO_TYPE(Moment, begin);
137 end = get_property ("beamAutoEnd", 0);
138 if (SMOB_IS_TYPE_B (Moment, end))
139 end_mom = * SMOB_TO_TYPE (Moment,end);
142 fifth guess [user override]: property plain, specific for duration type
144 if (type_str.length_i ())
146 SCM end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
147 if (SMOB_IS_TYPE_B (Moment, end_mult))
148 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
150 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
151 if (SMOB_IS_TYPE_B (Moment, begin_mult))
152 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
157 r = time->whole_in_measure_.mod_rat (end_mom);
161 if (stem_l_arr_p_ && !r)
165 Allow already started autobeam to end
167 SCM on = get_property ("noAutoBeaming", 0);
168 if (gh_boolean_p (on) && gh_scm2bool (on))
172 r = time->whole_in_measure_.mod_rat (begin_mom);
173 if (!stem_l_arr_p_ && (!begin_mom || !r))
179 Auto_beam_engraver::begin_beam ()
181 assert (!stem_l_arr_p_);
182 stem_l_arr_p_ = new Array<Stem*>;
183 assert (!grouping_p_);
184 grouping_p_ = new Beaming_info_list;
185 beam_start_moment_ = now_mom ();
186 beam_start_location_ = timer_l_->time_.whole_in_measure_;
190 Auto_beam_engraver::create_beam_p ()
192 Beam* beam_p = new Beam;
194 for (int i = 0; i < stem_l_arr_p_->size (); i++)
197 watch out for stem tremolos and abbreviation beams
199 if ((*stem_l_arr_p_)[i]->beam_l_)
203 beam_p->add_stem ((*stem_l_arr_p_)[i]);
206 /* urg, copied from Beam_engraver */
207 SCM prop = get_property ("beamslopedamping", 0);
208 if (SCM_NUMBERP(prop))
209 beam_p->set_elt_property (damping_scm_sym, prop);
211 prop = get_property ("autoKneeGap", 0);
212 if (SCM_NUMBERP(prop))
213 beam_p->set_elt_property (auto_knee_gap_scm_sym, prop);
215 prop = get_property ("autoInterstaffKneeGap", 0);
216 if (SCM_NUMBERP(prop))
217 beam_p->set_elt_property (auto_interstaff_knee_gap_scm_sym, prop);
219 prop = get_property ("beamquantisation", 0);
220 if (SCM_NUMBERP(prop))
221 beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
223 announce_element (Score_element_info (beam_p, 0));
228 Auto_beam_engraver::end_beam ()
230 if (stem_l_arr_p_->size () < 2)
236 finished_beam_p_ = create_beam_p ();
237 if (finished_beam_p_)
238 finished_grouping_p_ = grouping_p_;
239 delete stem_l_arr_p_;
242 shortest_mom_ = Moment (1, 8);
247 Auto_beam_engraver::typeset_beam ()
249 if (finished_beam_p_)
251 finished_grouping_p_->beamify ();
252 finished_beam_p_->set_beaming (finished_grouping_p_);
253 typeset_element (finished_beam_p_);
254 finished_beam_p_ = 0;
256 delete finished_grouping_p_;
257 finished_grouping_p_= 0;
262 Auto_beam_engraver::do_post_move_processing ()
265 don't beam over skips
269 Moment now = now_mom ();
270 if (extend_mom_ < now)
278 Auto_beam_engraver::do_pre_move_processing ()
284 Auto_beam_engraver::do_removal_processing ()
286 /* finished beams may be typeset */
288 /* but unfinished may need another announce/acknowledge pass */
294 Auto_beam_engraver::same_grace_state_b (Score_element* e)
296 bool gr = e->get_elt_property (grace_scm_sym) != SCM_BOOL_F;
297 SCM wg =get_property ("weAreGraceContext",0);
298 return (gh_boolean_p (wg) && gh_scm2bool (wg)) == gr;
302 Auto_beam_engraver::acknowledge_element (Score_element_info info)
304 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
309 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
313 else if (Chord_tremolo *b = dynamic_cast<Chord_tremolo*> (info.elem_l_))
317 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
321 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
327 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
329 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
332 programming_error ("Stem must have rhythmic structure");
337 Don't (start) auto-beam over empty stems; skips or rests
339 if (!stem_l->head_l_arr_.size ())
353 int durlog =rhythmic_req->duration_.durlog_i_;
362 if shortest duration would change
363 reconsider ending/starting beam first.
365 Moment mom = rhythmic_req->duration_.length_mom ();
366 consider_end_and_begin (mom);
369 if (mom < shortest_mom_)
371 if (stem_l_arr_p_->size ())
374 consider_end_and_begin (shortest_mom_);
380 Moment now = now_mom ();
382 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
384 stem_l_arr_p_->push (stem_l);
386 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
391 Auto_beam_engraver::junk_beam ()
393 assert (stem_l_arr_p_);
395 delete stem_l_arr_p_;
399 shortest_mom_ = Moment (1, 8);
403 Auto_beam_engraver::process_acknowledged ()
407 Moment now = now_mom ();
408 if ((extend_mom_ < now)
409 || ((extend_mom_ == now) && (last_add_mom_ != now )))
413 else if (!stem_l_arr_p_->size ())