2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "musical-request.hh"
15 #include "engraver-group-engraver.hh"
18 #include "engraver.hh"
23 TODO: figure what to do in grace?
25 class Auto_beam_engraver : public Engraver
28 Auto_beam_engraver ();
29 VIRTUAL_COPY_CONS (Translator);
32 virtual void do_pre_move_processing ();
33 virtual void do_post_move_processing ();
34 virtual void do_removal_processing ();
35 virtual void acknowledge_element (Score_element_info);
36 virtual void process_acknowledged ();
40 void consider_end_and_begin (Moment test_mom);
41 Spanner* create_beam_p ();
44 bool same_grace_state_b (Score_element* e);
48 Spanner *finished_beam_p_;
49 Link_array<Item>* stem_l_arr_p_;
53 Moment beam_start_moment_;
54 Moment beam_start_location_;
56 // We act as if beam were created, and start a grouping anyway.
57 Beaming_info_list*grouping_p_;
58 Beaming_info_list*finished_grouping_p_;
61 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
63 Auto_beam_engraver::Auto_beam_engraver ()
66 shortest_mom_ = Moment (1, 8);
68 finished_grouping_p_ = 0;
73 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
75 SCM wild = gh_list (ly_symbol2scm ("*"), ly_symbol2scm ("*"), SCM_UNDEFINED);
76 SCM b = gh_list (ly_symbol2scm ("begin"), SCM_UNDEFINED);
77 SCM e = gh_list (ly_symbol2scm ("end"), SCM_UNDEFINED);
79 Moment one_beat = *unsmob_moment( get_property ("beatLength"));
80 int num = *unsmob_moment (get_property("measureLength")) / one_beat;
81 int den = one_beat.den_i ();
82 SCM time = gh_list (gh_int2scm (num), gh_int2scm (den), SCM_UNDEFINED);
84 SCM type = gh_list (gh_int2scm (test_mom.num_i ()),
85 gh_int2scm (test_mom.den_i ()), SCM_UNDEFINED);
87 SCM settings = get_property ("autoBeamSettings");
90 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
91 In order of increasing priority:
95 iii. end <type> <num> <den>
103 [to be defined in config file]
104 i. easy catch-all rule
105 ii. exceptions for time signature
106 iii. exceptions for time signature, for specific duration type
110 v. override for specific duration type
116 first guess: begin beam at any position
118 Moment begin_mom (0);
120 first guess: end beam at end of beat
122 SCM one (get_property ("beatLength"));
125 if (unsmob_moment (one))
126 end_mom = *unsmob_moment (one);
129 second guess: property generic time exception
131 SCM begin = gh_assoc (gh_append3 (b, wild, time), settings);
133 if (begin != SCM_BOOL_F && unsmob_moment (gh_cdr (begin)))
134 begin_mom = * unsmob_moment (gh_cdr (begin));
136 SCM end = gh_assoc (gh_append3 (e, wild, time), settings);
137 if (end != SCM_BOOL_F && unsmob_moment (gh_cdr (end)))
138 end_mom = * unsmob_moment (gh_cdr (end));
141 third guess: property time exception, specific for duration type
143 SCM begin_mult = gh_assoc (gh_append3 (b, type, time), settings);
144 if (begin_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (begin_mult)))
145 begin_mom = * unsmob_moment (gh_cdr (begin_mult));
147 SCM end_mult = gh_assoc (gh_append3 (e, type, time), settings);
148 if (end_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (end_mult)))
149 end_mom = * unsmob_moment (gh_cdr (end_mult));
152 fourth guess [user override]: property plain generic
154 begin = gh_assoc (gh_append3 (b, wild, wild), settings);
155 if (begin != SCM_BOOL_F && unsmob_moment (gh_cdr (begin)))
156 begin_mom = * unsmob_moment (gh_cdr (begin));
158 end = gh_assoc (gh_append3 (e, wild, wild), settings);
159 if (end != SCM_BOOL_F && unsmob_moment (gh_cdr (end)))
160 end_mom = * unsmob_moment (gh_cdr (end));
163 fifth guess [user override]: property plain, specific for duration type
165 begin_mult = gh_assoc (gh_append3 (b, type, wild), settings);
166 if (begin_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (begin_mult)))
167 begin_mom = * unsmob_moment (gh_cdr (begin_mult));
169 end_mult = gh_assoc (gh_append3 (e, type, wild), settings);
170 if (end_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (end_mult)))
171 end_mom = * unsmob_moment (gh_cdr (end_mult));
175 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (end_mom);
179 if (stem_l_arr_p_ && stem_l_arr_p_->size () > 1 && !r)
183 Allow already started autobeam to end
185 SCM on = get_property ("noAutoBeaming");
190 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (begin_mom);
191 if (!stem_l_arr_p_ && (!begin_mom || !r))
196 Auto_beam_engraver::create_beam_p ()
198 Spanner* beam_p = new Spanner (get_property ("Beam"));
199 Beam::set_interface (beam_p);
201 for (int i = 0; i < stem_l_arr_p_->size (); i++)
204 watch out for stem tremolos and abbreviation beams
206 if (Stem::beam_l ((*stem_l_arr_p_)[i]))
210 Beam::add_stem (beam_p,(*stem_l_arr_p_)[i]);
213 announce_element (beam_p, 0);
219 Auto_beam_engraver::begin_beam ()
221 assert (!stem_l_arr_p_);
222 stem_l_arr_p_ = new Link_array<Item>;
223 assert (!grouping_p_);
224 grouping_p_ = new Beaming_info_list;
225 beam_start_moment_ = now_mom ();
226 beam_start_location_ = *unsmob_moment (get_property ("measurePosition"));
231 Auto_beam_engraver::junk_beam ()
233 assert (stem_l_arr_p_);
235 delete stem_l_arr_p_;
239 shortest_mom_ = Moment (1, 8);
243 Auto_beam_engraver::end_beam ()
245 if (stem_l_arr_p_->size () < 2)
251 finished_beam_p_ = create_beam_p ();
252 if (finished_beam_p_)
253 finished_grouping_p_ = grouping_p_;
254 delete stem_l_arr_p_;
257 shortest_mom_ = Moment (1, 8);
262 Auto_beam_engraver::typeset_beam ()
264 if (finished_beam_p_)
266 finished_grouping_p_->beamify ();
267 Beam::set_beaming (finished_beam_p_, finished_grouping_p_);
268 typeset_element (finished_beam_p_);
269 finished_beam_p_ = 0;
271 delete finished_grouping_p_;
272 finished_grouping_p_= 0;
277 Auto_beam_engraver::do_post_move_processing ()
280 don't beam over skips
284 Moment now = now_mom ();
285 if (extend_mom_ < now)
293 Auto_beam_engraver::do_pre_move_processing ()
297 Moment now = now_mom ();
298 if ((extend_mom_ < now)
299 || ((extend_mom_ == now) && (last_add_mom_ != now )))
303 else if (!stem_l_arr_p_->size ())
312 Auto_beam_engraver::do_removal_processing ()
314 /* finished beams may be typeset */
316 /* but unfinished may need another announce/acknowledge pass */
322 Auto_beam_engraver::same_grace_state_b (Score_element* e)
324 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
325 SCM wg =get_property ("weAreGraceContext");
326 return (to_boolean (wg)) == gr;
330 Auto_beam_engraver::acknowledge_element (Score_element_info info)
332 if (!same_grace_state_b (info.elem_l_))
337 if (Beam::has_interface (info.elem_l_))
341 else if (Bar::has_interface (info.elem_l_))
345 else if (Rest::has_interface (info.elem_l_))
351 if (Stem::has_interface (info.elem_l_))
353 Item* stem_l = dynamic_cast<Item *> (info.elem_l_);
355 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
358 programming_error ("Stem must have rhythmic structure");
363 Don't (start) auto-beam over empty stems; skips or rests
365 if (!Stem::heads_i (stem_l))
372 if (Stem::beam_l (stem_l))
379 int durlog = unsmob_duration (rhythmic_req->get_mus_property ("duration"))->duration_log ();
389 if shortest duration would change
390 reconsider ending/starting beam first.
392 Moment mom = unsmob_duration (rhythmic_req->get_mus_property ("duration"))->length_mom ();
393 consider_end_and_begin (mom);
396 if (mom < shortest_mom_)
398 if (stem_l_arr_p_->size ())
401 consider_end_and_begin (shortest_mom_);
407 Moment now = now_mom ();
409 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
411 stem_l_arr_p_->push (stem_l);
413 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
418 Auto_beam_engraver::process_acknowledged ()
421 consider_end_and_begin (shortest_mom_);