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"
14 #include "chord-tremolo.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)
58 Time_description const *time = &timer_l_->time_;
59 int num = time->whole_per_measure_ / time->one_beat_;
60 int den = time->one_beat_.den_i ();
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 = time->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 = time->whole_in_measure_.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 = time->whole_in_measure_.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_->time_.whole_in_measure_;
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]);
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_sym) != SCM_BOOL_F;
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 (Chord_tremolo *b = dynamic_cast<Chord_tremolo*> (info.elem_l_))
307 else if (Bar *b = dynamic_cast<Bar *> (info.elem_l_))
311 else if (Rest* rest_l = dynamic_cast<Rest *> (info.elem_l_))
317 if (Stem* stem_l = dynamic_cast<Stem *> (info.elem_l_))
319 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
322 programming_error ("Stem must have rhythmic structure");
327 Don't (start) auto-beam over empty stems; skips or rests
329 if (!stem_l->head_l_arr_.size ())
343 int durlog =rhythmic_req->duration_.durlog_i_;
352 if shortest duration would change
353 reconsider ending/starting beam first.
355 Moment mom = rhythmic_req->duration_.length_mom ();
356 consider_end_and_begin (mom);
359 if (mom < shortest_mom_)
361 if (stem_l_arr_p_->size ())
364 consider_end_and_begin (shortest_mom_);
370 Moment now = now_mom ();
372 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
374 stem_l_arr_p_->push (stem_l);
376 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
381 Auto_beam_engraver::junk_beam ()
383 assert (stem_l_arr_p_);
385 delete stem_l_arr_p_;
389 shortest_mom_ = Moment (1, 8);
393 Auto_beam_engraver::process_acknowledged ()
397 Moment now = now_mom ();
398 if ((extend_mom_ < now)
399 || ((extend_mom_ == now) && (last_add_mom_ != now )))
403 else if (!stem_l_arr_p_->size ())