2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "auto-beam-engraver.hh"
11 #include "musical-request.hh"
17 #include "timing-engraver.hh"
18 #include "engraver-group-engraver.hh"
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
24 TODO: remove all references to Timing_engraver; should read properties.
27 Auto_beam_engraver::Auto_beam_engraver ()
30 shortest_mom_ = Moment (1, 8);
32 finished_grouping_p_ = 0;
38 Auto_beam_engraver::do_creation_processing ()
40 Translator * t = daddy_grav_l ()->get_simple_translator ("Timing_engraver");
41 timer_l_ = dynamic_cast<Timing_engraver*> (t);
45 Auto_beam_engraver::do_try_music (Music*)
51 Auto_beam_engraver::do_process_music ()
53 consider_end_and_begin (shortest_mom_);
57 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
64 timer_l_->get_time_signature (&num, &den);
66 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
69 if (test_mom.num () != 1)
70 type_str = to_str (test_mom.num ());
71 if (test_mom.den () != 1)
72 type_str = type_str + "_" + to_str (test_mom.den ());
77 FIXME: SHOULD USE ALIST
82 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
83 In order of increasing priority:
86 ii. time<num>_<den>beamAutoEnd
87 iii. time<num>_<den>beamAutoEnd<type>
94 [to be defined in config file]
95 i. easy catch-all rule
96 ii. exceptions for time signature
97 iii. exceptions for time signature, for specific duration type
101 v. override for specific duration type
103 The user overrides should be required for common cases.
107 first guess: begin beam at any position
109 Moment begin_mom (0);
111 first guess: end beam at end of beat
113 SCM one (get_property ("beatLength"));
116 if (SMOB_IS_TYPE_B(Moment, one))
117 end_mom = *SMOB_TO_TYPE (Moment, one);
120 second guess: property generic time exception
122 SCM begin = get_property (time_str + "beamAutoBegin");
123 if (SMOB_IS_TYPE_B(Moment, begin))
124 begin_mom = * SMOB_TO_TYPE(Moment, begin);
126 SCM end = get_property (time_str + "beamAutoEnd");
127 if (SMOB_IS_TYPE_B (Moment, end))
128 end_mom = * SMOB_TO_TYPE(Moment,end);
131 third guess: property time exception, specific for duration type
133 if (type_str.length_i ())
135 SCM end_mult = get_property ( time_str + "beamAutoEnd" + type_str);
136 if (SMOB_IS_TYPE_B (Moment, end_mult))
137 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
139 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str);
140 if (SMOB_IS_TYPE_B (Moment, begin_mult))
141 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
145 fourth guess [user override]: property plain generic
147 begin = get_property ("beamAutoBegin");
148 if (SMOB_IS_TYPE_B(Moment, begin))
149 begin_mom = * SMOB_TO_TYPE(Moment, begin);
153 end = get_property ("beamAutoEnd");
154 if (SMOB_IS_TYPE_B (Moment, end))
155 end_mom = * SMOB_TO_TYPE (Moment,end);
158 fifth guess [user override]: property plain, specific for duration type
160 if (type_str.length_i ())
162 SCM end_mult = get_property (String ("beamAutoEnd") + type_str);
163 if (SMOB_IS_TYPE_B (Moment, end_mult))
164 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
166 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str);
167 if (SMOB_IS_TYPE_B (Moment, begin_mult))
168 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
173 r = timer_l_->measure_position ().mod_rat (end_mom);
177 if (stem_l_arr_p_ && !r)
181 Allow already started autobeam to end
183 SCM on = get_property ("noAutoBeaming");
188 r = timer_l_->measure_position ().mod_rat (begin_mom);
189 if (!stem_l_arr_p_ && (!begin_mom || !r))
195 Auto_beam_engraver::begin_beam ()
197 assert (!stem_l_arr_p_);
198 stem_l_arr_p_ = new Array<Stem*>;
199 assert (!grouping_p_);
200 grouping_p_ = new Beaming_info_list;
201 beam_start_moment_ = now_mom ();
202 beam_start_location_ = timer_l_->measure_position ();
206 Auto_beam_engraver::create_beam_p ()
208 Beam* beam_p = new Beam (get_property ("basicBeamProperties"));
210 for (int i = 0; i < stem_l_arr_p_->size (); i++)
213 watch out for stem tremolos and abbreviation beams
215 if ((*stem_l_arr_p_)[i]->beam_l ())
219 beam_p->add_stem ((*stem_l_arr_p_)[i]);
222 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_BOOL_T;
297 SCM wg =get_property ("weAreGraceContext");
298 return (to_boolean (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 (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->heads_i ())
342 if (stem_l->beam_l ())
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 ())