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 Scalar begin = get_property (time_str + "beamAutoBegin", 0);
107 if (begin.length_i ())
108 begin_mom = begin.to_rat ();
110 Scalar end = get_property (time_str + "beamAutoEnd", 0);
112 end_mom = end.to_rat ();
115 third guess: property time exception, specific for duration type
117 if (type_str.length_i ())
119 Scalar end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
120 if (end_mult.length_i ())
121 end_mom = end_mult.to_rat ();
122 Scalar begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
123 if (begin_mult.length_i ())
124 begin_mom = begin_mult.to_rat ();
128 fourth guess [user override]: property plain generic
130 begin = get_property ("beamAutoBegin", 0);
131 if (begin.length_i ())
132 begin_mom = begin.to_rat ();
134 end = get_property ("beamAutoEnd", 0);
136 end_mom = end.to_rat ();
139 fifth guess [user override]: property plain, specific for duration type
141 if (type_str.length_i ())
143 Scalar end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
144 if (end_mult.length_i ())
145 end_mom = end_mult.to_rat ();
146 Scalar begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
147 if (begin_mult.length_i ())
148 begin_mom = begin_mult.to_rat ();
153 r = time->whole_in_measure_.mod_rat (end_mom);
157 if (stem_l_arr_p_ && !r)
161 Allow already started autobeam to end
163 Scalar on = get_property ("noAutoBeaming", 0);
168 r = time->whole_in_measure_.mod_rat (begin_mom);
169 if (!stem_l_arr_p_ && (!begin_mom || !r))
175 Auto_beam_engraver::begin_beam ()
177 assert (!stem_l_arr_p_);
178 stem_l_arr_p_ = new Array<Stem*>;
179 assert (!grouping_p_);
180 grouping_p_ = new Beaming_info_list;
181 beam_start_moment_ = now_mom ();
182 beam_start_location_ = timer_l_->time_.whole_in_measure_;
186 Auto_beam_engraver::create_beam_p ()
188 Beam* beam_p = new Beam;
190 for (int i = 0; i < stem_l_arr_p_->size (); i++)
193 watch out for stem tremolos and abbreviation beams
195 if ((*stem_l_arr_p_)[i]->beam_l_)
199 beam_p->add_stem ((*stem_l_arr_p_)[i]);
202 /* urg, copied from Beam_engraver */
203 Scalar prop = get_property ("beamslopedamping", 0);
205 beam_p->set_elt_property (damping_scm_sym, gh_int2scm(prop));
207 prop = get_property ("autoKneeGap", 0);
209 beam_p->set_elt_property (auto_knee_gap_scm_sym, gh_int2scm(prop));
211 prop = get_property ("autoInterstaffKneeGap", 0);
213 beam_p->set_elt_property (auto_interstaff_knee_gap_scm_sym, gh_int2scm( prop));
215 prop = get_property ("beamquantisation", 0);
217 beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
219 announce_element (Score_element_info (beam_p, 0));
224 Auto_beam_engraver::end_beam ()
226 if (stem_l_arr_p_->size () < 2)
232 finished_beam_p_ = create_beam_p ();
233 if (finished_beam_p_)
234 finished_grouping_p_ = grouping_p_;
235 delete stem_l_arr_p_;
238 shortest_mom_ = Moment (1, 8);
243 Auto_beam_engraver::typeset_beam ()
245 if (finished_beam_p_)
247 finished_grouping_p_->beamify ();
248 finished_beam_p_->set_beaming (finished_grouping_p_);
249 typeset_element (finished_beam_p_);
250 finished_beam_p_ = 0;
252 delete finished_grouping_p_;
253 finished_grouping_p_= 0;
258 Auto_beam_engraver::do_post_move_processing ()
261 don't beam over skips
265 Moment now = now_mom ();
266 if (extend_mom_ < now)
274 Auto_beam_engraver::do_pre_move_processing ()
280 Auto_beam_engraver::do_removal_processing ()
282 /* finished beams may be typeset */
284 /* but unfinished may need another announce/acknoledge pass */
290 Auto_beam_engraver::same_grace_state_b (Score_element* e)
292 bool gr = (e->get_elt_property (grace_scm_sym) != SCM_BOOL_F) ;
294 return gr == get_property ("weAreGraceContext",0).to_bool ();
298 Auto_beam_engraver::acknowledge_element (Score_element_info info)
300 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
305 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
309 else if (Chord_tremolo *b = dynamic_cast<Chord_tremolo*> (info.elem_l_))
313 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
317 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
323 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
325 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
328 programming_error ("Stem must have rhythmic structure");
333 Don't (start) auto-beam over empty stems; skips or rests
335 if (!stem_l->head_l_arr_.size ())
349 int durlog =rhythmic_req->duration_.durlog_i_;
358 if shortest duration would change
359 reconsider ending/starting beam first.
361 Moment mom = rhythmic_req->duration_.length_mom ();
362 consider_end_and_begin (mom);
365 if (mom < shortest_mom_)
367 if (stem_l_arr_p_->size ())
370 consider_end_and_begin (shortest_mom_);
376 Moment now = now_mom ();
378 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
380 stem_l_arr_p_->push (stem_l);
382 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
387 Auto_beam_engraver::junk_beam ()
389 assert (stem_l_arr_p_);
391 delete stem_l_arr_p_;
395 shortest_mom_ = Moment (1, 8);
399 Auto_beam_engraver::process_acknowledged ()
403 Moment now = now_mom ();
404 if ((extend_mom_ < now)
405 || ((extend_mom_ == now) && (last_add_mom_ != now )))
409 else if (!stem_l_arr_p_->size ())