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_)
200 beam_p->add_stem ((*stem_l_arr_p_)[i]);
203 /* urg, copied from Beam_engraver */
204 Scalar prop = get_property ("beamslopedamping", 0);
206 beam_p->set_elt_property (damping_scm_sym, gh_int2scm(prop));
208 prop = get_property ("autoKneeGap", 0);
210 beam_p->set_elt_property (auto_knee_gap_scm_sym, gh_int2scm(prop));
212 prop = get_property ("autoInterstaffKneeGap", 0);
214 beam_p->set_elt_property (auto_interstaff_knee_gap_scm_sym, gh_int2scm( prop));
216 prop = get_property ("beamquantisation", 0);
218 beam_p->quantisation_ = (Beam::Quantisation)(int)prop;
220 announce_element (Score_element_info (beam_p, 0));
225 Auto_beam_engraver::end_beam ()
227 if (stem_l_arr_p_->size () < 2)
233 finished_beam_p_ = create_beam_p ();
234 if (finished_beam_p_)
235 finished_grouping_p_ = grouping_p_;
236 delete stem_l_arr_p_;
239 shortest_mom_ = Moment (1, 8);
244 Auto_beam_engraver::typeset_beam ()
246 if (finished_beam_p_)
248 finished_grouping_p_->beamify ();
249 finished_beam_p_->set_beaming (finished_grouping_p_);
250 typeset_element (finished_beam_p_);
251 finished_beam_p_ = 0;
253 delete finished_grouping_p_;
254 finished_grouping_p_= 0;
259 Auto_beam_engraver::do_post_move_processing ()
262 don't beam over skips
266 Moment now = now_mom ();
267 if (extend_mom_ < now)
275 Auto_beam_engraver::do_pre_move_processing ()
281 Auto_beam_engraver::do_removal_processing ()
283 /* finished beams may be typeset */
285 /* but unfinished may need another announce/acknoledge pass */
291 Auto_beam_engraver::same_grace_state_b (Score_element* e)
293 bool gr = (e->get_elt_property (grace_scm_sym) != SCM_BOOL_F) ;
295 return gr == get_property ("weAreGraceContext",0).to_bool ();
299 Auto_beam_engraver::acknowledge_element (Score_element_info info)
301 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
306 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
310 else if (Chord_tremolo *b = dynamic_cast<Chord_tremolo*> (info.elem_l_))
314 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
318 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
324 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
326 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
329 programming_error ("Stem must have rhythmic structure");
334 Don't (start) auto-beam over empty stems; skips or rests
336 if (!stem_l->head_l_arr_.size ())
350 int durlog =rhythmic_req->duration_.durlog_i_;
359 if shortest duration would change
360 reconsider ending/starting beam first.
362 Moment mom = rhythmic_req->duration_.length_mom ();
363 consider_end_and_begin (mom);
366 if (mom < shortest_mom_)
368 if (stem_l_arr_p_->size ())
371 consider_end_and_begin (shortest_mom_);
377 Moment now = now_mom ();
379 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
381 stem_l_arr_p_->push (stem_l);
383 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
388 Auto_beam_engraver::junk_beam ()
390 assert (stem_l_arr_p_);
392 delete stem_l_arr_p_;
396 shortest_mom_ = Moment (1, 8);
400 Auto_beam_engraver::process_acknowledged ()
404 Moment now = now_mom ();
405 if ((extend_mom_ < now)
406 || ((extend_mom_ == now) && (last_add_mom_ != now )))
410 else if (!stem_l_arr_p_->size ())