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 Moment end_mom = timer_l_->one_beat_;
111 second guess: property generic time exception
113 SCM begin = get_property (time_str + "beamAutoBegin", 0);
114 if (SMOB_IS_TYPE_B(Moment, begin))
115 begin_mom = * SMOB_TO_TYPE(Moment, begin);
117 SCM end = get_property (time_str + "beamAutoEnd", 0);
118 if (SMOB_IS_TYPE_B (Moment, end))
119 end_mom = * SMOB_TO_TYPE(Moment,end);
122 third guess: property time exception, specific for duration type
124 if (type_str.length_i ())
126 SCM end_mult = get_property (time_str + "beamAutoEnd" + type_str, 0);
127 if (SMOB_IS_TYPE_B (Moment, end_mult))
128 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
130 SCM begin_mult = get_property (time_str + "beamAutoBegin" + type_str, 0);
131 if (SMOB_IS_TYPE_B (Moment, begin_mult))
132 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
136 fourth guess [user override]: property plain generic
138 begin = get_property ("beamAutoBegin", 0);
139 if (SMOB_IS_TYPE_B(Moment, begin))
140 begin_mom = * SMOB_TO_TYPE(Moment, begin);
144 end = get_property ("beamAutoEnd", 0);
145 if (SMOB_IS_TYPE_B (Moment, end))
146 end_mom = * SMOB_TO_TYPE (Moment,end);
149 fifth guess [user override]: property plain, specific for duration type
151 if (type_str.length_i ())
153 SCM end_mult = get_property (String ("beamAutoEnd") + type_str, 0);
154 if (SMOB_IS_TYPE_B (Moment, end_mult))
155 end_mom = * SMOB_TO_TYPE (Moment,end_mult);
157 SCM begin_mult = get_property (String ("beamAutoBegin") + type_str, 0);
158 if (SMOB_IS_TYPE_B (Moment, begin_mult))
159 begin_mom = * SMOB_TO_TYPE (Moment,begin_mult);
164 r = timer_l_->measure_position ().mod_rat (end_mom);
168 if (stem_l_arr_p_ && !r)
172 Allow already started autobeam to end
174 SCM on = get_property ("noAutoBeaming", 0);
175 if (gh_boolean_p (on) && gh_scm2bool (on))
179 r = timer_l_->measure_position ().mod_rat (begin_mom);
180 if (!stem_l_arr_p_ && (!begin_mom || !r))
186 Auto_beam_engraver::begin_beam ()
188 assert (!stem_l_arr_p_);
189 stem_l_arr_p_ = new Array<Stem*>;
190 assert (!grouping_p_);
191 grouping_p_ = new Beaming_info_list;
192 beam_start_moment_ = now_mom ();
193 beam_start_location_ = timer_l_->measure_position ();
197 Auto_beam_engraver::create_beam_p ()
199 Beam* beam_p = new Beam;
201 for (int i = 0; i < stem_l_arr_p_->size (); i++)
204 watch out for stem tremolos and abbreviation beams
206 if ((*stem_l_arr_p_)[i]->beam_l_)
210 beam_p->add_stem ((*stem_l_arr_p_)[i]);
213 announce_element (Score_element_info (beam_p, 0));
219 Auto_beam_engraver::end_beam ()
221 if (stem_l_arr_p_->size () < 2)
227 finished_beam_p_ = create_beam_p ();
228 if (finished_beam_p_)
229 finished_grouping_p_ = grouping_p_;
230 delete stem_l_arr_p_;
233 shortest_mom_ = Moment (1, 8);
238 Auto_beam_engraver::typeset_beam ()
240 if (finished_beam_p_)
242 finished_grouping_p_->beamify ();
243 finished_beam_p_->set_beaming (finished_grouping_p_);
244 typeset_element (finished_beam_p_);
245 finished_beam_p_ = 0;
247 delete finished_grouping_p_;
248 finished_grouping_p_= 0;
253 Auto_beam_engraver::do_post_move_processing ()
256 don't beam over skips
260 Moment now = now_mom ();
261 if (extend_mom_ < now)
269 Auto_beam_engraver::do_pre_move_processing ()
275 Auto_beam_engraver::do_removal_processing ()
277 /* finished beams may be typeset */
279 /* but unfinished may need another announce/acknowledge pass */
285 Auto_beam_engraver::same_grace_state_b (Score_element* e)
287 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
288 SCM wg =get_property ("weAreGraceContext",0);
289 return (gh_boolean_p (wg) && gh_scm2bool (wg)) == gr;
293 Auto_beam_engraver::acknowledge_element (Score_element_info info)
295 if (!same_grace_state_b (info.elem_l_) || !timer_l_)
300 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
304 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
308 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
314 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
316 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
319 programming_error ("Stem must have rhythmic structure");
324 Don't (start) auto-beam over empty stems; skips or rests
326 if (!stem_l->head_l_arr_.size ())
340 int durlog =rhythmic_req->duration_.durlog_i_;
349 if shortest duration would change
350 reconsider ending/starting beam first.
352 Moment mom = rhythmic_req->duration_.length_mom ();
353 consider_end_and_begin (mom);
356 if (mom < shortest_mom_)
358 if (stem_l_arr_p_->size ())
361 consider_end_and_begin (shortest_mom_);
367 Moment now = now_mom ();
369 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
371 stem_l_arr_p_->push (stem_l);
373 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
378 Auto_beam_engraver::junk_beam ()
380 assert (stem_l_arr_p_);
382 delete stem_l_arr_p_;
386 shortest_mom_ = Moment (1, 8);
390 Auto_beam_engraver::process_acknowledged ()
394 Moment now = now_mom ();
395 if ((extend_mom_ < now)
396 || ((extend_mom_ == now) && (last_add_mom_ != now )))
400 else if (!stem_l_arr_p_->size ())