3 auto-beam-engraver.cc -- implement Auto_beam_engraver
5 source file of the GNU LilyPond music typesetter
7 (c) 1999--2000 Jan Nieuwenhuizen <janneke@gnu.org>
11 #include "musical-request.hh"
15 #include "engraver-group-engraver.hh"
18 #include "engraver.hh"
20 class Auto_beam_engraver : public Engraver
23 Auto_beam_engraver ();
24 VIRTUAL_COPY_CONS (Translator);
27 virtual bool do_try_music (Music*);
28 virtual void do_pre_move_processing ();
29 virtual void do_post_move_processing ();
30 virtual void do_removal_processing ();
31 virtual void acknowledge_element (Score_element_info);
32 virtual void do_process_music ();
33 virtual void process_acknowledged ();
36 void consider_end_and_begin (Moment test_mom);
37 Beam* create_beam_p ();
40 bool same_grace_state_b (Score_element* e);
44 Beam *finished_beam_p_;
45 Link_array<Item>* stem_l_arr_p_;
49 Moment beam_start_moment_;
50 Moment beam_start_location_;
52 // We act as if beam were created, and start a grouping anyway.
53 Beaming_info_list*grouping_p_;
54 Beaming_info_list*finished_grouping_p_;
60 ADD_THIS_TRANSLATOR (Auto_beam_engraver);
64 TODO: remove all references to Timing_engraver; should read properties.
67 Auto_beam_engraver::Auto_beam_engraver ()
70 shortest_mom_ = Moment (1, 8);
72 finished_grouping_p_ = 0;
78 Auto_beam_engraver::do_try_music (Music*)
84 Auto_beam_engraver::do_process_music ()
86 consider_end_and_begin (shortest_mom_);
90 Auto_beam_engraver::consider_end_and_begin (Moment test_mom)
92 Moment one_beat = *unsmob_moment( get_property ("beatLength"));
94 int num = *unsmob_moment (get_property("measureLength")) / one_beat;
95 int den = one_beat.den_i ();
98 String time_str = String ("time") + to_str (num) + "_" + to_str (den);
101 if (test_mom.num () != 1)
102 type_str = to_str (test_mom.num ());
103 if (test_mom.den () != 1)
104 type_str = type_str + "_" + to_str (test_mom.den ());
109 FIXME: SHOULD USE ALIST
114 Determine end moment for auto beaming (and begin, mostly 0==anywhere)
115 In order of increasing priority:
118 ii. time<num>_<den>beamAutoEnd
119 iii. time<num>_<den>beamAutoEnd<type>
126 [to be defined in config file]
127 i. easy catch-all rule
128 ii. exceptions for time signature
129 iii. exceptions for time signature, for specific duration type
133 v. override for specific duration type
135 The user overrides should be required for common cases.
139 first guess: begin beam at any position
141 Moment begin_mom (0);
143 first guess: end beam at end of beat
145 SCM one (get_property ("beatLength"));
148 if (unsmob_moment (one))
149 end_mom = *unsmob_moment (one);
152 second guess: property generic time exception
154 SCM begin = get_property ((time_str + "beamAutoBegin").ch_C());
155 if (unsmob_moment (begin))
156 begin_mom = * unsmob_moment (begin);
158 SCM end = get_property ((time_str + "beamAutoEnd").ch_C());
159 if (unsmob_moment (end))
160 end_mom = * unsmob_moment (end);
163 third guess: property time exception, specific for duration type
165 if (type_str.length_i ())
167 SCM end_mult = get_property ((time_str + "beamAutoEnd" + type_str).ch_C());
168 if (unsmob_moment (end_mult))
169 end_mom = * unsmob_moment (end_mult);
171 SCM begin_mult = get_property ((time_str + "beamAutoBegin" + type_str).ch_C());
172 if (unsmob_moment (begin_mult))
173 begin_mom = * unsmob_moment (begin_mult);
177 fourth guess [user override]: property plain generic
179 begin = get_property ("beamAutoBegin");
180 if (unsmob_moment (begin))
181 begin_mom = * unsmob_moment (begin);
185 end = get_property ("beamAutoEnd");
186 if (unsmob_moment (end))
187 end_mom = * unsmob_moment (end);
190 fifth guess [user override]: property plain, specific for duration type
192 if (type_str.length_i ())
194 SCM end_mult = get_property ((String ("beamAutoEnd") + type_str).ch_C());
195 if (unsmob_moment (end_mult))
196 end_mom = * unsmob_moment (end_mult);
198 SCM begin_mult = get_property ((String ("beamAutoBegin") + type_str).ch_C());
199 if (unsmob_moment (begin_mult))
200 begin_mom = * unsmob_moment (begin_mult);
205 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (end_mom);
209 if (stem_l_arr_p_ && !r)
213 Allow already started autobeam to end
215 SCM on = get_property ("noAutoBeaming");
220 r = unsmob_moment (get_property ("measurePosition"))->mod_rat (begin_mom);
221 if (!stem_l_arr_p_ && (!begin_mom || !r))
227 Auto_beam_engraver::begin_beam ()
229 assert (!stem_l_arr_p_);
230 stem_l_arr_p_ = new Link_array<Item>;
231 assert (!grouping_p_);
232 grouping_p_ = new Beaming_info_list;
233 beam_start_moment_ = now_mom ();
234 beam_start_location_ = *unsmob_moment (get_property ("measurePosition"));
238 Auto_beam_engraver::create_beam_p ()
240 Beam* beam_p = new Beam (get_property ("basicBeamProperties"));
242 for (int i = 0; i < stem_l_arr_p_->size (); i++)
245 watch out for stem tremolos and abbreviation beams
247 if (Stem::beam_l ((*stem_l_arr_p_)[i]))
251 beam_p->add_stem ((*stem_l_arr_p_)[i]);
254 announce_element (Score_element_info (beam_p, 0));
260 Auto_beam_engraver::end_beam ()
262 if (stem_l_arr_p_->size () < 2)
268 finished_beam_p_ = create_beam_p ();
269 if (finished_beam_p_)
270 finished_grouping_p_ = grouping_p_;
271 delete stem_l_arr_p_;
274 shortest_mom_ = Moment (1, 8);
279 Auto_beam_engraver::typeset_beam ()
281 if (finished_beam_p_)
283 finished_grouping_p_->beamify ();
284 finished_beam_p_->set_beaming (finished_grouping_p_);
285 typeset_element (finished_beam_p_);
286 finished_beam_p_ = 0;
288 delete finished_grouping_p_;
289 finished_grouping_p_= 0;
294 Auto_beam_engraver::do_post_move_processing ()
297 don't beam over skips
301 Moment now = now_mom ();
302 if (extend_mom_ < now)
310 Auto_beam_engraver::do_pre_move_processing ()
316 Auto_beam_engraver::do_removal_processing ()
318 /* finished beams may be typeset */
320 /* but unfinished may need another announce/acknowledge pass */
326 Auto_beam_engraver::same_grace_state_b (Score_element* e)
328 bool gr = e->get_elt_property ("grace") == SCM_BOOL_T;
329 SCM wg =get_property ("weAreGraceContext");
330 return (to_boolean (wg)) == gr;
334 Auto_beam_engraver::acknowledge_element (Score_element_info info)
336 if (!same_grace_state_b (info.elem_l_))
341 if (Beam *b = dynamic_cast<Beam *> (info.elem_l_))
345 else if (Bar::has_interface (info.elem_l_))
349 else if (Rest::has_interface (info.elem_l_))
355 if (Stem::has_interface (info.elem_l_))
357 Item* stem_l = dynamic_cast<Item *> (info.elem_l_);
359 Rhythmic_req *rhythmic_req = dynamic_cast <Rhythmic_req *> (info.req_l_);
362 programming_error ("Stem must have rhythmic structure");
367 Don't (start) auto-beam over empty stems; skips or rests
369 if (!Stem::heads_i (stem_l))
376 if (!Stem::beam_l (stem_l))
383 int durlog =rhythmic_req->duration_.durlog_i_;
392 if shortest duration would change
393 reconsider ending/starting beam first.
395 Moment mom = rhythmic_req->duration_.length_mom ();
396 consider_end_and_begin (mom);
399 if (mom < shortest_mom_)
401 if (stem_l_arr_p_->size ())
404 consider_end_and_begin (shortest_mom_);
410 Moment now = now_mom ();
412 grouping_p_->add_stem (now - beam_start_moment_ + beam_start_location_,
414 stem_l_arr_p_->push (stem_l);
416 extend_mom_ = extend_mom_ >? now + rhythmic_req->length_mom ();
421 Auto_beam_engraver::junk_beam ()
423 assert (stem_l_arr_p_);
425 delete stem_l_arr_p_;
429 shortest_mom_ = Moment (1, 8);
433 Auto_beam_engraver::process_acknowledged ()
437 Moment now = now_mom ();
438 if ((extend_mom_ < now)
439 || ((extend_mom_ == now) && (last_add_mom_ != now )))
443 else if (!stem_l_arr_p_->size ())