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 bool do_try_music (Music*);
33 virtual void do_pre_move_processing ();
34 virtual void do_post_move_processing ();
35 virtual void do_removal_processing ();
36 virtual void acknowledge_element (Score_element_info);
37 virtual void do_process_music ();
38 virtual void process_acknowledged ();
41 void consider_end_and_begin (Moment test_mom);
42 Spanner* create_beam_p ();
45 bool same_grace_state_b (Score_element* e);
49 Spanner *finished_beam_p_;
50 Link_array<Item>* stem_l_arr_p_;
54 Moment beam_start_moment_;
55 Moment beam_start_location_;
57 // We act as if beam were created, and start a grouping anyway.
58 Beaming_info_list*grouping_p_;
59 Beaming_info_list*finished_grouping_p_;
62 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
64 Auto_beam_engraver::Auto_beam_engraver ()
67 shortest_mom_ = Moment (1, 8);
69 finished_grouping_p_ = 0;
74 Auto_beam_engraver::do_try_music (Music*)
80 Auto_beam_engraver::do_process_music ()
82 consider_end_and_begin (shortest_mom_);
86 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
88 SCM wild = gh_list (ly_symbol2scm ("*"), ly_symbol2scm ("*"), SCM_UNDEFINED);
89 SCM b = gh_list (ly_symbol2scm ("begin"), SCM_UNDEFINED);
90 SCM e = gh_list (ly_symbol2scm ("end"), SCM_UNDEFINED);
92 Moment one_beat = *unsmob_moment( get_property ("beatLength"));
93 int num = *unsmob_moment (get_property("measureLength")) / one_beat;
94 int den = one_beat.den_i ();
95 SCM time = gh_list (gh_int2scm (num), gh_int2scm (den), SCM_UNDEFINED);
97 SCM type = gh_list (gh_int2scm (test_mom.num_i ()),
98 gh_int2scm (test_mom.den_i ()), SCM_UNDEFINED);
100 SCM settings = get_property ("autoBeamSettings");
103 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
104 In order of increasing priority:
107 ii. end * <num> <den>
108 iii. end <type> <num> <den>
116 [to be defined in config file]
117 i. easy catch-all rule
118 ii. exceptions for time signature
119 iii. exceptions for time signature, for specific duration type
123 v. override for specific duration type
129 first guess: begin beam at any position
131 Moment begin_mom (0);
133 first guess: end beam at end of beat
135 SCM one (get_property ("beatLength"));
138 if (unsmob_moment (one))
139 end_mom = *unsmob_moment (one);
142 second guess: property generic time exception
144 SCM begin = gh_assoc (gh_append3 (b, wild, time), settings);
146 if (begin != SCM_BOOL_F && unsmob_moment (gh_cdr (begin)))
147 begin_mom = * unsmob_moment (gh_cdr (begin));
149 SCM end = gh_assoc (gh_append3 (e, wild, time), settings);
150 if (end != SCM_BOOL_F && unsmob_moment (gh_cdr (end)))
151 end_mom = * unsmob_moment (gh_cdr (end));
154 third guess: property time exception, specific for duration type
156 SCM begin_mult = gh_assoc (gh_append3 (b, type, time), settings);
157 if (begin_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (begin_mult)))
158 begin_mom = * unsmob_moment (gh_cdr (begin_mult));
160 SCM end_mult = gh_assoc (gh_append3 (e, type, time), settings);
161 if (end_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (end_mult)))
162 end_mom = * unsmob_moment (gh_cdr (end_mult));
165 fourth guess [user override]: property plain generic
167 begin = gh_assoc (gh_append3 (b, wild, wild), settings);
168 if (begin != SCM_BOOL_F && unsmob_moment (gh_cdr (begin)))
169 begin_mom = * unsmob_moment (gh_cdr (begin));
171 end = gh_assoc (gh_append3 (e, wild, wild), settings);
172 if (end != SCM_BOOL_F && unsmob_moment (gh_cdr (end)))
173 end_mom = * unsmob_moment (gh_cdr (end));
176 fifth guess [user override]: property plain, specific for duration type
178 begin_mult = gh_assoc (gh_append3 (b, type, wild), settings);
179 if (begin_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (begin_mult)))
180 begin_mom = * unsmob_moment (gh_cdr (begin_mult));
182 end_mult = gh_assoc (gh_append3 (e, type, wild), settings);
183 if (end_mult != SCM_BOOL_F && unsmob_moment (gh_cdr (end_mult)))
184 end_mom = * unsmob_moment (gh_cdr (end_mult));
188 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (end_mom);
192 if (stem_l_arr_p_ && !r)
196 Allow already started autobeam to end
198 SCM on = get_property ("noAutoBeaming");
203 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (begin_mom);
204 if (!stem_l_arr_p_ && (!begin_mom || !r))
210 Auto_beam_engraver::begin_beam ()
212 assert (!stem_l_arr_p_);
213 stem_l_arr_p_ = new Link_array<Item>;
214 assert (!grouping_p_);
215 grouping_p_ = new Beaming_info_list;
216 beam_start_moment_ = now_mom ();
217 beam_start_location_ = *unsmob_moment (get_property ("measurePosition"));
221 Auto_beam_engraver::create_beam_p ()
223 Spanner* beam_p = new Spanner (get_property ("Beam"));
224 Beam::set_interface (beam_p);
226 for (int i = 0; i < stem_l_arr_p_->size (); i++)
229 watch out for stem tremolos and abbreviation beams
231 if (Stem::beam_l ((*stem_l_arr_p_)[i]))
235 Beam::add_stem (beam_p,(*stem_l_arr_p_)[i]);
238 announce_element (beam_p, 0);
244 Auto_beam_engraver::end_beam ()
246 if (stem_l_arr_p_->size () < 2)
252 finished_beam_p_ = create_beam_p ();
253 if (finished_beam_p_)
254 finished_grouping_p_ = grouping_p_;
255 delete stem_l_arr_p_;
258 shortest_mom_ = Moment (1, 8);
263 Auto_beam_engraver::typeset_beam ()
265 if (finished_beam_p_)
267 finished_grouping_p_->beamify ();
268 Beam::set_beaming (finished_beam_p_, finished_grouping_p_);
269 typeset_element (finished_beam_p_);
270 finished_beam_p_ = 0;
272 delete finished_grouping_p_;
273 finished_grouping_p_= 0;
278 Auto_beam_engraver::do_post_move_processing ()
281 don't beam over skips
285 Moment now = now_mom ();
286 if (extend_mom_ < now)
294 Auto_beam_engraver::do_pre_move_processing ()
300 Auto_beam_engraver::do_removal_processing ()
302 /* finished beams may be typeset */
304 /* but unfinished may need another announce/acknowledge pass */
310 Auto_beam_engraver::same_grace_state_b (Score_element* e)
312 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
313 SCM wg =get_property ("weAreGraceContext");
314 return (to_boolean (wg)) == gr;
318 Auto_beam_engraver::acknowledge_element (Score_element_info info)
320 if (!same_grace_state_b (info.elem_l_))
325 if (Beam::has_interface (info.elem_l_))
329 else if (Bar::has_interface (info.elem_l_))
333 else if (Rest::has_interface (info.elem_l_))
339 if (Stem::has_interface (info.elem_l_))
341 Item* stem_l = dynamic_cast<Item *> (info.elem_l_);
343 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
346 programming_error ("Stem must have rhythmic structure");
351 Don't (start) auto-beam over empty stems; skips or rests
353 if (!Stem::heads_i (stem_l))
360 if (Stem::beam_l (stem_l))
367 int durlog = unsmob_duration (rhythmic_req->get_mus_property ("duration"))->duration_log ();
377 if shortest duration would change
378 reconsider ending/starting beam first.
380 Moment mom = unsmob_duration (rhythmic_req->get_mus_property ("duration"))->length_mom ();
381 consider_end_and_begin (mom);
384 if (mom < shortest_mom_)
386 if (stem_l_arr_p_->size ())
389 consider_end_and_begin (shortest_mom_);
395 Moment now = now_mom ();
397 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
399 stem_l_arr_p_->push (stem_l);
401 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
406 Auto_beam_engraver::junk_beam ()
408 assert (stem_l_arr_p_);
410 delete stem_l_arr_p_;
414 shortest_mom_ = Moment (1, 8);
418 Auto_beam_engraver::process_acknowledged ()
422 Moment now = now_mom ();
423 if ((extend_mom_ < now)
424 || ((extend_mom_ == now) && (last_add_mom_ != now )))
428 else if (!stem_l_arr_p_->size ())