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)
59 timer_l_->get_time_signature (&num, &den);
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 ());
72 FIXME: SHOULD USE ALIST
77 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
78 In order of increasing priority:
81 ii. time<num>_<den>beamAutoEnd
82 iii. time<num>_<den>beamAutoEnd<type>
89 [to be defined in config file]
90 i. easy catch-all rule
91 ii. exceptions for time signature
92 iii. exceptions for time signature, for specific duration type
96 v. override for specific duration type
98 The user overrides should be required for common cases.
102 first guess: begin beam at any position
104 Moment begin_mom (0);
106 first guess: end beam at end of beat
108 SCM one (get_property ("beatLength"));
111 if (SMOB_IS_TYPE_B(Moment, one))
112 end_mom = *SMOB_TO_TYPE (Moment, one);
115 second guess: property generic time exception
117 SCM begin = get_property (time_str + "beamAutoBegin");
118 if (SMOB_IS_TYPE_B(Moment, begin))
119 begin_mom = * SMOB_TO_TYPE(Moment, begin);
121 SCM end = get_property (time_str + "beamAutoEnd");
122 if (SMOB_IS_TYPE_B (Moment, end))
123 end_mom = * SMOB_TO_TYPE(Moment,end);
126 third guess: property time exception, specific for duration type
128 if (type_str.length_i ())
130 SCM end_mult = get_property ( time_str + "beamAutoEnd" + type_str);
131 if (SMOB_IS_TYPE_B (Moment, end_mult))
132 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
134 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str);
135 if (SMOB_IS_TYPE_B (Moment, begin_mult))
136 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
140 fourth guess [user override]: property plain generic
142 begin = get_property ("beamAutoBegin");
143 if (SMOB_IS_TYPE_B(Moment, begin))
144 begin_mom = * SMOB_TO_TYPE(Moment, begin);
148 end = get_property ("beamAutoEnd");
149 if (SMOB_IS_TYPE_B (Moment, end))
150 end_mom = * SMOB_TO_TYPE (Moment,end);
153 fifth guess [user override]: property plain, specific for duration type
155 if (type_str.length_i ())
157 SCM end_mult = get_property (String ("beamAutoEnd") + type_str);
158 if (SMOB_IS_TYPE_B (Moment, end_mult))
159 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
161 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str);
162 if (SMOB_IS_TYPE_B (Moment, begin_mult))
163 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
168 r = timer_l_->measure_position ().mod_rat (end_mom);
172 if (stem_l_arr_p_ && !r)
176 Allow already started autobeam to end
178 SCM on = get_property ("noAutoBeaming");
183 r = timer_l_->measure_position ().mod_rat (begin_mom);
184 if (!stem_l_arr_p_ && (!begin_mom || !r))
190 Auto_beam_engraver::begin_beam ()
192 assert (!stem_l_arr_p_);
193 stem_l_arr_p_ = new Array<Stem*>;
194 assert (!grouping_p_);
195 grouping_p_ = new Beaming_info_list;
196 beam_start_moment_ = now_mom ();
197 beam_start_location_ = timer_l_->measure_position ();
201 Auto_beam_engraver::create_beam_p ()
203 Beam* beam_p = new Beam;
205 for (int i = 0; i < stem_l_arr_p_->size (); i++)
208 watch out for stem tremolos and abbreviation beams
210 if ((*stem_l_arr_p_)[i]->beam_l ())
214 beam_p->add_stem ((*stem_l_arr_p_)[i]);
217 announce_element (Score_element_info (beam_p, 0));
223 Auto_beam_engraver::end_beam ()
225 if (stem_l_arr_p_->size () < 2)
231 finished_beam_p_ = create_beam_p ();
232 if (finished_beam_p_)
233 finished_grouping_p_ = grouping_p_;
234 delete stem_l_arr_p_;
237 shortest_mom_ = Moment (1, 8);
242 Auto_beam_engraver::typeset_beam ()
244 if (finished_beam_p_)
246 finished_grouping_p_->beamify ();
247 finished_beam_p_->set_beaming (finished_grouping_p_);
248 typeset_element (finished_beam_p_);
249 finished_beam_p_ = 0;
251 delete finished_grouping_p_;
252 finished_grouping_p_= 0;
257 Auto_beam_engraver::do_post_move_processing ()
260 don't beam over skips
264 Moment now = now_mom ();
265 if (extend_mom_ < now)
273 Auto_beam_engraver::do_pre_move_processing ()
279 Auto_beam_engraver::do_removal_processing ()
281 /* finished beams may be typeset */
283 /* but unfinished may need another announce/acknowledge pass */
289 Auto_beam_engraver::same_grace_state_b (Score_element* e)
291 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
292 SCM wg =get_property ("weAreGraceContext");
293 return (to_boolean (wg)) == gr;
297 Auto_beam_engraver::acknowledge_element (Score_element_info info)
299 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
304 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
308 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
312 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
318 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
320 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
323 programming_error ("Stem must have rhythmic structure");
328 Don't (start) auto-beam over empty stems; skips or rests
330 if (!stem_l->heads_i ())
337 if (stem_l->beam_l ())
344 int durlog =rhythmic_req->duration_.durlog_i_;
353 if shortest duration would change
354 reconsider ending/starting beam first.
356 Moment mom = rhythmic_req->duration_.length_mom ();
357 consider_end_and_begin (mom);
360 if (mom < shortest_mom_)
362 if (stem_l_arr_p_->size ())
365 consider_end_and_begin (shortest_mom_);
371 Moment now = now_mom ();
373 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
375 stem_l_arr_p_->push (stem_l);
377 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
382 Auto_beam_engraver::junk_beam ()
384 assert (stem_l_arr_p_);
386 delete stem_l_arr_p_;
390 shortest_mom_ = Moment (1, 8);
394 Auto_beam_engraver::process_acknowledged ()
398 Moment now = now_mom ();
399 if ((extend_mom_ < now)
400 || ((extend_mom_ == now) && (last_add_mom_ != now )))
404 else if (!stem_l_arr_p_->size ())