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]);
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 (Chord_tremolo *b = dynamic_cast<Chord_tremolo*> (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->head_l_arr_.size ())
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 ())