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"
17 #include "timing-engraver.hh"
18 #include "engraver-group-engraver.hh"
20 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
22 Auto_beam_engraver::Auto_beam_engraver ()
25 shortest_mom_ = Moment (1, 8);
27 finished_grouping_p_ = 0;
33 Auto_beam_engraver::do_creation_processing ()
35 Translator * t = daddy_grav_l ()->get_simple_translator ("Timing_engraver");
36 timer_l_ = dynamic_cast<Timing_engraver*> (t);
40 Auto_beam_engraver::do_try_music (Music*)
46 Auto_beam_engraver::do_process_requests ()
48 consider_end_and_begin (shortest_mom_);
52 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
57 Time_description const *time = &timer_l_->time_;
58 int num = time->whole_per_measure_ / time->one_beat_;
59 int den = time->one_beat_.den_i ();
60 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
63 if (test_mom.num () != 1)
64 type_str = to_str (test_mom.num ());
65 if (test_mom.den () != 1)
66 type_str = type_str + "_" + to_str (test_mom.den ());
71 FIXME: SHOULD USE ALIST
76 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
77 In order of increasing priority:
80 ii. time<num>_<den>beamAutoEnd
81 iii. time<num>_<den>beamAutoEnd<type>
88 [to be defined in config file]
89 i. easy catch-all rule
90 ii. exceptions for time signature
91 iii. exceptions for time signature, for specific duration type
95 v. override for specific duration type
97 The user overrides should be required for common cases.
101 first guess: begin beam at any position
103 Moment begin_mom (0);
105 first guess: end beam at end of beat
107 Moment end_mom = time->one_beat_;
110 second guess: property generic time exception
112 SCM begin = get_property (time_str + "beamAutoBegin", 0);
113 if (SMOB_IS_TYPE_B(Moment, begin))
114 begin_mom = * SMOB_TO_TYPE(Moment, begin);
116 SCM end = get_property (time_str + "beamAutoEnd", 0);
117 if (SMOB_IS_TYPE_B (Moment, end))
118 end_mom = * SMOB_TO_TYPE(Moment,end);
121 third guess: property time exception, specific for duration type
123 if (type_str.length_i ())
125 SCM end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
126 if (SMOB_IS_TYPE_B (Moment, end_mult))
127 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
129 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
130 if (SMOB_IS_TYPE_B (Moment, begin_mult))
131 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
135 fourth guess [user override]: property plain generic
137 begin = get_property ("beamAutoBegin", 0);
138 if (SMOB_IS_TYPE_B(Moment, begin))
139 begin_mom = * SMOB_TO_TYPE(Moment, begin);
143 end = get_property ("beamAutoEnd", 0);
144 if (SMOB_IS_TYPE_B (Moment, end))
145 end_mom = * SMOB_TO_TYPE (Moment,end);
148 fifth guess [user override]: property plain, specific for duration type
150 if (type_str.length_i ())
152 SCM end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
153 if (SMOB_IS_TYPE_B (Moment, end_mult))
154 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
156 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
157 if (SMOB_IS_TYPE_B (Moment, begin_mult))
158 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
163 r = time->whole_in_measure_.mod_rat (end_mom);
167 if (stem_l_arr_p_ && !r)
171 Allow already started autobeam to end
173 SCM on = get_property ("noAutoBeaming", 0);
174 if (gh_boolean_p (on) && gh_scm2bool (on))
178 r = time->whole_in_measure_.mod_rat (begin_mom);
179 if (!stem_l_arr_p_ && (!begin_mom || !r))
185 Auto_beam_engraver::begin_beam ()
187 assert (!stem_l_arr_p_);
188 stem_l_arr_p_ = new Array<Stem*>;
189 assert (!grouping_p_);
190 grouping_p_ = new Beaming_info_list;
191 beam_start_moment_ = now_mom ();
192 beam_start_location_ = timer_l_->time_.whole_in_measure_;
196 Auto_beam_engraver::create_beam_p ()
198 Beam* beam_p = new Beam;
200 for (int i = 0; i < stem_l_arr_p_->size (); i++)
203 watch out for stem tremolos and abbreviation beams
205 if ((*stem_l_arr_p_)[i]->beam_l_)
209 beam_p->add_stem ((*stem_l_arr_p_)[i]);
212 announce_element (Score_element_info (beam_p, 0));
218 Auto_beam_engraver::end_beam ()
220 if (stem_l_arr_p_->size () < 2)
226 finished_beam_p_ = create_beam_p ();
227 if (finished_beam_p_)
228 finished_grouping_p_ = grouping_p_;
229 delete stem_l_arr_p_;
232 shortest_mom_ = Moment (1, 8);
237 Auto_beam_engraver::typeset_beam ()
239 if (finished_beam_p_)
241 finished_grouping_p_->beamify ();
242 finished_beam_p_->set_beaming (finished_grouping_p_);
243 typeset_element (finished_beam_p_);
244 finished_beam_p_ = 0;
246 delete finished_grouping_p_;
247 finished_grouping_p_= 0;
252 Auto_beam_engraver::do_post_move_processing ()
255 don't beam over skips
259 Moment now = now_mom ();
260 if (extend_mom_ < now)
268 Auto_beam_engraver::do_pre_move_processing ()
274 Auto_beam_engraver::do_removal_processing ()
276 /* finished beams may be typeset */
278 /* but unfinished may need another announce/acknowledge pass */
284 Auto_beam_engraver::same_grace_state_b (Score_element* e)
286 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
287 SCM wg =get_property ("weAreGraceContext",0);
288 return (gh_boolean_p (wg) && gh_scm2bool (wg)) == gr;
292 Auto_beam_engraver::acknowledge_element (Score_element_info info)
294 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
299 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
303 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
307 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
313 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
315 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
318 programming_error ("Stem must have rhythmic structure");
323 Don't (start) auto-beam over empty stems; skips or rests
325 if (!stem_l->head_l_arr_.size ())
339 int durlog =rhythmic_req->duration_.durlog_i_;
348 if shortest duration would change
349 reconsider ending/starting beam first.
351 Moment mom = rhythmic_req->duration_.length_mom ();
352 consider_end_and_begin (mom);
355 if (mom < shortest_mom_)
357 if (stem_l_arr_p_->size ())
360 consider_end_and_begin (shortest_mom_);
366 Moment now = now_mom ();
368 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
370 stem_l_arr_p_->push (stem_l);
372 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
377 Auto_beam_engraver::junk_beam ()
379 assert (stem_l_arr_p_);
381 delete stem_l_arr_p_;
385 shortest_mom_ = Moment (1, 8);
389 Auto_beam_engraver::process_acknowledged ()
393 Moment now = now_mom ();
394 if ((extend_mom_ < now)
395 || ((extend_mom_ == now) && (last_add_mom_ != now )))
399 else if (!stem_l_arr_p_->size ())