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"
15 #include "timing-engraver.hh"
16 #include "engraver-group-engraver.hh"
18 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
22 TODO: remove all references to Timing_engraver; should read properties.
25 Auto_beam_engraver::Auto_beam_engraver ()
28 shortest_mom_ = Moment (1, 8);
30 finished_grouping_p_ = 0;
36 Auto_beam_engraver::do_creation_processing ()
38 Translator * t = daddy_grav_l ()->get_simple_translator ("Timing_engraver");
39 timer_l_ = dynamic_cast<Timing_engraver*> (t);
43 Auto_beam_engraver::do_try_music (Music*)
49 Auto_beam_engraver::do_process_music ()
51 consider_end_and_begin (shortest_mom_);
55 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
62 timer_l_->get_time_signature (&num, &den);
64 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
67 if (test_mom.num () != 1)
68 type_str = to_str (test_mom.num ());
69 if (test_mom.den () != 1)
70 type_str = type_str + "_" + to_str (test_mom.den ());
75 FIXME: SHOULD USE ALIST
80 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
81 In order of increasing priority:
84 ii. time<num>_<den>beamAutoEnd
85 iii. time<num>_<den>beamAutoEnd<type>
92 [to be defined in config file]
93 i. easy catch-all rule
94 ii. exceptions for time signature
95 iii. exceptions for time signature, for specific duration type
99 v. override for specific duration type
101 The user overrides should be required for common cases.
105 first guess: begin beam at any position
107 Moment begin_mom (0);
109 first guess: end beam at end of beat
111 SCM one (get_property ("beatLength"));
114 if (unsmob_moment (one))
115 end_mom = *unsmob_moment (one);
118 second guess: property generic time exception
120 SCM begin = get_property ((time_str + "beamAutoBegin").ch_C());
121 if (unsmob_moment (begin))
122 begin_mom = * unsmob_moment (begin);
124 SCM end = get_property ((time_str + "beamAutoEnd").ch_C());
125 if (unsmob_moment (end))
126 end_mom = * unsmob_moment (end);
129 third guess: property time exception, specific for duration type
131 if (type_str.length_i ())
133 SCM end_mult = get_property ((time_str + "beamAutoEnd" + type_str).ch_C());
134 if (unsmob_moment (end_mult))
135 end_mom = * unsmob_moment (end_mult);
137 SCM begin_mult = get_property ((time_str + "beamAutoBegin" + type_str).ch_C());
138 if (unsmob_moment (begin_mult))
139 begin_mom = * unsmob_moment (begin_mult);
143 fourth guess [user override]: property plain generic
145 begin = get_property ("beamAutoBegin");
146 if (unsmob_moment (begin))
147 begin_mom = * unsmob_moment (begin);
151 end = get_property ("beamAutoEnd");
152 if (unsmob_moment (end))
153 end_mom = * unsmob_moment (end);
156 fifth guess [user override]: property plain, specific for duration type
158 if (type_str.length_i ())
160 SCM end_mult = get_property ((String ("beamAutoEnd") + type_str).ch_C());
161 if (unsmob_moment (end_mult))
162 end_mom = * unsmob_moment (end_mult);
164 SCM begin_mult = get_property ((String ("beamAutoBegin") + type_str).ch_C());
165 if (unsmob_moment (begin_mult))
166 begin_mom = * unsmob_moment (begin_mult);
171 r = timer_l_->measure_position ().mod_rat (end_mom);
175 if (stem_l_arr_p_ && !r)
179 Allow already started autobeam to end
181 SCM on = get_property ("noAutoBeaming");
186 r = timer_l_->measure_position ().mod_rat (begin_mom);
187 if (!stem_l_arr_p_ && (!begin_mom || !r))
193 Auto_beam_engraver::begin_beam ()
195 assert (!stem_l_arr_p_);
196 stem_l_arr_p_ = new Array<Stem*>;
197 assert (!grouping_p_);
198 grouping_p_ = new Beaming_info_list;
199 beam_start_moment_ = now_mom ();
200 beam_start_location_ = timer_l_->measure_position ();
204 Auto_beam_engraver::create_beam_p ()
206 Beam* beam_p = new Beam (get_property ("basicBeamProperties"));
208 for (int i = 0; i < stem_l_arr_p_->size (); i++)
211 watch out for stem tremolos and abbreviation beams
213 if ((*stem_l_arr_p_)[i]->beam_l ())
217 beam_p->add_stem ((*stem_l_arr_p_)[i]);
220 announce_element (Score_element_info (beam_p, 0));
226 Auto_beam_engraver::end_beam ()
228 if (stem_l_arr_p_->size () < 2)
234 finished_beam_p_ = create_beam_p ();
235 if (finished_beam_p_)
236 finished_grouping_p_ = grouping_p_;
237 delete stem_l_arr_p_;
240 shortest_mom_ = Moment (1, 8);
245 Auto_beam_engraver::typeset_beam ()
247 if (finished_beam_p_)
249 finished_grouping_p_->beamify ();
250 finished_beam_p_->set_beaming (finished_grouping_p_);
251 typeset_element (finished_beam_p_);
252 finished_beam_p_ = 0;
254 delete finished_grouping_p_;
255 finished_grouping_p_= 0;
260 Auto_beam_engraver::do_post_move_processing ()
263 don't beam over skips
267 Moment now = now_mom ();
268 if (extend_mom_ < now)
276 Auto_beam_engraver::do_pre_move_processing ()
282 Auto_beam_engraver::do_removal_processing ()
284 /* finished beams may be typeset */
286 /* but unfinished may need another announce/acknowledge pass */
292 Auto_beam_engraver::same_grace_state_b (Score_element* e)
294 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
295 SCM wg =get_property ("weAreGraceContext");
296 return (to_boolean (wg)) == gr;
300 Auto_beam_engraver::acknowledge_element (Score_element_info info)
302 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
307 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
311 else if (to_boolean (info.elem_l_->get_elt_property ("bar-interface")))
315 else if (to_boolean (info.elem_l_->get_elt_property ("rest-interface")))
321 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
323 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
326 programming_error ("Stem must have rhythmic structure");
331 Don't (start) auto-beam over empty stems; skips or rests
333 if (!stem_l->heads_i ())
340 if (stem_l->beam_l ())
347 int durlog =rhythmic_req->duration_.durlog_i_;
356 if shortest duration would change
357 reconsider ending/starting beam first.
359 Moment mom = rhythmic_req->duration_.length_mom ();
360 consider_end_and_begin (mom);
363 if (mom < shortest_mom_)
365 if (stem_l_arr_p_->size ())
368 consider_end_and_begin (shortest_mom_);
374 Moment now = now_mom ();
376 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
378 stem_l_arr_p_->push (stem_l);
380 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
385 Auto_beam_engraver::junk_beam ()
387 assert (stem_l_arr_p_);
389 delete stem_l_arr_p_;
393 shortest_mom_ = Moment (1, 8);
397 Auto_beam_engraver::process_acknowledged ()
401 Moment now = now_mom ();
402 if ((extend_mom_ < now)
403 || ((extend_mom_ == now) && (last_add_mom_ != now )))
407 else if (!stem_l_arr_p_->size ())