2 auto-beam-engraver.cc -- implement Auto_beam_engraver
4 source file of the GNU LilyPond music typesetter
6 (c) 1999--2006 Jan Nieuwenhuizen <janneke@gnu.org>
10 #include "beaming-pattern.hh"
13 #include "duration.hh"
14 #include "engraver.hh"
18 #include "stream-event.hh"
22 #include "translator.icc"
24 class Auto_beam_engraver : public Engraver
26 TRANSLATOR_DECLARATIONS (Auto_beam_engraver);
29 void stop_translation_timestep ();
30 void start_translation_timestep ();
31 void process_music ();
32 virtual void finalize ();
33 virtual void derived_mark () const;
35 DECLARE_ACKNOWLEDGER (rest);
36 DECLARE_ACKNOWLEDGER (beam);
37 DECLARE_ACKNOWLEDGER (bar_line);
38 DECLARE_ACKNOWLEDGER (stem);
39 DECLARE_TRANSLATOR_LISTENER (beam_forbid);
41 void process_acknowledged ();
44 bool test_moment (Direction, Moment);
45 void consider_begin (Moment);
46 void consider_end (Moment);
47 Spanner *create_beam ();
51 bool is_same_grace_state (Grob *e);
54 Stream_event *forbid_;
56 shortest_mom is the shortest note in the beam.
59 Spanner *finished_beam_;
60 vector<Item*> *stems_;
62 int process_acknowledged_count_;
65 Projected ending of the beam we're working on.
68 Moment beam_start_moment_;
69 Moment beam_start_location_;
71 bool subdivide_beams_;
74 // We act as if beam were created, and start a grouping anyway.
75 Beaming_pattern *grouping_;
78 Beaming_pattern *finished_grouping_;
80 void check_bar_property ();
84 Auto_beam_engraver::derived_mark () const
86 scm_gc_mark (beam_settings_);
90 Auto_beam_engraver::check_bar_property ()
92 /* Duplicated from process_music (), since
93 Repeat_acknowledge_engraver::process_music () may also set whichBar. */
95 Moment now = now_mom ();
96 if (scm_is_string (get_property ("whichBar"))
97 && beam_start_moment_ < now)
99 consider_end (shortest_mom_);
105 Auto_beam_engraver::process_music ()
107 if (scm_is_string (get_property ("whichBar")))
109 consider_end (shortest_mom_);
115 consider_end (shortest_mom_);
120 Auto_beam_engraver::Auto_beam_engraver ()
123 process_acknowledged_count_ = 0;
125 shortest_mom_ = Moment (Rational (1, 8));
127 finished_grouping_ = 0;
129 beam_settings_ = SCM_EOL;
132 IMPLEMENT_TRANSLATOR_LISTENER (Auto_beam_engraver, beam_forbid);
134 Auto_beam_engraver::listen_beam_forbid (Stream_event *ev)
136 ASSIGN_EVENT_ONCE (forbid_, ev);
140 Auto_beam_engraver::test_moment (Direction dir, Moment test)
142 return scm_call_3 (get_property ("autoBeamCheck"),
143 context ()->self_scm (),
145 test.smobbed_copy ())
150 Auto_beam_engraver::consider_begin (Moment test_mom)
152 bool on = to_boolean (get_property ("autoBeaming"));
156 bool b = test_moment (START, test_mom);
163 Auto_beam_engraver::consider_end (Moment test_mom)
167 /* Allow already started autobeam to end:
168 don't check for autoBeaming */
169 bool b = test_moment (STOP, test_mom);
176 Auto_beam_engraver::create_beam ()
178 if (to_boolean (get_property ("skipTypesetting")))
181 for (vsize i = 0; i < stems_->size (); i++)
182 if (Stem::get_beam ((*stems_)[i]))
186 Can't use make_spanner_from_properties() because we have to use
189 Spanner *beam = new Spanner (beam_settings_,
190 context ()->get_grob_key ("Beam"));
192 for (vsize i = 0; i < stems_->size (); i++)
193 Beam::add_stem (beam, (*stems_)[i]);
195 announce_grob (beam, (*stems_)[0]->self_scm ());
201 Auto_beam_engraver::begin_beam ()
203 if (stems_ || grouping_)
205 programming_error ("already have autobeam");
209 stems_ = new vector<Item*>;
210 grouping_ = new Beaming_pattern ();
211 beam_settings_ = updated_grob_properties (context (), ly_symbol2scm ("Beam"));
213 beam_start_moment_ = now_mom ();
215 = robust_scm2moment (get_property ("measurePosition"), Moment (0));
219 Auto_beam_engraver::junk_beam ()
228 beam_settings_ = SCM_EOL;
230 shortest_mom_ = Moment (Rational (1, 8));
234 Auto_beam_engraver::end_beam ()
236 if (stems_->size () < 2)
240 finished_beam_ = create_beam ();
244 announce_end_grob (finished_beam_, SCM_EOL);
245 finished_grouping_ = grouping_;
250 beam_settings_ = SCM_EOL;
253 shortest_mom_ = Moment (Rational (1, 8));
257 Auto_beam_engraver::typeset_beam ()
261 if (!finished_beam_->get_bound (RIGHT))
262 finished_beam_->set_bound (RIGHT, finished_beam_->get_bound (LEFT));
264 finished_grouping_->beamify (context ());
265 Beam::set_beaming (finished_beam_, finished_grouping_);
268 delete finished_grouping_;
269 finished_grouping_ = 0;
274 Auto_beam_engraver::start_translation_timestep ()
276 process_acknowledged_count_ = 0;
278 don't beam over skips
282 Moment now = now_mom ();
283 if (extend_mom_ < now)
290 Auto_beam_engraver::stop_translation_timestep ()
296 Auto_beam_engraver::finalize ()
298 /* finished beams may be typeset */
300 /* but unfinished may need another announce/acknowledge pass */
307 Auto_beam_engraver::acknowledge_beam (Grob_info info)
310 check_bar_property ();
316 Auto_beam_engraver::acknowledge_bar_line (Grob_info info)
319 check_bar_property ();
325 Auto_beam_engraver::acknowledge_rest (Grob_info info)
328 check_bar_property ();
334 Auto_beam_engraver::acknowledge_stem (Grob_info info)
336 check_bar_property ();
337 Item *stem = dynamic_cast<Item *> (info.grob ());
338 Stream_event *ev = info.ultimate_event_cause ();
339 if (!ev->in_event_class ("rhythmic-event"))
341 programming_error ("stem must have rhythmic structure");
346 Don't (start) auto-beam over empty stems; skips or rests
348 if (!Stem::head_count (stem))
355 if (Stem::get_beam (stem))
362 int durlog = unsmob_duration (ev->get_property ("duration"))->duration_log ();
374 Moment now = now_mom ();
375 if (bool (beam_start_location_.grace_part_) != bool (now.grace_part_))
378 Moment dur = unsmob_duration (ev->get_property ("duration"))->get_length ();
381 consider_begin (dur);
383 if (dur < shortest_mom_)
389 grouping_->add_stem (now - beam_start_moment_ + beam_start_location_,
391 stems_->push_back (stem);
393 extend_mom_ = max (extend_mom_, now) + get_event_length (ev);
397 Auto_beam_engraver::process_acknowledged ()
399 if (extend_mom_ > now_mom ())
402 if (!process_acknowledged_count_)
404 consider_end (shortest_mom_);
405 consider_begin (shortest_mom_);
407 else if (process_acknowledged_count_ > 1)
411 Moment now = now_mom ();
412 if ((extend_mom_ < now)
413 || ((extend_mom_ == now) && (last_add_mom_ != now)))
415 else if (!stems_->size ())
420 process_acknowledged_count_++;
423 ADD_ACKNOWLEDGER (Auto_beam_engraver, stem);
424 ADD_ACKNOWLEDGER (Auto_beam_engraver, bar_line);
425 ADD_ACKNOWLEDGER (Auto_beam_engraver, beam);
426 ADD_ACKNOWLEDGER (Auto_beam_engraver, rest);
427 ADD_TRANSLATOR (Auto_beam_engraver,
428 /* doc */ "Generate beams based on measure characteristics and observed "
429 "Stems. Uses beatLength, measureLength and measurePosition to decide "
430 "when to start and stop a beam. Overriding beaming is done through "
431 "@ref{Stem_engraver} properties @code{stemLeftBeamCount} and "
432 "@code{stemRightBeamCount}. ",