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>
11 #include "auto-beam-engraver.hh"
12 #include "musical-request.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)
60 timer_l_->get_time_signature (&num, &den);
62 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
65 if (test_mom.num () != 1)
66 type_str = to_str (test_mom.num ());
67 if (test_mom.den () != 1)
68 type_str = type_str + "_" + to_str (test_mom.den ());
73 FIXME: SHOULD USE ALIST
78 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
79 In order of increasing priority:
82 ii. time<num>_<den>beamAutoEnd
83 iii. time<num>_<den>beamAutoEnd<type>
90 [to be defined in config file]
91 i. easy catch-all rule
92 ii. exceptions for time signature
93 iii. exceptions for time signature, for specific duration type
97 v. override for specific duration type
99 The user overrides should be required for common cases.
103 first guess: begin beam at any position
105 Moment begin_mom (0);
107 first guess: end beam at end of beat
109 SCM one (get_property ("beatLength", 0));
112 if (SMOB_IS_TYPE_B(Moment, one))
113 end_mom = *SMOB_TO_TYPE (Moment, one);
116 second guess: property generic time exception
118 SCM begin = get_property (time_str + "beamAutoBegin", 0);
119 if (SMOB_IS_TYPE_B(Moment, begin))
120 begin_mom = * SMOB_TO_TYPE(Moment, begin);
122 SCM end = get_property (time_str + "beamAutoEnd", 0);
123 if (SMOB_IS_TYPE_B (Moment, end))
124 end_mom = * SMOB_TO_TYPE(Moment,end);
127 third guess: property time exception, specific for duration type
129 if (type_str.length_i ())
131 SCM end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
132 if (SMOB_IS_TYPE_B (Moment, end_mult))
133 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
135 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
136 if (SMOB_IS_TYPE_B (Moment, begin_mult))
137 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
141 fourth guess [user override]: property plain generic
143 begin = get_property ("beamAutoBegin", 0);
144 if (SMOB_IS_TYPE_B(Moment, begin))
145 begin_mom = * SMOB_TO_TYPE(Moment, begin);
149 end = get_property ("beamAutoEnd", 0);
150 if (SMOB_IS_TYPE_B (Moment, end))
151 end_mom = * SMOB_TO_TYPE (Moment,end);
154 fifth guess [user override]: property plain, specific for duration type
156 if (type_str.length_i ())
158 SCM end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
159 if (SMOB_IS_TYPE_B (Moment, end_mult))
160 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
162 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
163 if (SMOB_IS_TYPE_B (Moment, begin_mult))
164 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
169 r = timer_l_->measure_position ().mod_rat (end_mom);
173 if (stem_l_arr_p_ && !r)
177 Allow already started autobeam to end
179 SCM on = get_property ("noAutoBeaming", 0);
184 r = timer_l_->measure_position ().mod_rat (begin_mom);
185 if (!stem_l_arr_p_ && (!begin_mom || !r))
191 Auto_beam_engraver::begin_beam ()
193 assert (!stem_l_arr_p_);
194 stem_l_arr_p_ = new Array<Stem*>;
195 assert (!grouping_p_);
196 grouping_p_ = new Beaming_info_list;
197 beam_start_moment_ = now_mom ();
198 beam_start_location_ = timer_l_->measure_position ();
202 Auto_beam_engraver::create_beam_p ()
204 Beam* beam_p = new Beam;
206 for (int i = 0; i < stem_l_arr_p_->size (); i++)
209 watch out for stem tremolos and abbreviation beams
211 if ((*stem_l_arr_p_)[i]->beam_l ())
215 beam_p->add_stem ((*stem_l_arr_p_)[i]);
218 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/acknowledge pass */
290 Auto_beam_engraver::same_grace_state_b (Score_element* e)
292 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
293 SCM wg =get_property ("weAreGraceContext",0);
294 return (to_boolean (wg)) == gr;
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 (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
313 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
319 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
321 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
324 programming_error ("Stem must have rhythmic structure");
329 Don't (start) auto-beam over empty stems; skips or rests
331 if (!stem_l->heads_i ())
338 if (stem_l->beam_l ())
345 int durlog =rhythmic_req->duration_.durlog_i_;
354 if shortest duration would change
355 reconsider ending/starting beam first.
357 Moment mom = rhythmic_req->duration_.length_mom ();
358 consider_end_and_begin (mom);
361 if (mom < shortest_mom_)
363 if (stem_l_arr_p_->size ())
366 consider_end_and_begin (shortest_mom_);
372 Moment now = now_mom ();
374 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
376 stem_l_arr_p_->push (stem_l);
378 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
383 Auto_beam_engraver::junk_beam ()
385 assert (stem_l_arr_p_);
387 delete stem_l_arr_p_;
391 shortest_mom_ = Moment (1, 8);
395 Auto_beam_engraver::process_acknowledged ()
399 Moment now = now_mom ();
400 if ((extend_mom_ < now)
401 || ((extend_mom_ == now) && (last_add_mom_ != now )))
405 else if (!stem_l_arr_p_->size ())